vhost-user: Introduce a new protocol feature REPLY_ACK.
[qemu/cris-port.git] / hw / ppc / spapr_rtas.c
blobdc058e512b86952752b8023ad1fbfbc08db2b8db
1 /*
2 * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
4 * Hypercall based emulated RTAS
6 * Copyright (c) 2010-2011 David Gibson, IBM Corporation.
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:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
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.
27 #include "qemu/osdep.h"
28 #include "cpu.h"
29 #include "qemu/log.h"
30 #include "sysemu/sysemu.h"
31 #include "sysemu/char.h"
32 #include "hw/qdev.h"
33 #include "sysemu/device_tree.h"
34 #include "sysemu/cpus.h"
35 #include "sysemu/kvm.h"
37 #include "hw/ppc/spapr.h"
38 #include "hw/ppc/spapr_vio.h"
39 #include "hw/ppc/ppc.h"
40 #include "qapi-event.h"
41 #include "hw/boards.h"
43 #include <libfdt.h>
44 #include "hw/ppc/spapr_drc.h"
45 #include "qemu/cutils.h"
47 /* #define DEBUG_SPAPR */
49 #ifdef DEBUG_SPAPR
50 #define DPRINTF(fmt, ...) \
51 do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
52 #else
53 #define DPRINTF(fmt, ...) \
54 do { } while (0)
55 #endif
57 static sPAPRConfigureConnectorState *spapr_ccs_find(sPAPRMachineState *spapr,
58 uint32_t drc_index)
60 sPAPRConfigureConnectorState *ccs = NULL;
62 QTAILQ_FOREACH(ccs, &spapr->ccs_list, next) {
63 if (ccs->drc_index == drc_index) {
64 break;
68 return ccs;
71 static void spapr_ccs_add(sPAPRMachineState *spapr,
72 sPAPRConfigureConnectorState *ccs)
74 g_assert(!spapr_ccs_find(spapr, ccs->drc_index));
75 QTAILQ_INSERT_HEAD(&spapr->ccs_list, ccs, next);
78 static void spapr_ccs_remove(sPAPRMachineState *spapr,
79 sPAPRConfigureConnectorState *ccs)
81 QTAILQ_REMOVE(&spapr->ccs_list, ccs, next);
82 g_free(ccs);
85 void spapr_ccs_reset_hook(void *opaque)
87 sPAPRMachineState *spapr = opaque;
88 sPAPRConfigureConnectorState *ccs, *ccs_tmp;
90 QTAILQ_FOREACH_SAFE(ccs, &spapr->ccs_list, next, ccs_tmp) {
91 spapr_ccs_remove(spapr, ccs);
95 static void rtas_display_character(PowerPCCPU *cpu, sPAPRMachineState *spapr,
96 uint32_t token, uint32_t nargs,
97 target_ulong args,
98 uint32_t nret, target_ulong rets)
100 uint8_t c = rtas_ld(args, 0);
101 VIOsPAPRDevice *sdev = vty_lookup(spapr, 0);
103 if (!sdev) {
104 rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
105 } else {
106 vty_putchars(sdev, &c, sizeof(c));
107 rtas_st(rets, 0, RTAS_OUT_SUCCESS);
111 static void rtas_power_off(PowerPCCPU *cpu, sPAPRMachineState *spapr,
112 uint32_t token, uint32_t nargs, target_ulong args,
113 uint32_t nret, target_ulong rets)
115 if (nargs != 2 || nret != 1) {
116 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
117 return;
119 qemu_system_shutdown_request();
120 cpu_stop_current();
121 rtas_st(rets, 0, RTAS_OUT_SUCCESS);
124 static void rtas_system_reboot(PowerPCCPU *cpu, sPAPRMachineState *spapr,
125 uint32_t token, uint32_t nargs,
126 target_ulong args,
127 uint32_t nret, target_ulong rets)
129 if (nargs != 0 || nret != 1) {
130 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
131 return;
133 qemu_system_reset_request();
134 rtas_st(rets, 0, RTAS_OUT_SUCCESS);
137 static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_,
138 sPAPRMachineState *spapr,
139 uint32_t token, uint32_t nargs,
140 target_ulong args,
141 uint32_t nret, target_ulong rets)
143 target_ulong id;
144 PowerPCCPU *cpu;
146 if (nargs != 1 || nret != 2) {
147 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
148 return;
151 id = rtas_ld(args, 0);
152 cpu = ppc_get_vcpu_by_dt_id(id);
153 if (cpu != NULL) {
154 if (CPU(cpu)->halted) {
155 rtas_st(rets, 1, 0);
156 } else {
157 rtas_st(rets, 1, 2);
160 rtas_st(rets, 0, RTAS_OUT_SUCCESS);
161 return;
164 /* Didn't find a matching cpu */
165 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
169 * Set the timebase offset of the CPU to that of first CPU.
170 * This helps hotplugged CPU to have the correct timebase offset.
172 static void spapr_cpu_update_tb_offset(PowerPCCPU *cpu)
174 PowerPCCPU *fcpu = POWERPC_CPU(first_cpu);
176 cpu->env.tb_env->tb_offset = fcpu->env.tb_env->tb_offset;
179 static void spapr_cpu_set_endianness(PowerPCCPU *cpu)
181 PowerPCCPU *fcpu = POWERPC_CPU(first_cpu);
182 PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(fcpu);
184 if (!pcc->interrupts_big_endian(fcpu)) {
185 cpu->env.spr[SPR_LPCR] |= LPCR_ILE;
189 static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr,
190 uint32_t token, uint32_t nargs,
191 target_ulong args,
192 uint32_t nret, target_ulong rets)
194 target_ulong id, start, r3;
195 PowerPCCPU *cpu;
197 if (nargs != 3 || nret != 1) {
198 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
199 return;
202 id = rtas_ld(args, 0);
203 start = rtas_ld(args, 1);
204 r3 = rtas_ld(args, 2);
206 cpu = ppc_get_vcpu_by_dt_id(id);
207 if (cpu != NULL) {
208 CPUState *cs = CPU(cpu);
209 CPUPPCState *env = &cpu->env;
211 if (!cs->halted) {
212 rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
213 return;
216 /* This will make sure qemu state is up to date with kvm, and
217 * mark it dirty so our changes get flushed back before the
218 * new cpu enters */
219 kvm_cpu_synchronize_state(cs);
221 env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME);
222 env->nip = start;
223 env->gpr[3] = r3;
224 cs->halted = 0;
225 spapr_cpu_set_endianness(cpu);
226 spapr_cpu_update_tb_offset(cpu);
228 qemu_cpu_kick(cs);
230 rtas_st(rets, 0, RTAS_OUT_SUCCESS);
231 return;
234 /* Didn't find a matching cpu */
235 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
238 static void rtas_stop_self(PowerPCCPU *cpu, sPAPRMachineState *spapr,
239 uint32_t token, uint32_t nargs,
240 target_ulong args,
241 uint32_t nret, target_ulong rets)
243 CPUState *cs = CPU(cpu);
244 CPUPPCState *env = &cpu->env;
246 cs->halted = 1;
247 qemu_cpu_kick(cs);
249 * While stopping a CPU, the guest calls H_CPPR which
250 * effectively disables interrupts on XICS level.
251 * However decrementer interrupts in TCG can still
252 * wake the CPU up so here we disable interrupts in MSR
253 * as well.
254 * As rtas_start_cpu() resets the whole MSR anyway, there is
255 * no need to bother with specific bits, we just clear it.
257 env->msr = 0;
260 static inline int sysparm_st(target_ulong addr, target_ulong len,
261 const void *val, uint16_t vallen)
263 hwaddr phys = ppc64_phys_to_real(addr);
265 if (len < 2) {
266 return RTAS_OUT_SYSPARM_PARAM_ERROR;
268 stw_be_phys(&address_space_memory, phys, vallen);
269 cpu_physical_memory_write(phys + 2, val, MIN(len - 2, vallen));
270 return RTAS_OUT_SUCCESS;
273 static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu,
274 sPAPRMachineState *spapr,
275 uint32_t token, uint32_t nargs,
276 target_ulong args,
277 uint32_t nret, target_ulong rets)
279 target_ulong parameter = rtas_ld(args, 0);
280 target_ulong buffer = rtas_ld(args, 1);
281 target_ulong length = rtas_ld(args, 2);
282 target_ulong ret;
284 switch (parameter) {
285 case RTAS_SYSPARM_SPLPAR_CHARACTERISTICS: {
286 char *param_val = g_strdup_printf("MaxEntCap=%d,"
287 "DesMem=%llu,"
288 "DesProcs=%d,"
289 "MaxPlatProcs=%d",
290 max_cpus,
291 current_machine->ram_size / M_BYTE,
292 smp_cpus,
293 max_cpus);
294 ret = sysparm_st(buffer, length, param_val, strlen(param_val) + 1);
295 g_free(param_val);
296 break;
298 case RTAS_SYSPARM_DIAGNOSTICS_RUN_MODE: {
299 uint8_t param_val = DIAGNOSTICS_RUN_MODE_DISABLED;
301 ret = sysparm_st(buffer, length, &param_val, sizeof(param_val));
302 break;
304 case RTAS_SYSPARM_UUID:
305 ret = sysparm_st(buffer, length, qemu_uuid, (qemu_uuid_set ? 16 : 0));
306 break;
307 default:
308 ret = RTAS_OUT_NOT_SUPPORTED;
311 rtas_st(rets, 0, ret);
314 static void rtas_ibm_set_system_parameter(PowerPCCPU *cpu,
315 sPAPRMachineState *spapr,
316 uint32_t token, uint32_t nargs,
317 target_ulong args,
318 uint32_t nret, target_ulong rets)
320 target_ulong parameter = rtas_ld(args, 0);
321 target_ulong ret = RTAS_OUT_NOT_SUPPORTED;
323 switch (parameter) {
324 case RTAS_SYSPARM_SPLPAR_CHARACTERISTICS:
325 case RTAS_SYSPARM_DIAGNOSTICS_RUN_MODE:
326 case RTAS_SYSPARM_UUID:
327 ret = RTAS_OUT_NOT_AUTHORIZED;
328 break;
331 rtas_st(rets, 0, ret);
334 static void rtas_ibm_os_term(PowerPCCPU *cpu,
335 sPAPRMachineState *spapr,
336 uint32_t token, uint32_t nargs,
337 target_ulong args,
338 uint32_t nret, target_ulong rets)
340 target_ulong ret = 0;
342 qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE, &error_abort);
344 rtas_st(rets, 0, ret);
347 static void rtas_set_power_level(PowerPCCPU *cpu, sPAPRMachineState *spapr,
348 uint32_t token, uint32_t nargs,
349 target_ulong args, uint32_t nret,
350 target_ulong rets)
352 int32_t power_domain;
354 if (nargs != 2 || nret != 2) {
355 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
356 return;
359 /* we currently only use a single, "live insert" powerdomain for
360 * hotplugged/dlpar'd resources, so the power is always live/full (100)
362 power_domain = rtas_ld(args, 0);
363 if (power_domain != -1) {
364 rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED);
365 return;
368 rtas_st(rets, 0, RTAS_OUT_SUCCESS);
369 rtas_st(rets, 1, 100);
372 static void rtas_get_power_level(PowerPCCPU *cpu, sPAPRMachineState *spapr,
373 uint32_t token, uint32_t nargs,
374 target_ulong args, uint32_t nret,
375 target_ulong rets)
377 int32_t power_domain;
379 if (nargs != 1 || nret != 2) {
380 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
381 return;
384 /* we currently only use a single, "live insert" powerdomain for
385 * hotplugged/dlpar'd resources, so the power is always live/full (100)
387 power_domain = rtas_ld(args, 0);
388 if (power_domain != -1) {
389 rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED);
390 return;
393 rtas_st(rets, 0, RTAS_OUT_SUCCESS);
394 rtas_st(rets, 1, 100);
397 static bool sensor_type_is_dr(uint32_t sensor_type)
399 switch (sensor_type) {
400 case RTAS_SENSOR_TYPE_ISOLATION_STATE:
401 case RTAS_SENSOR_TYPE_DR:
402 case RTAS_SENSOR_TYPE_ALLOCATION_STATE:
403 return true;
406 return false;
409 static void rtas_set_indicator(PowerPCCPU *cpu, sPAPRMachineState *spapr,
410 uint32_t token, uint32_t nargs,
411 target_ulong args, uint32_t nret,
412 target_ulong rets)
414 uint32_t sensor_type;
415 uint32_t sensor_index;
416 uint32_t sensor_state;
417 uint32_t ret = RTAS_OUT_SUCCESS;
418 sPAPRDRConnector *drc;
419 sPAPRDRConnectorClass *drck;
421 if (nargs != 3 || nret != 1) {
422 ret = RTAS_OUT_PARAM_ERROR;
423 goto out;
426 sensor_type = rtas_ld(args, 0);
427 sensor_index = rtas_ld(args, 1);
428 sensor_state = rtas_ld(args, 2);
430 if (!sensor_type_is_dr(sensor_type)) {
431 goto out_unimplemented;
434 /* if this is a DR sensor we can assume sensor_index == drc_index */
435 drc = spapr_dr_connector_by_index(sensor_index);
436 if (!drc) {
437 DPRINTF("rtas_set_indicator: invalid sensor/DRC index: %xh\n",
438 sensor_index);
439 ret = RTAS_OUT_PARAM_ERROR;
440 goto out;
442 drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
444 switch (sensor_type) {
445 case RTAS_SENSOR_TYPE_ISOLATION_STATE:
446 /* if the guest is configuring a device attached to this
447 * DRC, we should reset the configuration state at this
448 * point since it may no longer be reliable (guest released
449 * device and needs to start over, or unplug occurred so
450 * the FDT is no longer valid)
452 if (sensor_state == SPAPR_DR_ISOLATION_STATE_ISOLATED) {
453 sPAPRConfigureConnectorState *ccs = spapr_ccs_find(spapr,
454 sensor_index);
455 if (ccs) {
456 spapr_ccs_remove(spapr, ccs);
459 ret = drck->set_isolation_state(drc, sensor_state);
460 break;
461 case RTAS_SENSOR_TYPE_DR:
462 ret = drck->set_indicator_state(drc, sensor_state);
463 break;
464 case RTAS_SENSOR_TYPE_ALLOCATION_STATE:
465 ret = drck->set_allocation_state(drc, sensor_state);
466 break;
467 default:
468 goto out_unimplemented;
471 out:
472 rtas_st(rets, 0, ret);
473 return;
475 out_unimplemented:
476 /* currently only DR-related sensors are implemented */
477 DPRINTF("rtas_set_indicator: sensor/indicator not implemented: %d\n",
478 sensor_type);
479 rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED);
482 static void rtas_get_sensor_state(PowerPCCPU *cpu, sPAPRMachineState *spapr,
483 uint32_t token, uint32_t nargs,
484 target_ulong args, uint32_t nret,
485 target_ulong rets)
487 uint32_t sensor_type;
488 uint32_t sensor_index;
489 uint32_t sensor_state = 0;
490 sPAPRDRConnector *drc;
491 sPAPRDRConnectorClass *drck;
492 uint32_t ret = RTAS_OUT_SUCCESS;
494 if (nargs != 2 || nret != 2) {
495 ret = RTAS_OUT_PARAM_ERROR;
496 goto out;
499 sensor_type = rtas_ld(args, 0);
500 sensor_index = rtas_ld(args, 1);
502 if (sensor_type != RTAS_SENSOR_TYPE_ENTITY_SENSE) {
503 /* currently only DR-related sensors are implemented */
504 DPRINTF("rtas_get_sensor_state: sensor/indicator not implemented: %d\n",
505 sensor_type);
506 ret = RTAS_OUT_NOT_SUPPORTED;
507 goto out;
510 drc = spapr_dr_connector_by_index(sensor_index);
511 if (!drc) {
512 DPRINTF("rtas_get_sensor_state: invalid sensor/DRC index: %xh\n",
513 sensor_index);
514 ret = RTAS_OUT_PARAM_ERROR;
515 goto out;
517 drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
518 ret = drck->entity_sense(drc, &sensor_state);
520 out:
521 rtas_st(rets, 0, ret);
522 rtas_st(rets, 1, sensor_state);
525 /* configure-connector work area offsets, int32_t units for field
526 * indexes, bytes for field offset/len values.
528 * as documented by PAPR+ v2.7, 13.5.3.5
530 #define CC_IDX_NODE_NAME_OFFSET 2
531 #define CC_IDX_PROP_NAME_OFFSET 2
532 #define CC_IDX_PROP_LEN 3
533 #define CC_IDX_PROP_DATA_OFFSET 4
534 #define CC_VAL_DATA_OFFSET ((CC_IDX_PROP_DATA_OFFSET + 1) * 4)
535 #define CC_WA_LEN 4096
537 static void configure_connector_st(target_ulong addr, target_ulong offset,
538 const void *buf, size_t len)
540 cpu_physical_memory_write(ppc64_phys_to_real(addr + offset),
541 buf, MIN(len, CC_WA_LEN - offset));
544 static void rtas_ibm_configure_connector(PowerPCCPU *cpu,
545 sPAPRMachineState *spapr,
546 uint32_t token, uint32_t nargs,
547 target_ulong args, uint32_t nret,
548 target_ulong rets)
550 uint64_t wa_addr;
551 uint64_t wa_offset;
552 uint32_t drc_index;
553 sPAPRDRConnector *drc;
554 sPAPRDRConnectorClass *drck;
555 sPAPRConfigureConnectorState *ccs;
556 sPAPRDRCCResponse resp = SPAPR_DR_CC_RESPONSE_CONTINUE;
557 int rc;
558 const void *fdt;
560 if (nargs != 2 || nret != 1) {
561 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
562 return;
565 wa_addr = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 0);
567 drc_index = rtas_ld(wa_addr, 0);
568 drc = spapr_dr_connector_by_index(drc_index);
569 if (!drc) {
570 DPRINTF("rtas_ibm_configure_connector: invalid DRC index: %xh\n",
571 drc_index);
572 rc = RTAS_OUT_PARAM_ERROR;
573 goto out;
576 drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
577 fdt = drck->get_fdt(drc, NULL);
578 if (!fdt) {
579 DPRINTF("rtas_ibm_configure_connector: Missing FDT for DRC index: %xh\n",
580 drc_index);
581 rc = SPAPR_DR_CC_RESPONSE_NOT_CONFIGURABLE;
582 goto out;
585 ccs = spapr_ccs_find(spapr, drc_index);
586 if (!ccs) {
587 ccs = g_new0(sPAPRConfigureConnectorState, 1);
588 (void)drck->get_fdt(drc, &ccs->fdt_offset);
589 ccs->drc_index = drc_index;
590 spapr_ccs_add(spapr, ccs);
593 do {
594 uint32_t tag;
595 const char *name;
596 const struct fdt_property *prop;
597 int fdt_offset_next, prop_len;
599 tag = fdt_next_tag(fdt, ccs->fdt_offset, &fdt_offset_next);
601 switch (tag) {
602 case FDT_BEGIN_NODE:
603 ccs->fdt_depth++;
604 name = fdt_get_name(fdt, ccs->fdt_offset, NULL);
606 /* provide the name of the next OF node */
607 wa_offset = CC_VAL_DATA_OFFSET;
608 rtas_st(wa_addr, CC_IDX_NODE_NAME_OFFSET, wa_offset);
609 configure_connector_st(wa_addr, wa_offset, name, strlen(name) + 1);
610 resp = SPAPR_DR_CC_RESPONSE_NEXT_CHILD;
611 break;
612 case FDT_END_NODE:
613 ccs->fdt_depth--;
614 if (ccs->fdt_depth == 0) {
615 /* done sending the device tree, don't need to track
616 * the state anymore
618 drck->set_configured(drc);
619 spapr_ccs_remove(spapr, ccs);
620 ccs = NULL;
621 resp = SPAPR_DR_CC_RESPONSE_SUCCESS;
622 } else {
623 resp = SPAPR_DR_CC_RESPONSE_PREV_PARENT;
625 break;
626 case FDT_PROP:
627 prop = fdt_get_property_by_offset(fdt, ccs->fdt_offset,
628 &prop_len);
629 name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
631 /* provide the name of the next OF property */
632 wa_offset = CC_VAL_DATA_OFFSET;
633 rtas_st(wa_addr, CC_IDX_PROP_NAME_OFFSET, wa_offset);
634 configure_connector_st(wa_addr, wa_offset, name, strlen(name) + 1);
636 /* provide the length and value of the OF property. data gets
637 * placed immediately after NULL terminator of the OF property's
638 * name string
640 wa_offset += strlen(name) + 1,
641 rtas_st(wa_addr, CC_IDX_PROP_LEN, prop_len);
642 rtas_st(wa_addr, CC_IDX_PROP_DATA_OFFSET, wa_offset);
643 configure_connector_st(wa_addr, wa_offset, prop->data, prop_len);
644 resp = SPAPR_DR_CC_RESPONSE_NEXT_PROPERTY;
645 break;
646 case FDT_END:
647 resp = SPAPR_DR_CC_RESPONSE_ERROR;
648 default:
649 /* keep seeking for an actionable tag */
650 break;
652 if (ccs) {
653 ccs->fdt_offset = fdt_offset_next;
655 } while (resp == SPAPR_DR_CC_RESPONSE_CONTINUE);
657 rc = resp;
658 out:
659 rtas_st(rets, 0, rc);
662 static struct rtas_call {
663 const char *name;
664 spapr_rtas_fn fn;
665 } rtas_table[RTAS_TOKEN_MAX - RTAS_TOKEN_BASE];
667 target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPRMachineState *spapr,
668 uint32_t token, uint32_t nargs, target_ulong args,
669 uint32_t nret, target_ulong rets)
671 if ((token >= RTAS_TOKEN_BASE) && (token < RTAS_TOKEN_MAX)) {
672 struct rtas_call *call = rtas_table + (token - RTAS_TOKEN_BASE);
674 if (call->fn) {
675 call->fn(cpu, spapr, token, nargs, args, nret, rets);
676 return H_SUCCESS;
680 /* HACK: Some Linux early debug code uses RTAS display-character,
681 * but assumes the token value is 0xa (which it is on some real
682 * machines) without looking it up in the device tree. This
683 * special case makes this work */
684 if (token == 0xa) {
685 rtas_display_character(cpu, spapr, 0xa, nargs, args, nret, rets);
686 return H_SUCCESS;
689 hcall_dprintf("Unknown RTAS token 0x%x\n", token);
690 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
691 return H_PARAMETER;
694 void spapr_rtas_register(int token, const char *name, spapr_rtas_fn fn)
696 assert((token >= RTAS_TOKEN_BASE) && (token < RTAS_TOKEN_MAX));
698 token -= RTAS_TOKEN_BASE;
700 assert(!rtas_table[token].name);
702 rtas_table[token].name = name;
703 rtas_table[token].fn = fn;
706 int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr,
707 hwaddr rtas_size)
709 int ret;
710 int i;
711 uint32_t lrdr_capacity[5];
712 MachineState *machine = MACHINE(qdev_get_machine());
713 sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
714 uint64_t max_hotplug_addr = spapr->hotplug_memory.base +
715 memory_region_size(&spapr->hotplug_memory.mr);
717 ret = fdt_add_mem_rsv(fdt, rtas_addr, rtas_size);
718 if (ret < 0) {
719 fprintf(stderr, "Couldn't add RTAS reserve entry: %s\n",
720 fdt_strerror(ret));
721 return ret;
724 ret = qemu_fdt_setprop_cell(fdt, "/rtas", "linux,rtas-base",
725 rtas_addr);
726 if (ret < 0) {
727 fprintf(stderr, "Couldn't add linux,rtas-base property: %s\n",
728 fdt_strerror(ret));
729 return ret;
732 ret = qemu_fdt_setprop_cell(fdt, "/rtas", "linux,rtas-entry",
733 rtas_addr);
734 if (ret < 0) {
735 fprintf(stderr, "Couldn't add linux,rtas-entry property: %s\n",
736 fdt_strerror(ret));
737 return ret;
740 ret = qemu_fdt_setprop_cell(fdt, "/rtas", "rtas-size",
741 rtas_size);
742 if (ret < 0) {
743 fprintf(stderr, "Couldn't add rtas-size property: %s\n",
744 fdt_strerror(ret));
745 return ret;
748 for (i = 0; i < RTAS_TOKEN_MAX - RTAS_TOKEN_BASE; i++) {
749 struct rtas_call *call = &rtas_table[i];
751 if (!call->name) {
752 continue;
755 ret = qemu_fdt_setprop_cell(fdt, "/rtas", call->name,
756 i + RTAS_TOKEN_BASE);
757 if (ret < 0) {
758 fprintf(stderr, "Couldn't add rtas token for %s: %s\n",
759 call->name, fdt_strerror(ret));
760 return ret;
765 lrdr_capacity[0] = cpu_to_be32(max_hotplug_addr >> 32);
766 lrdr_capacity[1] = cpu_to_be32(max_hotplug_addr & 0xffffffff);
767 lrdr_capacity[2] = 0;
768 lrdr_capacity[3] = cpu_to_be32(SPAPR_MEMORY_BLOCK_SIZE);
769 lrdr_capacity[4] = cpu_to_be32(max_cpus/smp_threads);
770 ret = qemu_fdt_setprop(fdt, "/rtas", "ibm,lrdr-capacity", lrdr_capacity,
771 sizeof(lrdr_capacity));
772 if (ret < 0) {
773 fprintf(stderr, "Couldn't add ibm,lrdr-capacity rtas property\n");
774 return ret;
777 return 0;
780 static void core_rtas_register_types(void)
782 spapr_rtas_register(RTAS_DISPLAY_CHARACTER, "display-character",
783 rtas_display_character);
784 spapr_rtas_register(RTAS_POWER_OFF, "power-off", rtas_power_off);
785 spapr_rtas_register(RTAS_SYSTEM_REBOOT, "system-reboot",
786 rtas_system_reboot);
787 spapr_rtas_register(RTAS_QUERY_CPU_STOPPED_STATE, "query-cpu-stopped-state",
788 rtas_query_cpu_stopped_state);
789 spapr_rtas_register(RTAS_START_CPU, "start-cpu", rtas_start_cpu);
790 spapr_rtas_register(RTAS_STOP_SELF, "stop-self", rtas_stop_self);
791 spapr_rtas_register(RTAS_IBM_GET_SYSTEM_PARAMETER,
792 "ibm,get-system-parameter",
793 rtas_ibm_get_system_parameter);
794 spapr_rtas_register(RTAS_IBM_SET_SYSTEM_PARAMETER,
795 "ibm,set-system-parameter",
796 rtas_ibm_set_system_parameter);
797 spapr_rtas_register(RTAS_IBM_OS_TERM, "ibm,os-term",
798 rtas_ibm_os_term);
799 spapr_rtas_register(RTAS_SET_POWER_LEVEL, "set-power-level",
800 rtas_set_power_level);
801 spapr_rtas_register(RTAS_GET_POWER_LEVEL, "get-power-level",
802 rtas_get_power_level);
803 spapr_rtas_register(RTAS_SET_INDICATOR, "set-indicator",
804 rtas_set_indicator);
805 spapr_rtas_register(RTAS_GET_SENSOR_STATE, "get-sensor-state",
806 rtas_get_sensor_state);
807 spapr_rtas_register(RTAS_IBM_CONFIGURE_CONNECTOR, "ibm,configure-connector",
808 rtas_ibm_configure_connector);
811 type_init(core_rtas_register_types)