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 */ 27 #include "cpu.h" 28 #include "sysemu/sysemu.h" 29 #include "sysemu/char.h" 30 #include "hw/qdev.h" 31 #include "sysemu/device_tree.h" 32 33 #include "hw/ppc/spapr.h" 34 #include "hw/ppc/spapr_vio.h" 35 #include "qapi-event.h" 36 37 #include <libfdt.h> 38 39 static void rtas_display_character(PowerPCCPU *cpu, sPAPREnvironment *spapr, 40 uint32_t token, uint32_t nargs, 41 target_ulong args, 42 uint32_t nret, target_ulong rets) 43 { 44 uint8_t c = rtas_ld(args, 0); 45 VIOsPAPRDevice *sdev = vty_lookup(spapr, 0); 46 47 if (!sdev) { 48 rtas_st(rets, 0, RTAS_OUT_HW_ERROR); 49 } else { 50 vty_putchars(sdev, &c, sizeof(c)); 51 rtas_st(rets, 0, RTAS_OUT_SUCCESS); 52 } 53 } 54 55 static void rtas_power_off(PowerPCCPU *cpu, sPAPREnvironment *spapr, 56 uint32_t token, uint32_t nargs, target_ulong args, 57 uint32_t nret, target_ulong rets) 58 { 59 if (nargs != 2 || nret != 1) { 60 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 61 return; 62 } 63 qemu_system_shutdown_request(); 64 rtas_st(rets, 0, RTAS_OUT_SUCCESS); 65 } 66 67 static void rtas_system_reboot(PowerPCCPU *cpu, sPAPREnvironment *spapr, 68 uint32_t token, uint32_t nargs, 69 target_ulong args, 70 uint32_t nret, target_ulong rets) 71 { 72 if (nargs != 0 || nret != 1) { 73 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 74 return; 75 } 76 qemu_system_reset_request(); 77 rtas_st(rets, 0, RTAS_OUT_SUCCESS); 78 } 79 80 static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_, 81 sPAPREnvironment *spapr, 82 uint32_t token, uint32_t nargs, 83 target_ulong args, 84 uint32_t nret, target_ulong rets) 85 { 86 target_ulong id; 87 PowerPCCPU *cpu; 88 89 if (nargs != 1 || nret != 2) { 90 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 91 return; 92 } 93 94 id = rtas_ld(args, 0); 95 cpu = ppc_get_vcpu_by_dt_id(id); 96 if (cpu != NULL) { 97 if (CPU(cpu)->halted) { 98 rtas_st(rets, 1, 0); 99 } else { 100 rtas_st(rets, 1, 2); 101 } 102 103 rtas_st(rets, 0, RTAS_OUT_SUCCESS); 104 return; 105 } 106 107 /* Didn't find a matching cpu */ 108 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 109 } 110 111 static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPREnvironment *spapr, 112 uint32_t token, uint32_t nargs, 113 target_ulong args, 114 uint32_t nret, target_ulong rets) 115 { 116 target_ulong id, start, r3; 117 PowerPCCPU *cpu; 118 119 if (nargs != 3 || nret != 1) { 120 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 121 return; 122 } 123 124 id = rtas_ld(args, 0); 125 start = rtas_ld(args, 1); 126 r3 = rtas_ld(args, 2); 127 128 cpu = ppc_get_vcpu_by_dt_id(id); 129 if (cpu != NULL) { 130 CPUState *cs = CPU(cpu); 131 CPUPPCState *env = &cpu->env; 132 133 if (!cs->halted) { 134 rtas_st(rets, 0, RTAS_OUT_HW_ERROR); 135 return; 136 } 137 138 /* This will make sure qemu state is up to date with kvm, and 139 * mark it dirty so our changes get flushed back before the 140 * new cpu enters */ 141 kvm_cpu_synchronize_state(cs); 142 143 env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME); 144 env->nip = start; 145 env->gpr[3] = r3; 146 cs->halted = 0; 147 148 qemu_cpu_kick(cs); 149 150 rtas_st(rets, 0, RTAS_OUT_SUCCESS); 151 return; 152 } 153 154 /* Didn't find a matching cpu */ 155 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 156 } 157 158 static void rtas_stop_self(PowerPCCPU *cpu, sPAPREnvironment *spapr, 159 uint32_t token, uint32_t nargs, 160 target_ulong args, 161 uint32_t nret, target_ulong rets) 162 { 163 CPUState *cs = CPU(cpu); 164 CPUPPCState *env = &cpu->env; 165 166 cs->halted = 1; 167 cpu_exit(cs); 168 /* 169 * While stopping a CPU, the guest calls H_CPPR which 170 * effectively disables interrupts on XICS level. 171 * However decrementer interrupts in TCG can still 172 * wake the CPU up so here we disable interrupts in MSR 173 * as well. 174 * As rtas_start_cpu() resets the whole MSR anyway, there is 175 * no need to bother with specific bits, we just clear it. 176 */ 177 env->msr = 0; 178 } 179 180 static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu, 181 sPAPREnvironment *spapr, 182 uint32_t token, uint32_t nargs, 183 target_ulong args, 184 uint32_t nret, target_ulong rets) 185 { 186 target_ulong parameter = rtas_ld(args, 0); 187 target_ulong buffer = rtas_ld(args, 1); 188 target_ulong length = rtas_ld(args, 2); 189 target_ulong ret = RTAS_OUT_SUCCESS; 190 191 switch (parameter) { 192 case RTAS_SYSPARM_SPLPAR_CHARACTERISTICS: { 193 char *param_val = g_strdup_printf("MaxEntCap=%d,MaxPlatProcs=%d", 194 max_cpus, smp_cpus); 195 rtas_st_buffer(buffer, length, (uint8_t *)param_val, strlen(param_val)); 196 g_free(param_val); 197 break; 198 } 199 case RTAS_SYSPARM_DIAGNOSTICS_RUN_MODE: { 200 uint8_t param_val = DIAGNOSTICS_RUN_MODE_DISABLED; 201 202 rtas_st_buffer(buffer, length, ¶m_val, sizeof(param_val)); 203 break; 204 } 205 case RTAS_SYSPARM_UUID: 206 rtas_st_buffer(buffer, length, qemu_uuid, (qemu_uuid_set ? 16 : 0)); 207 break; 208 default: 209 ret = RTAS_OUT_NOT_SUPPORTED; 210 } 211 212 rtas_st(rets, 0, ret); 213 } 214 215 static void rtas_ibm_set_system_parameter(PowerPCCPU *cpu, 216 sPAPREnvironment *spapr, 217 uint32_t token, uint32_t nargs, 218 target_ulong args, 219 uint32_t nret, target_ulong rets) 220 { 221 target_ulong parameter = rtas_ld(args, 0); 222 target_ulong ret = RTAS_OUT_NOT_SUPPORTED; 223 224 switch (parameter) { 225 case RTAS_SYSPARM_SPLPAR_CHARACTERISTICS: 226 case RTAS_SYSPARM_DIAGNOSTICS_RUN_MODE: 227 case RTAS_SYSPARM_UUID: 228 ret = RTAS_OUT_NOT_AUTHORIZED; 229 break; 230 } 231 232 rtas_st(rets, 0, ret); 233 } 234 235 static void rtas_ibm_os_term(PowerPCCPU *cpu, 236 sPAPREnvironment *spapr, 237 uint32_t token, uint32_t nargs, 238 target_ulong args, 239 uint32_t nret, target_ulong rets) 240 { 241 target_ulong ret = 0; 242 243 qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE, &error_abort); 244 245 rtas_st(rets, 0, ret); 246 } 247 248 static struct rtas_call { 249 const char *name; 250 spapr_rtas_fn fn; 251 } rtas_table[RTAS_TOKEN_MAX - RTAS_TOKEN_BASE]; 252 253 target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPREnvironment *spapr, 254 uint32_t token, uint32_t nargs, target_ulong args, 255 uint32_t nret, target_ulong rets) 256 { 257 if ((token >= RTAS_TOKEN_BASE) && (token < RTAS_TOKEN_MAX)) { 258 struct rtas_call *call = rtas_table + (token - RTAS_TOKEN_BASE); 259 260 if (call->fn) { 261 call->fn(cpu, spapr, token, nargs, args, nret, rets); 262 return H_SUCCESS; 263 } 264 } 265 266 /* HACK: Some Linux early debug code uses RTAS display-character, 267 * but assumes the token value is 0xa (which it is on some real 268 * machines) without looking it up in the device tree. This 269 * special case makes this work */ 270 if (token == 0xa) { 271 rtas_display_character(cpu, spapr, 0xa, nargs, args, nret, rets); 272 return H_SUCCESS; 273 } 274 275 hcall_dprintf("Unknown RTAS token 0x%x\n", token); 276 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 277 return H_PARAMETER; 278 } 279 280 void spapr_rtas_register(int token, const char *name, spapr_rtas_fn fn) 281 { 282 if (!((token >= RTAS_TOKEN_BASE) && (token < RTAS_TOKEN_MAX))) { 283 fprintf(stderr, "RTAS invalid token 0x%x\n", token); 284 exit(1); 285 } 286 287 token -= RTAS_TOKEN_BASE; 288 if (rtas_table[token].name) { 289 fprintf(stderr, "RTAS call \"%s\" is registered already as 0x%x\n", 290 rtas_table[token].name, token); 291 exit(1); 292 } 293 294 rtas_table[token].name = name; 295 rtas_table[token].fn = fn; 296 } 297 298 int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr, 299 hwaddr rtas_size) 300 { 301 int ret; 302 int i; 303 304 ret = fdt_add_mem_rsv(fdt, rtas_addr, rtas_size); 305 if (ret < 0) { 306 fprintf(stderr, "Couldn't add RTAS reserve entry: %s\n", 307 fdt_strerror(ret)); 308 return ret; 309 } 310 311 ret = qemu_fdt_setprop_cell(fdt, "/rtas", "linux,rtas-base", 312 rtas_addr); 313 if (ret < 0) { 314 fprintf(stderr, "Couldn't add linux,rtas-base property: %s\n", 315 fdt_strerror(ret)); 316 return ret; 317 } 318 319 ret = qemu_fdt_setprop_cell(fdt, "/rtas", "linux,rtas-entry", 320 rtas_addr); 321 if (ret < 0) { 322 fprintf(stderr, "Couldn't add linux,rtas-entry property: %s\n", 323 fdt_strerror(ret)); 324 return ret; 325 } 326 327 ret = qemu_fdt_setprop_cell(fdt, "/rtas", "rtas-size", 328 rtas_size); 329 if (ret < 0) { 330 fprintf(stderr, "Couldn't add rtas-size property: %s\n", 331 fdt_strerror(ret)); 332 return ret; 333 } 334 335 for (i = 0; i < RTAS_TOKEN_MAX - RTAS_TOKEN_BASE; i++) { 336 struct rtas_call *call = &rtas_table[i]; 337 338 if (!call->name) { 339 continue; 340 } 341 342 ret = qemu_fdt_setprop_cell(fdt, "/rtas", call->name, 343 i + RTAS_TOKEN_BASE); 344 if (ret < 0) { 345 fprintf(stderr, "Couldn't add rtas token for %s: %s\n", 346 call->name, fdt_strerror(ret)); 347 return ret; 348 } 349 350 } 351 return 0; 352 } 353 354 static void core_rtas_register_types(void) 355 { 356 spapr_rtas_register(RTAS_DISPLAY_CHARACTER, "display-character", 357 rtas_display_character); 358 spapr_rtas_register(RTAS_POWER_OFF, "power-off", rtas_power_off); 359 spapr_rtas_register(RTAS_SYSTEM_REBOOT, "system-reboot", 360 rtas_system_reboot); 361 spapr_rtas_register(RTAS_QUERY_CPU_STOPPED_STATE, "query-cpu-stopped-state", 362 rtas_query_cpu_stopped_state); 363 spapr_rtas_register(RTAS_START_CPU, "start-cpu", rtas_start_cpu); 364 spapr_rtas_register(RTAS_STOP_SELF, "stop-self", rtas_stop_self); 365 spapr_rtas_register(RTAS_IBM_GET_SYSTEM_PARAMETER, 366 "ibm,get-system-parameter", 367 rtas_ibm_get_system_parameter); 368 spapr_rtas_register(RTAS_IBM_SET_SYSTEM_PARAMETER, 369 "ibm,set-system-parameter", 370 rtas_ibm_set_system_parameter); 371 spapr_rtas_register(RTAS_IBM_OS_TERM, "ibm,os-term", 372 rtas_ibm_os_term); 373 } 374 375 type_init(core_rtas_register_types) 376