diff options
author | Sam Bobroff <sam.bobroff@au1.ibm.com> | 2017-03-20 10:46:49 +1100 |
---|---|---|
committer | David Gibson <david@gibson.dropbear.id.au> | 2017-04-26 12:00:41 +1000 |
commit | e957f6a9b92439a222ecd4ff1c8cdc9700710c72 (patch) | |
tree | 636fa2579717d1b21292ce4010a65a9f22cea749 /hw | |
parent | 9fb4541f5803f8d2ba116b12113386e26482ba30 (diff) |
spapr: Workaround for broken radix guests
For a little while around 4.9, Linux kernels that saw the radix bit in
ibm,pa-features would attempt to set up the MMU as if they were a
hypervisor, even if they were a guest, which would cause them to
crash.
Work around this by detecting pre-ISA 3.0 guests by their lack of that
bit in option vector 1, and then removing the radix bit from
ibm,pa-features. Note: This now requires regeneration of that node
after CAS negotiation.
Signed-off-by: Sam Bobroff <sam.bobroff@au1.ibm.com>
[dwg: Fix style nits]
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/ppc/spapr.c | 15 | ||||
-rw-r--r-- | hw/ppc/spapr_hcall.c | 6 |
2 files changed, 17 insertions, 4 deletions
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index d967ec30b4..a355512849 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -228,7 +228,8 @@ static int spapr_fixup_cpu_numa_dt(void *fdt, int offset, CPUState *cs) } /* Populate the "ibm,pa-features" property */ -static void spapr_populate_pa_features(CPUPPCState *env, void *fdt, int offset) +static void spapr_populate_pa_features(CPUPPCState *env, void *fdt, int offset, + bool legacy_guest) { uint8_t pa_features_206[] = { 6, 0, 0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 }; @@ -295,6 +296,12 @@ static void spapr_populate_pa_features(CPUPPCState *env, void *fdt, int offset) if (kvmppc_has_cap_htm() && pa_size > 24) { pa_features[24] |= 0x80; /* Transactional memory support */ } + if (legacy_guest && pa_size > 40) { + /* Workaround for broken kernels that attempt (guest) radix + * mode when they can't handle it, if they see the radix bit set + * in pa-features. So hide it from them. */ + pa_features[40 + 2] &= ~0x80; /* Radix MMU */ + } _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size))); } @@ -309,6 +316,7 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr) CPU_FOREACH(cs) { PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; DeviceClass *dc = DEVICE_GET_CLASS(cs); int index = ppc_get_vcpu_dt_id(cpu); int compat_smt = MIN(smp_threads, ppc_compat_max_threads(cpu)); @@ -350,6 +358,9 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr) if (ret < 0) { return ret; } + + spapr_populate_pa_features(env, fdt, offset, + spapr->cas_legacy_guest_workaround); } return ret; } @@ -547,7 +558,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, page_sizes_prop, page_sizes_prop_size))); } - spapr_populate_pa_features(env, fdt, offset); + spapr_populate_pa_features(env, fdt, offset, false); _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", cs->cpu_index / vcpus_per_socket))); diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index cbd1f296d6..9f18f75b88 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1062,7 +1062,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, uint32_t max_compat = cpu->max_compat; uint32_t best_compat = 0; int i; - sPAPROptionVector *ov5_guest, *ov5_cas_old, *ov5_updates; + sPAPROptionVector *ov1_guest, *ov5_guest, *ov5_cas_old, *ov5_updates; bool guest_radix; /* @@ -1114,6 +1114,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, /* For the future use: here @ov_table points to the first option vector */ ov_table = list; + ov1_guest = spapr_ovec_parse_vector(ov_table, 1); ov5_guest = spapr_ovec_parse_vector(ov_table, 5); if (spapr_ovec_test(ov5_guest, OV5_MMU_BOTH)) { error_report("guest requested hash and radix MMU, which is invalid."); @@ -1155,7 +1156,8 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, exit(EXIT_FAILURE); } } - + spapr->cas_legacy_guest_workaround = !spapr_ovec_test(ov1_guest, + OV1_PPC_3_00); if (!spapr->cas_reboot) { spapr->cas_reboot = (spapr_h_cas_compose_response(spapr, args[1], args[2], |