spapr_hcall.c 20.2 KB
Newer Older
1
#include "sysemu/sysemu.h"
2
#include "cpu.h"
3
#include "helper_regs.h"
P
Paolo Bonzini 已提交
4
#include "hw/ppc/spapr.h"
5
#include "mmu-hash64.h"
6 7 8 9 10 11 12 13

static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
                                     target_ulong pte_index)
{
    target_ulong rb, va_low;

    rb = (v & ~0x7fULL) << 16; /* AVA field */
    va_low = pte_index >> 3;
14
    if (v & HPTE64_V_SECONDARY) {
15 16 17
        va_low = ~va_low;
    }
    /* xor vsid from AVA */
18
    if (!(v & HPTE64_V_1TB_SEG)) {
19 20 21 22 23
        va_low ^= v >> 12;
    } else {
        va_low ^= v >> 24;
    }
    va_low &= 0x7ff;
24
    if (v & HPTE64_V_LARGE) {
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
        rb |= 1;                         /* L field */
#if 0 /* Disable that P7 specific bit for now */
        if (r & 0xff000) {
            /* non-16MB large page, must be 64k */
            /* (masks depend on page size) */
            rb |= 0x1000;                /* page encoding in LP field */
            rb |= (va_low & 0x7f) << 16; /* 7b of VA in AVA/LP field */
            rb |= (va_low & 0xfe);       /* AVAL field */
        }
#endif
    } else {
        /* 4kB page */
        rb |= (va_low & 0x7ff) << 12;   /* remaining 11b of AVA */
    }
    rb |= (v >> 54) & 0x300;            /* B field */
    return rb;
}

43
static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
44 45
                            target_ulong opcode, target_ulong *args)
{
46
    CPUPPCState *env = &cpu->env;
47 48 49 50
    target_ulong flags = args[0];
    target_ulong pte_index = args[1];
    target_ulong pteh = args[2];
    target_ulong ptel = args[3];
51 52
    target_ulong page_shift = 12;
    target_ulong raddr;
53
    target_ulong i;
54
    hwaddr hpte;
55 56

    /* only handle 4k and 16M pages for now */
57
    if (pteh & HPTE64_V_LARGE) {
58 59 60 61 62 63 64
#if 0 /* We don't support 64k pages yet */
        if ((ptel & 0xf000) == 0x1000) {
            /* 64k page */
        } else
#endif
        if ((ptel & 0xff000) == 0) {
            /* 16M page */
65
            page_shift = 24;
66 67 68 69 70 71 72 73 74
            /* lowest AVA bit must be 0 for 16M pages */
            if (pteh & 0x80) {
                return H_PARAMETER;
            }
        } else {
            return H_PARAMETER;
        }
    }

75
    raddr = (ptel & HPTE64_R_RPN) & ~((1ULL << page_shift) - 1);
76

77 78
    if (raddr < spapr->ram_limit) {
        /* Regular RAM - should have WIMG=0010 */
79
        if ((ptel & HPTE64_R_WIMG) != HPTE64_R_M) {
80 81 82 83 84 85 86
            return H_PARAMETER;
        }
    } else {
        /* Looks like an IO address */
        /* FIXME: What WIMG combinations could be sensible for IO?
         * For now we allow WIMG=010x, but are there others? */
        /* FIXME: Should we check against registered IO addresses? */
87
        if ((ptel & (HPTE64_R_W | HPTE64_R_I | HPTE64_R_M)) != HPTE64_R_I) {
88 89
            return H_PARAMETER;
        }
90
    }
91

92 93 94 95 96 97 98
    pteh &= ~0x60ULL;

    if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
        return H_PARAMETER;
    }
    if (likely((flags & H_EXACT) == 0)) {
        pte_index &= ~7ULL;
99
        hpte = pte_index * HASH_PTE_SIZE_64;
100 101 102 103
        for (i = 0; ; ++i) {
            if (i == 8) {
                return H_PTEG_FULL;
            }
104
            if ((ppc_hash64_load_hpte0(env, hpte) & HPTE64_V_VALID) == 0) {
105 106 107 108 109 110
                break;
            }
            hpte += HASH_PTE_SIZE_64;
        }
    } else {
        i = 0;
111 112
        hpte = pte_index * HASH_PTE_SIZE_64;
        if (ppc_hash64_load_hpte0(env, hpte) & HPTE64_V_VALID) {
113 114 115
            return H_PTEG_FULL;
        }
    }
116
    ppc_hash64_store_hpte1(env, hpte, ptel);
