static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,

                                   uint8_t devfn, hwaddr addr, bool is_write,

                                   IOMMUTLBEntry *entry)

{

    IntelIOMMUState *s = vtd_as->iommu_state;

    VTDContextEntry ce;

    uint8_t bus_num = pci_bus_num(bus);

    VTDContextCacheEntry *cc_entry = &vtd_as->context_cache_entry;

    uint64_t slpte, page_mask;

    uint32_t level;

    uint16_t source_id = vtd_make_source_id(bus_num, devfn);

    int ret_fr;

    bool is_fpd_set = false;

    bool reads = true;

    bool writes = true;

    uint8_t access_flags;

    VTDIOTLBEntry *iotlb_entry;



    /*

     * We have standalone memory region for interrupt addresses, we

     * should never receive translation requests in this region.

     */

    assert(!vtd_is_interrupt_addr(addr));



    /* Try to fetch slpte form IOTLB */

    iotlb_entry = vtd_lookup_iotlb(s, source_id, addr);

    if (iotlb_entry) {

        trace_vtd_iotlb_page_hit(source_id, addr, iotlb_entry->slpte,

                                 iotlb_entry->domain_id);

        slpte = iotlb_entry->slpte;

        access_flags = iotlb_entry->access_flags;

        page_mask = iotlb_entry->mask;

        goto out;

    }



    /* Try to fetch context-entry from cache first */

    if (cc_entry->context_cache_gen == s->context_cache_gen) {

        trace_vtd_iotlb_cc_hit(bus_num, devfn, cc_entry->context_entry.hi,

                               cc_entry->context_entry.lo,

                               cc_entry->context_cache_gen);

        ce = cc_entry->context_entry;

        is_fpd_set = ce.lo & VTD_CONTEXT_ENTRY_FPD;

    } else {

        ret_fr = vtd_dev_to_context_entry(s, bus_num, devfn, &ce);

        is_fpd_set = ce.lo & VTD_CONTEXT_ENTRY_FPD;

        if (ret_fr) {

            ret_fr = -ret_fr;

            if (is_fpd_set && vtd_is_qualified_fault(ret_fr)) {

                trace_vtd_fault_disabled();

            } else {

                vtd_report_dmar_fault(s, source_id, addr, ret_fr, is_write);

            }

            goto error;

        }

        /* Update context-cache */

        trace_vtd_iotlb_cc_update(bus_num, devfn, ce.hi, ce.lo,

                                  cc_entry->context_cache_gen,

                                  s->context_cache_gen);

        cc_entry->context_entry = ce;

        cc_entry->context_cache_gen = s->context_cache_gen;

    }



    /*

     * We don't need to translate for pass-through context entries.

     * Also, let's ignore IOTLB caching as well for PT devices.

     */

    if (vtd_ce_get_type(&ce) == VTD_CONTEXT_TT_PASS_THROUGH) {

        entry->iova = addr & VTD_PAGE_MASK_4K;

        entry->translated_addr = entry->iova;

        entry->addr_mask = ~VTD_PAGE_MASK_4K;

        entry->perm = IOMMU_RW;

        trace_vtd_translate_pt(source_id, entry->iova);



        /*

         * When this happens, it means firstly caching-mode is not

         * enabled, and this is the first passthrough translation for

         * the device. Let's enable the fast path for passthrough.

         *

         * When passthrough is disabled again for the device, we can

         * capture it via the context entry invalidation, then the

         * IOMMU region can be swapped back.

         */

        vtd_pt_enable_fast_path(s, source_id);



        return true;

    }



    ret_fr = vtd_iova_to_slpte(&ce, addr, is_write, &slpte, &level,

                               &reads, &writes);

    if (ret_fr) {

        ret_fr = -ret_fr;

        if (is_fpd_set && vtd_is_qualified_fault(ret_fr)) {

            trace_vtd_fault_disabled();

        } else {

            vtd_report_dmar_fault(s, source_id, addr, ret_fr, is_write);

        }

        goto error;

    }



    page_mask = vtd_slpt_level_page_mask(level);

    access_flags = IOMMU_ACCESS_FLAG(reads, writes);

    vtd_update_iotlb(s, source_id, VTD_CONTEXT_ENTRY_DID(ce.hi), addr, slpte,

                     access_flags, level);

out:

    entry->iova = addr & page_mask;

    entry->translated_addr = vtd_get_slpte_addr(slpte) & page_mask;

    entry->addr_mask = ~page_mask;

    entry->perm = access_flags;

    return true;



error:

    entry->iova = 0;

    entry->translated_addr = 0;

    entry->addr_mask = 0;

    entry->perm = IOMMU_NONE;

    return false;

}

