From 6dc6b557913f29e012880e381c0a3f452b415f1d Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 17 Mar 2020 15:49:17 +1000 Subject: [PATCH 01/18] target/ppc: Improve syscall exception logging system calls (at least in Linux) use registers r3-r8 for inputs, so include those registers in the dump. This also adds a mode for PAPR hcalls, which have a different calling convention. Signed-off-by: Nicholas Piggin Message-Id: <20200317054918.199161-1-npiggin@gmail.com> Signed-off-by: David Gibson --- target/ppc/excp_helper.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 08bc885ca60..81ee19ebae5 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -57,12 +57,29 @@ static void ppc_hw_interrupt(CPUPPCState *env) #else /* defined(CONFIG_USER_ONLY) */ static inline void dump_syscall(CPUPPCState *env) { - qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64 - " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64 + qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 + " r3=%016" PRIx64 " r4=%016" PRIx64 " r5=%016" PRIx64 + " r6=%016" PRIx64 " r7=%016" PRIx64 " r8=%016" PRIx64 " nip=" TARGET_FMT_lx "\n", ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3), ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5), - ppc_dump_gpr(env, 6), env->nip); + ppc_dump_gpr(env, 6), ppc_dump_gpr(env, 7), + ppc_dump_gpr(env, 8), env->nip); +} + +static inline void dump_hcall(CPUPPCState *env) +{ + qemu_log_mask(CPU_LOG_INT, "hypercall r3=%016" PRIx64 + " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64 + " r7=%016" PRIx64 " r8=%016" PRIx64 " r9=%016" PRIx64 + " r10=%016" PRIx64 " r11=%016" PRIx64 " r12=%016" PRIx64 + " nip=" TARGET_FMT_lx "\n", + ppc_dump_gpr(env, 3), ppc_dump_gpr(env, 4), + ppc_dump_gpr(env, 5), ppc_dump_gpr(env, 6), + ppc_dump_gpr(env, 7), ppc_dump_gpr(env, 8), + ppc_dump_gpr(env, 9), ppc_dump_gpr(env, 10), + ppc_dump_gpr(env, 11), ppc_dump_gpr(env, 12), + env->nip); } static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp, @@ -379,9 +396,14 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) } break; case POWERPC_EXCP_SYSCALL: /* System call exception */ - dump_syscall(env); lev = env->error_code; + if ((lev == 1) && cpu->vhyp) { + dump_hcall(env); + } else { + dump_syscall(env); + } + /* * We need to correct the NIP which in this case is supposed * to point to the next instruction From 86962462f89b2abbba18e5c2243d59bd408f04d4 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Wed, 25 Mar 2020 16:25:30 +0100 Subject: [PATCH 02/18] spapr: Don't check capabilities removed between CAS calls We currently check if some capability in OV5 was removed by the guest since the previous CAS, and we trigger a CAS reboot in that case. This was required because it could call for a device-tree property or node removal, that we didn't support until recently (see commit 6787d27b04a7 "spapr: add option vector handling in CAS-generated resets" for details). Now that we render a full FDT at CAS and that SLOF is able to handle node removal, we don't need to do a CAS reset in this case anymore. Also, this check can only return true if the guest has already called CAS since the last full system reset (otherwise spapr->ov5_cas is empty). Linux doesn't do that so this can be considered as dead code for the vast majority of existing setups. Drop the check. Since the only use of the ov5_cas_old variable is precisely the check itself, drop the variable as well. Signed-off-by: Greg Kurz Message-Id: <158514993021.478799.10928618293640651819.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/ppc/spapr_hcall.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 0d50fc91179..e8ee4475372 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1676,7 +1676,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, target_ulong fdt_bufsize = args[2]; target_ulong ov_table; uint32_t cas_pvr; - SpaprOptionVector *ov1_guest, *ov5_guest, *ov5_cas_old; + SpaprOptionVector *ov1_guest, *ov5_guest; bool guest_radix; Error *local_err = NULL; bool raw_mode_supported = false; @@ -1782,22 +1782,10 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, * by LoPAPR 1.1, 14.5.4.8, which QEMU doesn't implement, we don't need * to worry about this for now. */ - ov5_cas_old = spapr_ovec_clone(spapr->ov5_cas); - - /* also clear the radix/hash bit from the current ov5_cas bits to - * be in sync with the newly ov5 bits. Else the radix bit will be - * seen as being removed and this will generate a reset loop - */ - spapr_ovec_clear(ov5_cas_old, OV5_MMU_RADIX_300); /* full range of negotiated ov5 capabilities */ spapr_ovec_intersect(spapr->ov5_cas, spapr->ov5, ov5_guest); spapr_ovec_cleanup(ov5_guest); - /* capabilities that have been added since CAS-generated guest reset. - * if capabilities have since been removed, generate another reset - */ - spapr->cas_reboot = !spapr_ovec_subset(ov5_cas_old, spapr->ov5_cas); - spapr_ovec_cleanup(ov5_cas_old); /* Now that processing is finished, set the radix/hash bit for the * guest if it requested a valid mode; otherwise terminate the boot. */ if (guest_radix) { From b5b7f391817558f645034ea2e26bbed1e75eb731 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 26 Mar 2020 00:41:43 +1000 Subject: [PATCH 03/18] ppc/spapr: tweak change system reset helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than have the helper take an optional vector address override, instead have its caller modify env->nip itself. This is more consistent when adding pnv nmi support, and also with mce injection added later. Signed-off-by: Nicholas Piggin Message-Id: <20200325144147.221875-2-npiggin@gmail.com> Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/ppc/spapr.c | 9 ++++++--- target/ppc/cpu.h | 2 +- target/ppc/excp_helper.c | 5 +---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 9a2bd501aa6..785c41d2059 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -3385,13 +3385,13 @@ static void spapr_machine_finalizefn(Object *obj) void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg) { SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; cpu_synchronize_state(cs); /* If FWNMI is inactive, addr will be -1, which will deliver to 0x100 */ if (spapr->fwnmi_system_reset_addr != -1) { uint64_t rtas_addr, addr; - PowerPCCPU *cpu = POWERPC_CPU(cs); - CPUPPCState *env = &cpu->env; /* get rtas addr from fdt */ rtas_addr = spapr_get_rtas_addr(); @@ -3405,7 +3405,10 @@ void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg) stq_be_phys(&address_space_memory, addr + sizeof(uint64_t), 0); env->gpr[3] = addr; } - ppc_cpu_do_system_reset(cs, spapr->fwnmi_system_reset_addr); + ppc_cpu_do_system_reset(cs); + if (spapr->fwnmi_system_reset_addr != -1) { + env->nip = spapr->fwnmi_system_reset_addr; + } } static void spapr_nmi(NMIState *n, int cpu_index, Error **errp) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 88d94495554..f4a5304d435 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1220,7 +1220,7 @@ int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, int ppc32_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, int cpuid, void *opaque); #ifndef CONFIG_USER_ONLY -void ppc_cpu_do_system_reset(CPUState *cs, target_ulong vector); +void ppc_cpu_do_system_reset(CPUState *cs); void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector); extern const VMStateDescription vmstate_ppc_cpu; #endif diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 81ee19ebae5..1acc3786de0 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -983,15 +983,12 @@ static void ppc_hw_interrupt(CPUPPCState *env) } } -void ppc_cpu_do_system_reset(CPUState *cs, target_ulong vector) +void ppc_cpu_do_system_reset(CPUState *cs) { PowerPCCPU *cpu = POWERPC_CPU(cs); CPUPPCState *env = &cpu->env; powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET); - if (vector != -1) { - env->nip = vector; - } } void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector) From 01b552b05b0f21f8ff57a508f7ad26f7abbcd123 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 26 Mar 2020 00:41:44 +1000 Subject: [PATCH 04/18] ppc/pnv: Add support for NMI interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This implements the NMI interface for the PNV machine, similarly to commit 3431648272d ("spapr: Add support for new NMI interface") for SPAPR. Signed-off-by: Nicholas Piggin Message-Id: <20200325144147.221875-3-npiggin@gmail.com> Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/ppc/pnv.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index c9cb6fa357f..a3b7a8d0ff3 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -27,6 +27,7 @@ #include "sysemu/runstate.h" #include "sysemu/cpus.h" #include "sysemu/device_tree.h" +#include "sysemu/hw_accel.h" #include "target/ppc/cpu.h" #include "qemu/log.h" #include "hw/ppc/fdt.h" @@ -34,6 +35,7 @@ #include "hw/ppc/pnv.h" #include "hw/ppc/pnv_core.h" #include "hw/loader.h" +#include "hw/nmi.h" #include "exec/address-spaces.h" #include "qapi/visitor.h" #include "monitor/monitor.h" @@ -1977,10 +1979,35 @@ static void pnv_machine_set_hb(Object *obj, bool value, Error **errp) } } +static void pnv_cpu_do_nmi_on_cpu(CPUState *cs, run_on_cpu_data arg) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + + cpu_synchronize_state(cs); + ppc_cpu_do_system_reset(cs); + /* + * SRR1[42:45] is set to 0100 which the ISA defines as implementation + * dependent. POWER processors use this for xscom triggered interrupts, + * which come from the BMC or NMI IPIs. + */ + env->spr[SPR_SRR1] |= PPC_BIT(43); +} + +static void pnv_nmi(NMIState *n, int cpu_index, Error **errp) +{ + CPUState *cs; + + CPU_FOREACH(cs) { + async_run_on_cpu(cs, pnv_cpu_do_nmi_on_cpu, RUN_ON_CPU_NULL); + } +} + static void pnv_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc); + NMIClass *nc = NMI_CLASS(oc); mc->desc = "IBM PowerNV (Non-Virtualized)"; mc->init = pnv_init; @@ -1997,6 +2024,7 @@ static void pnv_machine_class_init(ObjectClass *oc, void *data) mc->default_ram_size = INITRD_LOAD_ADDR + INITRD_MAX_SIZE; mc->default_ram_id = "pnv.ram"; ispc->print_info = pnv_pic_print_info; + nc->nmi_monitor_handler = pnv_nmi; object_class_property_add_bool(oc, "hb-mode", pnv_machine_get_hb, pnv_machine_set_hb, @@ -2060,6 +2088,7 @@ static const TypeInfo types[] = { .class_size = sizeof(PnvMachineClass), .interfaces = (InterfaceInfo[]) { { TYPE_INTERRUPT_STATS_PROVIDER }, + { TYPE_NMI }, { }, }, }, From b4b83312e72461540ee155006f0d49e33bf0c58d Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Wed, 25 Mar 2020 16:25:36 +0100 Subject: [PATCH 05/18] spapr: Simplify selection of radix/hash during CAS The guest can select the MMU mode by setting bits 0-1 of byte 24 in OV5 to to 0b00 for hash or 0b01 for radix. As required by the architecture, we terminate the boot process if any other value is found there. The usual way to negotiate features in OV5 is basically ANDing the bitfield provided by the guest and the bitfield of features supported by QEMU, previously populated at machine init. For some not documented reason, MMU is treated differently : bit 1 of byte 24 (the radix/hash bit) is cleared from the guest OV5 and explicitely set in the final negotiated OV5 if radix was requested. Since the only expected input from the guest is the radix/hash bit being set or not, it seems more appropriate to handle this like we do for XIVE. Set the radix bit in spapr->ov5 at machine init if it has a chance to work (ie. power9, either TCG or a radix capable KVM) and rely exclusively on spapr_ovec_intersect() to set the radix bit in spapr->ov5_cas. Signed-off-by: Greg Kurz Message-Id: <158514993621.478799.4204740354545734293.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/ppc/spapr.c | 1 + hw/ppc/spapr_hcall.c | 6 +----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 785c41d2059..167b1216ba6 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2837,6 +2837,7 @@ static void spapr_machine_init(MachineState *machine) if ((!kvm_enabled() || kvmppc_has_cap_mmu_radix()) && ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0, spapr->max_compat_pvr)) { + spapr_ovec_set(spapr->ov5, OV5_MMU_RADIX_300); /* KVM and TCG always allow GTSE with radix... */ spapr_ovec_set(spapr->ov5, OV5_MMU_RADIX_GTSE); } diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index e8ee4475372..fb4fdd4a0c3 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1739,9 +1739,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, exit(EXIT_FAILURE); } - /* The radix/hash bit in byte 24 requires special handling: */ guest_radix = spapr_ovec_test(ov5_guest, OV5_MMU_RADIX_300); - spapr_ovec_clear(ov5_guest, OV5_MMU_RADIX_300); guest_xive = spapr_ovec_test(ov5_guest, OV5_XIVE_EXPLOIT); @@ -1786,14 +1784,12 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, /* full range of negotiated ov5 capabilities */ spapr_ovec_intersect(spapr->ov5_cas, spapr->ov5, ov5_guest); spapr_ovec_cleanup(ov5_guest); - /* Now that processing is finished, set the radix/hash bit for the - * guest if it requested a valid mode; otherwise terminate the boot. */ + if (guest_radix) { if (kvm_enabled() && !kvmppc_has_cap_mmu_radix()) { error_report("Guest requested unavailable MMU mode (radix)."); exit(EXIT_FAILURE); } - spapr_ovec_set(spapr->ov5_cas, OV5_MMU_RADIX_300); } else { if (kvm_enabled() && kvmppc_has_cap_mmu_radix() && !kvmppc_has_cap_mmu_hash_v3()) { From 91067db1abcdc6caf951494b8d7e4bfaaa0cb61d Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Wed, 25 Mar 2020 16:25:42 +0100 Subject: [PATCH 06/18] spapr/cas: Separate CAS handling from rebuilding the FDT At the moment "ibm,client-architecture-support" ("CAS") is implemented in SLOF and QEMU assists via the custom H_CAS hypercall which copies an updated flatten device tree (FDT) blob to the SLOF memory which it then uses to update its internal tree. When we enable the OpenFirmware client interface in QEMU, we won't need to copy the FDT to the guest as the client is expected to fetch the device tree using the client interface. This moves FDT rebuild out to a separate helper which is going to be called from the "ibm,client-architecture-support" handler and leaves writing FDT to the guest in the H_CAS handler. This should not cause any behavioral change. Signed-off-by: Alexey Kardashevskiy Message-Id: <20200310050733.29805-3-aik@ozlabs.ru> Signed-off-by: Greg Kurz Message-Id: <158514994229.478799.2178881312094922324.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/ppc/spapr.c | 1 - hw/ppc/spapr_hcall.c | 67 ++++++++++++++++++++++++++---------------- include/hw/ppc/spapr.h | 7 +++++ 3 files changed, 48 insertions(+), 27 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 167b1216ba6..f52488d397b 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -96,7 +96,6 @@ * * We load our kernel at 4M, leaving space for SLOF initial image */ -#define FDT_MAX_SIZE 0x100000 #define RTAS_MAX_ADDR 0x80000000 /* RTAS must stay below that */ #define FW_MAX_SIZE 0x400000 #define FW_FILE_NAME "slof.bin" diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index fb4fdd4a0c3..48a8745514a 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1665,16 +1665,12 @@ static void spapr_handle_transient_dev_before_cas(SpaprMachineState *spapr) spapr_clear_pending_hotplug_events(spapr); } -static target_ulong h_client_architecture_support(PowerPCCPU *cpu, - SpaprMachineState *spapr, - target_ulong opcode, - target_ulong *args) +target_ulong do_client_architecture_support(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong vec, + target_ulong fdt_bufsize) { - /* Working address in data buffer */ - target_ulong addr = ppc64_phys_to_real(args[0]); - target_ulong fdt_buf = args[1]; - target_ulong fdt_bufsize = args[2]; - target_ulong ov_table; + target_ulong ov_table; /* Working address in data buffer */ uint32_t cas_pvr; SpaprOptionVector *ov1_guest, *ov5_guest; bool guest_radix; @@ -1694,7 +1690,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, } } - cas_pvr = cas_check_pvr(spapr, cpu, &addr, &raw_mode_supported, &local_err); + cas_pvr = cas_check_pvr(spapr, cpu, &vec, &raw_mode_supported, &local_err); if (local_err) { error_report_err(local_err); return H_HARDWARE; @@ -1717,7 +1713,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 = addr; + ov_table = vec; ov1_guest = spapr_ovec_parse_vector(ov_table, 1); if (!ov1_guest) { @@ -1824,7 +1820,6 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, if (!spapr->cas_reboot) { void *fdt; - SpaprDeviceTreeUpdateHeader hdr = { .version_id = 1 }; /* If spapr_machine_reset() did not set up a HPT but one is necessary * (because the guest isn't going to use radix) then set it up here. */ @@ -1833,21 +1828,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, spapr_setup_hpt(spapr); } - if (fdt_bufsize < sizeof(hdr)) { - error_report("SLOF provided insufficient CAS buffer " - TARGET_FMT_lu " (min: %zu)", fdt_bufsize, sizeof(hdr)); - exit(EXIT_FAILURE); - } - - fdt_bufsize -= sizeof(hdr); - fdt = spapr_build_fdt(spapr, false, fdt_bufsize); - _FDT((fdt_pack(fdt))); - - cpu_physical_memory_write(fdt_buf, &hdr, sizeof(hdr)); - cpu_physical_memory_write(fdt_buf + sizeof(hdr), fdt, - fdt_totalsize(fdt)); - trace_spapr_cas_continue(fdt_totalsize(fdt) + sizeof(hdr)); g_free(spapr->fdt_blob); spapr->fdt_size = fdt_totalsize(fdt); @@ -1862,6 +1843,40 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, return H_SUCCESS; } +static target_ulong h_client_architecture_support(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + target_ulong vec = ppc64_phys_to_real(args[0]); + target_ulong fdt_buf = args[1]; + target_ulong fdt_bufsize = args[2]; + target_ulong ret; + SpaprDeviceTreeUpdateHeader hdr = { .version_id = 1 }; + + if (fdt_bufsize < sizeof(hdr)) { + error_report("SLOF provided insufficient CAS buffer " + TARGET_FMT_lu " (min: %zu)", fdt_bufsize, sizeof(hdr)); + exit(EXIT_FAILURE); + } + + fdt_bufsize -= sizeof(hdr); + + ret = do_client_architecture_support(cpu, spapr, vec, fdt_bufsize); + if (ret == H_SUCCESS) { + _FDT((fdt_pack(spapr->fdt_blob))); + spapr->fdt_size = fdt_totalsize(spapr->fdt_blob); + spapr->fdt_initial_size = spapr->fdt_size; + + cpu_physical_memory_write(fdt_buf, &hdr, sizeof(hdr)); + cpu_physical_memory_write(fdt_buf + sizeof(hdr), spapr->fdt_blob, + spapr->fdt_size); + trace_spapr_cas_continue(spapr->fdt_size + sizeof(hdr)); + } + + return ret; +} + static target_ulong h_home_node_associativity(PowerPCCPU *cpu, SpaprMachineState *spapr, target_ulong opcode, diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 42d64a03682..b7e13e5aafb 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -102,6 +102,8 @@ typedef enum { #define SPAPR_CAP_FIXED_CCD 0x03 #define SPAPR_CAP_FIXED_NA 0x10 /* Lets leave a bit of a gap... */ +#define FDT_MAX_SIZE 0x100000 + typedef struct SpaprCapabilities SpaprCapabilities; struct SpaprCapabilities { uint8_t caps[SPAPR_CAP_NUM]; @@ -566,6 +568,11 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn); target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode, target_ulong *args); +target_ulong do_client_architecture_support(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong addr, + target_ulong fdt_bufsize); + /* Virtual Processor Area structure constants */ #define VPA_MIN_SIZE 640 #define VPA_SIZE_OFFSET 0x4 From 087820e37f05c391c1ea77b1761ed489c928872e Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Wed, 25 Mar 2020 16:25:49 +0100 Subject: [PATCH 07/18] spapr: Drop CAS reboot flag The CAS reboot flag is false by default and all the locations that could set it to true have been dropped. This means that all code blocks depending on the flag being set is dead code and the other code blocks should be executed always. Just do that and drop the now uneeded CAS reboot flag. Fix a comment on the way to make checkpatch happy. Signed-off-by: Greg Kurz Message-Id: <158514994893.478799.11772512888322840990.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/ppc/spapr.c | 18 ++++-------------- hw/ppc/spapr_hcall.c | 33 ++++++++++++++------------------- include/hw/ppc/spapr.h | 1 - 3 files changed, 18 insertions(+), 34 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index f52488d397b..841b5ec59b1 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1579,9 +1579,7 @@ void spapr_setup_hpt(SpaprMachineState *spapr) { int hpt_shift; - if ((spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED) - || (spapr->cas_reboot - && !spapr_ovec_test(spapr->ov5_cas, OV5_HPT_RESIZE))) { + if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED) { hpt_shift = spapr_hpt_shift_for_ramsize(MACHINE(spapr)->maxram_size); } else { uint64_t current_ram_size; @@ -1645,16 +1643,10 @@ static void spapr_machine_reset(MachineState *machine) qemu_devices_reset(); - /* - * If this reset wasn't generated by CAS, we should reset our - * negotiated options and start from scratch - */ - if (!spapr->cas_reboot) { - spapr_ovec_cleanup(spapr->ov5_cas); - spapr->ov5_cas = spapr_ovec_new(); + spapr_ovec_cleanup(spapr->ov5_cas); + spapr->ov5_cas = spapr_ovec_new(); - ppc_set_compat_all(spapr->max_compat_pvr, &error_fatal); - } + ppc_set_compat_all(spapr->max_compat_pvr, &error_fatal); /* * This is fixing some of the default configuration of the XIVE @@ -1707,8 +1699,6 @@ static void spapr_machine_reset(MachineState *machine) spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT, 0, fdt_addr, 0); first_ppc_cpu->env.gpr[5] = 0; - spapr->cas_reboot = false; - spapr->fwnmi_system_reset_addr = -1; spapr->fwnmi_machine_check_addr = -1; spapr->fwnmi_machine_check_interlock = -1; diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 48a8745514a..0f54988f2e2 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1678,6 +1678,7 @@ target_ulong do_client_architecture_support(PowerPCCPU *cpu, bool raw_mode_supported = false; bool guest_xive; CPUState *cs; + void *fdt; /* CAS is supposed to be called early when only the boot vCPU is active. */ CPU_FOREACH(cs) { @@ -1818,27 +1819,21 @@ target_ulong do_client_architecture_support(PowerPCCPU *cpu, spapr_handle_transient_dev_before_cas(spapr); - if (!spapr->cas_reboot) { - void *fdt; - - /* If spapr_machine_reset() did not set up a HPT but one is necessary - * (because the guest isn't going to use radix) then set it up here. */ - if ((spapr->patb_entry & PATE1_GR) && !guest_radix) { - /* legacy hash or new hash: */ - spapr_setup_hpt(spapr); - } - - fdt = spapr_build_fdt(spapr, false, fdt_bufsize); - - g_free(spapr->fdt_blob); - spapr->fdt_size = fdt_totalsize(fdt); - spapr->fdt_initial_size = spapr->fdt_size; - spapr->fdt_blob = fdt; + /* + * If spapr_machine_reset() did not set up a HPT but one is necessary + * (because the guest isn't going to use radix) then set it up here. + */ + if ((spapr->patb_entry & PATE1_GR) && !guest_radix) { + /* legacy hash or new hash: */ + spapr_setup_hpt(spapr); } - if (spapr->cas_reboot) { - qemu_system_reset_request(SHUTDOWN_CAUSE_SUBSYSTEM_RESET); - } + fdt = spapr_build_fdt(spapr, false, fdt_bufsize); + + g_free(spapr->fdt_blob); + spapr->fdt_size = fdt_totalsize(fdt); + spapr->fdt_initial_size = spapr->fdt_size; + spapr->fdt_blob = fdt; return H_SUCCESS; } diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index b7e13e5aafb..e579eaf28c0 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -178,7 +178,6 @@ struct SpaprMachineState { SpaprEventSource *event_sources; /* ibm,client-architecture-support option negotiation */ - bool cas_reboot; bool cas_pre_isa3_guest; SpaprOptionVector *ov5; /* QEMU-supported option vectors */ SpaprOptionVector *ov5_cas; /* negotiated (via CAS) option vectors */ From 933abb9c238726c3f2862affd0d46b043a22c3e0 Mon Sep 17 00:00:00 2001 From: Suraj Jitindar Singh Date: Mon, 30 Mar 2020 11:49:40 +0200 Subject: [PATCH 08/18] target/ppc: Enforce that the root page directory size must be at least 5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the ISA the root page directory size of a radix tree for either process- or partition-scoped translation must be >= 5. Thus add this to the list of conditions checked when validating the partition table entry in validate_pate(); Signed-off-by: Suraj Jitindar Singh Reviewed-by: David Gibson Signed-off-by: Cédric Le Goater Message-Id: <20200330094946.24678-2-clg@kaod.org> Reviewed-by: Greg Kurz Signed-off-by: David Gibson --- target/ppc/mmu-radix64.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index 224e646c509..99678570581 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -212,6 +212,9 @@ static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate) if (lpid == 0 && !msr_hv) { return false; } + if ((pate->dw0 & PATE1_R_PRTS) < 5) { + return false; + } /* More checks ... */ return true; } From f208ec7160145a77647af9b01a393615e7a9f8c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 30 Mar 2020 11:49:41 +0200 Subject: [PATCH 09/18] target/ppc: Introduce a relocation bool in ppc_radix64_handle_mmu_fault() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It will ease the introduction of new routines for partition-scoped Radix translation. Signed-off-by: Suraj Jitindar Singh Signed-off-by: Cédric Le Goater Message-Id: <20200330094946.24678-3-clg@kaod.org> Reviewed-by: Greg Kurz Signed-off-by: David Gibson --- target/ppc/mmu-radix64.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index 99678570581..f6007e95656 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -229,12 +229,13 @@ int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, uint64_t lpid = 0, pid = 0, offset, size, prtbe0, pte; int page_size, prot, fault_cause = 0; ppc_v3_pate_t pate; + bool relocation; assert((rwx == 0) || (rwx == 1) || (rwx == 2)); + relocation = ((rwx == 2) && (msr_ir == 1)) || ((rwx != 2) && (msr_dr == 1)); /* HV or virtual hypervisor Real Mode Access */ - if ((msr_hv || cpu->vhyp) && - (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0)))) { + if (!relocation && (msr_hv || cpu->vhyp)) { /* In real mode top 4 effective addr bits (mostly) ignored */ raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL; From beae5e9dc6eedc7d7fda333a3b71aa9f7e6b4a3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 30 Mar 2020 11:49:42 +0200 Subject: [PATCH 10/18] target/ppc: Assert if HV mode is set when running under a pseries machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Suraj Jitindar Singh Signed-off-by: Cédric Le Goater Message-Id: <20200330094946.24678-4-clg@kaod.org> Reviewed-by: Greg Kurz Signed-off-by: David Gibson --- target/ppc/mmu-radix64.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index f6007e95656..d2422d1c54c 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -231,6 +231,7 @@ int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, ppc_v3_pate_t pate; bool relocation; + assert(!(msr_hv && cpu->vhyp)); assert((rwx == 0) || (rwx == 1) || (rwx == 2)); relocation = ((rwx == 2) && (msr_ir == 1)) || ((rwx != 2) && (msr_dr == 1)); From 05af7c77f5f24ef2bec25f2cab22170c29edaf37 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 26 Mar 2020 16:27:37 +1100 Subject: [PATCH 11/18] spapr: Don't allow unplug of NVLink2 devices Currently, we can't properly handle unplug of NVLink2 devices, because we don't have code to tear down their special memory resources. There's not a lot of impetus to implement that: since hardware NVLink2 devices can't be hot unplugged, the guest side drivers don't usually support unplug anyway. Therefore, simply prevent unplug of NVLink2 devices. Signed-off-by: David Gibson Reviewed-by: Alexey Kardashevskiy --- hw/ppc/spapr_pci.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 55ca9dee1e5..61b84a392d6 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -1665,6 +1665,10 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler, error_setg(errp, "PCI: Hot unplug of PCI bridges not supported"); return; } + if (object_property_get_uint(OBJECT(pdev), "nvlink2-tgt", NULL)) { + error_setg(errp, "PCI: Cannot unplug NVLink2 devices"); + return; + } /* ensure any other present functions are pending unplug */ if (PCI_FUNC(pdev->devfn) == 0) { From d92baf00aad9bba521c2b3cb23fe388c2067aaa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 3 Apr 2020 16:00:53 +0200 Subject: [PATCH 12/18] target/ppc: Introduce ppc_radix64_xlate() for Radix tree translation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is moving code under a new ppc_radix64_xlate() routine shared by the MMU Radix page fault handler and the 'get_phys_page_debug' PPC callback. The difference being that 'get_phys_page_debug' does not generate exceptions. The specific part of process-scoped Radix translation is moved under ppc_radix64_process_scoped_xlate() in preparation of the future support for partition-scoped Radix translation. Routines raising the exceptions now take a 'cause_excp' bool to cover the 'get_phys_page_debug' case. It should be functionally equivalent. Signed-off-by: Suraj Jitindar Singh Signed-off-by: Cédric Le Goater Message-Id: <20200403140056.59465-2-clg@kaod.org> Reviewed-by: Greg Kurz Signed-off-by: David Gibson --- target/ppc/mmu-radix64.c | 219 ++++++++++++++++++++++----------------- 1 file changed, 123 insertions(+), 96 deletions(-) diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index d2422d1c54c..4b0d0ff50a3 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -219,17 +219,127 @@ static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate) return true; } +static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, + vaddr eaddr, uint64_t pid, + ppc_v3_pate_t pate, hwaddr *g_raddr, + int *g_prot, int *g_page_size, + bool cause_excp) +{ + CPUState *cs = CPU(cpu); + uint64_t offset, size, prtbe_addr, prtbe0, pte; + int fault_cause = 0; + hwaddr pte_addr; + + /* Index Process Table by PID to Find Corresponding Process Table Entry */ + offset = pid * sizeof(struct prtb_entry); + size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12); + if (offset >= size) { + /* offset exceeds size of the process table */ + if (cause_excp) { + ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE); + } + return 1; + } + prtbe_addr = (pate.dw1 & PATE1_R_PRTB) + offset; + prtbe0 = ldq_phys(cs->as, prtbe_addr); + + /* Walk Radix Tree from Process Table Entry to Convert EA to RA */ + *g_page_size = PRTBE_R_GET_RTS(prtbe0); + pte = ppc_radix64_walk_tree(cpu, eaddr & R_EADDR_MASK, + prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS, + g_raddr, g_page_size, &fault_cause, &pte_addr); + + if (!(pte & R_PTE_VALID) || + ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot)) { + /* No valid pte or access denied due to protection */ + if (cause_excp) { + ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause); + } + return 1; + } + + ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, g_prot); + + return 0; +} + +static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx, + bool relocation, + hwaddr *raddr, int *psizep, int *protp, + bool cause_excp) +{ + uint64_t lpid = 0, pid = 0; + ppc_v3_pate_t pate; + int psize, prot; + hwaddr g_raddr; + + /* Virtual Mode Access - get the fully qualified address */ + if (!ppc_radix64_get_fully_qualified_addr(&cpu->env, eaddr, &lpid, &pid)) { + if (cause_excp) { + ppc_radix64_raise_segi(cpu, rwx, eaddr); + } + return 1; + } + + /* Get Process Table */ + if (cpu->vhyp) { + PPCVirtualHypervisorClass *vhc; + vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); + vhc->get_pate(cpu->vhyp, &pate); + } else { + if (!ppc64_v3_get_pate(cpu, lpid, &pate)) { + if (cause_excp) { + ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE); + } + return 1; + } + if (!validate_pate(cpu, lpid, &pate)) { + if (cause_excp) { + ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_R_BADCONFIG); + } + return 1; + } + /* We don't support guest mode yet */ + if (lpid != 0) { + error_report("PowerNV guest support Unimplemented"); + exit(1); + } + } + + *psizep = INT_MAX; + *protp = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + + /* + * Perform process-scoped translation if relocation enabled. + * + * - Translates an effective address to a host real address in + * quadrants 0 and 3 when HV=1. + */ + if (relocation) { + int ret = ppc_radix64_process_scoped_xlate(cpu, rwx, eaddr, pid, + pate, &g_raddr, &prot, + &psize, cause_excp); + if (ret) { + return ret; + } + *psizep = MIN(*psizep, psize); + *protp &= prot; + } else { + g_raddr = eaddr & R_EADDR_MASK; + } + + *raddr = g_raddr; + return 0; +} + int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, int mmu_idx) { CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; - PPCVirtualHypervisorClass *vhc; - hwaddr raddr, pte_addr; - uint64_t lpid = 0, pid = 0, offset, size, prtbe0, pte; - int page_size, prot, fault_cause = 0; - ppc_v3_pate_t pate; + int page_size, prot; bool relocation; + hwaddr raddr; assert(!(msr_hv && cpu->vhyp)); assert((rwx == 0) || (rwx == 1) || (rwx == 2)); @@ -262,55 +372,12 @@ int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, TARGET_FMT_lx "\n", env->spr[SPR_LPCR]); } - /* Virtual Mode Access - get the fully qualified address */ - if (!ppc_radix64_get_fully_qualified_addr(env, eaddr, &lpid, &pid)) { - ppc_radix64_raise_segi(cpu, rwx, eaddr); + /* Translate eaddr to raddr (where raddr is addr qemu needs for access) */ + if (ppc_radix64_xlate(cpu, eaddr, rwx, relocation, &raddr, + &page_size, &prot, true)) { return 1; } - /* Get Process Table */ - if (cpu->vhyp) { - vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); - vhc->get_pate(cpu->vhyp, &pate); - } else { - if (!ppc64_v3_get_pate(cpu, lpid, &pate)) { - ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE); - return 1; - } - if (!validate_pate(cpu, lpid, &pate)) { - ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_R_BADCONFIG); - } - /* We don't support guest mode yet */ - if (lpid != 0) { - error_report("PowerNV guest support Unimplemented"); - exit(1); - } - } - - /* Index Process Table by PID to Find Corresponding Process Table Entry */ - offset = pid * sizeof(struct prtb_entry); - size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12); - if (offset >= size) { - /* offset exceeds size of the process table */ - ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE); - return 1; - } - prtbe0 = ldq_phys(cs->as, (pate.dw1 & PATE1_R_PRTB) + offset); - - /* Walk Radix Tree from Process Table Entry to Convert EA to RA */ - page_size = PRTBE_R_GET_RTS(prtbe0); - pte = ppc_radix64_walk_tree(cpu, eaddr & R_EADDR_MASK, - prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS, - &raddr, &page_size, &fault_cause, &pte_addr); - if (!pte || ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, &prot)) { - /* Couldn't get pte or access denied due to protection */ - ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause); - return 1; - } - - /* Update Reference and Change Bits */ - ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, &prot); - tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK, prot, mmu_idx, 1UL << page_size); return 0; @@ -318,58 +385,18 @@ int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, hwaddr ppc_radix64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong eaddr) { - CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; - PPCVirtualHypervisorClass *vhc; - hwaddr raddr, pte_addr; - uint64_t lpid = 0, pid = 0, offset, size, prtbe0, pte; - int page_size, fault_cause = 0; - ppc_v3_pate_t pate; + int psize, prot; + hwaddr raddr; /* Handle Real Mode */ - if (msr_dr == 0) { + if ((msr_dr == 0) && (msr_hv || cpu->vhyp)) { /* In real mode top 4 effective addr bits (mostly) ignored */ return eaddr & 0x0FFFFFFFFFFFFFFFULL; } - /* Virtual Mode Access - get the fully qualified address */ - if (!ppc_radix64_get_fully_qualified_addr(env, eaddr, &lpid, &pid)) { - return -1; - } - - /* Get Process Table */ - if (cpu->vhyp) { - vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); - vhc->get_pate(cpu->vhyp, &pate); - } else { - if (!ppc64_v3_get_pate(cpu, lpid, &pate)) { - return -1; - } - if (!validate_pate(cpu, lpid, &pate)) { - return -1; - } - /* We don't support guest mode yet */ - if (lpid != 0) { - error_report("PowerNV guest support Unimplemented"); - exit(1); - } - } - - /* Index Process Table by PID to Find Corresponding Process Table Entry */ - offset = pid * sizeof(struct prtb_entry); - size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12); - if (offset >= size) { - /* offset exceeds size of the process table */ - return -1; - } - prtbe0 = ldq_phys(cs->as, (pate.dw1 & PATE1_R_PRTB) + offset); - - /* Walk Radix Tree from Process Table Entry to Convert EA to RA */ - page_size = PRTBE_R_GET_RTS(prtbe0); - pte = ppc_radix64_walk_tree(cpu, eaddr & R_EADDR_MASK, - prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS, - &raddr, &page_size, &fault_cause, &pte_addr); - if (!pte) { + if (ppc_radix64_xlate(cpu, eaddr, 0, msr_dr, &raddr, &psize, + &prot, false)) { return -1; } From 522ad21875ac48426c282ef2b7dfe87adb40afb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 3 Apr 2020 16:00:54 +0200 Subject: [PATCH 13/18] target/ppc: Extend ppc_radix64_check_prot() with a 'partition_scoped' bool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This prepares ground for partition-scoped Radix translation. Signed-off-by: Suraj Jitindar Singh Signed-off-by: Cédric Le Goater Reviewed-by: Greg Kurz Message-Id: <20200403140056.59465-3-clg@kaod.org> Signed-off-by: David Gibson --- target/ppc/mmu-radix64.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index 4b0d0ff50a3..11b3c6d48c6 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -105,7 +105,8 @@ static void ppc_radix64_raise_si(PowerPCCPU *cpu, int rwx, vaddr eaddr, static bool ppc_radix64_check_prot(PowerPCCPU *cpu, int rwx, uint64_t pte, - int *fault_cause, int *prot) + int *fault_cause, int *prot, + bool partition_scoped) { CPUPPCState *env = &cpu->env; const int need_prot[] = { PAGE_READ, PAGE_WRITE, PAGE_EXEC }; @@ -121,11 +122,11 @@ static bool ppc_radix64_check_prot(PowerPCCPU *cpu, int rwx, uint64_t pte, } /* Determine permissions allowed by Encoded Access Authority */ - if ((pte & R_PTE_EAA_PRIV) && msr_pr) { /* Insufficient Privilege */ + if (!partition_scoped && (pte & R_PTE_EAA_PRIV) && msr_pr) { *prot = 0; - } else if (msr_pr || (pte & R_PTE_EAA_PRIV)) { + } else if (msr_pr || (pte & R_PTE_EAA_PRIV) || partition_scoped) { *prot = ppc_radix64_get_prot_eaa(pte); - } else { /* !msr_pr && !(pte & R_PTE_EAA_PRIV) */ + } else { /* !msr_pr && !(pte & R_PTE_EAA_PRIV) && !partition_scoped */ *prot = ppc_radix64_get_prot_eaa(pte); *prot &= ppc_radix64_get_prot_amr(cpu); /* Least combined permissions */ } @@ -250,7 +251,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, g_raddr, g_page_size, &fault_cause, &pte_addr); if (!(pte & R_PTE_VALID) || - ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot)) { + ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot, false)) { /* No valid pte or access denied due to protection */ if (cause_excp) { ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause); From 6bffd48b9e8efcd6977c86f2ea8437771d15043c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 3 Apr 2020 16:00:55 +0200 Subject: [PATCH 14/18] target/ppc: Rework ppc_radix64_walk_tree() for partition-scoped translation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ppc_radix64_walk_tree() routine walks through the nested radix tables to look for a PTE. Split it in two and introduce a new routine ppc_radix64_next_level() which we will use for partition-scoped Radix translation when translating the process tree addresses. The prototypes are slightly change to use a 'AddressSpace *' parameter, instead of a 'PowerPCCPU *' which is not required, and to return an error code instead of a PTE value. It clarifies error handling in the callers. Signed-off-by: Suraj Jitindar Singh Signed-off-by: Greg Kurz Signed-off-by: Cédric Le Goater Message-Id: <20200403140056.59465-4-clg@kaod.org> Signed-off-by: David Gibson --- target/ppc/mmu-radix64.c | 79 ++++++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 27 deletions(-) diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index 11b3c6d48c6..2400da41e06 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -163,44 +163,67 @@ static void ppc_radix64_set_rc(PowerPCCPU *cpu, int rwx, uint64_t pte, } } -static uint64_t ppc_radix64_walk_tree(PowerPCCPU *cpu, vaddr eaddr, - uint64_t base_addr, uint64_t nls, - hwaddr *raddr, int *psize, - int *fault_cause, hwaddr *pte_addr) +static int ppc_radix64_next_level(AddressSpace *as, vaddr eaddr, + uint64_t *pte_addr, uint64_t *nls, + int *psize, uint64_t *pte, int *fault_cause) { - CPUState *cs = CPU(cpu); uint64_t index, pde; - if (nls < 5) { /* Directory maps less than 2**5 entries */ + if (*nls < 5) { /* Directory maps less than 2**5 entries */ *fault_cause |= DSISR_R_BADCONFIG; - return 0; + return 1; } /* Read page entry from guest address space */ - index = eaddr >> (*psize - nls); /* Shift */ - index &= ((1UL << nls) - 1); /* Mask */ - pde = ldq_phys(cs->as, base_addr + (index * sizeof(pde))); - if (!(pde & R_PTE_VALID)) { /* Invalid Entry */ + pde = ldq_phys(as, *pte_addr); + if (!(pde & R_PTE_VALID)) { /* Invalid Entry */ *fault_cause |= DSISR_NOPTE; - return 0; + return 1; } - *psize -= nls; + *pte = pde; + *psize -= *nls; + if (!(pde & R_PTE_LEAF)) { /* Prepare for next iteration */ + *nls = pde & R_PDE_NLS; + index = eaddr >> (*psize - *nls); /* Shift */ + index &= ((1UL << *nls) - 1); /* Mask */ + *pte_addr = (pde & R_PDE_NLB) + (index * sizeof(pde)); + } + return 0; +} - /* Check if Leaf Entry -> Page Table Entry -> Stop the Search */ - if (pde & R_PTE_LEAF) { - uint64_t rpn = pde & R_PTE_RPN; - uint64_t mask = (1UL << *psize) - 1; +static int ppc_radix64_walk_tree(AddressSpace *as, vaddr eaddr, + uint64_t base_addr, uint64_t nls, + hwaddr *raddr, int *psize, uint64_t *pte, + int *fault_cause, hwaddr *pte_addr) +{ + uint64_t index, pde, rpn , mask; - /* Or high bits of rpn and low bits to ea to form whole real addr */ - *raddr = (rpn & ~mask) | (eaddr & mask); - *pte_addr = base_addr + (index * sizeof(pde)); - return pde; + if (nls < 5) { /* Directory maps less than 2**5 entries */ + *fault_cause |= DSISR_R_BADCONFIG; + return 1; } - /* Next Level of Radix Tree */ - return ppc_radix64_walk_tree(cpu, eaddr, pde & R_PDE_NLB, pde & R_PDE_NLS, - raddr, psize, fault_cause, pte_addr); + index = eaddr >> (*psize - nls); /* Shift */ + index &= ((1UL << nls) - 1); /* Mask */ + *pte_addr = base_addr + (index * sizeof(pde)); + do { + int ret; + + ret = ppc_radix64_next_level(as, eaddr, pte_addr, &nls, psize, &pde, + fault_cause); + if (ret) { + return ret; + } + } while (!(pde & R_PTE_LEAF)); + + *pte = pde; + rpn = pde & R_PTE_RPN; + mask = (1UL << *psize) - 1; + + /* Or high bits of rpn and low bits to ea to form whole real addr */ + *raddr = (rpn & ~mask) | (eaddr & mask); + return 0; } static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate) @@ -230,6 +253,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, uint64_t offset, size, prtbe_addr, prtbe0, pte; int fault_cause = 0; hwaddr pte_addr; + int ret; /* Index Process Table by PID to Find Corresponding Process Table Entry */ offset = pid * sizeof(struct prtb_entry); @@ -246,11 +270,12 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, /* Walk Radix Tree from Process Table Entry to Convert EA to RA */ *g_page_size = PRTBE_R_GET_RTS(prtbe0); - pte = ppc_radix64_walk_tree(cpu, eaddr & R_EADDR_MASK, + ret = ppc_radix64_walk_tree(cs->as, eaddr & R_EADDR_MASK, prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS, - g_raddr, g_page_size, &fault_cause, &pte_addr); + g_raddr, g_page_size, &pte, &fault_cause, + &pte_addr); - if (!(pte & R_PTE_VALID) || + if (ret || ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot, false)) { /* No valid pte or access denied due to protection */ if (cause_excp) { From d04ea940c597201a6610c5d1712809ed35dd77ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 3 Apr 2020 16:00:56 +0200 Subject: [PATCH 15/18] target/ppc: Add support for Radix partition-scoped translation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Radix tree translation model currently supports process-scoped translation for the PowerNV machine (Hypervisor mode) and for the pSeries machine (Guest mode). Guests running under an emulated Hypervisor (PowerNV machine) require a new type of Radix translation, called partition-scoped, which is missing today. The Radix tree translation is a 2 steps process. The first step, process-scoped translation, converts an effective Address to a guest real address, and the second step, partition-scoped translation, converts a guest real address to a host real address. There are difference cases to covers : * Hypervisor real mode access: no Radix translation. * Hypervisor or host application access (quadrant 0 and 3) with relocation on: process-scoped translation. * Guest OS real mode access: only partition-scoped translation. * Guest OS real or guest application access (quadrant 0 and 3) with relocation on: both process-scoped translation and partition-scoped translations. * Hypervisor access in quadrant 1 and 2 with relocation on: both process-scoped translation and partition-scoped translations. The radix tree partition-scoped translation is performed using tables pointed to by the first double-word of the Partition Table Entries and process-scoped translation uses tables pointed to by the Process Table Entries (second double-word of the Partition Table Entries). Both partition-scoped and process-scoped translations process are identical and thus the radix tree traversing code is largely reused. However, errors in partition-scoped translations generate hypervisor exceptions. Signed-off-by: Suraj Jitindar Singh Signed-off-by: Greg Kurz Signed-off-by: Cédric Le Goater Message-Id: <20200403140056.59465-5-clg@kaod.org> [dwg: Fixup from Greg Kurz folded in] Signed-off-by: David Gibson --- target/ppc/cpu.h | 3 + target/ppc/excp_helper.c | 3 +- target/ppc/mmu-radix64.c | 194 +++++++++++++++++++++++++++++++++++---- 3 files changed, 181 insertions(+), 19 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index f4a5304d435..6b6dd7e483f 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -463,6 +463,9 @@ typedef struct ppc_v3_pate_t { #define DSISR_AMR 0x00200000 /* Unsupported Radix Tree Configuration */ #define DSISR_R_BADCONFIG 0x00080000 +#define DSISR_ATOMIC_RC 0x00040000 +/* Unable to translate address of (guest) pde or process/page table entry */ +#define DSISR_PRTABLE_FAULT 0x00020000 /* SRR1 error code fields */ diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 1acc3786de0..f0529796647 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -506,9 +506,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) case POWERPC_EXCP_ISEG: /* Instruction segment exception */ case POWERPC_EXCP_TRACE: /* Trace exception */ break; + case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ + msr |= env->error_code; case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ - case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */ case POWERPC_EXCP_SDOOR_HV: /* Hypervisor Doorbell interrupt */ diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index 2400da41e06..1404e53deca 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -103,6 +103,27 @@ static void ppc_radix64_raise_si(PowerPCCPU *cpu, int rwx, vaddr eaddr, } } +static void ppc_radix64_raise_hsi(PowerPCCPU *cpu, int rwx, vaddr eaddr, + hwaddr g_raddr, uint32_t cause) +{ + CPUState *cs = CPU(cpu); + CPUPPCState *env = &cpu->env; + + if (rwx == 2) { /* H Instruction Storage Interrupt */ + cs->exception_index = POWERPC_EXCP_HISI; + env->spr[SPR_ASDR] = g_raddr; + env->error_code = cause; + } else { /* H Data Storage Interrupt */ + cs->exception_index = POWERPC_EXCP_HDSI; + if (rwx == 1) { /* Write -> Store */ + cause |= DSISR_ISSTORE; + } + env->spr[SPR_HDSISR] = cause; + env->spr[SPR_HDAR] = eaddr; + env->spr[SPR_ASDR] = g_raddr; + env->error_code = 0; + } +} static bool ppc_radix64_check_prot(PowerPCCPU *cpu, int rwx, uint64_t pte, int *fault_cause, int *prot, @@ -243,6 +264,37 @@ static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate) return true; } +static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu, int rwx, + vaddr eaddr, hwaddr g_raddr, + ppc_v3_pate_t pate, + hwaddr *h_raddr, int *h_prot, + int *h_page_size, bool pde_addr, + bool cause_excp) +{ + int fault_cause = 0; + hwaddr pte_addr; + uint64_t pte; + + *h_page_size = PRTBE_R_GET_RTS(pate.dw0); + /* No valid pte or access denied due to protection */ + if (ppc_radix64_walk_tree(CPU(cpu)->as, g_raddr, pate.dw0 & PRTBE_R_RPDB, + pate.dw0 & PRTBE_R_RPDS, h_raddr, h_page_size, + &pte, &fault_cause, &pte_addr) || + ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, h_prot, true)) { + if (pde_addr) /* address being translated was that of a guest pde */ + fault_cause |= DSISR_PRTABLE_FAULT; + if (cause_excp) { + ppc_radix64_raise_hsi(cpu, rwx, eaddr, g_raddr, fault_cause); + } + return 1; + } + + /* Update Reference and Change Bits */ + ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, h_prot); + + return 0; +} + static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, vaddr eaddr, uint64_t pid, ppc_v3_pate_t pate, hwaddr *g_raddr, @@ -250,9 +302,10 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, bool cause_excp) { CPUState *cs = CPU(cpu); - uint64_t offset, size, prtbe_addr, prtbe0, pte; - int fault_cause = 0; - hwaddr pte_addr; + CPUPPCState *env = &cpu->env; + uint64_t offset, size, prtbe_addr, prtbe0, base_addr, nls, index, pte; + int fault_cause = 0, h_page_size, h_prot; + hwaddr h_raddr, pte_addr; int ret; /* Index Process Table by PID to Find Corresponding Process Table Entry */ @@ -266,18 +319,85 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, return 1; } prtbe_addr = (pate.dw1 & PATE1_R_PRTB) + offset; - prtbe0 = ldq_phys(cs->as, prtbe_addr); + + if (cpu->vhyp) { + prtbe0 = ldq_phys(cs->as, prtbe_addr); + } else { + /* + * Process table addresses are subject to partition-scoped + * translation + * + * On a Radix host, the partition-scoped page table for LPID=0 + * is only used to translate the effective addresses of the + * process table entries. + */ + ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, prtbe_addr, + pate, &h_raddr, &h_prot, + &h_page_size, 1, 1); + if (ret) { + return ret; + } + prtbe0 = ldq_phys(cs->as, h_raddr); + } /* Walk Radix Tree from Process Table Entry to Convert EA to RA */ *g_page_size = PRTBE_R_GET_RTS(prtbe0); - ret = ppc_radix64_walk_tree(cs->as, eaddr & R_EADDR_MASK, - prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS, - g_raddr, g_page_size, &pte, &fault_cause, - &pte_addr); - - if (ret || - ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot, false)) { - /* No valid pte or access denied due to protection */ + base_addr = prtbe0 & PRTBE_R_RPDB; + nls = prtbe0 & PRTBE_R_RPDS; + if (msr_hv || cpu->vhyp) { + /* + * Can treat process table addresses as real addresses + */ + ret = ppc_radix64_walk_tree(cs->as, eaddr & R_EADDR_MASK, base_addr, + nls, g_raddr, g_page_size, &pte, + &fault_cause, &pte_addr); + if (ret) { + /* No valid PTE */ + if (cause_excp) { + ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause); + } + return ret; + } + } else { + uint64_t rpn, mask; + + index = (eaddr & R_EADDR_MASK) >> (*g_page_size - nls); /* Shift */ + index &= ((1UL << nls) - 1); /* Mask */ + pte_addr = base_addr + (index * sizeof(pte)); + + /* + * Each process table address is subject to a partition-scoped + * translation + */ + do { + ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, pte_addr, + pate, &h_raddr, &h_prot, + &h_page_size, 1, 1); + if (ret) { + return ret; + } + + ret = ppc_radix64_next_level(cs->as, eaddr & R_EADDR_MASK, &h_raddr, + &nls, g_page_size, &pte, &fault_cause); + if (ret) { + /* No valid pte */ + if (cause_excp) { + ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause); + } + return ret; + } + pte_addr = h_raddr; + } while (!(pte & R_PTE_LEAF)); + + rpn = pte & R_PTE_RPN; + mask = (1UL << *g_page_size) - 1; + + /* Or high bits of rpn and low bits to ea to form whole real addr */ + *g_raddr = (rpn & ~mask) | (eaddr & mask); + } + + if (ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot, false)) { + /* Access denied due to protection */ if (cause_excp) { ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause); } @@ -289,11 +409,29 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, return 0; } +/* + * Radix tree translation is a 2 steps translation process: + * + * 1. Process-scoped translation: Guest Eff Addr -> Guest Real Addr + * 2. Partition-scoped translation: Guest Real Addr -> Host Real Addr + * + * MSR[HV] + * +-------------+----------------+---------------+ + * | | HV = 0 | HV = 1 | + * +-------------+----------------+---------------+ + * | Relocation | Partition | No | + * | = Off | Scoped | Translation | + * Relocation +-------------+----------------+---------------+ + * | Relocation | Partition & | Process | + * | = On | Process Scoped | Scoped | + * +-------------+----------------+---------------+ + */ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx, bool relocation, hwaddr *raddr, int *psizep, int *protp, bool cause_excp) { + CPUPPCState *env = &cpu->env; uint64_t lpid = 0, pid = 0; ppc_v3_pate_t pate; int psize, prot; @@ -325,11 +463,6 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx, } return 1; } - /* We don't support guest mode yet */ - if (lpid != 0) { - error_report("PowerNV guest support Unimplemented"); - exit(1); - } } *psizep = INT_MAX; @@ -340,6 +473,8 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx, * * - Translates an effective address to a host real address in * quadrants 0 and 3 when HV=1. + * + * - Translates an effective address to a guest real address. */ if (relocation) { int ret = ppc_radix64_process_scoped_xlate(cpu, rwx, eaddr, pid, @@ -354,7 +489,30 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx, g_raddr = eaddr & R_EADDR_MASK; } - *raddr = g_raddr; + if (cpu->vhyp) { + *raddr = g_raddr; + } else { + /* + * Perform partition-scoped translation if !HV or HV access to + * quadrants 1 or 2. Translates a guest real address to a host + * real address. + */ + if (lpid || !msr_hv) { + int ret; + + ret = ppc_radix64_partition_scoped_xlate(cpu, rwx, eaddr, g_raddr, + pate, raddr, &prot, &psize, + 0, cause_excp); + if (ret) { + return ret; + } + *psizep = MIN(*psizep, psize); + *protp &= prot; + } else { + *raddr = g_raddr; + } + } + return 0; } From 70fc9cb0920fce3c2c0a090e69bf06d39f4b2362 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 13 Apr 2020 17:36:28 -0300 Subject: [PATCH 16/18] spapr_nvdimm.c: make 'label-size' mandatory The pseries machine does not support NVDIMM modules without label. Attempting to do so, even if the overall block size is aligned with 256MB, will seg fault the guest kernel during NVDIMM probe. This can be avoided by forcing 'label-size' to always be present for sPAPR NVDIMMs. The verification was put before the alignment check because the presence of label-size affects the alignment calculation, so it's not optimal to warn the user about an alignment error, then about the lack of label-size, then about a new alignment error when the user sets a label-size. Signed-off-by: Daniel Henrique Barboza Message-Id: <20200413203628.31636-1-danielhb413@gmail.com> Signed-off-by: David Gibson --- hw/ppc/spapr_nvdimm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/ppc/spapr_nvdimm.c b/hw/ppc/spapr_nvdimm.c index 25be8082d79..9abcdcc26bf 100644 --- a/hw/ppc/spapr_nvdimm.c +++ b/hw/ppc/spapr_nvdimm.c @@ -37,6 +37,12 @@ void spapr_nvdimm_validate_opts(NVDIMMDevice *nvdimm, uint64_t size, QemuUUID uuid; int ret; + if (object_property_get_int(OBJECT(nvdimm), NVDIMM_LABEL_SIZE_PROP, + &error_abort) == 0) { + error_setg(errp, "NVDIMM device requires label-size to be set"); + return; + } + if (size % SPAPR_MINIMUM_SCM_BLOCK_SIZE) { error_setg(errp, "NVDIMM memory size excluding the label area" " must be a multiple of %" PRIu64 "MB", From 6c0f0cb319bd9f906d461a2e12a2b5d1eb588fa2 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Fri, 24 Apr 2020 11:56:17 +1000 Subject: [PATCH 17/18] spapr_nvdimm: Tweak error messages The restrictions here (which are checked at pre-plug time) are PAPR specific, rather than being inherent to the NVDIMM devices. Adjust the error messages to be clearer about this. Signed-off-by: David Gibson --- hw/ppc/spapr_nvdimm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/ppc/spapr_nvdimm.c b/hw/ppc/spapr_nvdimm.c index 9abcdcc26bf..81410aa63fe 100644 --- a/hw/ppc/spapr_nvdimm.c +++ b/hw/ppc/spapr_nvdimm.c @@ -39,13 +39,13 @@ void spapr_nvdimm_validate_opts(NVDIMMDevice *nvdimm, uint64_t size, if (object_property_get_int(OBJECT(nvdimm), NVDIMM_LABEL_SIZE_PROP, &error_abort) == 0) { - error_setg(errp, "NVDIMM device requires label-size to be set"); + error_setg(errp, "PAPR requires NVDIMM devices to have label-size set"); return; } if (size % SPAPR_MINIMUM_SCM_BLOCK_SIZE) { - error_setg(errp, "NVDIMM memory size excluding the label area" - " must be a multiple of %" PRIu64 "MB", + error_setg(errp, "PAPR requires NVDIMM memory size (excluding label)" + " to be a multiple of %" PRIu64 "MB", SPAPR_MINIMUM_SCM_BLOCK_SIZE / MiB); return; } From c4f6a4a3dd5f2aa15329b8158de25f50b5ba3252 Mon Sep 17 00:00:00 2001 From: Daniele Buono Date: Tue, 5 May 2020 14:38:17 -0400 Subject: [PATCH 18/18] target-ppc: fix rlwimi, rlwinm, rlwnm for Clang-9 Starting with Clang v9, -Wtype-limits is implemented and triggers a few "result of comparison is always true" errors when compiling PPC32 targets. The comparisons seem to be necessary only on PPC64, since the else branch in PPC32 only has a "g_assert_not_reached();" in all cases. This patch restructures the code so that the actual if/else is done on a local flag variable, that is set accordingly for PPC64, and always true for PPC32. Signed-off-by: Daniele Buono Message-Id: <20200505183818.32688-2-dbuono@linux.vnet.ibm.com> Signed-off-by: David Gibson --- target/ppc/translate.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 807d14faaa4..338529879f9 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -1882,6 +1882,7 @@ static void gen_rlwimi(DisasContext *ctx) tcg_gen_deposit_tl(t_ra, t_ra, t_rs, sh, me - mb + 1); } else { target_ulong mask; + bool mask_in_32b = true; TCGv t1; #if defined(TARGET_PPC64) @@ -1890,8 +1891,13 @@ static void gen_rlwimi(DisasContext *ctx) #endif mask = MASK(mb, me); +#if defined(TARGET_PPC64) + if (mask > 0xffffffffu) { + mask_in_32b = false; + } +#endif t1 = tcg_temp_new(); - if (mask <= 0xffffffffu) { + if (mask_in_32b) { TCGv_i32 t0 = tcg_temp_new_i32(); tcg_gen_trunc_tl_i32(t0, t_rs); tcg_gen_rotli_i32(t0, t0, sh); @@ -1933,12 +1939,18 @@ static void gen_rlwinm(DisasContext *ctx) tcg_gen_extract_tl(t_ra, t_rs, rsh, len); } else { target_ulong mask; + bool mask_in_32b = true; #if defined(TARGET_PPC64) mb += 32; me += 32; #endif mask = MASK(mb, me); - if (mask <= 0xffffffffu) { +#if defined(TARGET_PPC64) + if (mask > 0xffffffffu) { + mask_in_32b = false; + } +#endif + if (mask_in_32b) { if (sh == 0) { tcg_gen_andi_tl(t_ra, t_rs, mask); } else { @@ -1973,6 +1985,7 @@ static void gen_rlwnm(DisasContext *ctx) uint32_t mb = MB(ctx->opcode); uint32_t me = ME(ctx->opcode); target_ulong mask; + bool mask_in_32b = true; #if defined(TARGET_PPC64) mb += 32; @@ -1980,7 +1993,12 @@ static void gen_rlwnm(DisasContext *ctx) #endif mask = MASK(mb, me); - if (mask <= 0xffffffffu) { +#if defined(TARGET_PPC64) + if (mask > 0xffffffffu) { + mask_in_32b = false; + } +#endif + if (mask_in_32b) { TCGv_i32 t0 = tcg_temp_new_i32(); TCGv_i32 t1 = tcg_temp_new_i32(); tcg_gen_trunc_tl_i32(t0, t_rb);