117
    /* eieio();  FIXME: need some sort of barrier for smp? */
118
    ppc_hash64_store_hpte0(env, hpte, pteh | HPTE64_V_HPTE_DIRTY);
119 120 121 122 123

    args[0] = pte_index + i;
    return H_SUCCESS;
}

124
typedef enum {
125 126 127 128
    REMOVE_SUCCESS = 0,
    REMOVE_NOT_FOUND = 1,
    REMOVE_PARM = 2,
    REMOVE_HW = 3,
129
} RemoveResult;
130

131
static RemoveResult remove_hpte(CPUPPCState *env, target_ulong ptex,
132 133 134
                                target_ulong avpn,
                                target_ulong flags,
                                target_ulong *vp, target_ulong *rp)
135
{
136
    hwaddr hpte;
137 138
    target_ulong v, r, rb;

139 140
    if ((ptex * HASH_PTE_SIZE_64) & ~env->htab_mask) {
        return REMOVE_PARM;
141 142
    }

143
    hpte = ptex * HASH_PTE_SIZE_64;
144

145 146
    v = ppc_hash64_load_hpte0(env, hpte);
    r = ppc_hash64_load_hpte1(env, hpte);
147

148
    if ((v & HPTE64_V_VALID) == 0 ||
149 150
        ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
        ((flags & H_ANDCOND) && (v & avpn) != 0)) {
151
        return REMOVE_NOT_FOUND;
152
    }
153
    *vp = v;
154
    *rp = r;
155
    ppc_hash64_store_hpte0(env, hpte, HPTE64_V_HPTE_DIRTY);
156
    rb = compute_tlbie_rb(v, r, ptex);
157
    ppc_tlb_invalidate_one(env, rb);
158 159 160
    return REMOVE_SUCCESS;
}

161
static target_ulong h_remove(PowerPCCPU *cpu, sPAPREnvironment *spapr,
162 163
                             target_ulong opcode, target_ulong *args)
{
164
    CPUPPCState *env = &cpu->env;
165 166 167
    target_ulong flags = args[0];
    target_ulong pte_index = args[1];
    target_ulong avpn = args[2];
168
    RemoveResult ret;
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

    ret = remove_hpte(env, pte_index, avpn, flags,
                      &args[0], &args[1]);

    switch (ret) {
    case REMOVE_SUCCESS:
        return H_SUCCESS;

    case REMOVE_NOT_FOUND:
        return H_NOT_FOUND;

    case REMOVE_PARM:
        return H_PARAMETER;

    case REMOVE_HW:
        return H_HARDWARE;
    }

187
    g_assert_not_reached();
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
}

#define H_BULK_REMOVE_TYPE             0xc000000000000000ULL
#define   H_BULK_REMOVE_REQUEST        0x4000000000000000ULL
#define   H_BULK_REMOVE_RESPONSE       0x8000000000000000ULL
#define   H_BULK_REMOVE_END            0xc000000000000000ULL
#define H_BULK_REMOVE_CODE             0x3000000000000000ULL
#define   H_BULK_REMOVE_SUCCESS        0x0000000000000000ULL
#define   H_BULK_REMOVE_NOT_FOUND      0x1000000000000000ULL
#define   H_BULK_REMOVE_PARM           0x2000000000000000ULL
#define   H_BULK_REMOVE_HW             0x3000000000000000ULL
#define H_BULK_REMOVE_RC               0x0c00000000000000ULL
#define H_BULK_REMOVE_FLAGS            0x0300000000000000ULL
#define   H_BULK_REMOVE_ABSOLUTE       0x0000000000000000ULL
#define   H_BULK_REMOVE_ANDCOND        0x0100000000000000ULL
#define   H_BULK_REMOVE_AVPN           0x0200000000000000ULL
#define H_BULK_REMOVE_PTEX             0x00ffffffffffffffULL

#define H_BULK_REMOVE_MAX_BATCH        4

