Revision ed120055 hw/spapr_hcall.c
b/hw/spapr_hcall.c | ||
---|---|---|
4 | 4 |
#include "sysemu.h" |
5 | 5 |
#include "qemu-char.h" |
6 | 6 |
#include "exec-all.h" |
7 |
#include "exec.h" |
|
8 |
#include "helper_regs.h" |
|
7 | 9 |
#include "hw/spapr.h" |
8 | 10 |
|
9 | 11 |
#define HPTES_PER_GROUP 8 |
... | ... | |
255 | 257 |
return H_HARDWARE; |
256 | 258 |
} |
257 | 259 |
|
260 |
#define FLAGS_REGISTER_VPA 0x0000200000000000ULL |
|
261 |
#define FLAGS_REGISTER_DTL 0x0000400000000000ULL |
|
262 |
#define FLAGS_REGISTER_SLBSHADOW 0x0000600000000000ULL |
|
263 |
#define FLAGS_DEREGISTER_VPA 0x0000a00000000000ULL |
|
264 |
#define FLAGS_DEREGISTER_DTL 0x0000c00000000000ULL |
|
265 |
#define FLAGS_DEREGISTER_SLBSHADOW 0x0000e00000000000ULL |
|
266 |
|
|
267 |
#define VPA_MIN_SIZE 640 |
|
268 |
#define VPA_SIZE_OFFSET 0x4 |
|
269 |
#define VPA_SHARED_PROC_OFFSET 0x9 |
|
270 |
#define VPA_SHARED_PROC_VAL 0x2 |
|
271 |
|
|
272 |
static target_ulong register_vpa(CPUState *env, target_ulong vpa) |
|
273 |
{ |
|
274 |
uint16_t size; |
|
275 |
uint8_t tmp; |
|
276 |
|
|
277 |
if (vpa == 0) { |
|
278 |
hcall_dprintf("Can't cope with registering a VPA at logical 0\n"); |
|
279 |
return H_HARDWARE; |
|
280 |
} |
|
281 |
|
|
282 |
if (vpa % env->dcache_line_size) { |
|
283 |
return H_PARAMETER; |
|
284 |
} |
|
285 |
/* FIXME: bounds check the address */ |
|
286 |
|
|
287 |
size = lduw_phys(vpa + 0x4); |
|
288 |
|
|
289 |
if (size < VPA_MIN_SIZE) { |
|
290 |
return H_PARAMETER; |
|
291 |
} |
|
292 |
|
|
293 |
/* VPA is not allowed to cross a page boundary */ |
|
294 |
if ((vpa / 4096) != ((vpa + size - 1) / 4096)) { |
|
295 |
return H_PARAMETER; |
|
296 |
} |
|
297 |
|
|
298 |
env->vpa = vpa; |
|
299 |
|
|
300 |
tmp = ldub_phys(env->vpa + VPA_SHARED_PROC_OFFSET); |
|
301 |
tmp |= VPA_SHARED_PROC_VAL; |
|
302 |
stb_phys(env->vpa + VPA_SHARED_PROC_OFFSET, tmp); |
|
303 |
|
|
304 |
return H_SUCCESS; |
|
305 |
} |
|
306 |
|
|
307 |
static target_ulong deregister_vpa(CPUState *env, target_ulong vpa) |
|
308 |
{ |
|
309 |
if (env->slb_shadow) { |
|
310 |
return H_RESOURCE; |
|
311 |
} |
|
312 |
|
|
313 |
if (env->dispatch_trace_log) { |
|
314 |
return H_RESOURCE; |
|
315 |
} |
|
316 |
|
|
317 |
env->vpa = 0; |
|
318 |
return H_SUCCESS; |
|
319 |
} |
|
320 |
|
|
321 |
static target_ulong register_slb_shadow(CPUState *env, target_ulong addr) |
|
322 |
{ |
|
323 |
uint32_t size; |
|
324 |
|
|
325 |
if (addr == 0) { |
|
326 |
hcall_dprintf("Can't cope with SLB shadow at logical 0\n"); |
|
327 |
return H_HARDWARE; |
|
328 |
} |
|
329 |
|
|
330 |
size = ldl_phys(addr + 0x4); |
|
331 |
if (size < 0x8) { |
|
332 |
return H_PARAMETER; |
|
333 |
} |
|
334 |
|
|
335 |
if ((addr / 4096) != ((addr + size - 1) / 4096)) { |
|
336 |
return H_PARAMETER; |
|
337 |
} |
|
338 |
|
|
339 |
if (!env->vpa) { |
|
340 |
return H_RESOURCE; |
|
341 |
} |
|
342 |
|
|
343 |
env->slb_shadow = addr; |
|
344 |
|
|
345 |
return H_SUCCESS; |
|
346 |
} |
|
347 |
|
|
348 |
static target_ulong deregister_slb_shadow(CPUState *env, target_ulong addr) |
|
349 |
{ |
|
350 |
env->slb_shadow = 0; |
|
351 |
return H_SUCCESS; |
|
352 |
} |
|
353 |
|
|
354 |
static target_ulong register_dtl(CPUState *env, target_ulong addr) |
|
355 |
{ |
|
356 |
uint32_t size; |
|
357 |
|
|
358 |
if (addr == 0) { |
|
359 |
hcall_dprintf("Can't cope with DTL at logical 0\n"); |
|
360 |
return H_HARDWARE; |
|
361 |
} |
|
362 |
|
|
363 |
size = ldl_phys(addr + 0x4); |
|
364 |
|
|
365 |
if (size < 48) { |
|
366 |
return H_PARAMETER; |
|
367 |
} |
|
368 |
|
|
369 |
if (!env->vpa) { |
|
370 |
return H_RESOURCE; |
|
371 |
} |
|
372 |
|
|
373 |
env->dispatch_trace_log = addr; |
|
374 |
env->dtl_size = size; |
|
375 |
|
|
376 |
return H_SUCCESS; |
|
377 |
} |
|
378 |
|
|
379 |
static target_ulong deregister_dtl(CPUState *emv, target_ulong addr) |
|
380 |
{ |
|
381 |
env->dispatch_trace_log = 0; |
|
382 |
env->dtl_size = 0; |
|
383 |
|
|
384 |
return H_SUCCESS; |
|
385 |
} |
|
386 |
|
|
387 |
static target_ulong h_register_vpa(CPUState *env, sPAPREnvironment *spapr, |
|
388 |
target_ulong opcode, target_ulong *args) |
|
389 |
{ |
|
390 |
target_ulong flags = args[0]; |
|
391 |
target_ulong procno = args[1]; |
|
392 |
target_ulong vpa = args[2]; |
|
393 |
target_ulong ret = H_PARAMETER; |
|
394 |
CPUState *tenv; |
|
395 |
|
|
396 |
for (tenv = first_cpu; tenv; tenv = tenv->next_cpu) { |
|
397 |
if (tenv->cpu_index == procno) { |
|
398 |
break; |
|
399 |
} |
|
400 |
} |
|
401 |
|
|
402 |
if (!tenv) { |
|
403 |
return H_PARAMETER; |
|
404 |
} |
|
405 |
|
|
406 |
switch (flags) { |
|
407 |
case FLAGS_REGISTER_VPA: |
|
408 |
ret = register_vpa(tenv, vpa); |
|
409 |
break; |
|
410 |
|
|
411 |
case FLAGS_DEREGISTER_VPA: |
|
412 |
ret = deregister_vpa(tenv, vpa); |
|
413 |
break; |
|
414 |
|
|
415 |
case FLAGS_REGISTER_SLBSHADOW: |
|
416 |
ret = register_slb_shadow(tenv, vpa); |
|
417 |
break; |
|
418 |
|
|
419 |
case FLAGS_DEREGISTER_SLBSHADOW: |
|
420 |
ret = deregister_slb_shadow(tenv, vpa); |
|
421 |
break; |
|
422 |
|
|
423 |
case FLAGS_REGISTER_DTL: |
|
424 |
ret = register_dtl(tenv, vpa); |
|
425 |
break; |
|
426 |
|
|
427 |
case FLAGS_DEREGISTER_DTL: |
|
428 |
ret = deregister_dtl(tenv, vpa); |
|
429 |
break; |
|
430 |
} |
|
431 |
|
|
432 |
return ret; |
|
433 |
} |
|
434 |
|
|
435 |
static target_ulong h_cede(CPUState *env, sPAPREnvironment *spapr, |
|
436 |
target_ulong opcode, target_ulong *args) |
|
437 |
{ |
|
438 |
env->msr |= (1ULL << MSR_EE); |
|
439 |
hreg_compute_hflags(env); |
|
440 |
if (!cpu_has_work(env)) { |
|
441 |
env->halted = 1; |
|
442 |
} |
|
443 |
return H_SUCCESS; |
|
444 |
} |
|
445 |
|
|
258 | 446 |
static target_ulong h_rtas(CPUState *env, sPAPREnvironment *spapr, |
259 | 447 |
target_ulong opcode, target_ulong *args) |
260 | 448 |
{ |
... | ... | |
327 | 515 |
/* hcall-dabr */ |
328 | 516 |
spapr_register_hypercall(H_SET_DABR, h_set_dabr); |
329 | 517 |
|
518 |
/* hcall-splpar */ |
|
519 |
spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa); |
|
520 |
spapr_register_hypercall(H_CEDE, h_cede); |
|
521 |
|
|
330 | 522 |
/* qemu/KVM-PPC specific hcalls */ |
331 | 523 |
spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas); |
332 | 524 |
} |
Also available in: Unified diff