xref: /qemu/hw/ppc/spapr_vof.c (revision fc8c745d)
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