static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,

                                   uint8_t devfn, hwaddr addr, bool is_write,

                                   IOMMUTLBEntry *entry)

{

    IntelIOMMUState *s = vtd_as->iommu_state;

    VTDContextEntry ce;

    uint8_t bus_num = pci_bus_num(bus);

    VTDContextCacheEntry *cc_entry = &vtd_as->context_cache_entry;

    uint64_t slpte, page_mask;

    uint32_t level;

    uint16_t source_id = vtd_make_source_id(bus_num, devfn);

    int ret_fr;

    bool is_fpd_set = false;

    bool reads = true;

    bool writes = true;

    uint8_t access_flags;

    VTDIOTLBEntry *iotlb_entry;



    







    assert(!vtd_is_interrupt_addr(addr));



    

    iotlb_entry = vtd_lookup_iotlb(s, source_id, addr);

    if (iotlb_entry) {

        trace_vtd_iotlb_page_hit(source_id, addr, iotlb_entry->slpte,

                                 iotlb_entry->domain_id);

        slpte = iotlb_entry->slpte;

        access_flags = iotlb_entry->access_flags;

        page_mask = iotlb_entry->mask;

        goto out;

    }



    

    if (cc_entry->context_cache_gen == s->context_cache_gen) {

        trace_vtd_iotlb_cc_hit(bus_num, devfn, cc_entry->context_entry.hi,

                               cc_entry->context_entry.lo,

                               cc_entry->context_cache_gen);

        ce = cc_entry->context_entry;

        is_fpd_set = ce.lo & VTD_CONTEXT_ENTRY_FPD;

    } else {

        ret_fr = vtd_dev_to_context_entry(s, bus_num, devfn, &ce);

        is_fpd_set = ce.lo & VTD_CONTEXT_ENTRY_FPD;

        if (ret_fr) {

            ret_fr = -ret_fr;

            if (is_fpd_set && vtd_is_qualified_fault(ret_fr)) {

                trace_vtd_fault_disabled();

            } else {

                vtd_report_dmar_fault(s, source_id, addr, ret_fr, is_write);

            }

            goto error;

        }

        

        trace_vtd_iotlb_cc_update(bus_num, devfn, ce.hi, ce.lo,

                                  cc_entry->context_cache_gen,

                                  s->context_cache_gen);

        cc_entry->context_entry = ce;

        cc_entry->context_cache_gen = s->context_cache_gen;

    }



    







    if (vtd_ce_get_type(&ce) == VTD_CONTEXT_TT_PASS_THROUGH) {

        entry->iova = addr & VTD_PAGE_MASK_4K;

        entry->translated_addr = entry->iova;

        entry->addr_mask = ~VTD_PAGE_MASK_4K;

        entry->perm = IOMMU_RW;

        trace_vtd_translate_pt(source_id, entry->iova);



        

















        vtd_pt_enable_fast_path(s, source_id);



        return true;

    }



    ret_fr = vtd_iova_to_slpte(&ce, addr, is_write, &slpte, &level,

                               &reads, &writes);

    if (ret_fr) {

        ret_fr = -ret_fr;

        if (is_fpd_set && vtd_is_qualified_fault(ret_fr)) {

            trace_vtd_fault_disabled();

        } else {

            vtd_report_dmar_fault(s, source_id, addr, ret_fr, is_write);

        }

        goto error;

    }



    page_mask = vtd_slpt_level_page_mask(level);

    access_flags = IOMMU_ACCESS_FLAG(reads, writes);

    vtd_update_iotlb(s, source_id, VTD_CONTEXT_ENTRY_DID(ce.hi), addr, slpte,

                     access_flags, level);

out:

    entry->iova = addr & page_mask;

    entry->translated_addr = vtd_get_slpte_addr(slpte) & page_mask;

    entry->addr_mask = ~page_mask;

    entry->perm = access_flags;

    return true;



error:

    entry->iova = 0;

    entry->translated_addr = 0;

    entry->addr_mask = 0;

    entry->perm = IOMMU_NONE;

    return false;

}

