ASAravind Sivakumaran
Theme

Theme and appearance

Appearance
Palette

Pick any colour. The displayed accent adjusts for readable contrast in light or dark mode.

← IOMMU star map

SECURITY / SECURE DMA

Can a device reach a confidential VM's private memory?

The previous chapter kept the host's CPU out of a confidential VM's pages. A device is the other way in: it writes RAM directly (DMA). With SEV-SNP on, the IOMMU translates the device's address as usual, then checks the same Reverse Map Table (RMP) the CPU uses. These experiments run on the site's emulated AMD IOMMU (dmakit), driven the way a test drives hardware: posted writes say nothing, so each result reads the bytes and the event log.

What claims does this page make? 3 points
A device's request goes to the IOMMU, which checks the device table entry and translates the address, then to the RMP check, then to RAM. The host programs the IOMMU. Host programs the IOMMU NIC 03:00.0 sends IOVAs IOMMU device entry, tables, locks, event log RMP check host-owned page? RAM B shared, O private

Experiments

Words used in the experiments
B, O
B is a shared bounce buffer at SPA 0x2000000; O is guest A's private page at SPA 0x100002000 (the study notes' W18).
IOVA
The address the device uses. The IOMMU translates it to an SPA through the host's table for the device.
DTE, V, TV, Mode, I, sATS
The device table entry: valid, translation valid, page-table mode (0: none), ATS allowed, Secure ATS.
SNP_INIT
The command the host sends the AMD Secure Processor to turn SNP on. After it the IOMMU is "SNP-enabled".
RMP_PAGE_FAULT
The event-log record for a device access that failed the RMP check.
ATS, ATC
Address Translation Services: the device asks for a translation and keeps it in its own cache (ATC), then sends already translated requests.
COMPLETION_WAIT
A command that stores a value when every earlier command has finished; software polls that value.
0010h, 0018h, 0020h, 0028h, 0030h
Offsets of IOMMU registers: event log base, Control (IommuEn, CmdBufEn), the exclusion or completion-store base and limit, and the feature register.
Head, tail
Byte offsets in the command buffer: the IOMMU reads at head, software writes at tail; head = tail means the IOMMU has fetched every command, not that each has finished executing; completion is signalled separately (COMPLETION_WAIT).
ASID
The RMP's number for a guest (A is 1, as in confidential VMs); not the DTE's DomainID.
Target abort (CA)
The IOMMU refuses the request; nothing is read or written. A read or non-posted write gets a Completer Abort (CA) back; a posted write gets nothing.
IO_PAGE_FAULT, ILLEGAL_DEV_TABLE_ENTRY
Event records: no mapping or no permission in the tables; a device table entry the IOMMU must not use.
Flags
In RMP_PAGE_FAULT, which RMP checks failed: 0x2 ASID_MISMATCH (the page belongs to a guest), 0x20 PAGE_IMMUTABLE (a page nobody may write).
PASID, GVA
A tag on a request that picks a process address space, and an address in it.
Posted write
A PCIe Memory Write the device sends without waiting for an answer; a refusal sends nothing back, and software sees an event record only when event logging is enabled and the IOMMU reports that fault.

Experiment

    Intel and Arm:

    What the IOMMU holds after that step

    RAM · B and O

      RMP · pages not the host's

        IOMMU registers

          Device table entry

            Event log

              The device's ATC

                The last RMP_PAGE_FAULT, field by field

                  Runs on dmakit 4.3.0 (JavaScript; its C++ twin prints the same). Not modelled: RMP_HARDWARE_ERROR, the PAGE_LOCKED and PAGE_SIZE_MISMATCH flags, RMP checks of the IOMMU's own table reads, trusted devices (the trusted I/O chapter).

                  The order of the checks

                  For one ordinary (untranslated) DMA request on an SNP-enabled IOMMU:

                  1. Device table entry. V=0 is now an ILLEGAL_DEV_TABLE_ENTRY and the request is aborted; so is sATS=0 when the IOMMU lacks SnpPageMode0Sup (dmakit applies this to I=1 devices), and sATS=1 with Mode=0 (§2.12.2.4).
                  2. Translation. The host's table (and the guest's, with a PASID) turns the IOVA into an SPA; a missing or read-only entry is an IO_PAGE_FAULT, as without SNP. There is no exclusion range any more (§2.12.2.3).
                  3. RMP check. The SPA's page must be hypervisor-owned (§2.12.1). If not: target abort and RMP_PAGE_FAULT for DMA; R=W=0 and RMP_PAGE_FAULT for a translation request (Table 54).
                  4. Memory. Only now do the bytes move.

                  "Hypervisor-owned" is the point: to an ordinary device, a guest's private page is off limits however correct its mapping. A device may reach private memory only as a trusted device interface (SEV-TIO).

                  The fault record

                  The panel above takes the last RMP_PAGE_FAULT apart bit by bit (Figure 69, Table 71). Flags says which RMP checks failed; AT says which kind of request it was; SPA says the address is an SPA. The record has no DomainID and no PASID, so it cannot say which translation produced the address. The last line shows how Linux 7.3 prints the same 16 bytes: it reads an older layout of this record.

                  RequestIf the RMP check fails
                  Untranslated DMATarget abort; RMP_PAGE_FAULT; interrupt if enabled (Table 54).
                  ATS translation requestAnswered with R=W=0; RMP_PAGE_FAULT (Table 54).
                  Pretranslated DMARMP_PAGE_FAULT with AT=10b (Table 71); the model target-aborts.

                  Turning SNP on, step by step

                  1. BIOS decides whether the system may use SEV-SNP at all.
                  2. The IOMMU driver refuses SNP if SnpPageMode0Sup=0 and the default domain is passthrough or uses v2 tables, both of which need Mode=0 or GCR3-only entries (Linux 7.3); checks 0030h[SNPSup]; points 0020h/0028h at its completion page (iommu_set_cwwb_range); and gives every unused device V=1 without TV (init_device_table_dma).
                  3. The hypervisor sends SNP_INIT to the AMD Secure Processor. From then on the IOMMU is SNP-enabled: registers locked, the completion page and the logs immutable.
                  4. SNP-aware guests may be launched.

                  The event and PPR logs cannot be written by the CPU any more, so the driver stops clearing consumed entries (Linux's comments on errata 732 and 733). Undoing SNP (amd_iommu_snp_disable) makes exactly those pages shared again.

                  Secure ATS

                  Ordinary ATSSecure ATS (DTE[SATS]=1)
                  Translation replyThe SPAThe GPA before the last stage
                  A translated requestPassed on after DTE[I]=1 is checkedTranslated again, GPA → SPA
                  A device that forges an addressReaches any page the RMP allows (under SNP, any host page)Reaches only what the host table maps
                  NeedsDTE[I]=1DTE[I]=1, 0030h[SATSSup]=1, a host table (Mode ≠ 0)

                  "Secure" here means the device never holds an SPA; nothing is encrypted.

                  What did the request actually use?

                  Bounce buffers: how ordinary devices still work

                  A confidential VM's driver cannot let a NIC write its private page, so Linux copies through a shared bounce buffer (SWIOTLB): for a receive, the device writes B and the CPU copies B to O; for a send, the CPU copies O to B first. The copies are the CPU's, not the IOMMU's, and whatever reaches B is visible to the host. The Linux DMA buffers lab runs these copies byte by byte, and the buffer workbook asks what the host can read at each step.

                  Sources