qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [RFC 2/4] hw/i386: Introduce AMD IOMMU


From: Valentine Sinitsyn
Subject: Re: [Qemu-devel] [RFC 2/4] hw/i386: Introduce AMD IOMMU
Date: Sat, 12 Sep 2015 15:55:51 +0500
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.2.0

Hi David,

On 07.09.2015 17:46, Valentine Sinitsyn wrote:
...snip...
+/* TODO : Mark addresses as Accessed and Dirty */
+static void amd_iommu_do_translate(AMDIOMMUAddressSpace *as, hwaddr
addr, bool is_write, IOMMUTLBEntry *ret)
+{
+    AMDIOMMUState *s = as->iommu_state;
+
+    int present;
+    dma_addr_t pte_addr;
+    uint64_t entry[4], pte, pte_perms;
+    unsigned level;
+    unsigned perms;
+
+    if(!amd_iommu_get_dte(s, as->devfn, entry)){
+        goto no_translation;
+    }
+
+    pte = entry[0];
+
+    /*
+     * It's okay to check for either read or write permissions
+     * even for memory maps, since we don't support R/W maps.
+     */
+    perms = is_write ? IOMMU_PERM_WRITE : IOMMU_PERM_READ;
+
+    if(!(level = get_pte_translation_mode(pte))){
+        goto no_translation;
+    }
+
+    while(level > 0){
+        /*
+         * check permissions: the bitwise
+         * implication perms -> entry_perms must be true. Pages must
be present
+         * and permissions on all levels must be similar
+         */
+        pte_perms = amd_iommu_get_perms(pte);
+        present = pte & 1;
+        if(!present || perms != (perms & pte_perms)){
+            amd_iommu_page_fault(s, as->devfn, entry[1] &
DEV_DOMID_ID_MASK, addr, present,
+                                 !!(perms & IOMMU_PERM_WRITE));
+            return;
+        }
+
+        /* go to the next lower level */
+        pte_addr = pte & DEV_PT_ROOT_MASK;
+        pte_addr += ((addr >> ( 9 * level)) & 0xff8);
Does this work for six level page tables? The highest level has
different bit size there IIRC.

+        pte = ldq_phys(&address_space_memory, pte_addr);
+        level = (pte >> DEV_MODE_RSHIFT) & DEV_MODE_MASK;
+    }
+
+    ret->iova = addr & IOMMU_PAGE_MASK_4K;
+    ret->translated_addr = (pte & DEV_PT_ROOT_MASK) &
IOMMU_PAGE_MASK_4K;
+    ret->addr_mask = ~IOMMU_PAGE_MASK_4K;
+    ret->perm = IOMMU_RW;
+    return;
+
+no_translation:
+    ret->iova = addr;
+    ret->translated_addr = addr & IOMMU_PAGE_MASK_4K;
+    ret->addr_mask = ~IOMMU_PAGE_MASK_4K;
+    ret->perm = IOMMU_RW;
+    return;
Are you sure these transactions needs to be passed through rather than
target-aborted?
FYI: They are indeed passed-through; see Table 9 in the spec.

Valentine



reply via email to

[Prev in Thread] Current Thread [Next in Thread]