diff options
Diffstat (limited to 'hw/ppc')
-rw-r--r-- | hw/ppc/ppc405_boards.c | 14 | ||||
-rw-r--r-- | hw/ppc/ppc440_bamboo.c | 9 | ||||
-rw-r--r-- | hw/ppc/spapr.c | 6 | ||||
-rw-r--r-- | hw/ppc/spapr_caps.c | 124 | ||||
-rw-r--r-- | hw/ppc/spapr_hcall.c | 58 | ||||
-rw-r--r-- | hw/ppc/spapr_pci.c | 61 | ||||
-rw-r--r-- | hw/ppc/virtex_ml507.c | 8 |
7 files changed, 261 insertions, 19 deletions
diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c index e92db2c66a..6f7f2ee168 100644 --- a/hw/ppc/ppc405_boards.c +++ b/hw/ppc/ppc405_boards.c @@ -202,6 +202,13 @@ static void ref405ep_init(MachineState *machine) DriveInfo *dinfo; MemoryRegion *sysmem = get_system_memory(); +#ifdef TARGET_PPCEMB + if (!qtest_enabled()) { + warn_report("qemu-system-ppcemb is deprecated, " + "please use qemu-system-ppc instead."); + } +#endif + /* XXX: fix this */ memory_region_allocate_system_memory(&ram_memories[0], NULL, "ef405ep.ram", 0x08000000); @@ -497,6 +504,13 @@ static void taihu_405ep_init(MachineState *machine) int fl_idx, fl_sectors; DriveInfo *dinfo; +#ifdef TARGET_PPCEMB + if (!qtest_enabled()) { + warn_report("qemu-system-ppcemb is deprecated, " + "please use qemu-system-ppc instead."); + } +#endif + /* RAM is soldered to the board so the size cannot be changed */ ram_size = 0x08000000; memory_region_allocate_system_memory(ram, NULL, "taihu_405ep.ram", diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c index 693c215108..a299206fd4 100644 --- a/hw/ppc/ppc440_bamboo.c +++ b/hw/ppc/ppc440_bamboo.c @@ -13,6 +13,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" +#include "qemu/error-report.h" #include "net/net.h" #include "hw/hw.h" #include "hw/pci/pci.h" @@ -27,6 +28,7 @@ #include "hw/ppc/ppc.h" #include "ppc405.h" #include "sysemu/sysemu.h" +#include "sysemu/qtest.h" #include "hw/sysbus.h" #define BINARY_DEVICE_TREE_FILE "bamboo.dtb" @@ -191,6 +193,13 @@ static void bamboo_init(MachineState *machine) exit(1); } +#ifdef TARGET_PPCEMB + if (!qtest_enabled()) { + warn_report("qemu-system-ppcemb is deprecated, " + "please use qemu-system-ppc instead."); + } +#endif + qemu_register_reset(main_cpu_reset, cpu); ppc_booke_timers_init(cpu, 400000000, 0); ppc_dcr_init(env, NULL, NULL); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 88a78d31eb..32a876be56 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1791,6 +1791,9 @@ static const VMStateDescription vmstate_spapr = { &vmstate_spapr_cap_htm, &vmstate_spapr_cap_vsx, &vmstate_spapr_cap_dfp, + &vmstate_spapr_cap_cfpc, + &vmstate_spapr_cap_sbbc, + &vmstate_spapr_cap_ibs, NULL } }; @@ -3881,6 +3884,9 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF; smc->default_caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_ON; smc->default_caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_ON; + smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN; + smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN; + smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN; spapr_caps_add_properties(smc, &error_abort); } diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c index 5d52969bd5..62efdaee38 100644 --- a/hw/ppc/spapr_caps.c +++ b/hw/ppc/spapr_caps.c @@ -73,6 +73,66 @@ static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name, spapr->eff.caps[cap->index] = value ? SPAPR_CAP_ON : SPAPR_CAP_OFF; } +static void spapr_cap_get_tristate(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + sPAPRCapabilityInfo *cap = opaque; + sPAPRMachineState *spapr = SPAPR_MACHINE(obj); + char *val = NULL; + uint8_t value = spapr_get_cap(spapr, cap->index); + + switch (value) { + case SPAPR_CAP_BROKEN: + val = g_strdup("broken"); + break; + case SPAPR_CAP_WORKAROUND: + val = g_strdup("workaround"); + break; + case SPAPR_CAP_FIXED: + val = g_strdup("fixed"); + break; + default: + error_setg(errp, "Invalid value (%d) for cap-%s", value, cap->name); + return; + } + + visit_type_str(v, name, &val, errp); + g_free(val); +} + +static void spapr_cap_set_tristate(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + sPAPRCapabilityInfo *cap = opaque; + sPAPRMachineState *spapr = SPAPR_MACHINE(obj); + char *val; + Error *local_err = NULL; + uint8_t value; + + visit_type_str(v, name, &val, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + if (!strcasecmp(val, "broken")) { + value = SPAPR_CAP_BROKEN; + } else if (!strcasecmp(val, "workaround")) { + value = SPAPR_CAP_WORKAROUND; + } else if (!strcasecmp(val, "fixed")) { + value = SPAPR_CAP_FIXED; + } else { + error_setg(errp, "Invalid capability mode \"%s\" for cap-%s", val, + cap->name); + goto out; + } + + spapr->cmd_line_caps[cap->index] = true; + spapr->eff.caps[cap->index] = value; +out: + g_free(val); +} + static void cap_htm_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp) { if (!val) { @@ -120,6 +180,40 @@ static void cap_dfp_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp) } } +static void cap_safe_cache_apply(sPAPRMachineState *spapr, uint8_t val, + Error **errp) +{ + if (tcg_enabled() && val) { + /* TODO - for now only allow broken for TCG */ + error_setg(errp, "Requested safe cache capability level not supported by tcg, try a different value for cap-cfpc"); + } else if (kvm_enabled() && (val > kvmppc_get_cap_safe_cache())) { + error_setg(errp, "Requested safe cache capability level not supported by kvm, try a different value for cap-cfpc"); + } +} + +static void cap_safe_bounds_check_apply(sPAPRMachineState *spapr, uint8_t val, + Error **errp) +{ + if (tcg_enabled() && val) { + /* TODO - for now only allow broken for TCG */ + error_setg(errp, "Requested safe bounds check capability level not supported by tcg, try a different value for cap-sbbc"); + } else if (kvm_enabled() && (val > kvmppc_get_cap_safe_bounds_check())) { + error_setg(errp, "Requested safe bounds check capability level not supported by kvm, try a different value for cap-sbbc"); + } +} + +static void cap_safe_indirect_branch_apply(sPAPRMachineState *spapr, + uint8_t val, Error **errp) +{ + if (tcg_enabled() && val) { + /* TODO - for now only allow broken for TCG */ + error_setg(errp, "Requested safe indirect branch capability level not supported by tcg, try a different value for cap-ibs"); + } else if (kvm_enabled() && (val > kvmppc_get_cap_safe_indirect_branch())) { + error_setg(errp, "Requested safe indirect branch capability level not supported by kvm, try a different value for cap-ibs"); + } +} + +#define VALUE_DESC_TRISTATE " (broken, workaround, fixed)" sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = { [SPAPR_CAP_HTM] = { @@ -149,6 +243,33 @@ sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = { .type = "bool", .apply = cap_dfp_apply, }, + [SPAPR_CAP_CFPC] = { + .name = "cfpc", + .description = "Cache Flush on Privilege Change" VALUE_DESC_TRISTATE, + .index = SPAPR_CAP_CFPC, + .get = spapr_cap_get_tristate, + .set = spapr_cap_set_tristate, + .type = "string", + .apply = cap_safe_cache_apply, + }, + [SPAPR_CAP_SBBC] = { + .name = "sbbc", + .description = "Speculation Barrier Bounds Checking" VALUE_DESC_TRISTATE, + .index = SPAPR_CAP_SBBC, + .get = spapr_cap_get_tristate, + .set = spapr_cap_set_tristate, + .type = "string", + .apply = cap_safe_bounds_check_apply, + }, + [SPAPR_CAP_IBS] = { + .name = "ibs", + .description = "Indirect Branch Serialisation" VALUE_DESC_TRISTATE, + .index = SPAPR_CAP_IBS, + .get = spapr_cap_get_tristate, + .set = spapr_cap_set_tristate, + .type = "string", + .apply = cap_safe_indirect_branch_apply, + }, }; static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr, @@ -254,6 +375,9 @@ const VMStateDescription vmstate_spapr_cap_##cap = { \ SPAPR_CAP_MIG_STATE(htm, HTM); SPAPR_CAP_MIG_STATE(vsx, VSX); SPAPR_CAP_MIG_STATE(dfp, DFP); +SPAPR_CAP_MIG_STATE(cfpc, CFPC); +SPAPR_CAP_MIG_STATE(sbbc, SBBC); +SPAPR_CAP_MIG_STATE(ibs, IBS); void spapr_caps_reset(sPAPRMachineState *spapr) { diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 51eba52e86..4d0e6eb0cf 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1654,6 +1654,60 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, return H_SUCCESS; } +static target_ulong h_get_cpu_characteristics(PowerPCCPU *cpu, + sPAPRMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + uint64_t characteristics = H_CPU_CHAR_HON_BRANCH_HINTS & + ~H_CPU_CHAR_THR_RECONF_TRIG; + uint64_t behaviour = H_CPU_BEHAV_FAVOUR_SECURITY; + uint8_t safe_cache = spapr_get_cap(spapr, SPAPR_CAP_CFPC); + uint8_t safe_bounds_check = spapr_get_cap(spapr, SPAPR_CAP_SBBC); + uint8_t safe_indirect_branch = spapr_get_cap(spapr, SPAPR_CAP_IBS); + + switch (safe_cache) { + case SPAPR_CAP_WORKAROUND: + characteristics |= H_CPU_CHAR_L1D_FLUSH_ORI30; + characteristics |= H_CPU_CHAR_L1D_FLUSH_TRIG2; + characteristics |= H_CPU_CHAR_L1D_THREAD_PRIV; + behaviour |= H_CPU_BEHAV_L1D_FLUSH_PR; + break; + case SPAPR_CAP_FIXED: + break; + default: /* broken */ + assert(safe_cache == SPAPR_CAP_BROKEN); + behaviour |= H_CPU_BEHAV_L1D_FLUSH_PR; + break; + } + + switch (safe_bounds_check) { + case SPAPR_CAP_WORKAROUND: + characteristics |= H_CPU_CHAR_SPEC_BAR_ORI31; + behaviour |= H_CPU_BEHAV_BNDS_CHK_SPEC_BAR; + break; + case SPAPR_CAP_FIXED: + break; + default: /* broken */ + assert(safe_bounds_check == SPAPR_CAP_BROKEN); + behaviour |= H_CPU_BEHAV_BNDS_CHK_SPEC_BAR; + break; + } + + switch (safe_indirect_branch) { + case SPAPR_CAP_FIXED: + characteristics |= H_CPU_CHAR_BCCTRL_SERIALISED; + default: /* broken */ + assert(safe_indirect_branch == SPAPR_CAP_BROKEN); + break; + } + + args[0] = characteristics; + args[1] = behaviour; + + return H_SUCCESS; +} + static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1]; static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1]; @@ -1733,6 +1787,10 @@ static void hypercall_register_types(void) spapr_register_hypercall(H_INVALIDATE_PID, h_invalidate_pid); spapr_register_hypercall(H_REGISTER_PROC_TBL, h_register_process_table); + /* hcall-get-cpu-characteristics */ + spapr_register_hypercall(H_GET_CPU_CHARACTERISTICS, + h_get_cpu_characteristics); + /* "debugger" hcalls (also used by SLOF). Note: We do -not- differenciate * here between the "CI" and the "CACHE" variants, they will use whatever * mapping attributes qemu is using. When using KVM, the kernel will diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 37f18b3d32..39a14980d3 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -280,13 +280,42 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr, int *config_addr_key; Error *err = NULL; + /* Fins sPAPRPHBState */ + phb = spapr_pci_find_phb(spapr, buid); + if (phb) { + pdev = spapr_pci_find_dev(spapr, buid, config_addr); + } + if (!phb || !pdev) { + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); + return; + } + switch (func) { - case RTAS_CHANGE_MSI_FN: case RTAS_CHANGE_FN: - ret_intr_type = RTAS_TYPE_MSI; + if (msi_present(pdev)) { + ret_intr_type = RTAS_TYPE_MSI; + } else if (msix_present(pdev)) { + ret_intr_type = RTAS_TYPE_MSIX; + } else { + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); + return; + } + break; + case RTAS_CHANGE_MSI_FN: + if (msi_present(pdev)) { + ret_intr_type = RTAS_TYPE_MSI; + } else { + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); + return; + } break; case RTAS_CHANGE_MSIX_FN: - ret_intr_type = RTAS_TYPE_MSIX; + if (msix_present(pdev)) { + ret_intr_type = RTAS_TYPE_MSIX; + } else { + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); + return; + } break; default: error_report("rtas_ibm_change_msi(%u) is not implemented", func); @@ -294,16 +323,6 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr, return; } - /* Fins sPAPRPHBState */ - phb = spapr_pci_find_phb(spapr, buid); - if (phb) { - pdev = spapr_pci_find_dev(spapr, buid, config_addr); - } - if (!phb || !pdev) { - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); - return; - } - msi = (spapr_pci_msi *) g_hash_table_lookup(phb->msi, &config_addr); /* Releasing MSIs */ @@ -1286,13 +1305,17 @@ static void spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset, _FDT(fdt_setprop_cell(fdt, offset, "#size-cells", RESOURCE_CELLS_SIZE)); - max_msi = msi_nr_vectors_allocated(dev); - if (max_msi) { - _FDT(fdt_setprop_cell(fdt, offset, "ibm,req#msi", max_msi)); + if (msi_present(dev)) { + max_msi = msi_nr_vectors_allocated(dev); + if (max_msi) { + _FDT(fdt_setprop_cell(fdt, offset, "ibm,req#msi", max_msi)); + } } - max_msix = dev->msix_entries_nr; - if (max_msix) { - _FDT(fdt_setprop_cell(fdt, offset, "ibm,req#msi-x", max_msix)); + if (msix_present(dev)) { + max_msix = dev->msix_entries_nr; + if (max_msix) { + _FDT(fdt_setprop_cell(fdt, offset, "ibm,req#msi-x", max_msix)); + } } populate_resource_props(dev, &rp); diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c index 5ac4f76613..9fe7655074 100644 --- a/hw/ppc/virtex_ml507.c +++ b/hw/ppc/virtex_ml507.c @@ -29,6 +29,7 @@ #include "hw/char/serial.h" #include "hw/block/flash.h" #include "sysemu/sysemu.h" +#include "sysemu/qtest.h" #include "hw/devices.h" #include "hw/boards.h" #include "sysemu/device_tree.h" @@ -210,6 +211,13 @@ static void virtex_init(MachineState *machine) int kernel_size; int i; +#ifdef TARGET_PPCEMB + if (!qtest_enabled()) { + warn_report("qemu-system-ppcemb is deprecated, " + "please use qemu-system-ppc instead."); + } +#endif + /* init CPUs */ cpu = ppc440_init_xilinx(&ram_size, 1, machine->cpu_type, 400000000); env = &cpu->env; |