Skip to content

Commit

Permalink
intel-iommu: block output address in interrupt address range
Browse files Browse the repository at this point in the history
According to vtd spec v3.3 3.14:

"""
Software must not program paging-structure entries to remap any
address to the interrupt address range. 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.
"""

This patch blocks the request that result in interrupt address range.

Signed-off-by: Jason Wang <jasowang@redhat.com>
Message-Id: <20220210092815.45174-2-jasowang@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
  • Loading branch information
jasowang authored and taylorsimpson committed Jun 6, 2022
1 parent 53d6beb commit 6eb6e82
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 1 deletion.
27 changes: 26 additions & 1 deletion hw/i386/intel_iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 ")",
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
};

Expand Down
4 changes: 4 additions & 0 deletions hw/i386/intel_iommu_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,8 @@ typedef enum VTDFaultReason {
* context-entry.
*/
VTD_FR_CONTEXT_ENTRY_TT,
/* Output address in the interrupt address range */
VTD_FR_INTERRUPT_ADDR = 0xE,

/* Interrupt remapping transition faults */
VTD_FR_IR_REQ_RSVD = 0x20, /* One or more IR request reserved
Expand All @@ -304,6 +306,8 @@ typedef enum VTDFaultReason {

VTD_FR_PASID_TABLE_INV = 0x58, /*Invalid PASID table entry */

/* Output address in the interrupt address range for scalable mode */
VTD_FR_SM_INTERRUPT_ADDR = 0x87,
VTD_FR_MAX, /* Guard */
} VTDFaultReason;

Expand Down

0 comments on commit 6eb6e82

Please sign in to comment.