|
@@ -686,9 +686,18 @@ static inline bool vtd_pe_type_check(X86IOMMUState *x86_iommu,
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
-static int vtd_get_pasid_dire(dma_addr_t pasid_dir_base,
|
|
|
|
- uint32_t pasid,
|
|
|
|
- VTDPASIDDirEntry *pdire)
|
|
|
|
|
|
+static inline bool vtd_pdire_present(VTDPASIDDirEntry *pdire)
|
|
|
|
+{
|
|
|
|
+ return pdire->val & 1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * Caller of this function should check present bit if wants
|
|
|
|
+ * to use pdir entry for futher usage except for fpd bit check.
|
|
|
|
+ */
|
|
|
|
+static int vtd_get_pdire_from_pdir_table(dma_addr_t pasid_dir_base,
|
|
|
|
+ uint32_t pasid,
|
|
|
|
+ VTDPASIDDirEntry *pdire)
|
|
{
|
|
{
|
|
uint32_t index;
|
|
uint32_t index;
|
|
dma_addr_t addr, entry_size;
|
|
dma_addr_t addr, entry_size;
|
|
@@ -703,18 +712,22 @@ static int vtd_get_pasid_dire(dma_addr_t pasid_dir_base,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static int vtd_get_pasid_entry(IntelIOMMUState *s,
|
|
|
|
- uint32_t pasid,
|
|
|
|
- VTDPASIDDirEntry *pdire,
|
|
|
|
- VTDPASIDEntry *pe)
|
|
|
|
|
|
+static inline bool vtd_pe_present(VTDPASIDEntry *pe)
|
|
|
|
+{
|
|
|
|
+ return pe->val[0] & VTD_PASID_ENTRY_P;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int vtd_get_pe_in_pasid_leaf_table(IntelIOMMUState *s,
|
|
|
|
+ uint32_t pasid,
|
|
|
|
+ dma_addr_t addr,
|
|
|
|
+ VTDPASIDEntry *pe)
|
|
{
|
|
{
|
|
uint32_t index;
|
|
uint32_t index;
|
|
- dma_addr_t addr, entry_size;
|
|
|
|
|
|
+ dma_addr_t entry_size;
|
|
X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s);
|
|
X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s);
|
|
|
|
|
|
index = VTD_PASID_TABLE_INDEX(pasid);
|
|
index = VTD_PASID_TABLE_INDEX(pasid);
|
|
entry_size = VTD_PASID_ENTRY_SIZE;
|
|
entry_size = VTD_PASID_ENTRY_SIZE;
|
|
- addr = pdire->val & VTD_PASID_TABLE_BASE_ADDR_MASK;
|
|
|
|
addr = addr + index * entry_size;
|
|
addr = addr + index * entry_size;
|
|
if (dma_memory_read(&address_space_memory, addr, pe, entry_size)) {
|
|
if (dma_memory_read(&address_space_memory, addr, pe, entry_size)) {
|
|
return -VTD_FR_PASID_TABLE_INV;
|
|
return -VTD_FR_PASID_TABLE_INV;
|
|
@@ -732,25 +745,54 @@ static int vtd_get_pasid_entry(IntelIOMMUState *s,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static int vtd_get_pasid_entry_from_pasid(IntelIOMMUState *s,
|
|
|
|
- dma_addr_t pasid_dir_base,
|
|
|
|
- uint32_t pasid,
|
|
|
|
- VTDPASIDEntry *pe)
|
|
|
|
|
|
+/**
|
|
|
|
+ * Caller of this function should check present bit if wants
|
|
|
|
+ * to use pasid entry for futher usage except for fpd bit check.
|
|
|
|
+ */
|
|
|
|
+static int vtd_get_pe_from_pdire(IntelIOMMUState *s,
|
|
|
|
+ uint32_t pasid,
|
|
|
|
+ VTDPASIDDirEntry *pdire,
|
|
|
|
+ VTDPASIDEntry *pe)
|
|
|
|
+{
|
|
|
|
+ dma_addr_t addr = pdire->val & VTD_PASID_TABLE_BASE_ADDR_MASK;
|
|
|
|
+
|
|
|
|
+ return vtd_get_pe_in_pasid_leaf_table(s, pasid, addr, pe);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * This function gets a pasid entry from a specified pasid
|
|
|
|
+ * table (includes dir and leaf table) with a specified pasid.
|
|
|
|
+ * Sanity check should be done to ensure return a present
|
|
|
|
+ * pasid entry to caller.
|
|
|
|
+ */
|
|
|
|
+static int vtd_get_pe_from_pasid_table(IntelIOMMUState *s,
|
|
|
|
+ dma_addr_t pasid_dir_base,
|
|
|
|
+ uint32_t pasid,
|
|
|
|
+ VTDPASIDEntry *pe)
|
|
{
|
|
{
|
|
int ret;
|
|
int ret;
|
|
VTDPASIDDirEntry pdire;
|
|
VTDPASIDDirEntry pdire;
|
|
|
|
|
|
- ret = vtd_get_pasid_dire(pasid_dir_base, pasid, &pdire);
|
|
|
|
|
|
+ ret = vtd_get_pdire_from_pdir_table(pasid_dir_base,
|
|
|
|
+ pasid, &pdire);
|
|
if (ret) {
|
|
if (ret) {
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
- ret = vtd_get_pasid_entry(s, pasid, &pdire, pe);
|
|
|
|
|
|
+ if (!vtd_pdire_present(&pdire)) {
|
|
|
|
+ return -VTD_FR_PASID_TABLE_INV;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ret = vtd_get_pe_from_pdire(s, pasid, &pdire, pe);
|
|
if (ret) {
|
|
if (ret) {
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
- return ret;
|
|
|
|
|
|
+ if (!vtd_pe_present(pe)) {
|
|
|
|
+ return -VTD_FR_PASID_TABLE_INV;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
static int vtd_ce_get_rid2pasid_entry(IntelIOMMUState *s,
|
|
static int vtd_ce_get_rid2pasid_entry(IntelIOMMUState *s,
|
|
@@ -763,7 +805,7 @@ static int vtd_ce_get_rid2pasid_entry(IntelIOMMUState *s,
|
|
|
|
|
|
pasid = VTD_CE_GET_RID2PASID(ce);
|
|
pasid = VTD_CE_GET_RID2PASID(ce);
|
|
pasid_dir_base = VTD_CE_GET_PASID_DIR_TABLE(ce);
|
|
pasid_dir_base = VTD_CE_GET_PASID_DIR_TABLE(ce);
|
|
- ret = vtd_get_pasid_entry_from_pasid(s, pasid_dir_base, pasid, pe);
|
|
|
|
|
|
+ ret = vtd_get_pe_from_pasid_table(s, pasid_dir_base, pasid, pe);
|
|
|
|
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
@@ -781,7 +823,11 @@ static int vtd_ce_get_pasid_fpd(IntelIOMMUState *s,
|
|
pasid = VTD_CE_GET_RID2PASID(ce);
|
|
pasid = VTD_CE_GET_RID2PASID(ce);
|
|
pasid_dir_base = VTD_CE_GET_PASID_DIR_TABLE(ce);
|
|
pasid_dir_base = VTD_CE_GET_PASID_DIR_TABLE(ce);
|
|
|
|
|
|
- ret = vtd_get_pasid_dire(pasid_dir_base, pasid, &pdire);
|
|
|
|
|
|
+ /*
|
|
|
|
+ * No present bit check since fpd is meaningful even
|
|
|
|
+ * if the present bit is clear.
|
|
|
|
+ */
|
|
|
|
+ ret = vtd_get_pdire_from_pdir_table(pasid_dir_base, pasid, &pdire);
|
|
if (ret) {
|
|
if (ret) {
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
@@ -791,7 +837,15 @@ static int vtd_ce_get_pasid_fpd(IntelIOMMUState *s,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
- ret = vtd_get_pasid_entry(s, pasid, &pdire, &pe);
|
|
|
|
|
|
+ if (!vtd_pdire_present(&pdire)) {
|
|
|
|
+ return -VTD_FR_PASID_TABLE_INV;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * No present bit check since fpd is meaningful even
|
|
|
|
+ * if the present bit is clear.
|
|
|
|
+ */
|
|
|
|
+ ret = vtd_get_pe_from_pdire(s, pasid, &pdire, &pe);
|
|
if (ret) {
|
|
if (ret) {
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|