intel-iommu: add IOTLB using hash table
Add IOTLB to cache information about the translation of input-addresses. IOTLB use a GHashTable as cache. The key of the hash table is the logical-OR of gfn and source id after left-shifting. Signed-off-by: Le Tan <tamlokveer@gmail.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
		
							parent
							
								
									d92fa2dc6e
								
							
						
					
					
						commit
						b5a280c008
					
				@ -132,6 +132,35 @@ static uint64_t vtd_set_clear_mask_quad(IntelIOMMUState *s, hwaddr addr,
 | 
				
			|||||||
    return new_val;
 | 
					    return new_val;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* GHashTable functions */
 | 
				
			||||||
 | 
					static gboolean vtd_uint64_equal(gconstpointer v1, gconstpointer v2)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return *((const uint64_t *)v1) == *((const uint64_t *)v2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static guint vtd_uint64_hash(gconstpointer v)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return (guint)*(const uint64_t *)v;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static gboolean vtd_hash_remove_by_domain(gpointer key, gpointer value,
 | 
				
			||||||
 | 
					                                          gpointer user_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VTDIOTLBEntry *entry = (VTDIOTLBEntry *)value;
 | 
				
			||||||
 | 
					    uint16_t domain_id = *(uint16_t *)user_data;
 | 
				
			||||||
 | 
					    return entry->domain_id == domain_id;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static gboolean vtd_hash_remove_by_page(gpointer key, gpointer value,
 | 
				
			||||||
 | 
					                                        gpointer user_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VTDIOTLBEntry *entry = (VTDIOTLBEntry *)value;
 | 
				
			||||||
 | 
					    VTDIOTLBPageInvInfo *info = (VTDIOTLBPageInvInfo *)user_data;
 | 
				
			||||||
 | 
					    uint64_t gfn = info->gfn & info->mask;
 | 
				
			||||||
 | 
					    return (entry->domain_id == info->domain_id) &&
 | 
				
			||||||
 | 
					            ((entry->gfn & info->mask) == gfn);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Reset all the gen of VTDAddressSpace to zero and set the gen of
 | 
					/* Reset all the gen of VTDAddressSpace to zero and set the gen of
 | 
				
			||||||
 * IntelIOMMUState to 1.
 | 
					 * IntelIOMMUState to 1.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@ -159,6 +188,48 @@ static void vtd_reset_context_cache(IntelIOMMUState *s)
 | 
				
			|||||||
    s->context_cache_gen = 1;
 | 
					    s->context_cache_gen = 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void vtd_reset_iotlb(IntelIOMMUState *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    assert(s->iotlb);
 | 
				
			||||||
 | 
					    g_hash_table_remove_all(s->iotlb);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static VTDIOTLBEntry *vtd_lookup_iotlb(IntelIOMMUState *s, uint16_t source_id,
 | 
				
			||||||
 | 
					                                       hwaddr addr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint64_t key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    key = (addr >> VTD_PAGE_SHIFT_4K) |
 | 
				
			||||||
 | 
					           ((uint64_t)(source_id) << VTD_IOTLB_SID_SHIFT);
 | 
				
			||||||
 | 
					    return g_hash_table_lookup(s->iotlb, &key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id,
 | 
				
			||||||
 | 
					                             uint16_t domain_id, hwaddr addr, uint64_t slpte,
 | 
				
			||||||
 | 
					                             bool read_flags, bool write_flags)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VTDIOTLBEntry *entry = g_malloc(sizeof(*entry));
 | 
				
			||||||
 | 
					    uint64_t *key = g_malloc(sizeof(*key));
 | 
				
			||||||
 | 
					    uint64_t gfn = addr >> VTD_PAGE_SHIFT_4K;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    VTD_DPRINTF(CACHE, "update iotlb sid 0x%"PRIx16 " gpa 0x%"PRIx64
 | 
				
			||||||
 | 
					                " slpte 0x%"PRIx64 " did 0x%"PRIx16, source_id, addr, slpte,
 | 
				
			||||||
 | 
					                domain_id);
 | 
				
			||||||
 | 
					    if (g_hash_table_size(s->iotlb) >= VTD_IOTLB_MAX_SIZE) {
 | 
				
			||||||
 | 
					        VTD_DPRINTF(CACHE, "iotlb exceeds size limit, forced to reset");
 | 
				
			||||||
 | 
					        vtd_reset_iotlb(s);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    entry->gfn = gfn;
 | 
				
			||||||
 | 
					    entry->domain_id = domain_id;
 | 
				
			||||||
 | 
					    entry->slpte = slpte;
 | 
				
			||||||
 | 
					    entry->read_flags = read_flags;
 | 
				
			||||||
 | 
					    entry->write_flags = write_flags;
 | 
				
			||||||
 | 
					    *key = gfn | ((uint64_t)(source_id) << VTD_IOTLB_SID_SHIFT);
 | 
				
			||||||
 | 
					    g_hash_table_replace(s->iotlb, key, entry);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Given the reg addr of both the message data and address, generate an
 | 
					/* Given the reg addr of both the message data and address, generate an
 | 
				
			||||||
 * interrupt via MSI.
 | 
					 * interrupt via MSI.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@ -693,6 +764,7 @@ static void vtd_do_iommu_translate(VTDAddressSpace *vtd_as, uint8_t bus_num,
 | 
				
			|||||||
    bool is_fpd_set = false;
 | 
					    bool is_fpd_set = false;
 | 
				
			||||||
    bool reads = true;
 | 
					    bool reads = true;
 | 
				
			||||||
    bool writes = true;
 | 
					    bool writes = true;
 | 
				
			||||||
 | 
					    VTDIOTLBEntry *iotlb_entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Check if the request is in interrupt address range */
 | 
					    /* Check if the request is in interrupt address range */
 | 
				
			||||||
    if (vtd_is_interrupt_addr(addr)) {
 | 
					    if (vtd_is_interrupt_addr(addr)) {
 | 
				
			||||||
@ -716,6 +788,17 @@ static void vtd_do_iommu_translate(VTDAddressSpace *vtd_as, uint8_t bus_num,
 | 
				
			|||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    /* Try to fetch slpte form IOTLB */
 | 
				
			||||||
 | 
					    iotlb_entry = vtd_lookup_iotlb(s, source_id, addr);
 | 
				
			||||||
 | 
					    if (iotlb_entry) {
 | 
				
			||||||
 | 
					        VTD_DPRINTF(CACHE, "hit iotlb sid 0x%"PRIx16 " gpa 0x%"PRIx64
 | 
				
			||||||
 | 
					                    " slpte 0x%"PRIx64 " did 0x%"PRIx16, source_id, addr,
 | 
				
			||||||
 | 
					                    iotlb_entry->slpte, iotlb_entry->domain_id);
 | 
				
			||||||
 | 
					        slpte = iotlb_entry->slpte;
 | 
				
			||||||
 | 
					        reads = iotlb_entry->read_flags;
 | 
				
			||||||
 | 
					        writes = iotlb_entry->write_flags;
 | 
				
			||||||
 | 
					        goto out;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    /* Try to fetch context-entry from cache first */
 | 
					    /* Try to fetch context-entry from cache first */
 | 
				
			||||||
    if (cc_entry->context_cache_gen == s->context_cache_gen) {
 | 
					    if (cc_entry->context_cache_gen == s->context_cache_gen) {
 | 
				
			||||||
        VTD_DPRINTF(CACHE, "hit context-cache bus %d devfn %d "
 | 
					        VTD_DPRINTF(CACHE, "hit context-cache bus %d devfn %d "
 | 
				
			||||||
@ -760,6 +843,9 @@ static void vtd_do_iommu_translate(VTDAddressSpace *vtd_as, uint8_t bus_num,
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vtd_update_iotlb(s, source_id, VTD_CONTEXT_ENTRY_DID(ce.hi), addr, slpte,
 | 
				
			||||||
 | 
					                     reads, writes);
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
    entry->iova = addr & VTD_PAGE_MASK_4K;
 | 
					    entry->iova = addr & VTD_PAGE_MASK_4K;
 | 
				
			||||||
    entry->translated_addr = vtd_get_slpte_addr(slpte) & VTD_PAGE_MASK_4K;
 | 
					    entry->translated_addr = vtd_get_slpte_addr(slpte) & VTD_PAGE_MASK_4K;
 | 
				
			||||||
    entry->addr_mask = ~VTD_PAGE_MASK_4K;
 | 
					    entry->addr_mask = ~VTD_PAGE_MASK_4K;
 | 
				
			||||||
@ -859,6 +945,29 @@ static uint64_t vtd_context_cache_invalidate(IntelIOMMUState *s, uint64_t val)
 | 
				
			|||||||
    return caig;
 | 
					    return caig;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void vtd_iotlb_global_invalidate(IntelIOMMUState *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    vtd_reset_iotlb(s);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void vtd_iotlb_domain_invalidate(IntelIOMMUState *s, uint16_t domain_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    g_hash_table_foreach_remove(s->iotlb, vtd_hash_remove_by_domain,
 | 
				
			||||||
 | 
					                                &domain_id);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void vtd_iotlb_page_invalidate(IntelIOMMUState *s, uint16_t domain_id,
 | 
				
			||||||
 | 
					                                      hwaddr addr, uint8_t am)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VTDIOTLBPageInvInfo info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(am <= VTD_MAMV);
 | 
				
			||||||
 | 
					    info.domain_id = domain_id;
 | 
				
			||||||
 | 
					    info.gfn = addr >> VTD_PAGE_SHIFT_4K;
 | 
				
			||||||
 | 
					    info.mask = ~((1 << am) - 1);
 | 
				
			||||||
 | 
					    g_hash_table_foreach_remove(s->iotlb, vtd_hash_remove_by_page, &info);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Flush IOTLB
 | 
					/* Flush IOTLB
 | 
				
			||||||
 * Returns the IOTLB Actual Invalidation Granularity.
 | 
					 * Returns the IOTLB Actual Invalidation Granularity.
 | 
				
			||||||
 * @val: the content of the IOTLB_REG
 | 
					 * @val: the content of the IOTLB_REG
 | 
				
			||||||
@ -867,25 +976,44 @@ static uint64_t vtd_iotlb_flush(IntelIOMMUState *s, uint64_t val)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    uint64_t iaig;
 | 
					    uint64_t iaig;
 | 
				
			||||||
    uint64_t type = val & VTD_TLB_FLUSH_GRANU_MASK;
 | 
					    uint64_t type = val & VTD_TLB_FLUSH_GRANU_MASK;
 | 
				
			||||||
 | 
					    uint16_t domain_id;
 | 
				
			||||||
 | 
					    hwaddr addr;
 | 
				
			||||||
 | 
					    uint8_t am;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    switch (type) {
 | 
					    switch (type) {
 | 
				
			||||||
    case VTD_TLB_GLOBAL_FLUSH:
 | 
					    case VTD_TLB_GLOBAL_FLUSH:
 | 
				
			||||||
        VTD_DPRINTF(INV, "Global IOTLB flush");
 | 
					        VTD_DPRINTF(INV, "global invalidation");
 | 
				
			||||||
        iaig = VTD_TLB_GLOBAL_FLUSH_A;
 | 
					        iaig = VTD_TLB_GLOBAL_FLUSH_A;
 | 
				
			||||||
 | 
					        vtd_iotlb_global_invalidate(s);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case VTD_TLB_DSI_FLUSH:
 | 
					    case VTD_TLB_DSI_FLUSH:
 | 
				
			||||||
        VTD_DPRINTF(INV, "Domain-selective IOTLB flush");
 | 
					        domain_id = VTD_TLB_DID(val);
 | 
				
			||||||
 | 
					        VTD_DPRINTF(INV, "domain-selective invalidation domain 0x%"PRIx16,
 | 
				
			||||||
 | 
					                    domain_id);
 | 
				
			||||||
        iaig = VTD_TLB_DSI_FLUSH_A;
 | 
					        iaig = VTD_TLB_DSI_FLUSH_A;
 | 
				
			||||||
 | 
					        vtd_iotlb_domain_invalidate(s, domain_id);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case VTD_TLB_PSI_FLUSH:
 | 
					    case VTD_TLB_PSI_FLUSH:
 | 
				
			||||||
        VTD_DPRINTF(INV, "Page-selective-within-domain IOTLB flush");
 | 
					        domain_id = VTD_TLB_DID(val);
 | 
				
			||||||
 | 
					        addr = vtd_get_quad_raw(s, DMAR_IVA_REG);
 | 
				
			||||||
 | 
					        am = VTD_IVA_AM(addr);
 | 
				
			||||||
 | 
					        addr = VTD_IVA_ADDR(addr);
 | 
				
			||||||
 | 
					        VTD_DPRINTF(INV, "page-selective invalidation domain 0x%"PRIx16
 | 
				
			||||||
 | 
					                    " addr 0x%"PRIx64 " mask %"PRIu8, domain_id, addr, am);
 | 
				
			||||||
 | 
					        if (am > VTD_MAMV) {
 | 
				
			||||||
 | 
					            VTD_DPRINTF(GENERAL, "error: supported max address mask value is "
 | 
				
			||||||
 | 
					                        "%"PRIu8, (uint8_t)VTD_MAMV);
 | 
				
			||||||
 | 
					            iaig = 0;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        iaig = VTD_TLB_PSI_FLUSH_A;
 | 
					        iaig = VTD_TLB_PSI_FLUSH_A;
 | 
				
			||||||
 | 
					        vtd_iotlb_page_invalidate(s, domain_id, addr, am);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
        VTD_DPRINTF(GENERAL, "error: wrong iotlb flush granularity");
 | 
					        VTD_DPRINTF(GENERAL, "error: invalid granularity");
 | 
				
			||||||
        iaig = 0;
 | 
					        iaig = 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return iaig;
 | 
					    return iaig;
 | 
				
			||||||
@ -1123,6 +1251,56 @@ static bool vtd_process_context_cache_desc(IntelIOMMUState *s,
 | 
				
			|||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool vtd_process_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint16_t domain_id;
 | 
				
			||||||
 | 
					    uint8_t am;
 | 
				
			||||||
 | 
					    hwaddr addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((inv_desc->lo & VTD_INV_DESC_IOTLB_RSVD_LO) ||
 | 
				
			||||||
 | 
					        (inv_desc->hi & VTD_INV_DESC_IOTLB_RSVD_HI)) {
 | 
				
			||||||
 | 
					        VTD_DPRINTF(GENERAL, "error: non-zero reserved field in IOTLB "
 | 
				
			||||||
 | 
					                    "Invalidate Descriptor hi 0x%"PRIx64 " lo 0x%"PRIx64,
 | 
				
			||||||
 | 
					                    inv_desc->hi, inv_desc->lo);
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (inv_desc->lo & VTD_INV_DESC_IOTLB_G) {
 | 
				
			||||||
 | 
					    case VTD_INV_DESC_IOTLB_GLOBAL:
 | 
				
			||||||
 | 
					        VTD_DPRINTF(INV, "global invalidation");
 | 
				
			||||||
 | 
					        vtd_iotlb_global_invalidate(s);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case VTD_INV_DESC_IOTLB_DOMAIN:
 | 
				
			||||||
 | 
					        domain_id = VTD_INV_DESC_IOTLB_DID(inv_desc->lo);
 | 
				
			||||||
 | 
					        VTD_DPRINTF(INV, "domain-selective invalidation domain 0x%"PRIx16,
 | 
				
			||||||
 | 
					                    domain_id);
 | 
				
			||||||
 | 
					        vtd_iotlb_domain_invalidate(s, domain_id);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case VTD_INV_DESC_IOTLB_PAGE:
 | 
				
			||||||
 | 
					        domain_id = VTD_INV_DESC_IOTLB_DID(inv_desc->lo);
 | 
				
			||||||
 | 
					        addr = VTD_INV_DESC_IOTLB_ADDR(inv_desc->hi);
 | 
				
			||||||
 | 
					        am = VTD_INV_DESC_IOTLB_AM(inv_desc->hi);
 | 
				
			||||||
 | 
					        VTD_DPRINTF(INV, "page-selective invalidation domain 0x%"PRIx16
 | 
				
			||||||
 | 
					                    " addr 0x%"PRIx64 " mask %"PRIu8, domain_id, addr, am);
 | 
				
			||||||
 | 
					        if (am > VTD_MAMV) {
 | 
				
			||||||
 | 
					            VTD_DPRINTF(GENERAL, "error: supported max address mask value is "
 | 
				
			||||||
 | 
					                        "%"PRIu8, (uint8_t)VTD_MAMV);
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        vtd_iotlb_page_invalidate(s, domain_id, addr, am);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        VTD_DPRINTF(GENERAL, "error: invalid granularity in IOTLB Invalidate "
 | 
				
			||||||
 | 
					                    "Descriptor hi 0x%"PRIx64 " lo 0x%"PRIx64,
 | 
				
			||||||
 | 
					                    inv_desc->hi, inv_desc->lo);
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool vtd_process_inv_desc(IntelIOMMUState *s)
 | 
					static bool vtd_process_inv_desc(IntelIOMMUState *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    VTDInvDesc inv_desc;
 | 
					    VTDInvDesc inv_desc;
 | 
				
			||||||
@ -1149,6 +1327,9 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s)
 | 
				
			|||||||
    case VTD_INV_DESC_IOTLB:
 | 
					    case VTD_INV_DESC_IOTLB:
 | 
				
			||||||
        VTD_DPRINTF(INV, "IOTLB Invalidate Descriptor hi 0x%"PRIx64
 | 
					        VTD_DPRINTF(INV, "IOTLB Invalidate Descriptor hi 0x%"PRIx64
 | 
				
			||||||
                    " lo 0x%"PRIx64, inv_desc.hi, inv_desc.lo);
 | 
					                    " lo 0x%"PRIx64, inv_desc.hi, inv_desc.lo);
 | 
				
			||||||
 | 
					        if (!vtd_process_iotlb_desc(s, &inv_desc)) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case VTD_INV_DESC_WAIT:
 | 
					    case VTD_INV_DESC_WAIT:
 | 
				
			||||||
@ -1382,6 +1563,24 @@ static void vtd_mem_write(void *opaque, hwaddr addr,
 | 
				
			|||||||
        vtd_handle_iotlb_write(s);
 | 
					        vtd_handle_iotlb_write(s);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Invalidate Address Register, 64-bit */
 | 
				
			||||||
 | 
					    case DMAR_IVA_REG:
 | 
				
			||||||
 | 
					        VTD_DPRINTF(INV, "DMAR_IVA_REG write addr 0x%"PRIx64
 | 
				
			||||||
 | 
					                    ", size %d, val 0x%"PRIx64, addr, size, val);
 | 
				
			||||||
 | 
					        if (size == 4) {
 | 
				
			||||||
 | 
					            vtd_set_long(s, addr, val);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            vtd_set_quad(s, addr, val);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case DMAR_IVA_REG_HI:
 | 
				
			||||||
 | 
					        VTD_DPRINTF(INV, "DMAR_IVA_REG_HI write addr 0x%"PRIx64
 | 
				
			||||||
 | 
					                    ", size %d, val 0x%"PRIx64, addr, size, val);
 | 
				
			||||||
 | 
					        assert(size == 4);
 | 
				
			||||||
 | 
					        vtd_set_long(s, addr, val);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Fault Status Register, 32-bit */
 | 
					    /* Fault Status Register, 32-bit */
 | 
				
			||||||
    case DMAR_FSTS_REG:
 | 
					    case DMAR_FSTS_REG:
 | 
				
			||||||
        VTD_DPRINTF(FLOG, "DMAR_FSTS_REG write addr 0x%"PRIx64
 | 
					        VTD_DPRINTF(FLOG, "DMAR_FSTS_REG write addr 0x%"PRIx64
 | 
				
			||||||
@ -1658,10 +1857,11 @@ static void vtd_init(IntelIOMMUState *s)
 | 
				
			|||||||
    s->iq_last_desc_type = VTD_INV_DESC_NONE;
 | 
					    s->iq_last_desc_type = VTD_INV_DESC_NONE;
 | 
				
			||||||
    s->next_frcd_reg = 0;
 | 
					    s->next_frcd_reg = 0;
 | 
				
			||||||
    s->cap = VTD_CAP_FRO | VTD_CAP_NFR | VTD_CAP_ND | VTD_CAP_MGAW |
 | 
					    s->cap = VTD_CAP_FRO | VTD_CAP_NFR | VTD_CAP_ND | VTD_CAP_MGAW |
 | 
				
			||||||
             VTD_CAP_SAGAW;
 | 
					             VTD_CAP_SAGAW | VTD_CAP_MAMV | VTD_CAP_PSI;
 | 
				
			||||||
    s->ecap = VTD_ECAP_QI | VTD_ECAP_IRO;
 | 
					    s->ecap = VTD_ECAP_QI | VTD_ECAP_IRO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    vtd_reset_context_cache(s);
 | 
					    vtd_reset_context_cache(s);
 | 
				
			||||||
 | 
					    vtd_reset_iotlb(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Define registers with default values and bit semantics */
 | 
					    /* Define registers with default values and bit semantics */
 | 
				
			||||||
    vtd_define_long(s, DMAR_VER_REG, 0x10UL, 0, 0);
 | 
					    vtd_define_long(s, DMAR_VER_REG, 0x10UL, 0, 0);
 | 
				
			||||||
@ -1731,6 +1931,9 @@ static void vtd_realize(DeviceState *dev, Error **errp)
 | 
				
			|||||||
    memory_region_init_io(&s->csrmem, OBJECT(s), &vtd_mem_ops, s,
 | 
					    memory_region_init_io(&s->csrmem, OBJECT(s), &vtd_mem_ops, s,
 | 
				
			||||||
                          "intel_iommu", DMAR_REG_SIZE);
 | 
					                          "intel_iommu", DMAR_REG_SIZE);
 | 
				
			||||||
    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->csrmem);
 | 
					    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->csrmem);
 | 
				
			||||||
 | 
					    /* No corresponding destroy */
 | 
				
			||||||
 | 
					    s->iotlb = g_hash_table_new_full(vtd_uint64_hash, vtd_uint64_equal,
 | 
				
			||||||
 | 
					                                     g_free, g_free);
 | 
				
			||||||
    vtd_init(s);
 | 
					    vtd_init(s);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -111,6 +111,10 @@
 | 
				
			|||||||
#define VTD_INTERRUPT_ADDR_FIRST    0xfee00000ULL
 | 
					#define VTD_INTERRUPT_ADDR_FIRST    0xfee00000ULL
 | 
				
			||||||
#define VTD_INTERRUPT_ADDR_LAST     0xfeefffffULL
 | 
					#define VTD_INTERRUPT_ADDR_LAST     0xfeefffffULL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* The shift of source_id in the key of IOTLB hash table */
 | 
				
			||||||
 | 
					#define VTD_IOTLB_SID_SHIFT         36
 | 
				
			||||||
 | 
					#define VTD_IOTLB_MAX_SIZE          1024    /* Max size of the hash table */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* IOTLB_REG */
 | 
					/* IOTLB_REG */
 | 
				
			||||||
#define VTD_TLB_GLOBAL_FLUSH        (1ULL << 60) /* Global invalidation */
 | 
					#define VTD_TLB_GLOBAL_FLUSH        (1ULL << 60) /* Global invalidation */
 | 
				
			||||||
#define VTD_TLB_DSI_FLUSH           (2ULL << 60) /* Domain-selective */
 | 
					#define VTD_TLB_DSI_FLUSH           (2ULL << 60) /* Domain-selective */
 | 
				
			||||||
@ -121,6 +125,11 @@
 | 
				
			|||||||
#define VTD_TLB_PSI_FLUSH_A         (3ULL << 57)
 | 
					#define VTD_TLB_PSI_FLUSH_A         (3ULL << 57)
 | 
				
			||||||
#define VTD_TLB_FLUSH_GRANU_MASK_A  (3ULL << 57)
 | 
					#define VTD_TLB_FLUSH_GRANU_MASK_A  (3ULL << 57)
 | 
				
			||||||
#define VTD_TLB_IVT                 (1ULL << 63)
 | 
					#define VTD_TLB_IVT                 (1ULL << 63)
 | 
				
			||||||
 | 
					#define VTD_TLB_DID(val)            (((val) >> 32) & VTD_DOMAIN_ID_MASK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* IVA_REG */
 | 
				
			||||||
 | 
					#define VTD_IVA_ADDR(val)       ((val) & ~0xfffULL & ((1ULL << VTD_MGAW) - 1))
 | 
				
			||||||
 | 
					#define VTD_IVA_AM(val)         ((val) & 0x3fULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* GCMD_REG */
 | 
					/* GCMD_REG */
 | 
				
			||||||
#define VTD_GCMD_TE                 (1UL << 31)
 | 
					#define VTD_GCMD_TE                 (1UL << 31)
 | 
				
			||||||
@ -176,6 +185,9 @@
 | 
				
			|||||||
#define VTD_CAP_ND                  (((VTD_DOMAIN_ID_SHIFT - 4) / 2) & 7ULL)
 | 
					#define VTD_CAP_ND                  (((VTD_DOMAIN_ID_SHIFT - 4) / 2) & 7ULL)
 | 
				
			||||||
#define VTD_MGAW                    39  /* Maximum Guest Address Width */
 | 
					#define VTD_MGAW                    39  /* Maximum Guest Address Width */
 | 
				
			||||||
#define VTD_CAP_MGAW                (((VTD_MGAW - 1) & 0x3fULL) << 16)
 | 
					#define VTD_CAP_MGAW                (((VTD_MGAW - 1) & 0x3fULL) << 16)
 | 
				
			||||||
 | 
					#define VTD_MAMV                    9ULL
 | 
				
			||||||
 | 
					#define VTD_CAP_MAMV                (VTD_MAMV << 48)
 | 
				
			||||||
 | 
					#define VTD_CAP_PSI                 (1ULL << 39)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Supported Adjusted Guest Address Widths */
 | 
					/* Supported Adjusted Guest Address Widths */
 | 
				
			||||||
#define VTD_CAP_SAGAW_SHIFT         8
 | 
					#define VTD_CAP_SAGAW_SHIFT         8
 | 
				
			||||||
@ -293,6 +305,26 @@ typedef struct VTDInvDesc VTDInvDesc;
 | 
				
			|||||||
#define VTD_INV_DESC_CC_FM(val)         (((val) >> 48) & 3UL)
 | 
					#define VTD_INV_DESC_CC_FM(val)         (((val) >> 48) & 3UL)
 | 
				
			||||||
#define VTD_INV_DESC_CC_RSVD            0xfffc00000000ffc0ULL
 | 
					#define VTD_INV_DESC_CC_RSVD            0xfffc00000000ffc0ULL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Masks for IOTLB Invalidate Descriptor */
 | 
				
			||||||
 | 
					#define VTD_INV_DESC_IOTLB_G            (3ULL << 4)
 | 
				
			||||||
 | 
					#define VTD_INV_DESC_IOTLB_GLOBAL       (1ULL << 4)
 | 
				
			||||||
 | 
					#define VTD_INV_DESC_IOTLB_DOMAIN       (2ULL << 4)
 | 
				
			||||||
 | 
					#define VTD_INV_DESC_IOTLB_PAGE         (3ULL << 4)
 | 
				
			||||||
 | 
					#define VTD_INV_DESC_IOTLB_DID(val)     (((val) >> 16) & VTD_DOMAIN_ID_MASK)
 | 
				
			||||||
 | 
					#define VTD_INV_DESC_IOTLB_ADDR(val)    ((val) & ~0xfffULL & \
 | 
				
			||||||
 | 
					                                         ((1ULL << VTD_MGAW) - 1))
 | 
				
			||||||
 | 
					#define VTD_INV_DESC_IOTLB_AM(val)      ((val) & 0x3fULL)
 | 
				
			||||||
 | 
					#define VTD_INV_DESC_IOTLB_RSVD_LO      0xffffffff0000ff00ULL
 | 
				
			||||||
 | 
					#define VTD_INV_DESC_IOTLB_RSVD_HI      0xf80ULL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Information about page-selective IOTLB invalidate */
 | 
				
			||||||
 | 
					struct VTDIOTLBPageInvInfo {
 | 
				
			||||||
 | 
					    uint16_t domain_id;
 | 
				
			||||||
 | 
					    uint64_t gfn;
 | 
				
			||||||
 | 
					    uint8_t mask;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					typedef struct VTDIOTLBPageInvInfo VTDIOTLBPageInvInfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Pagesize of VTD paging structures, including root and context tables */
 | 
					/* Pagesize of VTD paging structures, including root and context tables */
 | 
				
			||||||
#define VTD_PAGE_SHIFT              12
 | 
					#define VTD_PAGE_SHIFT              12
 | 
				
			||||||
#define VTD_PAGE_SIZE               (1ULL << VTD_PAGE_SHIFT)
 | 
					#define VTD_PAGE_SIZE               (1ULL << VTD_PAGE_SHIFT)
 | 
				
			||||||
@ -330,7 +362,7 @@ typedef struct VTDRootEntry VTDRootEntry;
 | 
				
			|||||||
#define VTD_CONTEXT_ENTRY_RSVD_LO   (0xff0ULL | ~VTD_HAW_MASK)
 | 
					#define VTD_CONTEXT_ENTRY_RSVD_LO   (0xff0ULL | ~VTD_HAW_MASK)
 | 
				
			||||||
/* hi */
 | 
					/* hi */
 | 
				
			||||||
#define VTD_CONTEXT_ENTRY_AW        7ULL /* Adjusted guest-address-width */
 | 
					#define VTD_CONTEXT_ENTRY_AW        7ULL /* Adjusted guest-address-width */
 | 
				
			||||||
#define VTD_CONTEXT_ENTRY_DID       (0xffffULL << 8) /* Domain Identifier */
 | 
					#define VTD_CONTEXT_ENTRY_DID(val)  (((val) >> 8) & VTD_DOMAIN_ID_MASK)
 | 
				
			||||||
#define VTD_CONTEXT_ENTRY_RSVD_HI   0xffffffffff000080ULL
 | 
					#define VTD_CONTEXT_ENTRY_RSVD_HI   0xffffffffff000080ULL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define VTD_CONTEXT_ENTRY_NR        (VTD_PAGE_SIZE / sizeof(VTDContextEntry))
 | 
					#define VTD_CONTEXT_ENTRY_NR        (VTD_PAGE_SIZE / sizeof(VTDContextEntry))
 | 
				
			||||||
 | 
				
			|||||||
@ -48,7 +48,7 @@ typedef struct VTDContextEntry VTDContextEntry;
 | 
				
			|||||||
typedef struct VTDContextCacheEntry VTDContextCacheEntry;
 | 
					typedef struct VTDContextCacheEntry VTDContextCacheEntry;
 | 
				
			||||||
typedef struct IntelIOMMUState IntelIOMMUState;
 | 
					typedef struct IntelIOMMUState IntelIOMMUState;
 | 
				
			||||||
typedef struct VTDAddressSpace VTDAddressSpace;
 | 
					typedef struct VTDAddressSpace VTDAddressSpace;
 | 
				
			||||||
 | 
					typedef struct VTDIOTLBEntry VTDIOTLBEntry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Context-Entry */
 | 
					/* Context-Entry */
 | 
				
			||||||
struct VTDContextEntry {
 | 
					struct VTDContextEntry {
 | 
				
			||||||
@ -73,6 +73,14 @@ struct VTDAddressSpace {
 | 
				
			|||||||
    VTDContextCacheEntry context_cache_entry;
 | 
					    VTDContextCacheEntry context_cache_entry;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct VTDIOTLBEntry {
 | 
				
			||||||
 | 
					    uint64_t gfn;
 | 
				
			||||||
 | 
					    uint16_t domain_id;
 | 
				
			||||||
 | 
					    uint64_t slpte;
 | 
				
			||||||
 | 
					    bool read_flags;
 | 
				
			||||||
 | 
					    bool write_flags;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* The iommu (DMAR) device state struct */
 | 
					/* The iommu (DMAR) device state struct */
 | 
				
			||||||
struct IntelIOMMUState {
 | 
					struct IntelIOMMUState {
 | 
				
			||||||
    SysBusDevice busdev;
 | 
					    SysBusDevice busdev;
 | 
				
			||||||
@ -103,6 +111,7 @@ struct IntelIOMMUState {
 | 
				
			|||||||
    uint64_t ecap;                  /* The value of extended capability reg */
 | 
					    uint64_t ecap;                  /* The value of extended capability reg */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint32_t context_cache_gen;     /* Should be in [1,MAX] */
 | 
					    uint32_t context_cache_gen;     /* Should be in [1,MAX] */
 | 
				
			||||||
 | 
					    GHashTable *iotlb;              /* IOTLB */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    MemoryRegionIOMMUOps iommu_ops;
 | 
					    MemoryRegionIOMMUOps iommu_ops;
 | 
				
			||||||
    VTDAddressSpace **address_spaces[VTD_PCI_BUS_MAX];
 | 
					    VTDAddressSpace **address_spaces[VTD_PCI_BUS_MAX];
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user