static bool FUNC_0(VTDAddressSpace *vtd_as, PCIBus *bus,

                                   uint8_t devfn, hwaddr addr, bool is_write,

                                   IOMMUTLBEntry *entry)

{

    IntelIOMMUState *s = vtd_as->iommu_state;

    VTDContextEntry ce;

    uint8_t bus_num = pci_bus_num(bus);

    VTDContextCacheEntry *cc_entry = &vtd_as->context_cache_entry;

    uint64_t slpte, page_mask;

    uint32_t level;

    uint16_t source_id = vtd_make_source_id(bus_num, devfn);

    int VAR_0;

    bool is_fpd_set = false;

    bool reads = true;

    bool writes = true;

    uint8_t access_flags;

    VTDIOTLBEntry *iotlb_entry;



    







    assert(!vtd_is_interrupt_addr(addr));



    

    iotlb_entry = vtd_lookup_iotlb(s, source_id, addr);

    if (iotlb_entry) {

        trace_vtd_iotlb_page_hit(source_id, addr, iotlb_entry->slpte,

                                 iotlb_entry->domain_id);

        slpte = iotlb_entry->slpte;

        access_flags = iotlb_entry->access_flags;

        page_mask = iotlb_entry->mask;

        goto out;

    }



    

    if (cc_entry->context_cache_gen == s->context_cache_gen) {

        trace_vtd_iotlb_cc_hit(bus_num, devfn, cc_entry->context_entry.hi,

                               cc_entry->context_entry.lo,

                               cc_entry->context_cache_gen);

        ce = cc_entry->context_entry;

        is_fpd_set = ce.lo & VTD_CONTEXT_ENTRY_FPD;

    } else {

        VAR_0 = vtd_dev_to_context_entry(s, bus_num, devfn, &ce);

        is_fpd_set = ce.lo & VTD_CONTEXT_ENTRY_FPD;

        if (VAR_0) {

            VAR_0 = -VAR_0;

            if (is_fpd_set && vtd_is_qualified_fault(VAR_0)) {

                trace_vtd_fault_disabled();

            } else {

                vtd_report_dmar_fault(s, source_id, addr, VAR_0, is_write);

            }

            goto error;

        }

        

        trace_vtd_iotlb_cc_update(bus_num, devfn, ce.hi, ce.lo,

                                  cc_entry->context_cache_gen,

                                  s->context_cache_gen);

        cc_entry->context_entry = ce;

        cc_entry->context_cache_gen = s->context_cache_gen;

    }



    







    if (vtd_ce_get_type(&ce) == VTD_CONTEXT_TT_PASS_THROUGH) {

        entry->iova = addr & VTD_PAGE_MASK_4K;

        entry->translated_addr = entry->iova;

        entry->addr_mask = ~VTD_PAGE_MASK_4K;

        entry->perm = IOMMU_RW;

        trace_vtd_translate_pt(source_id, entry->iova);



        

















        vtd_pt_enable_fast_path(s, source_id);



        return true;

    }



    VAR_0 = vtd_iova_to_slpte(&ce, addr, is_write, &slpte, &level,

                               &reads, &writes);

    if (VAR_0) {

        VAR_0 = -VAR_0;

        if (is_fpd_set && vtd_is_qualified_fault(VAR_0)) {

            trace_vtd_fault_disabled();

        } else {

            vtd_report_dmar_fault(s, source_id, addr, VAR_0, is_write);

        }

        goto error;

    }



    page_mask = vtd_slpt_level_page_mask(level);

    access_flags = IOMMU_ACCESS_FLAG(reads, writes);

    vtd_update_iotlb(s, source_id, VTD_CONTEXT_ENTRY_DID(ce.hi), addr, slpte,

                     access_flags, level);

out:

    entry->iova = addr & page_mask;

    entry->translated_addr = vtd_get_slpte_addr(slpte) & page_mask;

    entry->addr_mask = ~page_mask;

    entry->perm = access_flags;

    return true;



error:

    entry->iova = 0;

    entry->translated_addr = 0;

    entry->addr_mask = 0;

    entry->perm = IOMMU_NONE;

    return false;

}

