mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-05 00:33:55 -06:00
intel_iommu: Rename slpte to pte
Because we will support both FST(a.k.a, FLT) and SST(a.k.a, SLT) translation, rename variable and functions from slpte to pte whenever possible. But some are SST only, they are renamed with sl_ prefix. Signed-off-by: Yi Liu <yi.l.liu@intel.com> Co-developed-by: Clément Mathieu--Drif <clement.mathieu--drif@eviden.com> Signed-off-by: Clément Mathieu--Drif <clement.mathieu--drif@eviden.com> Signed-off-by: Yi Sun <yi.y.sun@linux.intel.com> Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> Acked-by: Jason Wang <jasowang@redhat.com> Reviewed-by: Yi Liu <yi.l.liu@intel.com> Message-Id: <20241212083757.605022-6-zhenzhong.duan@intel.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
ad0a7f1e1e
commit
eda4c9b5b3
3 changed files with 78 additions and 77 deletions
|
@ -48,7 +48,8 @@
|
||||||
|
|
||||||
/* pe operations */
|
/* pe operations */
|
||||||
#define VTD_PE_GET_TYPE(pe) ((pe)->val[0] & VTD_SM_PASID_ENTRY_PGTT)
|
#define VTD_PE_GET_TYPE(pe) ((pe)->val[0] & VTD_SM_PASID_ENTRY_PGTT)
|
||||||
#define VTD_PE_GET_LEVEL(pe) (2 + (((pe)->val[0] >> 2) & VTD_SM_PASID_ENTRY_AW))
|
#define VTD_PE_GET_SL_LEVEL(pe) \
|
||||||
|
(2 + (((pe)->val[0] >> 2) & VTD_SM_PASID_ENTRY_AW))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PCI bus number (or SID) is not reliable since the device is usaully
|
* PCI bus number (or SID) is not reliable since the device is usaully
|
||||||
|
@ -284,15 +285,15 @@ static gboolean vtd_hash_remove_by_domain(gpointer key, gpointer value,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The shift of an addr for a certain level of paging structure */
|
/* The shift of an addr for a certain level of paging structure */
|
||||||
static inline uint32_t vtd_slpt_level_shift(uint32_t level)
|
static inline uint32_t vtd_pt_level_shift(uint32_t level)
|
||||||
{
|
{
|
||||||
assert(level != 0);
|
assert(level != 0);
|
||||||
return VTD_PAGE_SHIFT_4K + (level - 1) * VTD_SL_LEVEL_BITS;
|
return VTD_PAGE_SHIFT_4K + (level - 1) * VTD_LEVEL_BITS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t vtd_slpt_level_page_mask(uint32_t level)
|
static inline uint64_t vtd_pt_level_page_mask(uint32_t level)
|
||||||
{
|
{
|
||||||
return ~((1ULL << vtd_slpt_level_shift(level)) - 1);
|
return ~((1ULL << vtd_pt_level_shift(level)) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean vtd_hash_remove_by_page(gpointer key, gpointer value,
|
static gboolean vtd_hash_remove_by_page(gpointer key, gpointer value,
|
||||||
|
@ -349,7 +350,7 @@ static void vtd_reset_caches(IntelIOMMUState *s)
|
||||||
|
|
||||||
static uint64_t vtd_get_iotlb_gfn(hwaddr addr, uint32_t level)
|
static uint64_t vtd_get_iotlb_gfn(hwaddr addr, uint32_t level)
|
||||||
{
|
{
|
||||||
return (addr & vtd_slpt_level_page_mask(level)) >> VTD_PAGE_SHIFT_4K;
|
return (addr & vtd_pt_level_page_mask(level)) >> VTD_PAGE_SHIFT_4K;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Must be called with IOMMU lock held */
|
/* Must be called with IOMMU lock held */
|
||||||
|
@ -360,7 +361,7 @@ static VTDIOTLBEntry *vtd_lookup_iotlb(IntelIOMMUState *s, uint16_t source_id,
|
||||||
VTDIOTLBEntry *entry;
|
VTDIOTLBEntry *entry;
|
||||||
unsigned level;
|
unsigned level;
|
||||||
|
|
||||||
for (level = VTD_SL_PT_LEVEL; level < VTD_SL_PML4_LEVEL; level++) {
|
for (level = VTD_PT_LEVEL; level < VTD_PML4_LEVEL; level++) {
|
||||||
key.gfn = vtd_get_iotlb_gfn(addr, level);
|
key.gfn = vtd_get_iotlb_gfn(addr, level);
|
||||||
key.level = level;
|
key.level = level;
|
||||||
key.sid = source_id;
|
key.sid = source_id;
|
||||||
|
@ -377,7 +378,7 @@ out:
|
||||||
|
|
||||||
/* Must be with IOMMU lock held */
|
/* Must be with IOMMU lock held */
|
||||||
static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id,
|
static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id,
|
||||||
uint16_t domain_id, hwaddr addr, uint64_t slpte,
|
uint16_t domain_id, hwaddr addr, uint64_t pte,
|
||||||
uint8_t access_flags, uint32_t level,
|
uint8_t access_flags, uint32_t level,
|
||||||
uint32_t pasid)
|
uint32_t pasid)
|
||||||
{
|
{
|
||||||
|
@ -385,7 +386,7 @@ static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id,
|
||||||
struct vtd_iotlb_key *key = g_malloc(sizeof(*key));
|
struct vtd_iotlb_key *key = g_malloc(sizeof(*key));
|
||||||
uint64_t gfn = vtd_get_iotlb_gfn(addr, level);
|
uint64_t gfn = vtd_get_iotlb_gfn(addr, level);
|
||||||
|
|
||||||
trace_vtd_iotlb_page_update(source_id, addr, slpte, domain_id);
|
trace_vtd_iotlb_page_update(source_id, addr, pte, domain_id);
|
||||||
if (g_hash_table_size(s->iotlb) >= VTD_IOTLB_MAX_SIZE) {
|
if (g_hash_table_size(s->iotlb) >= VTD_IOTLB_MAX_SIZE) {
|
||||||
trace_vtd_iotlb_reset("iotlb exceeds size limit");
|
trace_vtd_iotlb_reset("iotlb exceeds size limit");
|
||||||
vtd_reset_iotlb_locked(s);
|
vtd_reset_iotlb_locked(s);
|
||||||
|
@ -393,9 +394,9 @@ static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id,
|
||||||
|
|
||||||
entry->gfn = gfn;
|
entry->gfn = gfn;
|
||||||
entry->domain_id = domain_id;
|
entry->domain_id = domain_id;
|
||||||
entry->slpte = slpte;
|
entry->pte = pte;
|
||||||
entry->access_flags = access_flags;
|
entry->access_flags = access_flags;
|
||||||
entry->mask = vtd_slpt_level_page_mask(level);
|
entry->mask = vtd_pt_level_page_mask(level);
|
||||||
entry->pasid = pasid;
|
entry->pasid = pasid;
|
||||||
|
|
||||||
key->gfn = gfn;
|
key->gfn = gfn;
|
||||||
|
@ -710,32 +711,32 @@ static inline dma_addr_t vtd_ce_get_slpt_base(VTDContextEntry *ce)
|
||||||
return ce->lo & VTD_CONTEXT_ENTRY_SLPTPTR;
|
return ce->lo & VTD_CONTEXT_ENTRY_SLPTPTR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t vtd_get_slpte_addr(uint64_t slpte, uint8_t aw)
|
static inline uint64_t vtd_get_pte_addr(uint64_t pte, uint8_t aw)
|
||||||
{
|
{
|
||||||
return slpte & VTD_SL_PT_BASE_ADDR_MASK(aw);
|
return pte & VTD_PT_BASE_ADDR_MASK(aw);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Whether the pte indicates the address of the page frame */
|
/* Whether the pte indicates the address of the page frame */
|
||||||
static inline bool vtd_is_last_slpte(uint64_t slpte, uint32_t level)
|
static inline bool vtd_is_last_pte(uint64_t pte, uint32_t level)
|
||||||
{
|
{
|
||||||
return level == VTD_SL_PT_LEVEL || (slpte & VTD_SL_PT_PAGE_SIZE_MASK);
|
return level == VTD_PT_LEVEL || (pte & VTD_PT_PAGE_SIZE_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the content of a spte located in @base_addr[@index] */
|
/* Get the content of a pte located in @base_addr[@index] */
|
||||||
static uint64_t vtd_get_slpte(dma_addr_t base_addr, uint32_t index)
|
static uint64_t vtd_get_pte(dma_addr_t base_addr, uint32_t index)
|
||||||
{
|
{
|
||||||
uint64_t slpte;
|
uint64_t pte;
|
||||||
|
|
||||||
assert(index < VTD_SL_PT_ENTRY_NR);
|
assert(index < VTD_PT_ENTRY_NR);
|
||||||
|
|
||||||
if (dma_memory_read(&address_space_memory,
|
if (dma_memory_read(&address_space_memory,
|
||||||
base_addr + index * sizeof(slpte),
|
base_addr + index * sizeof(pte),
|
||||||
&slpte, sizeof(slpte), MEMTXATTRS_UNSPECIFIED)) {
|
&pte, sizeof(pte), MEMTXATTRS_UNSPECIFIED)) {
|
||||||
slpte = (uint64_t)-1;
|
pte = (uint64_t)-1;
|
||||||
return slpte;
|
return pte;
|
||||||
}
|
}
|
||||||
slpte = le64_to_cpu(slpte);
|
pte = le64_to_cpu(pte);
|
||||||
return slpte;
|
return pte;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Given an iova and the level of paging structure, return the offset
|
/* Given an iova and the level of paging structure, return the offset
|
||||||
|
@ -743,12 +744,12 @@ static uint64_t vtd_get_slpte(dma_addr_t base_addr, uint32_t index)
|
||||||
*/
|
*/
|
||||||
static inline uint32_t vtd_iova_level_offset(uint64_t iova, uint32_t level)
|
static inline uint32_t vtd_iova_level_offset(uint64_t iova, uint32_t level)
|
||||||
{
|
{
|
||||||
return (iova >> vtd_slpt_level_shift(level)) &
|
return (iova >> vtd_pt_level_shift(level)) &
|
||||||
((1ULL << VTD_SL_LEVEL_BITS) - 1);
|
((1ULL << VTD_LEVEL_BITS) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check Capability Register to see if the @level of page-table is supported */
|
/* Check Capability Register to see if the @level of page-table is supported */
|
||||||
static inline bool vtd_is_level_supported(IntelIOMMUState *s, uint32_t level)
|
static inline bool vtd_is_sl_level_supported(IntelIOMMUState *s, uint32_t level)
|
||||||
{
|
{
|
||||||
return VTD_CAP_SAGAW_MASK & s->cap &
|
return VTD_CAP_SAGAW_MASK & s->cap &
|
||||||
(1ULL << (level - 2 + VTD_CAP_SAGAW_SHIFT));
|
(1ULL << (level - 2 + VTD_CAP_SAGAW_SHIFT));
|
||||||
|
@ -833,7 +834,7 @@ static int vtd_get_pe_in_pasid_leaf_table(IntelIOMMUState *s,
|
||||||
|
|
||||||
pgtt = VTD_PE_GET_TYPE(pe);
|
pgtt = VTD_PE_GET_TYPE(pe);
|
||||||
if (pgtt == VTD_SM_PASID_ENTRY_SLT &&
|
if (pgtt == VTD_SM_PASID_ENTRY_SLT &&
|
||||||
!vtd_is_level_supported(s, VTD_PE_GET_LEVEL(pe))) {
|
!vtd_is_sl_level_supported(s, VTD_PE_GET_SL_LEVEL(pe))) {
|
||||||
return -VTD_FR_PASID_TABLE_ENTRY_INV;
|
return -VTD_FR_PASID_TABLE_ENTRY_INV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -972,7 +973,7 @@ static uint32_t vtd_get_iova_level(IntelIOMMUState *s,
|
||||||
|
|
||||||
if (s->root_scalable) {
|
if (s->root_scalable) {
|
||||||
vtd_ce_get_rid2pasid_entry(s, ce, &pe, pasid);
|
vtd_ce_get_rid2pasid_entry(s, ce, &pe, pasid);
|
||||||
return VTD_PE_GET_LEVEL(&pe);
|
return VTD_PE_GET_SL_LEVEL(&pe);
|
||||||
}
|
}
|
||||||
|
|
||||||
return vtd_ce_get_level(ce);
|
return vtd_ce_get_level(ce);
|
||||||
|
@ -1040,9 +1041,9 @@ static inline uint64_t vtd_iova_limit(IntelIOMMUState *s,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return true if IOVA passes range check, otherwise false. */
|
/* Return true if IOVA passes range check, otherwise false. */
|
||||||
static inline bool vtd_iova_range_check(IntelIOMMUState *s,
|
static inline bool vtd_iova_sl_range_check(IntelIOMMUState *s,
|
||||||
uint64_t iova, VTDContextEntry *ce,
|
uint64_t iova, VTDContextEntry *ce,
|
||||||
uint8_t aw, uint32_t pasid)
|
uint8_t aw, uint32_t pasid)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Check if @iova is above 2^X-1, where X is the minimum of MGAW
|
* Check if @iova is above 2^X-1, where X is the minimum of MGAW
|
||||||
|
@ -1083,17 +1084,17 @@ static bool vtd_slpte_nonzero_rsvd(uint64_t slpte, uint32_t level)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We should have caught a guest-mis-programmed level earlier,
|
* We should have caught a guest-mis-programmed level earlier,
|
||||||
* via vtd_is_level_supported.
|
* via vtd_is_sl_level_supported.
|
||||||
*/
|
*/
|
||||||
assert(level < VTD_SPTE_RSVD_LEN);
|
assert(level < VTD_SPTE_RSVD_LEN);
|
||||||
/*
|
/*
|
||||||
* Zero level doesn't exist. The smallest level is VTD_SL_PT_LEVEL=1 and
|
* Zero level doesn't exist. The smallest level is VTD_PT_LEVEL=1 and
|
||||||
* checked by vtd_is_last_slpte().
|
* checked by vtd_is_last_pte().
|
||||||
*/
|
*/
|
||||||
assert(level);
|
assert(level);
|
||||||
|
|
||||||
if ((level == VTD_SL_PD_LEVEL || level == VTD_SL_PDP_LEVEL) &&
|
if ((level == VTD_PD_LEVEL || level == VTD_PDP_LEVEL) &&
|
||||||
(slpte & VTD_SL_PT_PAGE_SIZE_MASK)) {
|
(slpte & VTD_PT_PAGE_SIZE_MASK)) {
|
||||||
/* large page */
|
/* large page */
|
||||||
rsvd_mask = vtd_spte_rsvd_large[level];
|
rsvd_mask = vtd_spte_rsvd_large[level];
|
||||||
} else {
|
} else {
|
||||||
|
@ -1119,7 +1120,7 @@ static int vtd_iova_to_slpte(IntelIOMMUState *s, VTDContextEntry *ce,
|
||||||
uint64_t access_right_check;
|
uint64_t access_right_check;
|
||||||
uint64_t xlat, size;
|
uint64_t xlat, size;
|
||||||
|
|
||||||
if (!vtd_iova_range_check(s, iova, ce, aw_bits, pasid)) {
|
if (!vtd_iova_sl_range_check(s, iova, ce, aw_bits, pasid)) {
|
||||||
error_report_once("%s: detected IOVA overflow (iova=0x%" PRIx64 ","
|
error_report_once("%s: detected IOVA overflow (iova=0x%" PRIx64 ","
|
||||||
"pasid=0x%" PRIx32 ")", __func__, iova, pasid);
|
"pasid=0x%" PRIx32 ")", __func__, iova, pasid);
|
||||||
return -VTD_FR_ADDR_BEYOND_MGAW;
|
return -VTD_FR_ADDR_BEYOND_MGAW;
|
||||||
|
@ -1130,7 +1131,7 @@ static int vtd_iova_to_slpte(IntelIOMMUState *s, VTDContextEntry *ce,
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
offset = vtd_iova_level_offset(iova, level);
|
offset = vtd_iova_level_offset(iova, level);
|
||||||
slpte = vtd_get_slpte(addr, offset);
|
slpte = vtd_get_pte(addr, offset);
|
||||||
|
|
||||||
if (slpte == (uint64_t)-1) {
|
if (slpte == (uint64_t)-1) {
|
||||||
error_report_once("%s: detected read error on DMAR slpte "
|
error_report_once("%s: detected read error on DMAR slpte "
|
||||||
|
@ -1161,17 +1162,17 @@ static int vtd_iova_to_slpte(IntelIOMMUState *s, VTDContextEntry *ce,
|
||||||
return -VTD_FR_PAGING_ENTRY_RSVD;
|
return -VTD_FR_PAGING_ENTRY_RSVD;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vtd_is_last_slpte(slpte, level)) {
|
if (vtd_is_last_pte(slpte, level)) {
|
||||||
*slptep = slpte;
|
*slptep = slpte;
|
||||||
*slpte_level = level;
|
*slpte_level = level;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
addr = vtd_get_slpte_addr(slpte, aw_bits);
|
addr = vtd_get_pte_addr(slpte, aw_bits);
|
||||||
level--;
|
level--;
|
||||||
}
|
}
|
||||||
|
|
||||||
xlat = vtd_get_slpte_addr(*slptep, aw_bits);
|
xlat = vtd_get_pte_addr(*slptep, aw_bits);
|
||||||
size = ~vtd_slpt_level_page_mask(level) + 1;
|
size = ~vtd_pt_level_page_mask(level) + 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* From VT-d spec 3.14: Untranslated requests and translation
|
* From VT-d spec 3.14: Untranslated requests and translation
|
||||||
|
@ -1322,14 +1323,14 @@ static int vtd_page_walk_level(dma_addr_t addr, uint64_t start,
|
||||||
|
|
||||||
trace_vtd_page_walk_level(addr, level, start, end);
|
trace_vtd_page_walk_level(addr, level, start, end);
|
||||||
|
|
||||||
subpage_size = 1ULL << vtd_slpt_level_shift(level);
|
subpage_size = 1ULL << vtd_pt_level_shift(level);
|
||||||
subpage_mask = vtd_slpt_level_page_mask(level);
|
subpage_mask = vtd_pt_level_page_mask(level);
|
||||||
|
|
||||||
while (iova < end) {
|
while (iova < end) {
|
||||||
iova_next = (iova & subpage_mask) + subpage_size;
|
iova_next = (iova & subpage_mask) + subpage_size;
|
||||||
|
|
||||||
offset = vtd_iova_level_offset(iova, level);
|
offset = vtd_iova_level_offset(iova, level);
|
||||||
slpte = vtd_get_slpte(addr, offset);
|
slpte = vtd_get_pte(addr, offset);
|
||||||
|
|
||||||
if (slpte == (uint64_t)-1) {
|
if (slpte == (uint64_t)-1) {
|
||||||
trace_vtd_page_walk_skip_read(iova, iova_next);
|
trace_vtd_page_walk_skip_read(iova, iova_next);
|
||||||
|
@ -1352,12 +1353,12 @@ static int vtd_page_walk_level(dma_addr_t addr, uint64_t start,
|
||||||
*/
|
*/
|
||||||
entry_valid = read_cur | write_cur;
|
entry_valid = read_cur | write_cur;
|
||||||
|
|
||||||
if (!vtd_is_last_slpte(slpte, level) && entry_valid) {
|
if (!vtd_is_last_pte(slpte, level) && entry_valid) {
|
||||||
/*
|
/*
|
||||||
* This is a valid PDE (or even bigger than PDE). We need
|
* This is a valid PDE (or even bigger than PDE). We need
|
||||||
* to walk one further level.
|
* to walk one further level.
|
||||||
*/
|
*/
|
||||||
ret = vtd_page_walk_level(vtd_get_slpte_addr(slpte, info->aw),
|
ret = vtd_page_walk_level(vtd_get_pte_addr(slpte, info->aw),
|
||||||
iova, MIN(iova_next, end), level - 1,
|
iova, MIN(iova_next, end), level - 1,
|
||||||
read_cur, write_cur, info);
|
read_cur, write_cur, info);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1374,7 +1375,7 @@ static int vtd_page_walk_level(dma_addr_t addr, uint64_t start,
|
||||||
event.entry.perm = IOMMU_ACCESS_FLAG(read_cur, write_cur);
|
event.entry.perm = IOMMU_ACCESS_FLAG(read_cur, write_cur);
|
||||||
event.entry.addr_mask = ~subpage_mask;
|
event.entry.addr_mask = ~subpage_mask;
|
||||||
/* NOTE: this is only meaningful if entry_valid == true */
|
/* NOTE: this is only meaningful if entry_valid == true */
|
||||||
event.entry.translated_addr = vtd_get_slpte_addr(slpte, info->aw);
|
event.entry.translated_addr = vtd_get_pte_addr(slpte, info->aw);
|
||||||
event.type = event.entry.perm ? IOMMU_NOTIFIER_MAP :
|
event.type = event.entry.perm ? IOMMU_NOTIFIER_MAP :
|
||||||
IOMMU_NOTIFIER_UNMAP;
|
IOMMU_NOTIFIER_UNMAP;
|
||||||
ret = vtd_page_walk_one(&event, info);
|
ret = vtd_page_walk_one(&event, info);
|
||||||
|
@ -1408,11 +1409,11 @@ static int vtd_page_walk(IntelIOMMUState *s, VTDContextEntry *ce,
|
||||||
dma_addr_t addr = vtd_get_iova_pgtbl_base(s, ce, pasid);
|
dma_addr_t addr = vtd_get_iova_pgtbl_base(s, ce, pasid);
|
||||||
uint32_t level = vtd_get_iova_level(s, ce, pasid);
|
uint32_t level = vtd_get_iova_level(s, ce, pasid);
|
||||||
|
|
||||||
if (!vtd_iova_range_check(s, start, ce, info->aw, pasid)) {
|
if (!vtd_iova_sl_range_check(s, start, ce, info->aw, pasid)) {
|
||||||
return -VTD_FR_ADDR_BEYOND_MGAW;
|
return -VTD_FR_ADDR_BEYOND_MGAW;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vtd_iova_range_check(s, end, ce, info->aw, pasid)) {
|
if (!vtd_iova_sl_range_check(s, end, ce, info->aw, pasid)) {
|
||||||
/* Fix end so that it reaches the maximum */
|
/* Fix end so that it reaches the maximum */
|
||||||
end = vtd_iova_limit(s, ce, info->aw, pasid);
|
end = vtd_iova_limit(s, ce, info->aw, pasid);
|
||||||
}
|
}
|
||||||
|
@ -1527,7 +1528,7 @@ static int vtd_dev_to_context_entry(IntelIOMMUState *s, uint8_t bus_num,
|
||||||
|
|
||||||
/* Check if the programming of context-entry is valid */
|
/* Check if the programming of context-entry is valid */
|
||||||
if (!s->root_scalable &&
|
if (!s->root_scalable &&
|
||||||
!vtd_is_level_supported(s, vtd_ce_get_level(ce))) {
|
!vtd_is_sl_level_supported(s, vtd_ce_get_level(ce))) {
|
||||||
error_report_once("%s: invalid context entry: hi=%"PRIx64
|
error_report_once("%s: invalid context entry: hi=%"PRIx64
|
||||||
", lo=%"PRIx64" (level %d not supported)",
|
", lo=%"PRIx64" (level %d not supported)",
|
||||||
__func__, ce->hi, ce->lo,
|
__func__, ce->hi, ce->lo,
|
||||||
|
@ -1897,7 +1898,7 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
|
||||||
VTDContextEntry ce;
|
VTDContextEntry ce;
|
||||||
uint8_t bus_num = pci_bus_num(bus);
|
uint8_t bus_num = pci_bus_num(bus);
|
||||||
VTDContextCacheEntry *cc_entry;
|
VTDContextCacheEntry *cc_entry;
|
||||||
uint64_t slpte, page_mask;
|
uint64_t pte, page_mask;
|
||||||
uint32_t level, pasid = vtd_as->pasid;
|
uint32_t level, pasid = vtd_as->pasid;
|
||||||
uint16_t source_id = PCI_BUILD_BDF(bus_num, devfn);
|
uint16_t source_id = PCI_BUILD_BDF(bus_num, devfn);
|
||||||
int ret_fr;
|
int ret_fr;
|
||||||
|
@ -1918,13 +1919,13 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
|
||||||
|
|
||||||
cc_entry = &vtd_as->context_cache_entry;
|
cc_entry = &vtd_as->context_cache_entry;
|
||||||
|
|
||||||
/* Try to fetch slpte form IOTLB, we don't need RID2PASID logic */
|
/* Try to fetch pte from IOTLB, we don't need RID2PASID logic */
|
||||||
if (!rid2pasid) {
|
if (!rid2pasid) {
|
||||||
iotlb_entry = vtd_lookup_iotlb(s, source_id, pasid, addr);
|
iotlb_entry = vtd_lookup_iotlb(s, source_id, pasid, addr);
|
||||||
if (iotlb_entry) {
|
if (iotlb_entry) {
|
||||||
trace_vtd_iotlb_page_hit(source_id, addr, iotlb_entry->slpte,
|
trace_vtd_iotlb_page_hit(source_id, addr, iotlb_entry->pte,
|
||||||
iotlb_entry->domain_id);
|
iotlb_entry->domain_id);
|
||||||
slpte = iotlb_entry->slpte;
|
pte = iotlb_entry->pte;
|
||||||
access_flags = iotlb_entry->access_flags;
|
access_flags = iotlb_entry->access_flags;
|
||||||
page_mask = iotlb_entry->mask;
|
page_mask = iotlb_entry->mask;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -1996,20 +1997,20 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try to fetch slpte form IOTLB for RID2PASID slow path */
|
/* Try to fetch pte from IOTLB for RID2PASID slow path */
|
||||||
if (rid2pasid) {
|
if (rid2pasid) {
|
||||||
iotlb_entry = vtd_lookup_iotlb(s, source_id, pasid, addr);
|
iotlb_entry = vtd_lookup_iotlb(s, source_id, pasid, addr);
|
||||||
if (iotlb_entry) {
|
if (iotlb_entry) {
|
||||||
trace_vtd_iotlb_page_hit(source_id, addr, iotlb_entry->slpte,
|
trace_vtd_iotlb_page_hit(source_id, addr, iotlb_entry->pte,
|
||||||
iotlb_entry->domain_id);
|
iotlb_entry->domain_id);
|
||||||
slpte = iotlb_entry->slpte;
|
pte = iotlb_entry->pte;
|
||||||
access_flags = iotlb_entry->access_flags;
|
access_flags = iotlb_entry->access_flags;
|
||||||
page_mask = iotlb_entry->mask;
|
page_mask = iotlb_entry->mask;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret_fr = vtd_iova_to_slpte(s, &ce, addr, is_write, &slpte, &level,
|
ret_fr = vtd_iova_to_slpte(s, &ce, addr, is_write, &pte, &level,
|
||||||
&reads, &writes, s->aw_bits, pasid);
|
&reads, &writes, s->aw_bits, pasid);
|
||||||
if (ret_fr) {
|
if (ret_fr) {
|
||||||
vtd_report_fault(s, -ret_fr, is_fpd_set, source_id,
|
vtd_report_fault(s, -ret_fr, is_fpd_set, source_id,
|
||||||
|
@ -2017,14 +2018,14 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
page_mask = vtd_slpt_level_page_mask(level);
|
page_mask = vtd_pt_level_page_mask(level);
|
||||||
access_flags = IOMMU_ACCESS_FLAG(reads, writes);
|
access_flags = IOMMU_ACCESS_FLAG(reads, writes);
|
||||||
vtd_update_iotlb(s, source_id, vtd_get_domain_id(s, &ce, pasid),
|
vtd_update_iotlb(s, source_id, vtd_get_domain_id(s, &ce, pasid),
|
||||||
addr, slpte, access_flags, level, pasid);
|
addr, pte, access_flags, level, pasid);
|
||||||
out:
|
out:
|
||||||
vtd_iommu_unlock(s);
|
vtd_iommu_unlock(s);
|
||||||
entry->iova = addr & page_mask;
|
entry->iova = addr & page_mask;
|
||||||
entry->translated_addr = vtd_get_slpte_addr(slpte, s->aw_bits) & page_mask;
|
entry->translated_addr = vtd_get_pte_addr(pte, s->aw_bits) & page_mask;
|
||||||
entry->addr_mask = ~page_mask;
|
entry->addr_mask = ~page_mask;
|
||||||
entry->perm = access_flags;
|
entry->perm = access_flags;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -533,24 +533,24 @@ typedef struct VTDRootEntry VTDRootEntry;
|
||||||
/* Second Level Page Translation Pointer*/
|
/* Second Level Page Translation Pointer*/
|
||||||
#define VTD_SM_PASID_ENTRY_SLPTPTR (~0xfffULL)
|
#define VTD_SM_PASID_ENTRY_SLPTPTR (~0xfffULL)
|
||||||
|
|
||||||
/* Paging Structure common */
|
|
||||||
#define VTD_SL_PT_PAGE_SIZE_MASK (1ULL << 7)
|
|
||||||
/* Bits to decide the offset for each level */
|
|
||||||
#define VTD_SL_LEVEL_BITS 9
|
|
||||||
|
|
||||||
/* Second Level Paging Structure */
|
/* Second Level Paging Structure */
|
||||||
#define VTD_SL_PML4_LEVEL 4
|
|
||||||
#define VTD_SL_PDP_LEVEL 3
|
|
||||||
#define VTD_SL_PD_LEVEL 2
|
|
||||||
#define VTD_SL_PT_LEVEL 1
|
|
||||||
#define VTD_SL_PT_ENTRY_NR 512
|
|
||||||
|
|
||||||
/* Masks for Second Level Paging Entry */
|
/* Masks for Second Level Paging Entry */
|
||||||
#define VTD_SL_RW_MASK 3ULL
|
#define VTD_SL_RW_MASK 3ULL
|
||||||
#define VTD_SL_R 1ULL
|
#define VTD_SL_R 1ULL
|
||||||
#define VTD_SL_W (1ULL << 1)
|
#define VTD_SL_W (1ULL << 1)
|
||||||
#define VTD_SL_PT_BASE_ADDR_MASK(aw) (~(VTD_PAGE_SIZE - 1) & VTD_HAW_MASK(aw))
|
|
||||||
#define VTD_SL_IGN_COM 0xbff0000000000000ULL
|
#define VTD_SL_IGN_COM 0xbff0000000000000ULL
|
||||||
#define VTD_SL_TM (1ULL << 62)
|
#define VTD_SL_TM (1ULL << 62)
|
||||||
|
|
||||||
|
/* Common for both First Level and Second Level */
|
||||||
|
#define VTD_PML4_LEVEL 4
|
||||||
|
#define VTD_PDP_LEVEL 3
|
||||||
|
#define VTD_PD_LEVEL 2
|
||||||
|
#define VTD_PT_LEVEL 1
|
||||||
|
#define VTD_PT_ENTRY_NR 512
|
||||||
|
#define VTD_PT_PAGE_SIZE_MASK (1ULL << 7)
|
||||||
|
#define VTD_PT_BASE_ADDR_MASK(aw) (~(VTD_PAGE_SIZE - 1) & VTD_HAW_MASK(aw))
|
||||||
|
|
||||||
|
/* Bits to decide the offset for each level */
|
||||||
|
#define VTD_LEVEL_BITS 9
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -152,7 +152,7 @@ struct VTDIOTLBEntry {
|
||||||
uint64_t gfn;
|
uint64_t gfn;
|
||||||
uint16_t domain_id;
|
uint16_t domain_id;
|
||||||
uint32_t pasid;
|
uint32_t pasid;
|
||||||
uint64_t slpte;
|
uint64_t pte;
|
||||||
uint64_t mask;
|
uint64_t mask;
|
||||||
uint8_t access_flags;
|
uint8_t access_flags;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue