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 |
}
|