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 <a...@ozlabs.ru> --- include/hw/ppc/spapr.h | 7 +++++ hw/ppc/spapr.c | 1 - hw/ppc/spapr_hcall.c | 67 ++++++++++++++++++++++++++---------------- 3 files changed, 48 insertions(+), 27 deletions(-) diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index a1fba95c824b..3b50f36c338a 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]; @@ -551,6 +553,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 diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 660a4b60e072..60153bf0b771 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -95,7 +95,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 b8bb66b5c0d4..da50d8ee5dd7 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1660,16 +1660,12 @@ static bool spapr_hotplugged_dev_before_cas(void) return false; } -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, *ov5_cas_old; bool guest_radix; @@ -1689,7 +1685,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; @@ -1712,7 +1708,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) { @@ -1836,7 +1832,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. */ @@ -1845,21 +1840,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, spapr_setup_hpt_and_vrma(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); @@ -1874,6 +1855,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, -- 2.17.1