This introduces a SPAPR TCE TABLE device class with a put_tce() callback. This reworks the H_PUT_TCE, H_PUT_TCE_INDIRECT, H_STUFF_TCE hypercall handlers to make use of the new put_tce() callback.
Signed-off-by: Alexey Kardashevskiy <a...@ozlabs.ru> --- hw/ppc/spapr_iommu.c | 76 +++++++++++++++++++++++++++++++++++++++----------- include/hw/ppc/spapr.h | 13 +++++++++ 2 files changed, 73 insertions(+), 16 deletions(-) diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c index 022e268..0b235b3 100644 --- a/hw/ppc/spapr_iommu.c +++ b/hw/ppc/spapr_iommu.c @@ -235,17 +235,34 @@ static target_ulong h_put_tce_indirect(PowerPCCPU *cpu, target_ulong npages = args[3]; target_ulong ret = H_PARAMETER; sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn); + sPAPRTCETableClass *info; + + if (!tcet) { + return H_PARAMETER; + } + + info = SPAPR_TCE_TABLE_GET_CLASS(tcet); + if (!info || !info->put_tce) { + return H_PARAMETER; + } + + if ((tce_list & SPAPR_TCE_PAGE_MASK) || (npages > 512)) { + return H_PARAMETER; + } ioba &= ~SPAPR_TCE_PAGE_MASK; tce_list &= ~SPAPR_TCE_PAGE_MASK; + if (liobn & 0xFFFFFFFF00000000ULL) { + hcall_dprintf("spapr_vio_put_tce on out-of-boundsw LIOBN " + TARGET_FMT_lx "\n", liobn); + return H_PARAMETER; + } - if (tcet) { - for (i = 0; i < npages; i++, ioba += SPAPR_TCE_PAGE_SIZE) { - target_ulong tce = ldq_phys(tce_list + i * sizeof(target_ulong)); - ret = put_tce_emu(tcet, ioba, tce); - if (ret) { - break; - } + for (i = 0; i < npages; ++i, ioba += SPAPR_TCE_PAGE_SIZE) { + target_ulong tce = ldq_phys(tce_list + i * sizeof(target_ulong)); + ret = info->put_tce(tcet, ioba, tce); + if (ret) { + break; } } trace_spapr_iommu_indirect(liobn, ioba, tce_list, ret); @@ -263,15 +280,29 @@ static target_ulong h_stuff_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong npages = args[3]; target_ulong ret = H_PARAMETER; sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn); + sPAPRTCETableClass *info; + + if (!tcet) { + return H_PARAMETER; + } + + info = SPAPR_TCE_TABLE_GET_CLASS(tcet); + if (!info || !info->put_tce) { + return H_PARAMETER; + } + + if (liobn & 0xFFFFFFFF00000000ULL) { + hcall_dprintf("spapr_vio_put_tce on out-of-boundsw LIOBN " + TARGET_FMT_lx "\n", liobn); + return H_PARAMETER; + } ioba &= ~SPAPR_TCE_PAGE_MASK; - if (tcet) { - for (i = 0; i < npages; ++i, ioba += SPAPR_TCE_PAGE_SIZE) { - ret = put_tce_emu(tcet, ioba, tce_value); - if (ret) { - break; - } + for (i = 0; i < npages; ++i, ioba += SPAPR_TCE_PAGE_SIZE) { + ret = info->put_tce(tcet, ioba, tce_value); + if (ret) { + break; } } trace_spapr_iommu_stuff(liobn, ioba, tce_value, ret); @@ -287,12 +318,21 @@ static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong tce = args[2]; target_ulong ret = H_PARAMETER; sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn); + sPAPRTCETableClass *info; + + if (!tcet) { + return H_PARAMETER; + } + + info = SPAPR_TCE_TABLE_GET_CLASS(tcet); + if (!info || !info->put_tce) { + return H_PARAMETER; + } ioba &= ~(SPAPR_TCE_PAGE_SIZE - 1); - if (tcet) { - ret = put_tce_emu(tcet, ioba, tce); - } + ret = info->put_tce(tcet, ioba, tce); + trace_spapr_iommu_put(liobn, ioba, tce, ret); return ret; @@ -342,9 +382,12 @@ int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname, static void spapr_tce_table_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + sPAPRTCETableClass *stc = SPAPR_TCE_TABLE_CLASS(klass); + dc->vmsd = &vmstate_spapr_tce_table; dc->init = spapr_tce_table_realize; dc->reset = spapr_tce_reset; + stc->put_tce = put_tce_emu; QLIST_INIT(&spapr_tce_tables); @@ -359,6 +402,7 @@ static TypeInfo spapr_tce_table_info = { .parent = TYPE_DEVICE, .instance_size = sizeof(sPAPRTCETable), .class_init = spapr_tce_table_class_init, + .class_size = sizeof(sPAPRTCETableClass), .instance_finalize = spapr_tce_table_finalize, }; diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index ca175b0..a54de97 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -362,12 +362,25 @@ int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr, #define RTAS_ERROR_LOG_MAX 2048 +typedef struct sPAPRTCETableClass sPAPRTCETableClass; typedef struct sPAPRTCETable sPAPRTCETable; #define TYPE_SPAPR_TCE_TABLE "spapr-tce-table" #define SPAPR_TCE_TABLE(obj) \ OBJECT_CHECK(sPAPRTCETable, (obj), TYPE_SPAPR_TCE_TABLE) +#define SPAPR_TCE_TABLE_CLASS(klass) \ + OBJECT_CLASS_CHECK(sPAPRTCETableClass, (klass), TYPE_SPAPR_TCE_TABLE) +#define SPAPR_TCE_TABLE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(sPAPRTCETableClass, (obj), TYPE_SPAPR_TCE_TABLE) + +struct sPAPRTCETableClass { + DeviceClass parent_class; + + target_ulong (*put_tce)(sPAPRTCETable *tcet, target_ulong ioba, + target_ulong tce); +}; + struct sPAPRTCETable { DeviceState parent; uint32_t liobn; -- 1.8.4.rc4