208
static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPREnvironment *spapr,
209 210
                                  target_ulong opcode, target_ulong *args)
{
211
    CPUPPCState *env = &cpu->env;
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
    int i;

    for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) {
        target_ulong *tsh = &args[i*2];
        target_ulong tsl = args[i*2 + 1];
        target_ulong v, r, ret;

        if ((*tsh & H_BULK_REMOVE_TYPE) == H_BULK_REMOVE_END) {
            break;
        } else if ((*tsh & H_BULK_REMOVE_TYPE) != H_BULK_REMOVE_REQUEST) {
            return H_PARAMETER;
        }

        *tsh &= H_BULK_REMOVE_PTEX | H_BULK_REMOVE_FLAGS;
        *tsh |= H_BULK_REMOVE_RESPONSE;

        if ((*tsh & H_BULK_REMOVE_ANDCOND) && (*tsh & H_BULK_REMOVE_AVPN)) {
            *tsh |= H_BULK_REMOVE_PARM;
            return H_PARAMETER;
        }

        ret = remove_hpte(env, *tsh & H_BULK_REMOVE_PTEX, tsl,
                          (*tsh & H_BULK_REMOVE_FLAGS) >> 26,
                          &v, &r);

        *tsh |= ret << 60;

        switch (ret) {
        case REMOVE_SUCCESS:
241
            *tsh |= (r & (HPTE64_R_C | HPTE64_R_R)) << 43;
242 243 244 245 246 247 248 249 250 251
            break;

        case REMOVE_PARM:
            return H_PARAMETER;

        case REMOVE_HW:
            return H_HARDWARE;
        }
    }

252 253 254
    return H_SUCCESS;
}

255
static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr,
256 257
                              target_ulong opcode, target_ulong *args)
{
258
    CPUPPCState *env = &cpu->env;
259 260 261
    target_ulong flags = args[0];
    target_ulong pte_index = args[1];
    target_ulong avpn = args[2];
262
    hwaddr hpte;
263 264 265 266 267 268
    target_ulong v, r, rb;

    if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
        return H_PARAMETER;
    }

269
    hpte = pte_index * HASH_PTE_SIZE_64;
270

271 272
    v = ppc_hash64_load_hpte0(env, hpte);
    r = ppc_hash64_load_hpte1(env, hpte);
273

274
    if ((v & HPTE64_V_VALID) == 0 ||
275 276 277 278
        ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
        return H_NOT_FOUND;
    }

279 280 281 282 283
    r &= ~(HPTE64_R_PP0 | HPTE64_R_PP | HPTE64_R_N |
           HPTE64_R_KEY_HI | HPTE64_R_KEY_LO);
    r |= (flags << 55) & HPTE64_R_PP0;
    r |= (flags << 48) & HPTE64_R_KEY_HI;
    r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO);
284
    rb = compute_tlbie_rb(v, r, pte_index);
285
    ppc_hash64_store_hpte0(env, hpte, (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY);
286
    ppc_tlb_invalidate_one(env, rb);
287
    ppc_hash64_store_hpte1(env, hpte, r);
288
    /* Don't need a memory barrier, due to qemu's global lock */
289
    ppc_hash64_store_hpte0(env, hpte, v | HPTE64_V_HPTE_DIRTY);
290 291 292
    return H_SUCCESS;
}

E
Erlon Cruz 已提交
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
static target_ulong h_read(PowerPCCPU *cpu, sPAPREnvironment *spapr,
                           target_ulong opcode, target_ulong *args)
{
    CPUPPCState *env = &cpu->env;
    target_ulong flags = args[0];
    target_ulong pte_index = args[1];
    uint8_t *hpte;
    int i, ridx, n_entries = 1;

    if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
        return H_PARAMETER;
    }

    if (flags & H_READ_4) {
        /* Clear the two low order bits */
        pte_index &= ~(3ULL);
        n_entries = 4;
    }

    hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);

    for (i = 0, ridx = 0; i < n_entries; i++) {
        args[ridx++] = ldq_p(hpte);
        args[ridx++] = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
        hpte += HASH_PTE_SIZE_64;
    }

    return H_SUCCESS;
}

323
static target_ulong h_set_dabr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
324 325 326 327 328 329
                               target_ulong opcode, target_ulong *args)
{
    /* FIXME: actually implement this */
    return H_HARDWARE;
}

330 331 332 333 334 335 336 337 338 339 340 341
#define FLAGS_REGISTER_VPA         0x0000200000000000ULL
#define FLAGS_REGISTER_DTL         0x0000400000000000ULL
#define FLAGS_REGISTER_SLBSHADOW   0x0000600000000000ULL
#define FLAGS_DEREGISTER_VPA       0x0000a00000000000ULL
#define FLAGS_DEREGISTER_DTL       0x0000c00000000000ULL
#define FLAGS_DEREGISTER_SLBSHADOW 0x0000e00000000000ULL

#define VPA_MIN_SIZE           640
#define VPA_SIZE_OFFSET        0x4
#define VPA_SHARED_PROC_OFFSET 0x9
#define VPA_SHARED_PROC_VAL    0x2

