+/* 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);