]> git.proxmox.com Git - mirror_qemu.git/blame - hw/ppc/spapr_rtas.c
pseries: Clean up error handling in spapr_vga_init()
[mirror_qemu.git] / hw / ppc / spapr_rtas.c
CommitLineData
39ac8455
DG
1/*
2 * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
3 *
4 * Hypercall based emulated RTAS
5 *
6 * Copyright (c) 2010-2011 David Gibson, IBM Corporation.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 *
26 */
0d75590d 27#include "qemu/osdep.h"
39ac8455 28#include "cpu.h"
9c17d615 29#include "sysemu/sysemu.h"
dccfcd0e 30#include "sysemu/char.h"
39ac8455 31#include "hw/qdev.h"
9c17d615 32#include "sysemu/device_tree.h"
db4ef288 33#include "sysemu/cpus.h"
39ac8455 34
0d09e41a
PB
35#include "hw/ppc/spapr.h"
36#include "hw/ppc/spapr_vio.h"
e010ad8f 37#include "qapi-event.h"
e3943228 38#include "hw/boards.h"
39ac8455
DG
39
40#include <libfdt.h>
8c8639df
MD
41#include "hw/ppc/spapr_drc.h"
42
43/* #define DEBUG_SPAPR */
44
45#ifdef DEBUG_SPAPR
46#define DPRINTF(fmt, ...) \
47 do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
48#else
49#define DPRINTF(fmt, ...) \
50 do { } while (0)
51#endif
52
28e02042 53static sPAPRConfigureConnectorState *spapr_ccs_find(sPAPRMachineState *spapr,
46503c2b
MR
54 uint32_t drc_index)
55{
56 sPAPRConfigureConnectorState *ccs = NULL;
57
58 QTAILQ_FOREACH(ccs, &spapr->ccs_list, next) {
59 if (ccs->drc_index == drc_index) {
60 break;
61 }
62 }
63
64 return ccs;
65}
66
28e02042 67static void spapr_ccs_add(sPAPRMachineState *spapr,
46503c2b
MR
68 sPAPRConfigureConnectorState *ccs)
69{
70 g_assert(!spapr_ccs_find(spapr, ccs->drc_index));
71 QTAILQ_INSERT_HEAD(&spapr->ccs_list, ccs, next);
72}
73
28e02042 74static void spapr_ccs_remove(sPAPRMachineState *spapr,
46503c2b
MR
75 sPAPRConfigureConnectorState *ccs)
76{
77 QTAILQ_REMOVE(&spapr->ccs_list, ccs, next);
78 g_free(ccs);
79}
80
81void spapr_ccs_reset_hook(void *opaque)
82{
28e02042 83 sPAPRMachineState *spapr = opaque;
46503c2b
MR
84 sPAPRConfigureConnectorState *ccs, *ccs_tmp;
85
86 QTAILQ_FOREACH_SAFE(ccs, &spapr->ccs_list, next, ccs_tmp) {
87 spapr_ccs_remove(spapr, ccs);
88 }
89}
39ac8455 90
28e02042 91static void rtas_display_character(PowerPCCPU *cpu, sPAPRMachineState *spapr,
821303f5
DG
92 uint32_t token, uint32_t nargs,
93 target_ulong args,
94 uint32_t nret, target_ulong rets)
95{
96 uint8_t c = rtas_ld(args, 0);
5f2e2ba2 97 VIOsPAPRDevice *sdev = vty_lookup(spapr, 0);
821303f5
DG
98
99 if (!sdev) {
a64d325d 100 rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
821303f5
DG
101 } else {
102 vty_putchars(sdev, &c, sizeof(c));
a64d325d 103 rtas_st(rets, 0, RTAS_OUT_SUCCESS);
821303f5
DG
104 }
105}
106
28e02042 107static void rtas_power_off(PowerPCCPU *cpu, sPAPRMachineState *spapr,
821303f5
DG
108 uint32_t token, uint32_t nargs, target_ulong args,
109 uint32_t nret, target_ulong rets)
110{
111 if (nargs != 2 || nret != 1) {
a64d325d 112 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
821303f5
DG
113 return;
114 }
115 qemu_system_shutdown_request();
a64d325d 116 rtas_st(rets, 0, RTAS_OUT_SUCCESS);
821303f5
DG
117}
118
28e02042 119static void rtas_system_reboot(PowerPCCPU *cpu, sPAPRMachineState *spapr,
c821a43c
DG
120 uint32_t token, uint32_t nargs,
121 target_ulong args,
122 uint32_t nret, target_ulong rets)
123{
124 if (nargs != 0 || nret != 1) {
a64d325d 125 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
c821a43c
DG
126 return;
127 }
128 qemu_system_reset_request();
a64d325d 129 rtas_st(rets, 0, RTAS_OUT_SUCCESS);
c821a43c
DG
130}
131
210b580b 132static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_,
28e02042 133 sPAPRMachineState *spapr,
a9f8ad8f
DG
134 uint32_t token, uint32_t nargs,
135 target_ulong args,
136 uint32_t nret, target_ulong rets)
137{
138 target_ulong id;
0f20ba62 139 PowerPCCPU *cpu;
a9f8ad8f
DG
140
141 if (nargs != 1 || nret != 2) {
a64d325d 142 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
a9f8ad8f
DG
143 return;
144 }
145
146 id = rtas_ld(args, 0);
0f20ba62 147 cpu = ppc_get_vcpu_by_dt_id(id);
05318a85 148 if (cpu != NULL) {
0f20ba62 149 if (CPU(cpu)->halted) {
a9f8ad8f
DG
150 rtas_st(rets, 1, 0);
151 } else {
152 rtas_st(rets, 1, 2);
153 }
154
a64d325d 155 rtas_st(rets, 0, RTAS_OUT_SUCCESS);
a9f8ad8f
DG
156 return;
157 }
158
159 /* Didn't find a matching cpu */
a64d325d 160 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
a9f8ad8f
DG
161}
162
28e02042 163static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr,
a9f8ad8f
DG
164 uint32_t token, uint32_t nargs,
165 target_ulong args,
166 uint32_t nret, target_ulong rets)
167{
168 target_ulong id, start, r3;
0f20ba62 169 PowerPCCPU *cpu;
a9f8ad8f
DG
170
171 if (nargs != 3 || nret != 1) {
a64d325d 172 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
a9f8ad8f
DG
173 return;
174 }
175
176 id = rtas_ld(args, 0);
177 start = rtas_ld(args, 1);
178 r3 = rtas_ld(args, 2);
179
0f20ba62
AK
180 cpu = ppc_get_vcpu_by_dt_id(id);
181 if (cpu != NULL) {
182 CPUState *cs = CPU(cpu);
c67e216b 183 CPUPPCState *env = &cpu->env;
a9f8ad8f 184
c67e216b 185 if (!cs->halted) {
a64d325d 186 rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
a9f8ad8f
DG
187 return;
188 }
189
048706d9
DG
190 /* This will make sure qemu state is up to date with kvm, and
191 * mark it dirty so our changes get flushed back before the
192 * new cpu enters */
dd1750d7 193 kvm_cpu_synchronize_state(cs);
048706d9 194
a9f8ad8f
DG
195 env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME);
196 env->nip = start;
197 env->gpr[3] = r3;
c67e216b 198 cs->halted = 0;
a9f8ad8f 199
c67e216b 200 qemu_cpu_kick(cs);
a9f8ad8f 201
a64d325d 202 rtas_st(rets, 0, RTAS_OUT_SUCCESS);
a9f8ad8f
DG
203 return;
204 }
205
206 /* Didn't find a matching cpu */
a64d325d 207 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
a9f8ad8f
DG
208}
209
28e02042 210static void rtas_stop_self(PowerPCCPU *cpu, sPAPRMachineState *spapr,
59760f2d
AK
211 uint32_t token, uint32_t nargs,
212 target_ulong args,
213 uint32_t nret, target_ulong rets)
214{
215 CPUState *cs = CPU(cpu);
216 CPUPPCState *env = &cpu->env;
217
218 cs->halted = 1;
9102deda 219 qemu_cpu_kick(cs);
59760f2d
AK
220 /*
221 * While stopping a CPU, the guest calls H_CPPR which
222 * effectively disables interrupts on XICS level.
223 * However decrementer interrupts in TCG can still
224 * wake the CPU up so here we disable interrupts in MSR
225 * as well.
226 * As rtas_start_cpu() resets the whole MSR anyway, there is
227 * no need to bother with specific bits, we just clear it.
228 */
229 env->msr = 0;
230}
231
c920f7b4
DG
232static inline int sysparm_st(target_ulong addr, target_ulong len,
233 const void *val, uint16_t vallen)
234{
235 hwaddr phys = ppc64_phys_to_real(addr);
236
237 if (len < 2) {
238 return RTAS_OUT_SYSPARM_PARAM_ERROR;
239 }
240 stw_be_phys(&address_space_memory, phys, vallen);
241 cpu_physical_memory_write(phys + 2, val, MIN(len - 2, vallen));
242 return RTAS_OUT_SUCCESS;
243}
244
3ada6b11 245static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu,
28e02042 246 sPAPRMachineState *spapr,
3ada6b11
AK
247 uint32_t token, uint32_t nargs,
248 target_ulong args,
249 uint32_t nret, target_ulong rets)
250{
251 target_ulong parameter = rtas_ld(args, 0);
252 target_ulong buffer = rtas_ld(args, 1);
253 target_ulong length = rtas_ld(args, 2);
c920f7b4 254 target_ulong ret;
3ada6b11
AK
255
256 switch (parameter) {
3b50d897 257 case RTAS_SYSPARM_SPLPAR_CHARACTERISTICS: {
e3943228
SB
258 char *param_val = g_strdup_printf("MaxEntCap=%d,"
259 "DesMem=%llu,"
260 "DesProcs=%d,"
261 "MaxPlatProcs=%d",
262 max_cpus,
263 current_machine->ram_size / M_BYTE,
264 smp_cpus,
265 max_cpus);
c920f7b4 266 ret = sysparm_st(buffer, length, param_val, strlen(param_val) + 1);
3b50d897
S
267 g_free(param_val);
268 break;
269 }
3052d951
S
270 case RTAS_SYSPARM_DIAGNOSTICS_RUN_MODE: {
271 uint8_t param_val = DIAGNOSTICS_RUN_MODE_DISABLED;
272
c920f7b4 273 ret = sysparm_st(buffer, length, &param_val, sizeof(param_val));
3ada6b11
AK
274 break;
275 }
b907d7b0 276 case RTAS_SYSPARM_UUID:
c920f7b4 277 ret = sysparm_st(buffer, length, qemu_uuid, (qemu_uuid_set ? 16 : 0));
b907d7b0 278 break;
3052d951
S
279 default:
280 ret = RTAS_OUT_NOT_SUPPORTED;
281 }
3ada6b11
AK
282
283 rtas_st(rets, 0, ret);
284}
285
286static void rtas_ibm_set_system_parameter(PowerPCCPU *cpu,
28e02042 287 sPAPRMachineState *spapr,
3ada6b11
AK
288 uint32_t token, uint32_t nargs,
289 target_ulong args,
290 uint32_t nret, target_ulong rets)
291{
292 target_ulong parameter = rtas_ld(args, 0);
293 target_ulong ret = RTAS_OUT_NOT_SUPPORTED;
294
295 switch (parameter) {
3b50d897 296 case RTAS_SYSPARM_SPLPAR_CHARACTERISTICS:
3052d951 297 case RTAS_SYSPARM_DIAGNOSTICS_RUN_MODE:
b907d7b0 298 case RTAS_SYSPARM_UUID:
3ada6b11
AK
299 ret = RTAS_OUT_NOT_AUTHORIZED;
300 break;
301 }
302
303 rtas_st(rets, 0, ret);
304}
305
2e14072f 306static void rtas_ibm_os_term(PowerPCCPU *cpu,
28e02042 307 sPAPRMachineState *spapr,
2e14072f
ND
308 uint32_t token, uint32_t nargs,
309 target_ulong args,
310 uint32_t nret, target_ulong rets)
311{
312 target_ulong ret = 0;
313
314 qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE, &error_abort);
315
316 rtas_st(rets, 0, ret);
317}
318
28e02042 319static void rtas_set_power_level(PowerPCCPU *cpu, sPAPRMachineState *spapr,
094d2058
NF
320 uint32_t token, uint32_t nargs,
321 target_ulong args, uint32_t nret,
322 target_ulong rets)
323{
324 int32_t power_domain;
325
326 if (nargs != 2 || nret != 2) {
327 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
328 return;
329 }
330
331 /* we currently only use a single, "live insert" powerdomain for
332 * hotplugged/dlpar'd resources, so the power is always live/full (100)
333 */
334 power_domain = rtas_ld(args, 0);
335 if (power_domain != -1) {
336 rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED);
337 return;
338 }
339
340 rtas_st(rets, 0, RTAS_OUT_SUCCESS);
341 rtas_st(rets, 1, 100);
342}
343
28e02042 344static void rtas_get_power_level(PowerPCCPU *cpu, sPAPRMachineState *spapr,
094d2058
NF
345 uint32_t token, uint32_t nargs,
346 target_ulong args, uint32_t nret,
347 target_ulong rets)
348{
349 int32_t power_domain;
350
351 if (nargs != 1 || nret != 2) {
352 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
353 return;
354 }
355
356 /* we currently only use a single, "live insert" powerdomain for
357 * hotplugged/dlpar'd resources, so the power is always live/full (100)
358 */
359 power_domain = rtas_ld(args, 0);
360 if (power_domain != -1) {
361 rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED);
362 return;
363 }
364
365 rtas_st(rets, 0, RTAS_OUT_SUCCESS);
366 rtas_st(rets, 1, 100);
367}
368
8c8639df
MD
369static bool sensor_type_is_dr(uint32_t sensor_type)
370{
371 switch (sensor_type) {
372 case RTAS_SENSOR_TYPE_ISOLATION_STATE:
373 case RTAS_SENSOR_TYPE_DR:
374 case RTAS_SENSOR_TYPE_ALLOCATION_STATE:
375 return true;
376 }
377
378 return false;
379}
380
28e02042 381static void rtas_set_indicator(PowerPCCPU *cpu, sPAPRMachineState *spapr,
8c8639df
MD
382 uint32_t token, uint32_t nargs,
383 target_ulong args, uint32_t nret,
384 target_ulong rets)
385{
386 uint32_t sensor_type;
387 uint32_t sensor_index;
388 uint32_t sensor_state;
0cb688d2 389 uint32_t ret = RTAS_OUT_SUCCESS;
8c8639df
MD
390 sPAPRDRConnector *drc;
391 sPAPRDRConnectorClass *drck;
392
393 if (nargs != 3 || nret != 1) {
0cb688d2
MR
394 ret = RTAS_OUT_PARAM_ERROR;
395 goto out;
8c8639df
MD
396 }
397
398 sensor_type = rtas_ld(args, 0);
399 sensor_index = rtas_ld(args, 1);
400 sensor_state = rtas_ld(args, 2);
401
402 if (!sensor_type_is_dr(sensor_type)) {
403 goto out_unimplemented;
404 }
405
406 /* if this is a DR sensor we can assume sensor_index == drc_index */
407 drc = spapr_dr_connector_by_index(sensor_index);
408 if (!drc) {
409 DPRINTF("rtas_set_indicator: invalid sensor/DRC index: %xh\n",
410 sensor_index);
0cb688d2
MR
411 ret = RTAS_OUT_PARAM_ERROR;
412 goto out;
8c8639df
MD
413 }
414 drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
415
416 switch (sensor_type) {
417 case RTAS_SENSOR_TYPE_ISOLATION_STATE:
46503c2b
MR
418 /* if the guest is configuring a device attached to this
419 * DRC, we should reset the configuration state at this
420 * point since it may no longer be reliable (guest released
421 * device and needs to start over, or unplug occurred so
422 * the FDT is no longer valid)
423 */
424 if (sensor_state == SPAPR_DR_ISOLATION_STATE_ISOLATED) {
425 sPAPRConfigureConnectorState *ccs = spapr_ccs_find(spapr,
426 sensor_index);
427 if (ccs) {
428 spapr_ccs_remove(spapr, ccs);
429 }
430 }
0cb688d2 431 ret = drck->set_isolation_state(drc, sensor_state);
8c8639df
MD
432 break;
433 case RTAS_SENSOR_TYPE_DR:
0cb688d2 434 ret = drck->set_indicator_state(drc, sensor_state);
8c8639df
MD
435 break;
436 case RTAS_SENSOR_TYPE_ALLOCATION_STATE:
0cb688d2 437 ret = drck->set_allocation_state(drc, sensor_state);
8c8639df
MD
438 break;
439 default:
440 goto out_unimplemented;
441 }
442
0cb688d2
MR
443out:
444 rtas_st(rets, 0, ret);
8c8639df
MD
445 return;
446
447out_unimplemented:
448 /* currently only DR-related sensors are implemented */
449 DPRINTF("rtas_set_indicator: sensor/indicator not implemented: %d\n",
450 sensor_type);
451 rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED);
452}
453
28e02042 454static void rtas_get_sensor_state(PowerPCCPU *cpu, sPAPRMachineState *spapr,
886445a6
MD
455 uint32_t token, uint32_t nargs,
456 target_ulong args, uint32_t nret,
457 target_ulong rets)
458{
459 uint32_t sensor_type;
460 uint32_t sensor_index;
0cb688d2 461 uint32_t sensor_state = 0;
886445a6
MD
462 sPAPRDRConnector *drc;
463 sPAPRDRConnectorClass *drck;
0cb688d2 464 uint32_t ret = RTAS_OUT_SUCCESS;
886445a6
MD
465
466 if (nargs != 2 || nret != 2) {
0cb688d2
MR
467 ret = RTAS_OUT_PARAM_ERROR;
468 goto out;
886445a6
MD
469 }
470
471 sensor_type = rtas_ld(args, 0);
472 sensor_index = rtas_ld(args, 1);
473
474 if (sensor_type != RTAS_SENSOR_TYPE_ENTITY_SENSE) {
475 /* currently only DR-related sensors are implemented */
476 DPRINTF("rtas_get_sensor_state: sensor/indicator not implemented: %d\n",
477 sensor_type);
0cb688d2
MR
478 ret = RTAS_OUT_NOT_SUPPORTED;
479 goto out;
886445a6
MD
480 }
481
482 drc = spapr_dr_connector_by_index(sensor_index);
483 if (!drc) {
484 DPRINTF("rtas_get_sensor_state: invalid sensor/DRC index: %xh\n",
485 sensor_index);
0cb688d2
MR
486 ret = RTAS_OUT_PARAM_ERROR;
487 goto out;
886445a6
MD
488 }
489 drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
0cb688d2 490 ret = drck->entity_sense(drc, &sensor_state);
886445a6 491
0cb688d2
MR
492out:
493 rtas_st(rets, 0, ret);
494 rtas_st(rets, 1, sensor_state);
886445a6
MD
495}
496
46503c2b
MR
497/* configure-connector work area offsets, int32_t units for field
498 * indexes, bytes for field offset/len values.
499 *
500 * as documented by PAPR+ v2.7, 13.5.3.5
501 */
502#define CC_IDX_NODE_NAME_OFFSET 2
503#define CC_IDX_PROP_NAME_OFFSET 2
504#define CC_IDX_PROP_LEN 3
505#define CC_IDX_PROP_DATA_OFFSET 4
506#define CC_VAL_DATA_OFFSET ((CC_IDX_PROP_DATA_OFFSET + 1) * 4)
507#define CC_WA_LEN 4096
508
f201987b
DG
509static void configure_connector_st(target_ulong addr, target_ulong offset,
510 const void *buf, size_t len)
511{
512 cpu_physical_memory_write(ppc64_phys_to_real(addr + offset),
513 buf, MIN(len, CC_WA_LEN - offset));
514}
515
46503c2b 516static void rtas_ibm_configure_connector(PowerPCCPU *cpu,
28e02042 517 sPAPRMachineState *spapr,
46503c2b
MR
518 uint32_t token, uint32_t nargs,
519 target_ulong args, uint32_t nret,
520 target_ulong rets)
521{
522 uint64_t wa_addr;
523 uint64_t wa_offset;
524 uint32_t drc_index;
525 sPAPRDRConnector *drc;
526 sPAPRDRConnectorClass *drck;
527 sPAPRConfigureConnectorState *ccs;
528 sPAPRDRCCResponse resp = SPAPR_DR_CC_RESPONSE_CONTINUE;
529 int rc;
530 const void *fdt;
531
532 if (nargs != 2 || nret != 1) {
533 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
534 return;
535 }
536
537 wa_addr = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 0);
538
539 drc_index = rtas_ld(wa_addr, 0);
540 drc = spapr_dr_connector_by_index(drc_index);
541 if (!drc) {
542 DPRINTF("rtas_ibm_configure_connector: invalid DRC index: %xh\n",
543 drc_index);
544 rc = RTAS_OUT_PARAM_ERROR;
545 goto out;
546 }
547
548 drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
549 fdt = drck->get_fdt(drc, NULL);
e6fc9568
BR
550 if (!fdt) {
551 DPRINTF("rtas_ibm_configure_connector: Missing FDT for DRC index: %xh\n",
552 drc_index);
553 rc = SPAPR_DR_CC_RESPONSE_NOT_CONFIGURABLE;
554 goto out;
555 }
46503c2b
MR
556
557 ccs = spapr_ccs_find(spapr, drc_index);
558 if (!ccs) {
559 ccs = g_new0(sPAPRConfigureConnectorState, 1);
560 (void)drck->get_fdt(drc, &ccs->fdt_offset);
561 ccs->drc_index = drc_index;
562 spapr_ccs_add(spapr, ccs);
563 }
564
565 do {
566 uint32_t tag;
567 const char *name;
568 const struct fdt_property *prop;
569 int fdt_offset_next, prop_len;
570
571 tag = fdt_next_tag(fdt, ccs->fdt_offset, &fdt_offset_next);
572
573 switch (tag) {
574 case FDT_BEGIN_NODE:
575 ccs->fdt_depth++;
576 name = fdt_get_name(fdt, ccs->fdt_offset, NULL);
577
578 /* provide the name of the next OF node */
579 wa_offset = CC_VAL_DATA_OFFSET;
580 rtas_st(wa_addr, CC_IDX_NODE_NAME_OFFSET, wa_offset);
f201987b 581 configure_connector_st(wa_addr, wa_offset, name, strlen(name) + 1);
46503c2b
MR
582 resp = SPAPR_DR_CC_RESPONSE_NEXT_CHILD;
583 break;
584 case FDT_END_NODE:
585 ccs->fdt_depth--;
586 if (ccs->fdt_depth == 0) {
587 /* done sending the device tree, don't need to track
588 * the state anymore
589 */
590 drck->set_configured(drc);
591 spapr_ccs_remove(spapr, ccs);
592 ccs = NULL;
593 resp = SPAPR_DR_CC_RESPONSE_SUCCESS;
594 } else {
595 resp = SPAPR_DR_CC_RESPONSE_PREV_PARENT;
596 }
597 break;
598 case FDT_PROP:
599 prop = fdt_get_property_by_offset(fdt, ccs->fdt_offset,
600 &prop_len);
601 name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
602
603 /* provide the name of the next OF property */
604 wa_offset = CC_VAL_DATA_OFFSET;
605 rtas_st(wa_addr, CC_IDX_PROP_NAME_OFFSET, wa_offset);
f201987b 606 configure_connector_st(wa_addr, wa_offset, name, strlen(name) + 1);
46503c2b
MR
607
608 /* provide the length and value of the OF property. data gets
609 * placed immediately after NULL terminator of the OF property's
610 * name string
611 */
612 wa_offset += strlen(name) + 1,
613 rtas_st(wa_addr, CC_IDX_PROP_LEN, prop_len);
614 rtas_st(wa_addr, CC_IDX_PROP_DATA_OFFSET, wa_offset);
f201987b 615 configure_connector_st(wa_addr, wa_offset, prop->data, prop_len);
46503c2b
MR
616 resp = SPAPR_DR_CC_RESPONSE_NEXT_PROPERTY;
617 break;
618 case FDT_END:
619 resp = SPAPR_DR_CC_RESPONSE_ERROR;
620 default:
621 /* keep seeking for an actionable tag */
622 break;
623 }
624 if (ccs) {
625 ccs->fdt_offset = fdt_offset_next;
626 }
627 } while (resp == SPAPR_DR_CC_RESPONSE_CONTINUE);
628
629 rc = resp;
630out:
631 rtas_st(rets, 0, rc);
632}
633
39ac8455
DG
634static struct rtas_call {
635 const char *name;
636 spapr_rtas_fn fn;
3a3b8502 637} rtas_table[RTAS_TOKEN_MAX - RTAS_TOKEN_BASE];
39ac8455 638
28e02042 639target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPRMachineState *spapr,
39ac8455
DG
640 uint32_t token, uint32_t nargs, target_ulong args,
641 uint32_t nret, target_ulong rets)
642{
3a3b8502
AK
643 if ((token >= RTAS_TOKEN_BASE) && (token < RTAS_TOKEN_MAX)) {
644 struct rtas_call *call = rtas_table + (token - RTAS_TOKEN_BASE);
39ac8455
DG
645
646 if (call->fn) {
210b580b 647 call->fn(cpu, spapr, token, nargs, args, nret, rets);
39ac8455
DG
648 return H_SUCCESS;
649 }
650 }
651
821303f5
DG
652 /* HACK: Some Linux early debug code uses RTAS display-character,
653 * but assumes the token value is 0xa (which it is on some real
654 * machines) without looking it up in the device tree. This
655 * special case makes this work */
656 if (token == 0xa) {
210b580b 657 rtas_display_character(cpu, spapr, 0xa, nargs, args, nret, rets);
821303f5
DG
658 return H_SUCCESS;
659 }
660
39ac8455 661 hcall_dprintf("Unknown RTAS token 0x%x\n", token);
a64d325d 662 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
39ac8455
DG
663 return H_PARAMETER;
664}
665
3a3b8502 666void spapr_rtas_register(int token, const char *name, spapr_rtas_fn fn)
39ac8455 667{
3a3b8502
AK
668 if (!((token >= RTAS_TOKEN_BASE) && (token < RTAS_TOKEN_MAX))) {
669 fprintf(stderr, "RTAS invalid token 0x%x\n", token);
670 exit(1);
c89d5299
DG
671 }
672
3a3b8502
AK
673 token -= RTAS_TOKEN_BASE;
674 if (rtas_table[token].name) {
675 fprintf(stderr, "RTAS call \"%s\" is registered already as 0x%x\n",
676 rtas_table[token].name, token);
677 exit(1);
678 }
39ac8455 679
3a3b8502
AK
680 rtas_table[token].name = name;
681 rtas_table[token].fn = fn;
39ac8455
DG
682}
683
a8170e5e
AK
684int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr,
685 hwaddr rtas_size)
39ac8455
DG
686{
687 int ret;
688 int i;
db4ef288
BR
689 uint32_t lrdr_capacity[5];
690 MachineState *machine = MACHINE(qdev_get_machine());
39ac8455
DG
691
692 ret = fdt_add_mem_rsv(fdt, rtas_addr, rtas_size);
693 if (ret < 0) {
694 fprintf(stderr, "Couldn't add RTAS reserve entry: %s\n",
695 fdt_strerror(ret));
696 return ret;
697 }
698
5a4348d1
PC
699 ret = qemu_fdt_setprop_cell(fdt, "/rtas", "linux,rtas-base",
700 rtas_addr);
39ac8455
DG
701 if (ret < 0) {
702 fprintf(stderr, "Couldn't add linux,rtas-base property: %s\n",
703 fdt_strerror(ret));
704 return ret;
705 }
706
5a4348d1
PC
707 ret = qemu_fdt_setprop_cell(fdt, "/rtas", "linux,rtas-entry",
708 rtas_addr);
39ac8455
DG
709 if (ret < 0) {
710 fprintf(stderr, "Couldn't add linux,rtas-entry property: %s\n",
711 fdt_strerror(ret));
712 return ret;
713 }
714
5a4348d1
PC
715 ret = qemu_fdt_setprop_cell(fdt, "/rtas", "rtas-size",
716 rtas_size);
39ac8455
DG
717 if (ret < 0) {
718 fprintf(stderr, "Couldn't add rtas-size property: %s\n",
719 fdt_strerror(ret));
720 return ret;
721 }
722
3a3b8502 723 for (i = 0; i < RTAS_TOKEN_MAX - RTAS_TOKEN_BASE; i++) {
39ac8455
DG
724 struct rtas_call *call = &rtas_table[i];
725
d36b66f7 726 if (!call->name) {
39ac8455
DG
727 continue;
728 }
729
5a4348d1 730 ret = qemu_fdt_setprop_cell(fdt, "/rtas", call->name,
3a3b8502 731 i + RTAS_TOKEN_BASE);
39ac8455
DG
732 if (ret < 0) {
733 fprintf(stderr, "Couldn't add rtas token for %s: %s\n",
734 call->name, fdt_strerror(ret));
735 return ret;
736 }
737
738 }
db4ef288
BR
739
740 lrdr_capacity[0] = cpu_to_be32(((uint64_t)machine->maxram_size) >> 32);
741 lrdr_capacity[1] = cpu_to_be32(machine->maxram_size & 0xffffffff);
742 lrdr_capacity[2] = 0;
743 lrdr_capacity[3] = cpu_to_be32(SPAPR_MEMORY_BLOCK_SIZE);
744 lrdr_capacity[4] = cpu_to_be32(max_cpus/smp_threads);
745 ret = qemu_fdt_setprop(fdt, "/rtas", "ibm,lrdr-capacity", lrdr_capacity,
746 sizeof(lrdr_capacity));
747 if (ret < 0) {
748 fprintf(stderr, "Couldn't add ibm,lrdr-capacity rtas property\n");
749 return ret;
750 }
751
39ac8455
DG
752 return 0;
753}
821303f5 754
83f7d43a 755static void core_rtas_register_types(void)
821303f5 756{
3a3b8502
AK
757 spapr_rtas_register(RTAS_DISPLAY_CHARACTER, "display-character",
758 rtas_display_character);
3a3b8502
AK
759 spapr_rtas_register(RTAS_POWER_OFF, "power-off", rtas_power_off);
760 spapr_rtas_register(RTAS_SYSTEM_REBOOT, "system-reboot",
761 rtas_system_reboot);
762 spapr_rtas_register(RTAS_QUERY_CPU_STOPPED_STATE, "query-cpu-stopped-state",
a9f8ad8f 763 rtas_query_cpu_stopped_state);
3a3b8502
AK
764 spapr_rtas_register(RTAS_START_CPU, "start-cpu", rtas_start_cpu);
765 spapr_rtas_register(RTAS_STOP_SELF, "stop-self", rtas_stop_self);
766 spapr_rtas_register(RTAS_IBM_GET_SYSTEM_PARAMETER,
767 "ibm,get-system-parameter",
3ada6b11 768 rtas_ibm_get_system_parameter);
3a3b8502
AK
769 spapr_rtas_register(RTAS_IBM_SET_SYSTEM_PARAMETER,
770 "ibm,set-system-parameter",
3ada6b11 771 rtas_ibm_set_system_parameter);
2e14072f
ND
772 spapr_rtas_register(RTAS_IBM_OS_TERM, "ibm,os-term",
773 rtas_ibm_os_term);
094d2058
NF
774 spapr_rtas_register(RTAS_SET_POWER_LEVEL, "set-power-level",
775 rtas_set_power_level);
776 spapr_rtas_register(RTAS_GET_POWER_LEVEL, "get-power-level",
777 rtas_get_power_level);
8c8639df
MD
778 spapr_rtas_register(RTAS_SET_INDICATOR, "set-indicator",
779 rtas_set_indicator);
886445a6
MD
780 spapr_rtas_register(RTAS_GET_SENSOR_STATE, "get-sensor-state",
781 rtas_get_sensor_state);
46503c2b
MR
782 spapr_rtas_register(RTAS_IBM_CONFIGURE_CONNECTOR, "ibm,configure-connector",
783 rtas_ibm_configure_connector);
821303f5 784}
83f7d43a
AF
785
786type_init(core_rtas_register_types)