A
Andreas Färber 已提交
342
static target_ulong register_vpa(CPUPPCState *env, target_ulong vpa)
343 344 345 346 347 348 349 350 351 352 353 354 355 356
{
    uint16_t size;
    uint8_t tmp;

    if (vpa == 0) {
        hcall_dprintf("Can't cope with registering a VPA at logical 0\n");
        return H_HARDWARE;
    }

    if (vpa % env->dcache_line_size) {
        return H_PARAMETER;
    }
    /* FIXME: bounds check the address */

357
    size = lduw_be_phys(vpa + 0x4);
358 359 360 361 362 363 364 365 366 367

    if (size < VPA_MIN_SIZE) {
        return H_PARAMETER;
    }

    /* VPA is not allowed to cross a page boundary */
    if ((vpa / 4096) != ((vpa + size - 1) / 4096)) {
        return H_PARAMETER;
    }

368
    env->vpa_addr = vpa;
369

370
    tmp = ldub_phys(env->vpa_addr + VPA_SHARED_PROC_OFFSET);
371
    tmp |= VPA_SHARED_PROC_VAL;
372
    stb_phys(env->vpa_addr + VPA_SHARED_PROC_OFFSET, tmp);
373 374 375 376

    return H_SUCCESS;
}

A
Andreas Färber 已提交
377
static target_ulong deregister_vpa(CPUPPCState *env, target_ulong vpa)
378
{
379
    if (env->slb_shadow_addr) {
380 381 382
        return H_RESOURCE;
    }

383
    if (env->dtl_addr) {
384 385 386
        return H_RESOURCE;
    }

387
    env->vpa_addr = 0;
388 389 390
    return H_SUCCESS;
}

A
Andreas Färber 已提交
391
static target_ulong register_slb_shadow(CPUPPCState *env, target_ulong addr)
392 393 394 395 396 397 398 399
{
    uint32_t size;

    if (addr == 0) {
        hcall_dprintf("Can't cope with SLB shadow at logical 0\n");
        return H_HARDWARE;
    }

400
    size = ldl_be_phys(addr + 0x4);
401 402 403 404 405 406 407 408
    if (size < 0x8) {
        return H_PARAMETER;
    }

    if ((addr / 4096) != ((addr + size - 1) / 4096)) {
        return H_PARAMETER;
    }

409
    if (!env->vpa_addr) {
410 411 412
        return H_RESOURCE;
    }

413 414
    env->slb_shadow_addr = addr;
    env->slb_shadow_size = size;
415 416 417 418

    return H_SUCCESS;
}

A
Andreas Färber 已提交
419
static target_ulong deregister_slb_shadow(CPUPPCState *env, target_ulong addr)
420
{
421 422
    env->slb_shadow_addr = 0;
    env->slb_shadow_size = 0;
423 424 425
    return H_SUCCESS;
}

A
Andreas Färber 已提交
426
static target_ulong register_dtl(CPUPPCState *env, target_ulong addr)
427 428 429 430 431 432 433 434
{
    uint32_t size;

    if (addr == 0) {
        hcall_dprintf("Can't cope with DTL at logical 0\n");
        return H_HARDWARE;
    }

435
    size = ldl_be_phys(addr + 0x4);
436 437 438 439 440

    if (size < 48) {
        return H_PARAMETER;
    }

441
    if (!env->vpa_addr) {
442 443 444
        return H_RESOURCE;
    }

445
    env->dtl_addr = addr;
446 447 448 449 450
    env->dtl_size = size;

    return H_SUCCESS;
}

451
static target_ulong deregister_dtl(CPUPPCState *env, target_ulong addr)
452
{
453
    env->dtl_addr = 0;
454 455 456 457 458
    env->dtl_size = 0;

    return H_SUCCESS;
}