static bool FUNC_0(VTDAddressSpace *vtd_as, PCIBus *bus,
uint8_t devfn, hwaddr addr, bool is_write,
IOMMUTLBEntry *entry)
{ IntelIOMMUState *s = vtd_as->iommu_state; VTDContextEntry ce; uint8_t bus_num = pci_bus_num(bus); VTDContextCacheEntry *cc_entry = &vtd_as->context_cache_entry; uint64_t slpte, page_mask; uint32_t level; uint16_t source_id = vtd_make_source_id(bus_num, devfn); int VAR_0; bool is_fpd_set = false; bool reads = true; bool writes = true; uint8_t access_flags; VTDIOTLBEntry *iotlb_entry; assert(!vtd_is_interrupt_addr(addr)); iotlb_entry = vtd_lookup_iotlb(s, source_id, addr); if (iotlb_entry) { trace_vtd_iotlb_page_hit(source_id, addr, iotlb_entry->slpte,
iotlb_entry->domain_id); slpte = iotlb_entry->slpte; access_flags = iotlb_entry->access_flags; page_mask = iotlb_entry->mask; goto out; } if (cc_entry->context_cache_gen == s->context_cache_gen) { trace_vtd_iotlb_cc_hit(bus_num, devfn, cc_entry->context_entry.hi,
cc_entry->context_entry.lo,
cc_entry->context_cache_gen); ce = cc_entry->context_entry; is_fpd_set = ce.lo & VTD_CONTEXT_ENTRY_FPD; } else { VAR_0 = vtd_dev_to_context_entry(s, bus_num, devfn, &ce); is_fpd_set = ce.lo & VTD_CONTEXT_ENTRY_FPD; if (VAR_0) { VAR_0 = -VAR_0; if (is_fpd_set && vtd_is_qualified_fault(VAR_0)) { trace_vtd_fault_disabled(); } else { vtd_report_dmar_fault(s, source_id, addr, VAR_0, is_write); } goto error; } trace_vtd_iotlb_cc_update(bus_num, devfn, ce.hi, ce.lo,
cc_entry->context_cache_gen,
s->context_cache_gen); cc_entry->context_entry = ce; cc_entry->context_cache_gen = s->context_cache_gen; } if (vtd_ce_get_type(&ce) == VTD_CONTEXT_TT_PASS_THROUGH) { entry->iova = addr & VTD_PAGE_MASK_4K; entry->translated_addr = entry->iova; entry->addr_mask = ~VTD_PAGE_MASK_4K; entry->perm = IOMMU_RW; trace_vtd_translate_pt(source_id, entry->iova); vtd_pt_enable_fast_path(s, source_id); return true; } VAR_0 = vtd_iova_to_slpte(&ce, addr, is_write, &slpte, &level,
&reads, &writes); if (VAR_0) { VAR_0 = -VAR_0; if (is_fpd_set && vtd_is_qualified_fault(VAR_0)) { trace_vtd_fault_disabled(); } else { vtd_report_dmar_fault(s, source_id, addr, VAR_0, is_write); } goto error; } page_mask = vtd_slpt_level_page_mask(level); access_flags = IOMMU_ACCESS_FLAG(reads, writes); vtd_update_iotlb(s, source_id, VTD_CONTEXT_ENTRY_DID(ce.hi), addr, slpte,
access_flags, level); out:
entry->iova = addr & page_mask; entry->translated_addr = vtd_get_slpte_addr(slpte) & page_mask; entry->addr_mask = ~page_mask; entry->perm = access_flags; return true; error:
entry->iova = 0; entry->translated_addr = 0; entry->addr_mask = 0; entry->perm = IOMMU_NONE; return false; }