ppc/ppc405: Fix boot from kernel
[qemu.git] / hw / ppc / spapr_vof.c
blob40ce8fe0037ce545e3ff58c55fd23d7de5299104
1 /*
2 * SPAPR machine hooks to Virtual Open Firmware,
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 #include "qemu/osdep.h"
7 #include "qemu-common.h"
8 #include "qapi/error.h"
9 #include "hw/ppc/spapr.h"
10 #include "hw/ppc/spapr_vio.h"
11 #include "hw/ppc/spapr_cpu_core.h"
12 #include "hw/ppc/fdt.h"
13 #include "hw/ppc/vof.h"
14 #include "sysemu/sysemu.h"
15 #include "qom/qom-qobject.h"
16 #include "trace.h"
18 target_ulong spapr_h_vof_client(PowerPCCPU *cpu, SpaprMachineState *spapr,
19 target_ulong opcode, target_ulong *_args)
21 int ret = vof_client_call(MACHINE(spapr), spapr->vof, spapr->fdt_blob,
22 ppc64_phys_to_real(_args[0]));
24 if (ret) {
25 return H_PARAMETER;
27 return H_SUCCESS;
30 void spapr_vof_client_dt_finalize(SpaprMachineState *spapr, void *fdt)
32 char *stdout_path = spapr_vio_stdout_path(spapr->vio_bus);
34 vof_build_dt(fdt, spapr->vof);
36 if (spapr->vof->bootargs) {
37 int chosen;
39 _FDT(chosen = fdt_path_offset(fdt, "/chosen"));
41 * If the client did not change "bootargs", spapr_dt_chosen() must have
42 * stored machine->kernel_cmdline in it before getting here.
44 _FDT(fdt_setprop_string(fdt, chosen, "bootargs", spapr->vof->bootargs));
48 * SLOF-less setup requires an open instance of stdout for early
49 * kernel printk. By now all phandles are settled so we can open
50 * the default serial console.
52 if (stdout_path) {
53 _FDT(vof_client_open_store(fdt, spapr->vof, "/chosen", "stdout",
54 stdout_path));
58 void spapr_vof_reset(SpaprMachineState *spapr, void *fdt, Error **errp)
60 target_ulong stack_ptr;
61 Vof *vof = spapr->vof;
62 PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
64 vof_init(vof, spapr->rma_size, errp);
66 stack_ptr = vof_claim(vof, 0, VOF_STACK_SIZE, VOF_STACK_SIZE);
67 if (stack_ptr == -1) {
68 error_setg(errp, "Memory allocation for stack failed");
69 return;
71 /* Stack grows downwards plus reserve space for the minimum stack frame */
72 stack_ptr += VOF_STACK_SIZE - 0x20;
74 if (spapr->kernel_size &&
75 vof_claim(vof, spapr->kernel_addr, spapr->kernel_size, 0) == -1) {
76 error_setg(errp, "Memory for kernel is in use");
77 return;
80 if (spapr->initrd_size &&
81 vof_claim(vof, spapr->initrd_base, spapr->initrd_size, 0) == -1) {
82 error_setg(errp, "Memory for initramdisk is in use");
83 return;
86 spapr_vof_client_dt_finalize(spapr, fdt);
88 spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT,
89 stack_ptr, spapr->initrd_base,
90 spapr->initrd_size);
91 /* VOF is 32bit BE so enforce MSR here */
92 first_ppc_cpu->env.msr &= ~((1ULL << MSR_SF) | (1ULL << MSR_LE));
95 * At this point the expected allocation map is:
97 * 0..c38 - the initial firmware
98 * 8000..10000 - stack
99 * 400000.. - kernel
100 * 3ea0000.. - initramdisk
102 * We skip writing FDT as nothing expects it; OF client interface is
103 * going to be used for reading the device tree.
107 void spapr_vof_quiesce(MachineState *ms)
109 SpaprMachineState *spapr = SPAPR_MACHINE(ms);
111 spapr->fdt_size = fdt_totalsize(spapr->fdt_blob);
112 spapr->fdt_initial_size = spapr->fdt_size;
115 bool spapr_vof_setprop(MachineState *ms, const char *path, const char *propname,
116 void *val, int vallen)
118 SpaprMachineState *spapr = SPAPR_MACHINE(ms);
121 * We only allow changing properties which we know how to update in QEMU
122 * OR
123 * the ones which we know that they need to survive during "quiesce".
126 if (strcmp(path, "/rtas") == 0) {
127 if (strcmp(propname, "linux,rtas-base") == 0 ||
128 strcmp(propname, "linux,rtas-entry") == 0) {
129 /* These need to survive quiesce so let them store in the FDT */
130 return true;
134 if (strcmp(path, "/chosen") == 0) {
135 if (strcmp(propname, "bootargs") == 0) {
136 Vof *vof = spapr->vof;
138 g_free(vof->bootargs);
139 vof->bootargs = g_strndup(val, vallen);
140 return true;
142 if (strcmp(propname, "linux,initrd-start") == 0) {
143 if (vallen == sizeof(uint32_t)) {
144 spapr->initrd_base = ldl_be_p(val);
145 return true;
147 if (vallen == sizeof(uint64_t)) {
148 spapr->initrd_base = ldq_be_p(val);
149 return true;
151 return false;
153 if (strcmp(propname, "linux,initrd-end") == 0) {
154 if (vallen == sizeof(uint32_t)) {
155 spapr->initrd_size = ldl_be_p(val) - spapr->initrd_base;
156 return true;
158 if (vallen == sizeof(uint64_t)) {
159 spapr->initrd_size = ldq_be_p(val) - spapr->initrd_base;
160 return true;
162 return false;
166 return true;