459
static target_ulong h_register_vpa(PowerPCCPU *cpu, sPAPREnvironment *spapr,
460 461 462 463 464 465
                                   target_ulong opcode, target_ulong *args)
{
    target_ulong flags = args[0];
    target_ulong procno = args[1];
    target_ulong vpa = args[2];
    target_ulong ret = H_PARAMETER;
A
Andreas Färber 已提交
466
    CPUPPCState *tenv;
467
    CPUState *tcpu;
468

469 470
    tcpu = qemu_get_cpu(procno);
    if (!tcpu) {
471 472
        return H_PARAMETER;
    }
473
    tenv = tcpu->env_ptr;
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503

    switch (flags) {
    case FLAGS_REGISTER_VPA:
        ret = register_vpa(tenv, vpa);
        break;

    case FLAGS_DEREGISTER_VPA:
        ret = deregister_vpa(tenv, vpa);
        break;

    case FLAGS_REGISTER_SLBSHADOW:
        ret = register_slb_shadow(tenv, vpa);
        break;

    case FLAGS_DEREGISTER_SLBSHADOW:
        ret = deregister_slb_shadow(tenv, vpa);
        break;

    case FLAGS_REGISTER_DTL:
        ret = register_dtl(tenv, vpa);
        break;

    case FLAGS_DEREGISTER_DTL:
        ret = deregister_dtl(tenv, vpa);
        break;
    }

    return ret;
}

504
static target_ulong h_cede(PowerPCCPU *cpu, sPAPREnvironment *spapr,
505 506
                           target_ulong opcode, target_ulong *args)
{
507
    CPUPPCState *env = &cpu->env;
508
    CPUState *cs = CPU(cpu);
509

510 511
    env->msr |= (1ULL << MSR_EE);
    hreg_compute_hflags(env);
512
    if (!cpu_has_work(cs)) {
513
        cs->halted = 1;
514
        env->exception_index = EXCP_HLT;
515
        cs->exit_request = 1;
516 517 518 519
    }
    return H_SUCCESS;
}

520
static target_ulong h_rtas(PowerPCCPU *cpu, sPAPREnvironment *spapr,
521 522 523
                           target_ulong opcode, target_ulong *args)
{
    target_ulong rtas_r3 = args[0];
524 525 526
    uint32_t token = ldl_be_phys(rtas_r3);
    uint32_t nargs = ldl_be_phys(rtas_r3 + 4);
    uint32_t nret = ldl_be_phys(rtas_r3 + 8);
527

528
    return spapr_rtas_call(cpu, spapr, token, nargs, rtas_r3 + 12,
529 530 531
                           nret, rtas_r3 + 12 + 4*nargs);
}

532
static target_ulong h_logical_load(PowerPCCPU *cpu, sPAPREnvironment *spapr,
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
                                   target_ulong opcode, target_ulong *args)
{
    target_ulong size = args[0];
    target_ulong addr = args[1];

    switch (size) {
    case 1:
        args[0] = ldub_phys(addr);
        return H_SUCCESS;
    case 2:
        args[0] = lduw_phys(addr);
        return H_SUCCESS;
    case 4:
        args[0] = ldl_phys(addr);
        return H_SUCCESS;
    case 8:
        args[0] = ldq_phys(addr);
        return H_SUCCESS;
    }
    return H_PARAMETER;
}

555
static target_ulong h_logical_store(PowerPCCPU *cpu, sPAPREnvironment *spapr,
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
                                    target_ulong opcode, target_ulong *args)
{
    target_ulong size = args[0];
    target_ulong addr = args[1];
    target_ulong val  = args[2];

    switch (size) {
    case 1:
        stb_phys(addr, val);
        return H_SUCCESS;
    case 2:
        stw_phys(addr, val);
        return H_SUCCESS;
    case 4:
        stl_phys(addr, val);
        return H_SUCCESS;
    case 8:
        stq_phys(addr, val);
        return H_SUCCESS;
    }
    return H_PARAMETER;
}

579
static target_ulong h_logical_memop(PowerPCCPU *cpu, sPAPREnvironment *spapr,
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
                                    target_ulong opcode, target_ulong *args)
{
    target_ulong dst   = args[0]; /* Destination address */
    target_ulong src   = args[1]; /* Source address */
    target_ulong esize = args[2]; /* Element size (0=1,1=2,2=4,3=8) */
    target_ulong count = args[3]; /* Element count */
    target_ulong op    = args[4]; /* 0 = copy, 1 = invert */
    uint64_t tmp;
    unsigned int mask = (1 << esize) - 1;
    int step = 1 << esize;

    if (count > 0x80000000) {
        return H_PARAMETER;
    }

    if ((dst & mask) || (src & mask) || (op > 1)) {
        return H_PARAMETER;
    }

    if (dst >= src && dst < (src + (count << esize))) {
            dst = dst + ((count - 1) << esize);
            src = src + ((count - 1) << esize);
            step = -step;
    }

    while (count--) {
        switch (esize) {
        case 0:
            tmp = ldub_phys(src);
            break;
        case 1:
            tmp = lduw_phys(src);
            break;
        case 2:
            tmp = ldl_phys(src);
            break;
        case 3:
            tmp = ldq_phys(src);
            break;
        default:
            return H_PARAMETER;
        }
        if (op == 1) {
            tmp = ~tmp;
        }
        switch (esize) {
        case 0:
            stb_phys(dst, tmp);
            break;
        case 1:
            stw_phys(dst, tmp);
            break;
        case 2:
            stl_phys(dst, tmp);
            break;
        case 3:
            stq_phys(dst, tmp);
            break;
        }
        dst = dst + step;
        src = src + step;
    }

    return H_SUCCESS;
}

