### Setup and Run Pre-commit Hooks Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/README.adoc Steps to install the pre-commit tool, install git hooks in the local repository, and run all pre-commit checks on all files. ```shell # Do once on your system pip3 install pre-commit ``` ```shell # Do once in local repo pre-commit install ``` ```shell pre-commit run --all-files ``` -------------------------------- ### SoC IOMMU Integration Example Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/src/iommu_intro.adoc Depicts a typical System on a Chip (SoC) architecture featuring RISC-V harts, memory controllers, IO devices, and two IOMMU instances, illustrating their placement and connectivity through IO Bridges and Root Ports. ```text Example of IOMMUs integration in SoC. (Visual representation of the diagram is described in the text) ``` -------------------------------- ### RISC-V IOMMU Command Queue Programming Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/src/iommu_sw_guidelines.adoc Guides the programming of the command queue. This involves determining the queue size, allocating a memory buffer, calculating its physical page number and log2 size, and programming the command queue base pointer, size, and control registers. ```C /* Determine N (power of two) for command queue entries. */ /* Allocate N x 16-bytes buffer, aligned to max(4KiB, N x 16-bytes). */ /* Let k = log2(N), B = physical page number (PPN) of the buffer. */ /* Program registers: */ /* temp_cqb_var.PPN = B */ /* temp_cqb_var.LOG2SZ-1 = (k - 1) */ /* cqb = temp_cqb_var */ /* cqt = 0 */ /* cqcsr.cqen = 1 */ /* Poll on cqcsr.cqon until it reads 1. */ ``` -------------------------------- ### Get Attributes from Request - `get_attribs_from_req` Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/iommu_ref_model/README.md Extracts read, write, execute, and privilege attributes from a request object. ```C void get_attribs_from_req(hb_to_iommu_req_t *req, uint8_t *read, uint8_t *write, uint8_t *exec, uint8_t *priv) ``` -------------------------------- ### RISC-V IOMMU Initialization Steps Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/src/iommu_sw_guidelines.adoc Details the sequence of operations required to initialize the IOMMU. This includes reading capabilities, checking version compatibility, configuring feature controls, handling interrupt signaling, and setting up various queues and pointers. ```C /* 1. Read the `capabilities` register to discover the capabilities of the IOMMU. */ /* 2. Stop and report failure if `capabilities.version` is not supported. */ /* 3. Read the feature control register (`fctl`). */ /* 4. Stop and report failure if big-endian memory access is needed and `capabilities.END` is 0 and `fctl.BE` is 0. */ /* 5. If big-endian memory access is needed and `capabilities.END` is 1, set `fctl.BE` to 1 if not already set. */ /* 6. Stop and report failure if wired-signaled-interrupts are needed and `capabilities.IGS` is not `WSI`. */ /* 7. If wired-signaled-interrupts are needed and `capabilities.IGS` is `BOTH`, set `fctl.WSI` to 1 if not already set. */ /* 8. Stop and report failure if other required capabilities are not supported. */ /* 9. Program interrupt vectors using the `icvec` register. */ /* 10. If using wired interrupts, configure the platform level interrupt controller. */ /* 11. If using MSI, configure `msi_addr_V`, `msi_data_V`, and `msi_vec_ctl_V` registers. */ ``` -------------------------------- ### Build RISC-V IOMMU Documentation Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/README.adoc Command to navigate into the repository directory and initiate the documentation build process using the Makefile. ```shell cd ./riscv-iommu && make build ``` -------------------------------- ### IOMMU Address Translation Diagram Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/src/iommu_intro.adoc Illustrates the address translation process within an IOMMU for a Guest OS environment, showing the interaction between devices, first-stage and second-stage page tables, and main memory. ```ditaa +---------------------------------------------------+ | Main memory | | | | | | ^ ^ ^ | +------|------------------|-----------------|-------+ | | | +------|------------------|-----------------|-------+ | | IOMMU | | | | +------------+ +------------+ | | | | device D1 | | device D2 | | | | |2nd−stage PT| |2nd−stage PT| | | | +------------+ +------------+ | | | ^ ^ | | | | | | | | +------------+ | +------------+ | | | device D1 | | | device D3 | | | |1st−stage PT| | |1st−stage PT| | | +------------+ | +------------+ | | ^ | ^ | +------|------------------|-----------------|-------+ | | | +-----------+ +-----------+ +-----------+ | | Device D1 | | Device D2 | | Device D3 | | +-----------+ +-----------+ +-----------+ | ``` -------------------------------- ### RISC-V IOMMU Address Translation Concepts Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/src/iommu_intro.adoc Explains the different address translation stages and their analogy to RISC-V hart configurations. Covers VA, GPA, SPA, and memory protection enforcement. ```APIDOC RISC-V IOMMU Address Translation: - **Single-Stage Translation**: - Analogous to a RISC-V hart with single-stage address translation. - IOVA is a VA. - **Two-Stage Translation**: - In effect when neither stage's virtual memory scheme is `Bare`. - First stage: Translates VA to GPA. - Second stage: Translates GPA to SPA. - Each stage enforces configured memory protections. - Typically used when device control is passed to a VM, allowing Guest OS to constrain device memory access. - Analogous to a RISC-V hart with two-stage translation (G-stage and VS-stage active). - **Address Translation Cache (IOATC)**: - Similar to CPU MMU TLBs to mitigate overhead. - IOMMU may employ IOATC to cache address translations. - Software mechanisms exist to synchronize IOATC with memory-resident data structures. - **Device-Side ATC (DevATC)**: - Some devices participate in translation, providing their own ATC. - Shares translation caching responsibility, reducing IOATC 'thrashing'. - Device can size DevATC for performance and prefetch translations. - Requires cooperation between device and IOMMU via a protocol. - **PCIe ATS (Address Translation Services)**: - Protocol used by devices to request translations for DevATC and synchronize with software updates. - **I/O Page Faults**: - Enables dynamic page residency management. - Device may implement Page Request Interface (PRI) to request memory manager to make a page resident if a translation target is unavailable. ``` -------------------------------- ### IOMMU Command Ordering and Synchronization Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/src/iommu_in_memory_queues.adoc Explains how IOMMU commands are fetched and executed, and the guarantees provided by IOFENCE.C regarding memory access ordering and completion. ```APIDOC IOMMU Command Execution: - Commands are fetched in order but may execute out of order. - `cqh` advancement is not a guarantee of command execution or commit. IOFENCE.C Guarantees: - A `IOFENCE.C` command completion (indicated by `cqh` advancing past its index) guarantees that all previous commands fetched from the CQ have been completed and committed. - If `IOFENCE.C` times out waiting for previous commands, `cmd_to` bit in `cqcsr` is set. `cqh` then holds the index of the timed-out `IOFENCE.C`. Memory Access Ordering: - `PR` bit (1): Requests IOMMU to ensure all previous read requests from devices are committed to a global ordering point, observable by all RISC-V harts and IOMMUs. - `PW` bit (1): Requests IOMMU to ensure all previous write requests from devices are committed to a global ordering point, observable by all RISC-V harts and IOMMUs. - `WSI` bit (1): Causes a wired-interrupt on completion of `IOFENCE.C` by setting `cqcsr.fence_w_ip`. Synchronization for Memory Reclamation: - Before reclaiming memory, software should ensure previous IOMMU-processed accesses are committed globally. - Sequence: Update page tables to disallow device access, then use `IOTINVAL.VMA` or `IOTINVAL.GVMA`. - If reclaimed memory was read-accessible: Request ordering of all previous reads. - If reclaimed memory was write-accessible: Request ordering of all previous reads and writes. Limitations: - `IOFENCE.C` with `PR`/`PW` only guarantees ordering for requests *already processed* by the IOMMU. - For in-flight requests not yet processed, an interconnect-specific fence action is needed (e.g., PCIe completion response). - Ordering guarantees apply to main-memory accesses; I/O memory ordering is implementation-defined. Related Commands: - `IOTINVAL.VMA`, `IOTINVAL.GVMA`: Used for synchronizing IOMMU with page table updates during memory reclamation. - `ATS.INVAL`: Specified to have a timeout. ``` -------------------------------- ### Clone and Initialize RISC-V IOMMU Repository Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/README.adoc Commands to clone the RISC-V IOMMU repository, including submodules, and initialize them for use. This ensures all necessary components are fetched. ```shell git clone --recurse-submodules https://github.com/riscv-non-isa/riscv-iommu.git ``` ```shell git clone --recurse-submodules https://github.com/riscv-non-isa/riscv-iommu.git && cd riscv-iommu && git submodule update --init --recursive ``` -------------------------------- ### Run Test Application (Bash) Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/iommu_ref_model/README.md Executes the test application for the RISC-V IOMMU reference model. This command builds and runs the test suite, providing status and coverage reports on the reference model's implementation. ```bash make run ``` -------------------------------- ### RISC-V IOMMU Page-Request Queue Programming Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/src/iommu_sw_guidelines.adoc Explains how to program the page-request queue. This involves determining the queue size, allocating a memory buffer, calculating its physical page number and log2 size, and programming the page-request queue base pointer, head, and control registers. ```C /* Determine N (power of two) for page-request queue entries. */ /* Allocate N x 16-bytes buffer, aligned to max(4KiB, N x 16-bytes). */ /* Let k = log2(N), B = physical page number (PPN) of the buffer. */ /* Program registers: */ /* temp_pqb_var.PPN = B */ /* temp_pqb_var.LOG2SZ-1 = (k - 1) */ /* pqb = temp_pqb_var */ /* pqh = 0 */ /* pqcsr.pqen = 1 */ /* Poll on pqcsr.pqon until it reads 1. */ ``` -------------------------------- ### RISC-V IOMMU DDT Initialization Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/src/iommu_sw_guidelines.adoc Configures the IOMMU's Device Directory Table (DDT) by determining the appropriate mode (M) based on the data width (Dw) and IOMMU device-context format. It involves programming the ddtp register with the determined mode and the physical page number (PPN) of the allocated memory. ```APIDOC Determine IOMMU mode (M) based on Dw and device-context format: Extended-format device-contexts: If Dw <= 6-bits and 1LVL supported then M = 1LVL If Dw <= 15-bits and 2LVL supported then M = 2LVL If Dw <= 24-bits and 3LVL supported then M = 3LVL Base-format device-contexts: If Dw <= 7-bits and 1LVL supported then M = 1LVL If Dw <= 16-bits and 2LVL supported then M = 2LVL If Dw <= 24-bits and 3LVL supported then M = 3LVL Program the ddtp register: temp_ddtp_var.iommu_mode = M temp_ddtp_var.PPN = B (PPN of allocated memory) ddtp = temp_ddtp_var ``` -------------------------------- ### IOMMU Fault Handling and Transaction Aborting Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/src/iommu_hw_guidelines.adoc Describes how the IOMMU handles faults signaled by PMA/PMP checkers and how transactions are aborted. Covers signaling of IOMMU-initiated accesses, write transaction handling, and read transaction completion with status codes. ```APIDOC Fault Handling: - IO bridge may invoke PMA/PMP checkers on memory accesses from IO devices or IOMMU. - If a memory access violates PMA/PMP, the IO bridge may abort the access. Transaction Aborting: - IOMMU-initiated implicit memory access faults: - IO bridge signals faults to the IOMMU (signaling details are implementation-defined). - Write transactions: - IO bridge may discard the write (discard details are implementation-defined). - For protocols requiring write responses (e.g., AXI), a response (e.g., SLVERR on BRESP) may be generated. - For PCIe, posted writes are discarded without response. - Read transactions: - IO bridge may provide a completion with implementation-defined data (e.g., all 0s or 1s). - A status code may be returned (e.g., SLVERR on RRESP for AXI, 'Unsupported Request' or 'Completer Abort' for PCIe). ``` -------------------------------- ### Handle Page Request - `handle_page_request` Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/iommu_ref_model/README.md Sends a page request message to the IOMMU from the test bench. ```C void handle_page_request(ats_msg_t *pr) ``` -------------------------------- ### Page-Request-Queue Base Register (PQB) Fields Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/src/iommu_registers.adoc Details the Page-Request-Queue Base Register (PQB), which configures the base address and size of the page-request queue. Includes bit assignments, read/write attributes, and functional descriptions for each field. ```APIDOC Page-Request-Queue Base Register (PQB): This 64-bit register (WARL) holds the PPN of the root page of the page-request-queue and number of entries in the queue. Each "Page Request" message is 16 bytes. The IOMMU behavior on writing `pqb` when `pqcsr.busy` or `pqon` bits are 1 is `UNSPECIFIED`. The software recommended sequence to change `pqb` is to first disable the page-request-queue by clearing `pqen` and wait for both `pqcsr.busy` and `pqon` to be 0 before changing the `pqb`. The status of bits `31:pqb.LOG2SZ` in `pqh` following a write to `pqb` is 0 and the bits `pqb.LOG2SZ-1:0` in `pqh` assume a valid but otherwise `UNSPECIFIED` value. Register Fields: - `LOG2SZ-1` (Bits 4:0): The `LOG2SZ-1` field holds the number of entries in the page-request-queue as a log-to-base-2 minus 1. A value of 0 indicates a queue of 2 entries. Each page-request is 16-bytes. If the page-request-queue has 256 or fewer entries then the base address of the queue is always aligned to 4-KiB. If the page-request-queue has more than 256 entries then the page-request-queue base address must be naturally aligned to `2^LOG2SZ^ x 16`. (Attribute: WARL) - `reserved` (Bits 9:5): Reserved for standard use. (Attribute: WPRI) ``` -------------------------------- ### RISC-V IOMMU: Locate Process-context Process Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/src/iommu_data_structures.adoc Outlines the procedure for locating a Process-context using its `process_id`, leveraging information from the Device-context. This involves translating page table pointers (GPA to SPA) and traversing a Process Description Table (PDT). ```APIDOC APIDOC: GetProcessContext: Purpose: Locate the Process-context for a transaction using its `process_id`. Inputs: - `process_id`: Identifier for the process. - `DC.iohgatp`: Device-context's IO Host Gateway Address Translation and Protection structure. - `pdtp.ppn`: Process Data Table root page PPN from `DC`. - `pdtp.MODE`: Mode determining the number of levels (e.g., PD20, PD17, PD8). - `PDI[i]`: Process Data Table Index at level `i`. Process: 1. Initialize `a = pdtp.PPN x 2^12^` and `i = LEVELS - 1`. 2. If `DC.iohgatp.mode != Bare`: - `a` is a GPA. Invoke second-stage address translation for `a` to get SPA. - If faults occur during translation, stop and report the fault. - Use the translated `a` for subsequent steps. 3. If `i == 0`, proceed to step 9. 4. Load `pdte` from address `a + PDI[i] x 8`. - Check for PMA/PMP violations (cause = 265). - Check for data corruption (cause = 269). 5. If `pdte.V == 0`, stop and report "PDT entry not valid" (cause = 266). 6. If reserved bits are set in `pdte`, stop and report "PDT entry misconfigured" (cause = 267). 7. Decrement `i` and update `a = pdte.PPN x 2^12^`. Go to step 2. Output: Successfully located Process-context. ``` -------------------------------- ### Page-request-queue tail (pqt) Register Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/src/iommu_registers.adoc Documentation for the Page-request-queue tail (`pqt`) register. This 32-bit register indicates where the IOMMU writes the next page-request. ```APIDOC Page-request-queue tail (`pqt`): Type: 32-bit register (RO) Fields: `index` (31:0): RO. Holds the index into the page-request-queue where IOMMU writes the next "Page Request" message. ``` -------------------------------- ### RISC-V IOMMU Context Identifiers and MSI Handling Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/src/iommu_intro.adoc Details software-defined context identifiers (GSCID, PSCID) for managing virtual address spaces and how the IOMMU handles Message-Signaled Interrupts (MSI) for virtual machines. ```APIDOC RISC-V IOMMU Context Management and Interrupts: - **Guest Soft-Context Identifier (GSCID)**: - Software-defined identifier. - Configured by software to indicate a collection of devices assigned to the same VM. - Devices access a common virtual address space. - IOMMU may use GSCID to tag IOATC entries, avoiding duplication and simplifying invalidation. - **Process Soft-Context Identifier (PSCID)**: - Software-defined identifier. - Configured by software to identify a collection of processes sharing a common virtual address space. - IOMMU may use PSCID to tag IOATC entries. - **Message-Signaled Interrupts (MSI) Handling**: - In systems with IMSIC (Incoming Message-Signaled Interrupt Controller). - IOMMU can be programmed by hypervisor to direct MSIs from guest OS devices to a guest interrupt file in IMSIC. - MSIs are memory writes and subject to IOMMU address translation. - RISC-V Advanced Interrupt Architecture (AIA) requires IOMMUs to treat MSIs directed to VMs specially. - Special handling simplifies software and allows optional support for memory-resident interrupt files. - Device context is configured with parameters to identify memory accesses to a virtual interrupt file. - These accesses are translated using an MSI address translation table configured by software in the device context. ``` -------------------------------- ### RISC-V IOMMU Fault Queue Programming Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/src/iommu_sw_guidelines.adoc Details the process for programming the fault queue. This includes determining the queue size, allocating a memory buffer, calculating its physical page number and log2 size, and programming the fault queue base pointer, head, and control registers. ```C /* Determine N (power of two) for fault queue entries. */ /* Allocate N x 32-bytes buffer, aligned to max(4KiB, N x 32-bytes). */ /* Let k = log2(N), B = physical page number (PPN) of the buffer. */ /* Program registers: */ /* temp_fqb_var.PPN = B */ /* temp_fqb_var.LOG2SZ-1 = (k - 1) */ /* fqb = temp_fqb_var */ /* fqh = 0 */ /* fqcsr.fqen = 1 */ /* Poll on fqcsr.fqon until it reads 1. */ ``` -------------------------------- ### PCIe Device Integration for IOMMU Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/src/iommu_hw_guidelines.adoc Guidelines for integrating an IOMMU as a PCIe device. Specifies the required PCIe Base Class, Sub-Class, and Programming Interface. Details BAR mapping for registers and support for MSI/MSI-X capabilities. ```APIDOC PCIe Device Integration: - PCIe Base Class: 08h - PCIe Sub-Class: 06h - PCIe Programming Interface: 00h Register Mapping: - IOMMU registers must be mapped as PCIe BAR mapped registers. Interrupt Support: - Recommended to support MSI-X capability. - MSI-X capability block must point to 'msi_cfg_tbl' in BAR mapped registers. - MSI-X PBA can be in the same or a different BAR. ``` -------------------------------- ### PCIe ATS Page Request Handling Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/src/iommu_data_structures.adoc Describes the IOMMU's process for handling PCIe ATS Page Request or Stop Marker messages, including device context lookup, queueing, and error conditions. ```APIDOC PCIe ATS Page Request Handling: - Message Types: "Page Request", "Stop Marker" (cite:[PCI]). - Initial Step: IOMMU locates device-context to check ATS and PRI enablement (`EN_ATS`, `EN_PRI`). - If ATS and PRI Enabled (`EN_ATS`=1, `EN_PRI`=1): - IOMMU queues message into in-memory queue: `page-request-queue` (`PQ`). - Software handler may generate "Page Request Group Response" message. - Error Conditions for PQ: - Queue disabled. - Queue full. - IOMMU access faults when accessing queue memory. - These conditions specified in <>. - If `ddtp.iommu_mode` is `Bare` or `Off`: - IOMMU cannot locate device-context for requester. - If `EN_PRI`=0, `EN_ATS`=0, or unable to locate `DC` for `EN_PRI` config, or request not queued to `PQ`: - IOMMU behavior depends on the type of "Page Request". ``` -------------------------------- ### RISC-V IOMMU: A/D Bit Updates and Page Promotions Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/src/iommu_sw_guidelines.adoc Covers handling of Accessed (A) and Dirty (D) bit updates and page promotions in RISC-V IOMMU. If hardware manages A/D bits, software must invalidate cached PTEs after clearing these bits. Page promotions require careful handling to avoid multiple cached entries, potentially necessitating PTE clearing and `IOTINVAL` commands, especially when attributes differ. ```APIDOC A/D Bit Updates: - When hardware manages A/D bits, clearing them in PTEs requires invalidating corresponding cached PTEs in the IOMMU. - Failure to invalidate may prevent the IOMMU from setting these bits on subsequent transactions. Page Promotions (Superpages): - Upgrading a page to a superpage without clearing the original non-leaf PTE's valid bit and invalidating cached translations can lead to multiple cached entries for one address. - Behavior is defined if only page size changes, but other attribute changes require clearing the V bit and executing `IOTINVAL`. - Ensure original and new PTEs have identical permission and memory type attributes for PTE updates without `IOTINVAL`. ``` -------------------------------- ### RISC-V IOMMU Reference Model Test Bench APIs (APIDOC) Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/iommu_ref_model/README.md These are the API functions that the RISC-V IOMMU reference model expects the test bench to implement. They facilitate memory access, global observability synchronization, and message passing between the IOMMU model and the test bench. ```APIDOC uint8_t read_memory(uint64_t address, uint8_t size, char *data) - Purpose: Reads data from memory for the reference model. - Parameters: - address: The memory address to read from. - size: The number of bytes to read. - data: A buffer to store the read data. - Returns: - Bit 0 set (1): Indicates an access violation. - Bit 1 set (2): Indicates data corruption. - 0: Successful read. uint8_t read_memory_for_AMO(uint64_t address, uint8_t size, char *data) - Purpose: Reads memory specifically for Atomic Memory Operations (AMO). - Parameters: - address: The memory address to read from. - size: The number of bytes to read. - data: A buffer to store the read data. - Returns: - Bit 0 set (1): Indicates an access violation. - Bit 1 set (2): Indicates data corruption. - 0: Successful read. - Note: Functionally identical to read_memory otherwise. uint8_t write_memory(char *data, uint64_t address, uint32_t size) - Purpose: Writes data to memory for the reference model. - Parameters: - data: A buffer containing the data to write. - address: The memory address to write to. - size: The number of bytes to write. - Returns: - Bit 0 set (1): Indicates an access violation. - 0: Successful write. void iommu_to_hb_do_global_observability_sync(uint8_t PR, uint8_t PW) - Purpose: Requests the test bench to perform global observability actions. - Parameters: - PR (uint8_t): If 1, perform actions for previous reads. - PW (uint8_t): If 1, perform actions for previous writes. - Behavior: Upon return, the IOMMU model assumes all requested previous operations are globally observed. void send_msg_iommu_to_hb(ats_msg_t *prgr) - Purpose: Sends an ATS message from the IOMMU to the test bench. - Parameters: - prgr: A pointer to the ATS message structure (e.g., Invalidation request or page request group response). - Behavior: Transmits messages for IOMMU-initiated communication with the host bridge. ``` -------------------------------- ### RISC-V IOMMU Interfaces Overview Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/src/iommu_intro.adoc Details the primary interfaces used by the RISC-V IOMMU for communication with other system components like the IO Bridge and host processors. ```APIDOC Host Interface: Purpose: Provides access to the IOMMU's memory-mapped registers for global configuration and maintenance operations by the host harts. Device Translation Request Interface: Purpose: Receives translation requests from the IO Bridge. Information Provided: - Hardware Identities: `device_id`, `process_id` (and its validity) for context retrieval. - IOVA: Input/Output Virtual Address. - Transaction Type: Translated or Untranslated. - Operation Type: Read, Write, Execute, or Atomic operation. - Privilege Mode: Associated privilege mode (defaults to User if not specified). - Access Size: Number of bytes accessed. - Opaque Information: Optional tags not interpreted by IOMMU but returned for correlation. Data Structure Interface: Purpose: Used by the IOMMU for implicit memory access to fetch data structures from main memory. Accessed Data Structures: - Device and Process Directories: For context information and translation rules. - Page Table Entries: First-stage and/or second-stage for IOVA translation. - In-Memory Queues: Command-queue, fault-queue, and page-request-queue for software interfacing. Device Translation Completion Interface: Purpose: Provides completion responses for address translations. Information Provided: - Status: Success or fault indication. - Supervisor Physical Address (SPA): If the request completed successfully. - Opaque Information: Tags associated with the request, if applicable. - Page-Based Memory Types (PBMT): Resolved between page table entries, if Svpbmt is supported. ATS Interface (Optional PCIe ATS Capability): Purpose: Communicates with ATS-capable endpoints via the PCIe Root Port. Functionality: - Receive ATS translation requests and return completions. - Send ATS "Invalidation Request" messages and receive "Invalidation Completion" messages. - Receive "Page Request" and "Stop Marker" messages, and send "Page Request Group Response" messages. ``` -------------------------------- ### Page-request-queue head (pqh) Register Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/src/iommu_registers.adoc Documentation for the Page-request-queue head (`pqh`) register. This 32-bit register holds the index for fetching the next page-request from the queue. ```APIDOC Page-request-queue head (`pqh`): Type: 32-bit register (RW) Fields: `index` (31:0): WARL. Holds the index into the page-request-queue from which software reads the next "Page Request" message. Only `LOG2SZ-1:0` bits are writable. ``` -------------------------------- ### RISC-V IOMMU: Locate Device-context Process Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/src/iommu_data_structures.adoc Details the step-by-step procedure for locating a Device-context using its `device_id`. This process involves traversing a Device Description Table (DDT) based on the IOMMU's mode and checking for various validity and configuration errors at each step. ```APIDOC APIDOC: GetDeviceContext: Purpose: Locate the Device-context for a transaction using its `device_id`. Parameters: - `device_id`: Identifier for the device. - `ddtp.PPN`: Physical Page Number from the Device Description Table Pointer. - `ddtp.iommu_mode`: IOMMU mode (e.g., 3LVL, 2LVL, 1LVL) determining the number of levels. - `DDI[i]`: Device Description Table Index at level `i`. - `PMA`, `PMP`: Physical Memory Access and Protection checks. - `capabilities.MSI_FLAT`: Capability flag affecting `DC_SIZE`. Process: 1. Initialize `a = ddtp.PPN x 2^12^` and `i = LEVELS - 1`. 2. If `i == 0`, proceed to step 8. 3. Load `ddte` from address `a + DDI[i] x 8`. - Check for PMA/PMP violations (cause = 257). - Check for data corruption (cause = 268). 4. If `ddte.V == 0`, stop and report "DDT entry not valid" (cause = 258). 5. If reserved bits are set in `ddte`, stop and report "DDT entry misconfigured" (cause = 259). 6. Decrement `i` and update `a = ddte.PPN x 2^12^`. Go to step 2. 7. Load `DC` (Device-context) of `DC_SIZE` bytes from address `a + DDI[0] * DC_SIZE`. - `DC_SIZE` is 64 bytes if `capabilities.MSI_FLAT` is 1, else 32 bytes. - Check for PMA/PMP violations (cause = 257). - Check for data corruption (cause = 268). 8. If `DC.tc.V == 0`, stop and report "DDT entry not valid" (cause = 258). 9. If `DC` is misconfigured (per <>), stop and report "DDT entry misconfigured" (cause = 259). Output: Successfully located Device-context (`DC`). ``` -------------------------------- ### IOVA Translation Process Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/src/iommu_data_structures.adoc Details the step-by-step procedure for translating an Input/Output Virtual Address (IOVA) through the RISC-V IOMMU. It covers conditional checks, device and process context lookups, and page table traversals, referencing specific fields and modes. ```APIDOC Process to translate an IOVA: 1. If ddtp.iommu_mode == Off then stop and report "All inbound transactions disallowed" (cause = 256). 2. If ddtp.iommu_mode == Bare and any of the following conditions hold then stop and report "Transaction type disallowed" (cause = 260); else go to step 20 with translated address same as the IOVA. - Transaction type is a Translated request (read, write/AMO, read-for-execute) or is a PCIe ATS Translation request. 3. If capabilities.MSI_FLAT is 0 then the IOMMU uses base-format device context. Let DDI[0] be device_id[6:0], DDI[1] be device_id[15:7], and DDI[2] be device_id[23:16]. 4. If capabilities.MSI_FLAT is 1 then the IOMMU uses extended-format device context. Let DDI[0] be device_id[5:0], DDI[1] be device_id[14:6], and DDI[2] be device_id[23:15]. 5. If the device_id is wider than that supported by the IOMMU mode, as determined by the following checks then stop and report "Transaction type disallowed" (cause = 260). - ddtp.iommu_mode is 2LVL and DDI[2] is not 0 - ddtp.iommu_mode is 1LVL and either DDI[2] is not 0 or DDI[1] is not 0 6. Use device_id to then locate the device-context (DC) as specified in <>. 7. If any of the following conditions hold then stop and report "Transaction type disallowed" (cause = 260). - Transaction type is a Translated request (read, write/AMO, read-for-execute) or is a PCIe ATS Translation request and DC.tc.EN_ATS is 0. - Transaction has a valid process_id and DC.tc.PDTV is 0. - Transaction has a valid process_id and DC.tc.PDTV is 1 and the process_id is wider than that supported by pdtp.MODE. - Transaction type is not supported by the IOMMU. 8. If request is a Translated request and DC.tc.T2GPA is 0 then the translation process is complete. Go to step 20. 9. If request is a Translated request and DC.tc.T2GPA is 1 then the IOVA is a GPA. Go to step 17 with following page table information: - Let A be the IOVA (the IOVA is a GPA). - Let iosatp.MODE be Bare - The PSCID value is not used when first-stage is Bare. - Let iohgatp be the value in the DC.iohgatp field 10. If DC.tc.PDTV is set to 0 then go to step 17 with the following page table information: - Let iosatp.MODE be the value in the DC.fsc.MODE field - Let iosatp.PPN be the value in the DC.fsc.PPN field - Let PSCID be the value in the DC.ta.PSCID field - Let iohgatp be the value in the DC.iohgatp field 11. If DPE is 1 and there is no process_id associated with the transaction then let process_id be the default value of 0. 12. If DPE is 0 and there is no process_id associated with the transaction then then go to step 17 with the following page table information: - Let iosatp.MODE be Bare - The PSCID value is not used when first-stage is Bare. - Let iohgatp be the value in the DC.iohgatp field 13. If DC.fsc.pdtp.MODE = Bare then go to step 17 with the following page table information: - Let iosatp.MODE be Bare - The PSCID value is not used when first-stage is Bare. - Let iohgatp be value in DC.iohgatp field 14. Locate the process-context (PC) as specified in <>. 15. if any of the following conditions hold then stop and report "Transaction type disallowed" (cause = 260). - The transaction requests supervisor privilege but PC.ta.ENS is not set. 16. Go to step 17 with the following page table information: - Let iosatp.MODE be the value in the PC.fsc.MODE field - Let iosatp.PPN be the value in the PC.fsc.PPN field - Let PSCID be the value in the PC.ta.PSCID field - Let iohgatp be the value in the DC.iohgatp field 17. Use the process specified in Section "Two-Stage Address Translation" of the RISC-V Privileged specification cite:[PRIV] to determine the GPA accessed by the transaction. If a fault is detected by the first stage address translation process then stop and report the fault. If the translation process is completed successfully then let A be the translated GPA. 18. If MSI address translations using MSI page tables is enabled (i.e., DC.msiptp.MODE != Off) then the MSI address translation process specified in <> is invoked. If the GPA A is not determined to be ``` -------------------------------- ### RISC-V IOMMU Command Opcodes Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/src/iommu_in_memory_queues.adoc Lists the defined and reserved opcodes for IOMMU commands, specifying their encoding and general description. This table helps in understanding the command categories. ```APIDOC IOMMU Command Opcodes: | opcode | Encoding | Description | |----------|----------|-------------------------------------------------| | IOTINVAL | 1 | IOMMU page-table cache invalidation commands. | | IOFENCE | 2 | IOMMU command-queue fence commands. | | IODIR | 3 | IOMMU directory cache invalidation commands. | | ATS | 4 | IOMMU PCIe ATS commands. | | Reserved | 5-63 | Reserved for future standard use. | | Custom | 64-127 | Designated for custom use. | Note: Undefined functions for opcodes 0-63 are reserved. Illegal commands use reserved encodings or set reserved bits. Unsupported commands are defined but not implemented. ``` -------------------------------- ### RISC-V IOMMU DDT Pointer Programming Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/src/iommu_sw_guidelines.adoc Describes the programming of the Device-Dependent Table (DDT) pointer. This step involves determining the device ID width and context data structure format based on IOMMU capabilities, and allocating memory for the root DDT. ```C /* Determine supported `device_id` width `Dw` and context data structure format. */ /* If `capabilities.MSI` is 0, use base-format device-contexts. */ /* Else, use extended-format device-contexts. */ /* Allocate a page (4 KiB) of memory to use as the root DDT. */ ``` -------------------------------- ### IOHgatp Register Specification Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/src/iommu_data_structures.adoc Defines the structure and purpose of the IOHgatp (IO hypervisor guest address translation and protection) register. This register holds the root page table pointer and guest context ID for second-stage address translation, managed by the hypervisor. ```APIDOC IO hypervisor guest address translation and protection (`iohgatp`) This field holds the PPN of the root second-stage page table and a virtual machine identified by a guest soft-context ID (`GSCID`), to facilitate address-translation fences on a per-virtual-machine basis. If multiple devices are associated to a VM with a common second-stage page table, the hypervisor is expected to program the same `GSCID` in each `iohgatp`. The `MODE` field is used to select the second-stage address translation scheme. Fields: - PPN: Physical Page Number of the root second-stage page table. - GSCID: Guest Soft-Context ID, identifies the virtual machine. - MODE: Selects the second-stage address translation scheme. ``` ```Wavedrom { "reg": [ { "bits": 44, "name": "PPN" }, { "bits": 16, "name": "GSCID" }, { "bits": 4, "name": "MODE" } ], "config": { "lanes": 2, "hspace": 1024, "fontsize": 16 } } ``` -------------------------------- ### IOMMU In-memory Queues Diagram Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/src/iommu_in_memory_queues.adoc A visual representation of the Command Queue (CQ), Fault Queue (FQ), and Page Request Queue (PQ) connections within the IOMMU architecture. ```ditaa +---+---+--------------------------------+---+----+ +-------->|.. | . | Command Queue | . | .. | +-------->+---+---+--------------------------------+---+----+ | ^ ^ +-+-+ | | |CQB| | | +---+ | | |CQH+---------+ | +---+ | |CQT+--------------------------------------------------+ +---+ +---+---+--------------------------------+---+----+ +-------->|.. | . | Fault Queue | . | .. | +-------->+---+---+--------------------------------+---+----+ | ^ ^ +-+-+ | | |FQB| | | +---+ | | |FQH+---------+ | +---+ | |FQT+--------------------------------------------------+ +---+ +---+---+--------------------------------+---+----+ +-------->|.. | . | Page Request Queue | . | .. | +-------->+---+---+--------------------------------+---+----+ | ^ ^ +-+-+ | | |PQB| | | +---+ | | |PQH+---------+ | +---+ | |PQT+--------------------------------------------------+ +---+ ``` -------------------------------- ### IOMMU Interrupt Handling - Page Fault Queue (PQ) Source: https://github.com/riscv-non-isa/riscv-iommu/blob/main/src/iommu_sw_guidelines.adoc Describes interrupt handling for the Page Fault Queue (PQ). If `ipsr.pip` is set, an interrupt is pending from PQ. The handler reads `pqcsr` to check for errors (`pqmf`, `pqof`), similar to FQ error handling. The text is truncated before full PQ error correction and clearing details are provided. ```APIDOC PQ Interrupt Handling: - Condition: `ipsr.pip` bit is set. - Action: Read `pqcsr` register. - Error Detection: - Check `pqmf`, `pqof` bits for errors. - If error bits are set, page fault reporting is disabled. - Error Correction: - Correct error cause. - Clear error bits in `pqcsr` by writing 1 to them. - Clearing all error bits re-enables page fault reporting. - Clear PQ interrupt flag: Write 1 to `ipsr.pip`. ```