From: Yi Min Zhao <zyimin@linux.vnet.ibm.com>
To: qemu-devel@nongnu.org
Cc: borntraeger@de.ibm.com, pasic@linux.vnet.ibm.com,
pmorel@linux.vnet.ibm.com, cohuck@redhat.com,
alex.williamson@redhat.com, marcel@redhat.com,
zyimin@linux.vnet.ibm.com
Subject: [Qemu-devel] [PATCH 1/3] s390x/pci: fixup the code walking IOMMU tables
Date: Tue, 30 Jan 2018 10:47:13 +0100 [thread overview]
Message-ID: <20180130094715.11578-2-zyimin@linux.vnet.ibm.com> (raw)
In-Reply-To: <20180130094715.11578-1-zyimin@linux.vnet.ibm.com>
Current s390x PCI IOMMU code is lack of flags' checking, including:
1) protection bit
2) table length
3) table offset
4) intermediate tables' invalid bit
5) format control bit
This patch introduces a new struct named S390IOTLBEntry, and makes up
these missed checkings. At the same time, inform the guest with the
corresponding error number when the check fails.
Reviewed-by: Pierre Morel <pmorel@linux.vnet.ibm.com>
Signed-off-by: Yi Min Zhao <zyimin@linux.vnet.ibm.com>
---
hw/s390x/s390-pci-bus.c | 223 ++++++++++++++++++++++++++++++++++++++---------
hw/s390x/s390-pci-bus.h | 10 +++
hw/s390x/s390-pci-inst.c | 10 ---
3 files changed, 190 insertions(+), 53 deletions(-)
diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
index 2b1e1409bf..e349d73abe 100644
--- a/hw/s390x/s390-pci-bus.c
+++ b/hw/s390x/s390-pci-bus.c
@@ -309,49 +309,186 @@ static uint64_t get_st_pto(uint64_t entry)
: 0;
}
-static uint64_t s390_guest_io_table_walk(uint64_t guest_iota,
- uint64_t guest_dma_address)
+static bool rt_entry_isvalid(uint64_t entry)
{
- uint64_t sto_a, pto_a, px_a;
- uint64_t sto, pto, pte;
- uint32_t rtx, sx, px;
-
- rtx = calc_rtx(guest_dma_address);
- sx = calc_sx(guest_dma_address);
- px = calc_px(guest_dma_address);
-
- sto_a = guest_iota + rtx * sizeof(uint64_t);
- sto = address_space_ldq(&address_space_memory, sto_a,
- MEMTXATTRS_UNSPECIFIED, NULL);
- sto = get_rt_sto(sto);
- if (!sto) {
- pte = 0;
+ return (entry & ZPCI_TABLE_VALID_MASK) == ZPCI_TABLE_VALID;
+}
+
+static bool pt_entry_isvalid(uint64_t entry)
+{
+ return (entry & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID;
+}
+
+static bool entry_isprotected(uint64_t entry)
+{
+ return (entry & ZPCI_TABLE_PROT_MASK) == ZPCI_TABLE_PROTECTED;
+}
+
+/* ett is expected table type, -1 page table, 0 segment table, 1 region table */
+static uint64_t get_table_index(uint64_t iova, int8_t ett)
+{
+ switch (ett) {
+ case -1:
+ return calc_px(iova);
+ case 0:
+ return calc_sx(iova);
+ case 1:
+ return calc_rtx(iova);
+ }
+
+ return -1;
+}
+
+static bool entry_isvalid(uint64_t entry, int8_t ett)
+{
+ switch (ett) {
+ case -1:
+ return pt_entry_isvalid(entry);
+ case 0:
+ case 1:
+ return rt_entry_isvalid(entry);
+ }
+
+ return false;
+}
+
+/* Return true if address translation is done */
+static bool translate_iscomplete(uint64_t entry, int8_t ett)
+{
+ switch (ett) {
+ case 0:
+ return (entry & ZPCI_TABLE_FC) ? true : false;
+ case 1:
+ return false;
+ }
+
+ return true;
+}
+
+static uint64_t get_frame_size(int8_t ett)
+{
+ switch (ett) {
+ case -1:
+ return 1ULL << 12;
+ case 0:
+ return 1ULL << 20;
+ case 1:
+ return 1ULL << 31;
+ }
+
+ return 0;
+}
+
+static uint64_t get_next_table_origin(uint64_t entry, int8_t ett)
+{
+ switch (ett) {
+ case -1:
+ return entry & ZPCI_PTE_ADDR_MASK;
+ case 0:
+ return get_st_pto(entry);
+ case 1:
+ return get_rt_sto(entry);
+ }
+
+ return 0;
+}
+
+/**
+ * table_translate: do translation within one table and return the following
+ * table origin
+ *
+ * @entry: the entry being traslated, the result is stored in this.
+ * @to: the address of table origin.
+ * @ett: expected table type, 1 region table, 0 segment table and -1 page table.
+ * @error: error code
+ */
+static uint64_t table_translate(S390IOTLBEntry *entry, uint64_t to, int8_t ett,
+ uint16_t *error)
+{
+ uint64_t tx, te, nto = 0;
+ uint16_t err = 0;
+
+ tx = get_table_index(entry->iova, ett);
+ te = address_space_ldq(&address_space_memory, to + tx * sizeof(uint64_t),
+ MEMTXATTRS_UNSPECIFIED, NULL);
+
+ if (!te) {
+ err = ERR_EVENT_INVALTE;
goto out;
}
- pto_a = sto + sx * sizeof(uint64_t);
- pto = address_space_ldq(&address_space_memory, pto_a,
- MEMTXATTRS_UNSPECIFIED, NULL);
- pto = get_st_pto(pto);
- if (!pto) {
- pte = 0;
+ if (!entry_isvalid(te, ett)) {
+ entry->perm &= IOMMU_NONE;
goto out;
}
- px_a = pto + px * sizeof(uint64_t);
- pte = address_space_ldq(&address_space_memory, px_a,
- MEMTXATTRS_UNSPECIFIED, NULL);
+ if (ett == 1 && ((te & ZPCI_TABLE_LEN_RTX) != ZPCI_TABLE_LEN_RTX ||
+ te & ZPCI_TABLE_OFFSET_MASK)) {
+ err = ERR_EVENT_INVALTL;
+ goto out;
+ }
+ nto = get_next_table_origin(te, ett);
+ if (!nto) {
+ err = ERR_EVENT_TT;
+ goto out;
+ }
+
+ if (entry_isprotected(te)) {
+ entry->perm &= IOMMU_RO;
+ } else {
+ entry->perm &= IOMMU_RW;
+ }
+
+ if (translate_iscomplete(te, ett)) {
+ switch (ett) {
+ case -1:
+ entry->translated_addr = te & ZPCI_PTE_ADDR_MASK;
+ break;
+ case 0:
+ entry->translated_addr = (te & ZPCI_SFAA_MASK) |
+ (entry->iova & ~ZPCI_SFAA_MASK);
+ break;
+ }
+ nto = 0;
+ }
out:
- return pte;
+ if (err) {
+ entry->perm = IOMMU_NONE;
+ *error = err;
+ }
+ entry->len = get_frame_size(ett);
+ return nto;
+}
+
+static uint16_t s390_guest_io_table_walk(uint64_t g_iota, hwaddr addr,
+ S390IOTLBEntry *entry)
+{
+ uint64_t to = s390_pci_get_table_origin(g_iota);
+ int8_t ett = 1;
+ uint16_t error = 0;
+
+ entry->iova = addr & PAGE_MASK;
+ entry->translated_addr = 0;
+ entry->perm = IOMMU_RW;
+
+ if (entry_isprotected(g_iota)) {
+ entry->perm &= IOMMU_RO;
+ }
+
+ while (to) {
+ to = table_translate(entry, to, ett--, &error);
+ }
+
+ return error;
}
static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr,
IOMMUAccessFlags flag)
{
- uint64_t pte;
- uint32_t flags;
S390PCIIOMMU *iommu = container_of(mr, S390PCIIOMMU, iommu_mr);
+ S390IOTLBEntry entry;
+ uint16_t error = 0;
IOMMUTLBEntry ret = {
.target_as = &address_space_memory,
.iova = 0,
@@ -374,26 +511,26 @@ static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr,
DPRINTF("iommu trans addr 0x%" PRIx64 "\n", addr);
if (addr < iommu->pba || addr > iommu->pal) {
- return ret;
+ error = ERR_EVENT_OORANGE;
+ goto err;
}
- pte = s390_guest_io_table_walk(s390_pci_get_table_origin(iommu->g_iota),
- addr);
- if (!pte) {
- return ret;
- }
+ error = s390_guest_io_table_walk(iommu->g_iota, addr, &entry);
- flags = pte & ZPCI_PTE_FLAG_MASK;
- ret.iova = addr;
- ret.translated_addr = pte & ZPCI_PTE_ADDR_MASK;
- ret.addr_mask = 0xfff;
+ ret.iova = entry.iova;
+ ret.translated_addr = entry.translated_addr;
+ ret.addr_mask = entry.len - 1;
+ ret.perm = entry.perm;
- if (flags & ZPCI_PTE_INVALID) {
- ret.perm = IOMMU_NONE;
- } else {
- ret.perm = IOMMU_RW;
+ if ((flag != IOMMU_NONE) && !(flag & ret.perm)) {
+ error = ERR_EVENT_TPROTE;
+ }
+err:
+ if (error) {
+ iommu->pbdev->state = ZPCI_FS_ERROR;
+ s390_pci_generate_error_event(error, iommu->pbdev->fh,
+ iommu->pbdev->fid, addr, 0);
}
-
return ret;
}
diff --git a/hw/s390x/s390-pci-bus.h b/hw/s390x/s390-pci-bus.h
index 2993f0ddef..ca22ef393b 100644
--- a/hw/s390x/s390-pci-bus.h
+++ b/hw/s390x/s390-pci-bus.h
@@ -148,6 +148,8 @@ enum ZpciIoatDtype {
#define ZPCI_STE_FLAG_MASK 0x7ffULL
#define ZPCI_STE_ADDR_MASK (~ZPCI_STE_FLAG_MASK)
+#define ZPCI_SFAA_MASK (~((1ULL << 20) - 1))
+
/* I/O Page tables */
#define ZPCI_PTE_VALID_MASK 0x400
#define ZPCI_PTE_INVALID 0x400
@@ -165,6 +167,7 @@ enum ZpciIoatDtype {
#define ZPCI_TABLE_INVALID 0x20
#define ZPCI_TABLE_PROTECTED 0x200
#define ZPCI_TABLE_UNPROTECTED 0x000
+#define ZPCI_TABLE_FC 0x400
#define ZPCI_TABLE_VALID_MASK 0x20
#define ZPCI_TABLE_PROT_MASK 0x200
@@ -253,6 +256,13 @@ typedef struct S390MsixInfo {
uint32_t pba_offset;
} S390MsixInfo;
+typedef struct S390IOTLBEntry {
+ uint64_t iova;
+ uint64_t translated_addr;
+ uint64_t len;
+ uint64_t perm;
+} S390IOTLBEntry;
+
typedef struct S390PCIBusDevice S390PCIBusDevice;
typedef struct S390PCIIOMMU {
Object parent_obj;
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index be449210d9..63fa06fb97 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -644,16 +644,6 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
while (start < end) {
entry = imrc->translate(iommu_mr, start, IOMMU_NONE);
-
- if (!entry.translated_addr) {
- pbdev->state = ZPCI_FS_ERROR;
- setcc(cpu, ZPCI_PCI_LS_ERR);
- s390_set_status_code(env, r1, ZPCI_PCI_ST_INSUF_RES);
- s390_pci_generate_error_event(ERR_EVENT_SERR, pbdev->fh, pbdev->fid,
- start, ERR_EVENT_Q_BIT);
- goto out;
- }
-
memory_region_notify_iommu(iommu_mr, entry);
start += entry.addr_mask + 1;
}
--
2.14.3 (Apple Git-98)
next prev parent reply other threads:[~2018-01-30 9:47 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-01-30 9:47 [Qemu-devel] [PATCH 0/3] s390x/pci: fixup and optimize IOTLB code Yi Min Zhao
2018-01-30 9:47 ` Yi Min Zhao [this message]
2018-01-31 7:42 ` [Qemu-devel] [PATCH 1/3] s390x/pci: fixup the code walking IOMMU tables Thomas Huth
2018-01-31 8:46 ` Yi Min Zhao
2018-01-31 10:58 ` Cornelia Huck
2018-02-01 11:28 ` Yi Min Zhao
2018-02-01 11:56 ` Pierre Morel
2018-02-01 12:15 ` Cornelia Huck
2018-02-01 13:17 ` Pierre Morel
2018-01-30 9:47 ` [Qemu-devel] [PATCH 2/3] s390x/pci: fixup global refresh Yi Min Zhao
2018-01-31 11:35 ` Cornelia Huck
2018-02-01 12:55 ` Pierre Morel
2018-01-30 9:47 ` [Qemu-devel] [PATCH 3/3] s390x/pci: use the right pal and pba in reg_ioat() Yi Min Zhao
2018-01-31 11:44 ` Cornelia Huck
2018-02-01 11:33 ` Pierre Morel
2018-02-01 12:02 ` Cornelia Huck
2018-02-02 3:50 ` Yi Min Zhao
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180130094715.11578-2-zyimin@linux.vnet.ibm.com \
--to=zyimin@linux.vnet.ibm.com \
--cc=alex.williamson@redhat.com \
--cc=borntraeger@de.ibm.com \
--cc=cohuck@redhat.com \
--cc=marcel@redhat.com \
--cc=pasic@linux.vnet.ibm.com \
--cc=pmorel@linux.vnet.ibm.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).