1*fc8c745dSAlexey Kardashevskiy /* 2*fc8c745dSAlexey Kardashevskiy * SPAPR machine hooks to Virtual Open Firmware, 3*fc8c745dSAlexey Kardashevskiy * 4*fc8c745dSAlexey Kardashevskiy * SPDX-License-Identifier: GPL-2.0-or-later 5*fc8c745dSAlexey Kardashevskiy */ 6*fc8c745dSAlexey Kardashevskiy #include "qemu/osdep.h" 7*fc8c745dSAlexey Kardashevskiy #include "qemu-common.h" 8*fc8c745dSAlexey Kardashevskiy #include "qapi/error.h" 9*fc8c745dSAlexey Kardashevskiy #include "hw/ppc/spapr.h" 10*fc8c745dSAlexey Kardashevskiy #include "hw/ppc/spapr_vio.h" 11*fc8c745dSAlexey Kardashevskiy #include "hw/ppc/fdt.h" 12*fc8c745dSAlexey Kardashevskiy #include "hw/ppc/vof.h" 13*fc8c745dSAlexey Kardashevskiy #include "sysemu/sysemu.h" 14*fc8c745dSAlexey Kardashevskiy #include "qom/qom-qobject.h" 15*fc8c745dSAlexey Kardashevskiy #include "trace.h" 16*fc8c745dSAlexey Kardashevskiy 17*fc8c745dSAlexey Kardashevskiy target_ulong spapr_h_vof_client(PowerPCCPU *cpu, SpaprMachineState *spapr, 18*fc8c745dSAlexey Kardashevskiy target_ulong opcode, target_ulong *_args) 19*fc8c745dSAlexey Kardashevskiy { 20*fc8c745dSAlexey Kardashevskiy int ret = vof_client_call(MACHINE(spapr), spapr->vof, spapr->fdt_blob, 21*fc8c745dSAlexey Kardashevskiy ppc64_phys_to_real(_args[0])); 22*fc8c745dSAlexey Kardashevskiy 23*fc8c745dSAlexey Kardashevskiy if (ret) { 24*fc8c745dSAlexey Kardashevskiy return H_PARAMETER; 25*fc8c745dSAlexey Kardashevskiy } 26*fc8c745dSAlexey Kardashevskiy return H_SUCCESS; 27*fc8c745dSAlexey Kardashevskiy } 28*fc8c745dSAlexey Kardashevskiy 29*fc8c745dSAlexey Kardashevskiy void spapr_vof_client_dt_finalize(SpaprMachineState *spapr, void *fdt) 30*fc8c745dSAlexey Kardashevskiy { 31*fc8c745dSAlexey Kardashevskiy char *stdout_path = spapr_vio_stdout_path(spapr->vio_bus); 32*fc8c745dSAlexey Kardashevskiy int chosen; 33*fc8c745dSAlexey Kardashevskiy 34*fc8c745dSAlexey Kardashevskiy vof_build_dt(fdt, spapr->vof); 35*fc8c745dSAlexey Kardashevskiy 36*fc8c745dSAlexey Kardashevskiy _FDT(chosen = fdt_path_offset(fdt, "/chosen")); 37*fc8c745dSAlexey Kardashevskiy _FDT(fdt_setprop_string(fdt, chosen, "bootargs", 38*fc8c745dSAlexey Kardashevskiy spapr->vof->bootargs ? : "")); 39*fc8c745dSAlexey Kardashevskiy 40*fc8c745dSAlexey Kardashevskiy /* 41*fc8c745dSAlexey Kardashevskiy * SLOF-less setup requires an open instance of stdout for early 42*fc8c745dSAlexey Kardashevskiy * kernel printk. By now all phandles are settled so we can open 43*fc8c745dSAlexey Kardashevskiy * the default serial console. 44*fc8c745dSAlexey Kardashevskiy */ 45*fc8c745dSAlexey Kardashevskiy if (stdout_path) { 46*fc8c745dSAlexey Kardashevskiy _FDT(vof_client_open_store(fdt, spapr->vof, "/chosen", "stdout", 47*fc8c745dSAlexey Kardashevskiy stdout_path)); 48*fc8c745dSAlexey Kardashevskiy } 49*fc8c745dSAlexey Kardashevskiy } 50*fc8c745dSAlexey Kardashevskiy 51*fc8c745dSAlexey Kardashevskiy void spapr_vof_reset(SpaprMachineState *spapr, void *fdt, 52*fc8c745dSAlexey Kardashevskiy target_ulong *stack_ptr, Error **errp) 53*fc8c745dSAlexey Kardashevskiy { 54*fc8c745dSAlexey Kardashevskiy Vof *vof = spapr->vof; 55*fc8c745dSAlexey Kardashevskiy 56*fc8c745dSAlexey Kardashevskiy vof_init(vof, spapr->rma_size, errp); 57*fc8c745dSAlexey Kardashevskiy 58*fc8c745dSAlexey Kardashevskiy *stack_ptr = vof_claim(vof, 0, VOF_STACK_SIZE, VOF_STACK_SIZE); 59*fc8c745dSAlexey Kardashevskiy if (*stack_ptr == -1) { 60*fc8c745dSAlexey Kardashevskiy error_setg(errp, "Memory allocation for stack failed"); 61*fc8c745dSAlexey Kardashevskiy return; 62*fc8c745dSAlexey Kardashevskiy } 63*fc8c745dSAlexey Kardashevskiy /* Stack grows downwards plus reserve space for the minimum stack frame */ 64*fc8c745dSAlexey Kardashevskiy *stack_ptr += VOF_STACK_SIZE - 0x20; 65*fc8c745dSAlexey Kardashevskiy 66*fc8c745dSAlexey Kardashevskiy if (spapr->kernel_size && 67*fc8c745dSAlexey Kardashevskiy vof_claim(vof, spapr->kernel_addr, spapr->kernel_size, 0) == -1) { 68*fc8c745dSAlexey Kardashevskiy error_setg(errp, "Memory for kernel is in use"); 69*fc8c745dSAlexey Kardashevskiy return; 70*fc8c745dSAlexey Kardashevskiy } 71*fc8c745dSAlexey Kardashevskiy 72*fc8c745dSAlexey Kardashevskiy if (spapr->initrd_size && 73*fc8c745dSAlexey Kardashevskiy vof_claim(vof, spapr->initrd_base, spapr->initrd_size, 0) == -1) { 74*fc8c745dSAlexey Kardashevskiy error_setg(errp, "Memory for initramdisk is in use"); 75*fc8c745dSAlexey Kardashevskiy return; 76*fc8c745dSAlexey Kardashevskiy } 77*fc8c745dSAlexey Kardashevskiy 78*fc8c745dSAlexey Kardashevskiy spapr_vof_client_dt_finalize(spapr, fdt); 79*fc8c745dSAlexey Kardashevskiy 80*fc8c745dSAlexey Kardashevskiy /* 81*fc8c745dSAlexey Kardashevskiy * At this point the expected allocation map is: 82*fc8c745dSAlexey Kardashevskiy * 83*fc8c745dSAlexey Kardashevskiy * 0..c38 - the initial firmware 84*fc8c745dSAlexey Kardashevskiy * 8000..10000 - stack 85*fc8c745dSAlexey Kardashevskiy * 400000.. - kernel 86*fc8c745dSAlexey Kardashevskiy * 3ea0000.. - initramdisk 87*fc8c745dSAlexey Kardashevskiy * 88*fc8c745dSAlexey Kardashevskiy * We skip writing FDT as nothing expects it; OF client interface is 89*fc8c745dSAlexey Kardashevskiy * going to be used for reading the device tree. 90*fc8c745dSAlexey Kardashevskiy */ 91*fc8c745dSAlexey Kardashevskiy } 92*fc8c745dSAlexey Kardashevskiy 93*fc8c745dSAlexey Kardashevskiy void spapr_vof_quiesce(MachineState *ms) 94*fc8c745dSAlexey Kardashevskiy { 95*fc8c745dSAlexey Kardashevskiy SpaprMachineState *spapr = SPAPR_MACHINE(ms); 96*fc8c745dSAlexey Kardashevskiy 97*fc8c745dSAlexey Kardashevskiy spapr->fdt_size = fdt_totalsize(spapr->fdt_blob); 98*fc8c745dSAlexey Kardashevskiy spapr->fdt_initial_size = spapr->fdt_size; 99*fc8c745dSAlexey Kardashevskiy } 100*fc8c745dSAlexey Kardashevskiy 101*fc8c745dSAlexey Kardashevskiy bool spapr_vof_setprop(MachineState *ms, const char *path, const char *propname, 102*fc8c745dSAlexey Kardashevskiy void *val, int vallen) 103*fc8c745dSAlexey Kardashevskiy { 104*fc8c745dSAlexey Kardashevskiy SpaprMachineState *spapr = SPAPR_MACHINE(ms); 105*fc8c745dSAlexey Kardashevskiy 106*fc8c745dSAlexey Kardashevskiy /* 107*fc8c745dSAlexey Kardashevskiy * We only allow changing properties which we know how to update in QEMU 108*fc8c745dSAlexey Kardashevskiy * OR 109*fc8c745dSAlexey Kardashevskiy * the ones which we know that they need to survive during "quiesce". 110*fc8c745dSAlexey Kardashevskiy */ 111*fc8c745dSAlexey Kardashevskiy 112*fc8c745dSAlexey Kardashevskiy if (strcmp(path, "/rtas") == 0) { 113*fc8c745dSAlexey Kardashevskiy if (strcmp(propname, "linux,rtas-base") == 0 || 114*fc8c745dSAlexey Kardashevskiy strcmp(propname, "linux,rtas-entry") == 0) { 115*fc8c745dSAlexey Kardashevskiy /* These need to survive quiesce so let them store in the FDT */ 116*fc8c745dSAlexey Kardashevskiy return true; 117*fc8c745dSAlexey Kardashevskiy } 118*fc8c745dSAlexey Kardashevskiy } 119*fc8c745dSAlexey Kardashevskiy 120*fc8c745dSAlexey Kardashevskiy if (strcmp(path, "/chosen") == 0) { 121*fc8c745dSAlexey Kardashevskiy if (strcmp(propname, "bootargs") == 0) { 122*fc8c745dSAlexey Kardashevskiy Vof *vof = spapr->vof; 123*fc8c745dSAlexey Kardashevskiy 124*fc8c745dSAlexey Kardashevskiy g_free(vof->bootargs); 125*fc8c745dSAlexey Kardashevskiy vof->bootargs = g_strndup(val, vallen); 126*fc8c745dSAlexey Kardashevskiy return true; 127*fc8c745dSAlexey Kardashevskiy } 128*fc8c745dSAlexey Kardashevskiy if (strcmp(propname, "linux,initrd-start") == 0) { 129*fc8c745dSAlexey Kardashevskiy if (vallen == sizeof(uint32_t)) { 130*fc8c745dSAlexey Kardashevskiy spapr->initrd_base = ldl_be_p(val); 131*fc8c745dSAlexey Kardashevskiy return true; 132*fc8c745dSAlexey Kardashevskiy } 133*fc8c745dSAlexey Kardashevskiy if (vallen == sizeof(uint64_t)) { 134*fc8c745dSAlexey Kardashevskiy spapr->initrd_base = ldq_be_p(val); 135*fc8c745dSAlexey Kardashevskiy return true; 136*fc8c745dSAlexey Kardashevskiy } 137*fc8c745dSAlexey Kardashevskiy return false; 138*fc8c745dSAlexey Kardashevskiy } 139*fc8c745dSAlexey Kardashevskiy if (strcmp(propname, "linux,initrd-end") == 0) { 140*fc8c745dSAlexey Kardashevskiy if (vallen == sizeof(uint32_t)) { 141*fc8c745dSAlexey Kardashevskiy spapr->initrd_size = ldl_be_p(val) - spapr->initrd_base; 142*fc8c745dSAlexey Kardashevskiy return true; 143*fc8c745dSAlexey Kardashevskiy } 144*fc8c745dSAlexey Kardashevskiy if (vallen == sizeof(uint64_t)) { 145*fc8c745dSAlexey Kardashevskiy spapr->initrd_size = ldq_be_p(val) - spapr->initrd_base; 146*fc8c745dSAlexey Kardashevskiy return true; 147*fc8c745dSAlexey Kardashevskiy } 148*fc8c745dSAlexey Kardashevskiy return false; 149*fc8c745dSAlexey Kardashevskiy } 150*fc8c745dSAlexey Kardashevskiy } 151*fc8c745dSAlexey Kardashevskiy 152*fc8c745dSAlexey Kardashevskiy return true; 153*fc8c745dSAlexey Kardashevskiy } 154