646
static target_ulong h_logical_icbi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
647 648 649 650 651 652
                                   target_ulong opcode, target_ulong *args)
{
    /* Nothing to do on emulation, KVM will trap this in the kernel */
    return H_SUCCESS;
}

653
static target_ulong h_logical_dcbf(PowerPCCPU *cpu, sPAPREnvironment *spapr,
654 655 656 657 658 659
                                   target_ulong opcode, target_ulong *args)
{
    /* Nothing to do on emulation, KVM will trap this in the kernel */
    return H_SUCCESS;
}

660 661
static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1];
662 663 664

void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
{
665 666 667 668
    spapr_hcall_fn *slot;

    if (opcode <= MAX_HCALL_OPCODE) {
        assert((opcode & 0x3) == 0);
669

670 671 672
        slot = &papr_hypercall_table[opcode / 4];
    } else {
        assert((opcode >= KVMPPC_HCALL_BASE) && (opcode <= KVMPPC_HCALL_MAX));
673

674 675
        slot = &kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
    }
676

677
    assert(!(*slot));
678
    *slot = fn;
679 680
}

681
target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
682 683 684 685
                             target_ulong *args)
{
    if ((opcode <= MAX_HCALL_OPCODE)
        && ((opcode & 0x3) == 0)) {
686 687 688
        spapr_hcall_fn fn = papr_hypercall_table[opcode / 4];

        if (fn) {
689
            return fn(cpu, spapr, opcode, args);
690 691 692 693
        }
    } else if ((opcode >= KVMPPC_HCALL_BASE) &&
               (opcode <= KVMPPC_HCALL_MAX)) {
        spapr_hcall_fn fn = kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
694 695

        if (fn) {
696
            return fn(cpu, spapr, opcode, args);
697 698 699 700 701 702
        }
    }

    hcall_dprintf("Unimplemented hcall 0x" TARGET_FMT_lx "\n", opcode);
    return H_FUNCTION;
}
703

A
Andreas Färber 已提交
704
static void hypercall_register_types(void)
705 706 707 708 709
{
    /* hcall-pft */
    spapr_register_hypercall(H_ENTER, h_enter);
    spapr_register_hypercall(H_REMOVE, h_remove);
    spapr_register_hypercall(H_PROTECT, h_protect);
E
Erlon Cruz 已提交
710
    spapr_register_hypercall(H_READ, h_read);
711

712 713 714
    /* hcall-bulk */
    spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove);

715 716 717
    /* hcall-dabr */
    spapr_register_hypercall(H_SET_DABR, h_set_dabr);

718 719 720 721
    /* hcall-splpar */
    spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa);
    spapr_register_hypercall(H_CEDE, h_cede);

722 723 724 725 726 727 728 729 730 731 732
    /* "debugger" hcalls (also used by SLOF). Note: We do -not- differenciate
     * here between the "CI" and the "CACHE" variants, they will use whatever
     * mapping attributes qemu is using. When using KVM, the kernel will
     * enforce the attributes more strongly
     */
    spapr_register_hypercall(H_LOGICAL_CI_LOAD, h_logical_load);
    spapr_register_hypercall(H_LOGICAL_CI_STORE, h_logical_store);
    spapr_register_hypercall(H_LOGICAL_CACHE_LOAD, h_logical_load);
    spapr_register_hypercall(H_LOGICAL_CACHE_STORE, h_logical_store);
    spapr_register_hypercall(H_LOGICAL_ICBI, h_logical_icbi);
    spapr_register_hypercall(H_LOGICAL_DCBF, h_logical_dcbf);
733
    spapr_register_hypercall(KVMPPC_H_LOGICAL_MEMOP, h_logical_memop);
734

735 736
    /* qemu/KVM-PPC specific hcalls */
    spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
737
}
A
Andreas Färber 已提交
738 739

type_init(hypercall_register_types)