|
@@ -1020,6 +1020,7 @@ static int vtd_iova_to_slpte(IntelIOMMUState *s, VTDContextEntry *ce,
|
|
|
uint32_t offset;
|
|
|
uint64_t slpte;
|
|
|
uint64_t access_right_check;
|
|
|
+ uint64_t xlat, size;
|
|
|
|
|
|
if (!vtd_iova_range_check(s, iova, ce, aw_bits)) {
|
|
|
error_report_once("%s: detected IOVA overflow (iova=0x%" PRIx64 ")",
|
|
@@ -1064,11 +1065,33 @@ static int vtd_iova_to_slpte(IntelIOMMUState *s, VTDContextEntry *ce,
|
|
|
if (vtd_is_last_slpte(slpte, level)) {
|
|
|
*slptep = slpte;
|
|
|
*slpte_level = level;
|
|
|
- return 0;
|
|
|
+ break;
|
|
|
}
|
|
|
addr = vtd_get_slpte_addr(slpte, aw_bits);
|
|
|
level--;
|
|
|
}
|
|
|
+
|
|
|
+ xlat = vtd_get_slpte_addr(*slptep, aw_bits);
|
|
|
+ size = ~vtd_slpt_level_page_mask(level) + 1;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * From VT-d spec 3.14: Untranslated requests and translation
|
|
|
+ * requests that result in an address in the interrupt range will be
|
|
|
+ * blocked with condition code LGN.4 or SGN.8.
|
|
|
+ */
|
|
|
+ if ((xlat > VTD_INTERRUPT_ADDR_LAST ||
|
|
|
+ xlat + size - 1 < VTD_INTERRUPT_ADDR_FIRST)) {
|
|
|
+ return 0;
|
|
|
+ } else {
|
|
|
+ error_report_once("%s: xlat address is in interrupt range "
|
|
|
+ "(iova=0x%" PRIx64 ", level=0x%" PRIx32 ", "
|
|
|
+ "slpte=0x%" PRIx64 ", write=%d, "
|
|
|
+ "xlat=0x%" PRIx64 ", size=0x%" PRIx64 ")",
|
|
|
+ __func__, iova, level, slpte, is_write,
|
|
|
+ xlat, size);
|
|
|
+ return s->scalable_mode ? -VTD_FR_SM_INTERRUPT_ADDR :
|
|
|
+ -VTD_FR_INTERRUPT_ADDR;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
typedef int (*vtd_page_walk_hook)(IOMMUTLBEvent *event, void *private);
|
|
@@ -1628,10 +1651,12 @@ static const bool vtd_qualified_faults[] = {
|
|
|
[VTD_FR_PAGING_ENTRY_INV] = true,
|
|
|
[VTD_FR_ROOT_TABLE_INV] = false,
|
|
|
[VTD_FR_CONTEXT_TABLE_INV] = false,
|
|
|
+ [VTD_FR_INTERRUPT_ADDR] = true,
|
|
|
[VTD_FR_ROOT_ENTRY_RSVD] = false,
|
|
|
[VTD_FR_PAGING_ENTRY_RSVD] = true,
|
|
|
[VTD_FR_CONTEXT_ENTRY_TT] = true,
|
|
|
[VTD_FR_PASID_TABLE_INV] = false,
|
|
|
+ [VTD_FR_SM_INTERRUPT_ADDR] = true,
|
|
|
[VTD_FR_MAX] = false,
|
|
|
};
|
|
|
|