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