aboutsummaryrefslogtreecommitdiff
path: root/hw/ppc
diff options
context:
space:
mode:
Diffstat (limited to 'hw/ppc')
-rw-r--r--hw/ppc/ppc405_boards.c14
-rw-r--r--hw/ppc/ppc440_bamboo.c9
-rw-r--r--hw/ppc/spapr.c6
-rw-r--r--hw/ppc/spapr_caps.c124
-rw-r--r--hw/ppc/spapr_hcall.c58
-rw-r--r--hw/ppc/spapr_pci.c61
-rw-r--r--hw/ppc/virtex_ml507.c8
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;