intel_iommu.c (892721d91d9deb2affe4e61334b1dd1b43728f92) | intel_iommu.c (07f7b73398de3b60f28301a9af2a2338710105c7) |
---|---|
1/* 2 * QEMU emulation of an Intel IOMMU (VT-d) 3 * (DMA Remapping device) 4 * 5 * Copyright (C) 2013 Knut Omang, Oracle <knut.omang@oracle.com> 6 * Copyright (C) 2014 Le Tan, <tamlokveer@gmail.com> 7 * 8 * This program is free software; you can redistribute it and/or modify --- 223 unchanged lines hidden (view full) --- 232 } 233 234out: 235 return entry; 236} 237 238static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id, 239 uint16_t domain_id, hwaddr addr, uint64_t slpte, | 1/* 2 * QEMU emulation of an Intel IOMMU (VT-d) 3 * (DMA Remapping device) 4 * 5 * Copyright (C) 2013 Knut Omang, Oracle <knut.omang@oracle.com> 6 * Copyright (C) 2014 Le Tan, <tamlokveer@gmail.com> 7 * 8 * This program is free software; you can redistribute it and/or modify --- 223 unchanged lines hidden (view full) --- 232 } 233 234out: 235 return entry; 236} 237 238static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id, 239 uint16_t domain_id, hwaddr addr, uint64_t slpte, |
240 bool read_flags, bool write_flags, 241 uint32_t level) | 240 uint8_t access_flags, uint32_t level) |
242{ 243 VTDIOTLBEntry *entry = g_malloc(sizeof(*entry)); 244 uint64_t *key = g_malloc(sizeof(*key)); 245 uint64_t gfn = vtd_get_iotlb_gfn(addr, level); 246 247 trace_vtd_iotlb_page_update(source_id, addr, slpte, domain_id); 248 if (g_hash_table_size(s->iotlb) >= VTD_IOTLB_MAX_SIZE) { 249 trace_vtd_iotlb_reset("iotlb exceeds size limit"); 250 vtd_reset_iotlb(s); 251 } 252 253 entry->gfn = gfn; 254 entry->domain_id = domain_id; 255 entry->slpte = slpte; | 241{ 242 VTDIOTLBEntry *entry = g_malloc(sizeof(*entry)); 243 uint64_t *key = g_malloc(sizeof(*key)); 244 uint64_t gfn = vtd_get_iotlb_gfn(addr, level); 245 246 trace_vtd_iotlb_page_update(source_id, addr, slpte, domain_id); 247 if (g_hash_table_size(s->iotlb) >= VTD_IOTLB_MAX_SIZE) { 248 trace_vtd_iotlb_reset("iotlb exceeds size limit"); 249 vtd_reset_iotlb(s); 250 } 251 252 entry->gfn = gfn; 253 entry->domain_id = domain_id; 254 entry->slpte = slpte; |
256 entry->read_flags = read_flags; 257 entry->write_flags = write_flags; | 255 entry->access_flags = access_flags; |
258 entry->mask = vtd_slpt_level_page_mask(level); 259 *key = vtd_get_iotlb_key(gfn, source_id, level); 260 g_hash_table_replace(s->iotlb, key, entry); 261} 262 263/* Given the reg addr of both the message data and address, generate an 264 * interrupt via MSI. 265 */ --- 816 unchanged lines hidden (view full) --- 1082 VTDContextCacheEntry *cc_entry = &vtd_as->context_cache_entry; 1083 uint64_t slpte, page_mask; 1084 uint32_t level; 1085 uint16_t source_id = vtd_make_source_id(bus_num, devfn); 1086 int ret_fr; 1087 bool is_fpd_set = false; 1088 bool reads = true; 1089 bool writes = true; | 256 entry->mask = vtd_slpt_level_page_mask(level); 257 *key = vtd_get_iotlb_key(gfn, source_id, level); 258 g_hash_table_replace(s->iotlb, key, entry); 259} 260 261/* Given the reg addr of both the message data and address, generate an 262 * interrupt via MSI. 263 */ --- 816 unchanged lines hidden (view full) --- 1080 VTDContextCacheEntry *cc_entry = &vtd_as->context_cache_entry; 1081 uint64_t slpte, page_mask; 1082 uint32_t level; 1083 uint16_t source_id = vtd_make_source_id(bus_num, devfn); 1084 int ret_fr; 1085 bool is_fpd_set = false; 1086 bool reads = true; 1087 bool writes = true; |
1088 uint8_t access_flags; |
|
1090 VTDIOTLBEntry *iotlb_entry; 1091 1092 /* 1093 * We have standalone memory region for interrupt addresses, we 1094 * should never receive translation requests in this region. 1095 */ 1096 assert(!vtd_is_interrupt_addr(addr)); 1097 1098 /* Try to fetch slpte form IOTLB */ 1099 iotlb_entry = vtd_lookup_iotlb(s, source_id, addr); 1100 if (iotlb_entry) { 1101 trace_vtd_iotlb_page_hit(source_id, addr, iotlb_entry->slpte, 1102 iotlb_entry->domain_id); 1103 slpte = iotlb_entry->slpte; | 1089 VTDIOTLBEntry *iotlb_entry; 1090 1091 /* 1092 * We have standalone memory region for interrupt addresses, we 1093 * should never receive translation requests in this region. 1094 */ 1095 assert(!vtd_is_interrupt_addr(addr)); 1096 1097 /* Try to fetch slpte form IOTLB */ 1098 iotlb_entry = vtd_lookup_iotlb(s, source_id, addr); 1099 if (iotlb_entry) { 1100 trace_vtd_iotlb_page_hit(source_id, addr, iotlb_entry->slpte, 1101 iotlb_entry->domain_id); 1102 slpte = iotlb_entry->slpte; |
1104 reads = iotlb_entry->read_flags; 1105 writes = iotlb_entry->write_flags; | 1103 access_flags = iotlb_entry->access_flags; |
1106 page_mask = iotlb_entry->mask; 1107 goto out; 1108 } 1109 1110 /* Try to fetch context-entry from cache first */ 1111 if (cc_entry->context_cache_gen == s->context_cache_gen) { 1112 trace_vtd_iotlb_cc_hit(bus_num, devfn, cc_entry->context_entry.hi, 1113 cc_entry->context_entry.lo, --- 53 unchanged lines hidden (view full) --- 1167 trace_vtd_fault_disabled(); 1168 } else { 1169 vtd_report_dmar_fault(s, source_id, addr, ret_fr, is_write); 1170 } 1171 goto error; 1172 } 1173 1174 page_mask = vtd_slpt_level_page_mask(level); | 1104 page_mask = iotlb_entry->mask; 1105 goto out; 1106 } 1107 1108 /* Try to fetch context-entry from cache first */ 1109 if (cc_entry->context_cache_gen == s->context_cache_gen) { 1110 trace_vtd_iotlb_cc_hit(bus_num, devfn, cc_entry->context_entry.hi, 1111 cc_entry->context_entry.lo, --- 53 unchanged lines hidden (view full) --- 1165 trace_vtd_fault_disabled(); 1166 } else { 1167 vtd_report_dmar_fault(s, source_id, addr, ret_fr, is_write); 1168 } 1169 goto error; 1170 } 1171 1172 page_mask = vtd_slpt_level_page_mask(level); |
1173 access_flags = IOMMU_ACCESS_FLAG(reads, writes); |
|
1175 vtd_update_iotlb(s, source_id, VTD_CONTEXT_ENTRY_DID(ce.hi), addr, slpte, | 1174 vtd_update_iotlb(s, source_id, VTD_CONTEXT_ENTRY_DID(ce.hi), addr, slpte, |
1176 reads, writes, level); | 1175 access_flags, level); |
1177out: 1178 entry->iova = addr & page_mask; 1179 entry->translated_addr = vtd_get_slpte_addr(slpte) & page_mask; 1180 entry->addr_mask = ~page_mask; | 1176out: 1177 entry->iova = addr & page_mask; 1178 entry->translated_addr = vtd_get_slpte_addr(slpte) & page_mask; 1179 entry->addr_mask = ~page_mask; |
1181 entry->perm = IOMMU_ACCESS_FLAG(reads, writes); | 1180 entry->perm = access_flags; |
1182 return true; 1183 1184error: 1185 entry->iova = 0; 1186 entry->translated_addr = 0; 1187 entry->addr_mask = 0; 1188 entry->perm = IOMMU_NONE; 1189 return false; --- 1908 unchanged lines hidden --- | 1181 return true; 1182 1183error: 1184 entry->iova = 0; 1185 entry->translated_addr = 0; 1186 entry->addr_mask = 0; 1187 entry->perm = IOMMU_NONE; 1188 return false; --- 1908 unchanged lines hidden --- |