Statistics
| Branch: | Revision:

root / hw / spapr_hcall.c @ 9c17d615

History | View | Annotate | Download (20.7 kB)

1
#include "sysemu/sysemu.h"
2
#include "cpu.h"
3
#include "sysemu/sysemu.h"
4
#include "helper_regs.h"
5
#include "hw/spapr.h"
6

    
7
#define HPTES_PER_GROUP 8
8

    
9
#define HPTE_V_SSIZE_SHIFT      62
10
#define HPTE_V_AVPN_SHIFT       7
11
#define HPTE_V_AVPN             0x3fffffffffffff80ULL
12
#define HPTE_V_AVPN_VAL(x)      (((x) & HPTE_V_AVPN) >> HPTE_V_AVPN_SHIFT)
13
#define HPTE_V_COMPARE(x, y)    (!(((x) ^ (y)) & 0xffffffffffffff80UL))
14
#define HPTE_V_BOLTED           0x0000000000000010ULL
15
#define HPTE_V_LOCK             0x0000000000000008ULL
16
#define HPTE_V_LARGE            0x0000000000000004ULL
17
#define HPTE_V_SECONDARY        0x0000000000000002ULL
18
#define HPTE_V_VALID            0x0000000000000001ULL
19

    
20
#define HPTE_R_PP0              0x8000000000000000ULL
21
#define HPTE_R_TS               0x4000000000000000ULL
22
#define HPTE_R_KEY_HI           0x3000000000000000ULL
23
#define HPTE_R_RPN_SHIFT        12
24
#define HPTE_R_RPN              0x3ffffffffffff000ULL
25
#define HPTE_R_FLAGS            0x00000000000003ffULL
26
#define HPTE_R_PP               0x0000000000000003ULL
27
#define HPTE_R_N                0x0000000000000004ULL
28
#define HPTE_R_G                0x0000000000000008ULL
29
#define HPTE_R_M                0x0000000000000010ULL
30
#define HPTE_R_I                0x0000000000000020ULL
31
#define HPTE_R_W                0x0000000000000040ULL
32
#define HPTE_R_WIMG             0x0000000000000078ULL
33
#define HPTE_R_C                0x0000000000000080ULL
34
#define HPTE_R_R                0x0000000000000100ULL
35
#define HPTE_R_KEY_LO           0x0000000000000e00ULL
36

    
37
#define HPTE_V_1TB_SEG          0x4000000000000000ULL
38
#define HPTE_V_VRMA_MASK        0x4001ffffff000000ULL
39

    
40
static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
41
                                     target_ulong pte_index)
42
{
43
    target_ulong rb, va_low;
44

    
45
    rb = (v & ~0x7fULL) << 16; /* AVA field */
46
    va_low = pte_index >> 3;
47
    if (v & HPTE_V_SECONDARY) {
48
        va_low = ~va_low;
49
    }
50
    /* xor vsid from AVA */
51
    if (!(v & HPTE_V_1TB_SEG)) {
52
        va_low ^= v >> 12;
53
    } else {
54
        va_low ^= v >> 24;
55
    }
56
    va_low &= 0x7ff;
57
    if (v & HPTE_V_LARGE) {
58
        rb |= 1;                         /* L field */
59
#if 0 /* Disable that P7 specific bit for now */
60
        if (r & 0xff000) {
61
            /* non-16MB large page, must be 64k */
62
            /* (masks depend on page size) */
63
            rb |= 0x1000;                /* page encoding in LP field */
64
            rb |= (va_low & 0x7f) << 16; /* 7b of VA in AVA/LP field */
65
            rb |= (va_low & 0xfe);       /* AVAL field */
66
        }
67
#endif
68
    } else {
69
        /* 4kB page */
70
        rb |= (va_low & 0x7ff) << 12;   /* remaining 11b of AVA */
71
    }
72
    rb |= (v >> 54) & 0x300;            /* B field */
73
    return rb;
74
}
75

    
76
static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
77
                            target_ulong opcode, target_ulong *args)
78
{
79
    CPUPPCState *env = &cpu->env;
80
    target_ulong flags = args[0];
81
    target_ulong pte_index = args[1];
82
    target_ulong pteh = args[2];
83
    target_ulong ptel = args[3];
84
    target_ulong page_shift = 12;
85
    target_ulong raddr;
86
    target_ulong i;
87
    uint8_t *hpte;
88

    
89
    /* only handle 4k and 16M pages for now */
90
    if (pteh & HPTE_V_LARGE) {
91
#if 0 /* We don't support 64k pages yet */
92
        if ((ptel & 0xf000) == 0x1000) {
93
            /* 64k page */
94
        } else
95
#endif
96
        if ((ptel & 0xff000) == 0) {
97
            /* 16M page */
98
            page_shift = 24;
99
            /* lowest AVA bit must be 0 for 16M pages */
100
            if (pteh & 0x80) {
101
                return H_PARAMETER;
102
            }
103
        } else {
104
            return H_PARAMETER;
105
        }
106
    }
107

    
108
    raddr = (ptel & HPTE_R_RPN) & ~((1ULL << page_shift) - 1);
109

    
110
    if (raddr < spapr->ram_limit) {
111
        /* Regular RAM - should have WIMG=0010 */
112
        if ((ptel & HPTE_R_WIMG) != HPTE_R_M) {
113
            return H_PARAMETER;
114
        }
115
    } else {
116
        /* Looks like an IO address */
117
        /* FIXME: What WIMG combinations could be sensible for IO?
118
         * For now we allow WIMG=010x, but are there others? */
119
        /* FIXME: Should we check against registered IO addresses? */
120
        if ((ptel & (HPTE_R_W | HPTE_R_I | HPTE_R_M)) != HPTE_R_I) {
121
            return H_PARAMETER;
122
        }
123
    }
124

    
125
    pteh &= ~0x60ULL;
126

    
127
    if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
128
        return H_PARAMETER;
129
    }
130
    if (likely((flags & H_EXACT) == 0)) {
131
        pte_index &= ~7ULL;
132
        hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
133
        for (i = 0; ; ++i) {
134
            if (i == 8) {
135
                return H_PTEG_FULL;
136
            }
137
            if ((ldq_p(hpte) & HPTE_V_VALID) == 0) {
138
                break;
139
            }
140
            hpte += HASH_PTE_SIZE_64;
141
        }
142
    } else {
143
        i = 0;
144
        hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
145
        if (ldq_p(hpte) & HPTE_V_VALID) {
146
            return H_PTEG_FULL;
147
        }
148
    }
149
    stq_p(hpte + (HASH_PTE_SIZE_64/2), ptel);
150
    /* eieio();  FIXME: need some sort of barrier for smp? */
151
    stq_p(hpte, pteh);
152

    
153
    args[0] = pte_index + i;
154
    return H_SUCCESS;
155
}
156

    
157
enum {
158
    REMOVE_SUCCESS = 0,
159
    REMOVE_NOT_FOUND = 1,
160
    REMOVE_PARM = 2,
161
    REMOVE_HW = 3,
162
};
163

    
164
static target_ulong remove_hpte(CPUPPCState *env, target_ulong ptex,
165
                                target_ulong avpn,
166
                                target_ulong flags,
167
                                target_ulong *vp, target_ulong *rp)
168
{
169
    uint8_t *hpte;
170
    target_ulong v, r, rb;
171

    
172
    if ((ptex * HASH_PTE_SIZE_64) & ~env->htab_mask) {
173
        return REMOVE_PARM;
174
    }
175

    
176
    hpte = env->external_htab + (ptex * HASH_PTE_SIZE_64);
177

    
178
    v = ldq_p(hpte);
179
    r = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
180

    
181
    if ((v & HPTE_V_VALID) == 0 ||
182
        ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
183
        ((flags & H_ANDCOND) && (v & avpn) != 0)) {
184
        return REMOVE_NOT_FOUND;
185
    }
186
    *vp = v;
187
    *rp = r;
188
    stq_p(hpte, 0);
189
    rb = compute_tlbie_rb(v, r, ptex);
190
    ppc_tlb_invalidate_one(env, rb);
191
    return REMOVE_SUCCESS;
192
}
193

    
194
static target_ulong h_remove(PowerPCCPU *cpu, sPAPREnvironment *spapr,
195
                             target_ulong opcode, target_ulong *args)
196
{
197
    CPUPPCState *env = &cpu->env;
198
    target_ulong flags = args[0];
199
    target_ulong pte_index = args[1];
200
    target_ulong avpn = args[2];
201
    int ret;
202

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

    
206
    switch (ret) {
207
    case REMOVE_SUCCESS:
208
        return H_SUCCESS;
209

    
210
    case REMOVE_NOT_FOUND:
211
        return H_NOT_FOUND;
212

    
213
    case REMOVE_PARM:
214
        return H_PARAMETER;
215

    
216
    case REMOVE_HW:
217
        return H_HARDWARE;
218
    }
219

    
220
    assert(0);
221
}
222

    
223
#define H_BULK_REMOVE_TYPE             0xc000000000000000ULL
224
#define   H_BULK_REMOVE_REQUEST        0x4000000000000000ULL
225
#define   H_BULK_REMOVE_RESPONSE       0x8000000000000000ULL
226
#define   H_BULK_REMOVE_END            0xc000000000000000ULL
227
#define H_BULK_REMOVE_CODE             0x3000000000000000ULL
228
#define   H_BULK_REMOVE_SUCCESS        0x0000000000000000ULL
229
#define   H_BULK_REMOVE_NOT_FOUND      0x1000000000000000ULL
230
#define   H_BULK_REMOVE_PARM           0x2000000000000000ULL
231
#define   H_BULK_REMOVE_HW             0x3000000000000000ULL
232
#define H_BULK_REMOVE_RC               0x0c00000000000000ULL
233
#define H_BULK_REMOVE_FLAGS            0x0300000000000000ULL
234
#define   H_BULK_REMOVE_ABSOLUTE       0x0000000000000000ULL
235
#define   H_BULK_REMOVE_ANDCOND        0x0100000000000000ULL
236
#define   H_BULK_REMOVE_AVPN           0x0200000000000000ULL
237
#define H_BULK_REMOVE_PTEX             0x00ffffffffffffffULL
238

    
239
#define H_BULK_REMOVE_MAX_BATCH        4
240

    
241
static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPREnvironment *spapr,
242
                                  target_ulong opcode, target_ulong *args)
243
{
244
    CPUPPCState *env = &cpu->env;
245
    int i;
246

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

    
252
        if ((*tsh & H_BULK_REMOVE_TYPE) == H_BULK_REMOVE_END) {
253
            break;
254
        } else if ((*tsh & H_BULK_REMOVE_TYPE) != H_BULK_REMOVE_REQUEST) {
255
            return H_PARAMETER;
256
        }
257

    
258
        *tsh &= H_BULK_REMOVE_PTEX | H_BULK_REMOVE_FLAGS;
259
        *tsh |= H_BULK_REMOVE_RESPONSE;
260

    
261
        if ((*tsh & H_BULK_REMOVE_ANDCOND) && (*tsh & H_BULK_REMOVE_AVPN)) {
262
            *tsh |= H_BULK_REMOVE_PARM;
263
            return H_PARAMETER;
264
        }
265

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

    
270
        *tsh |= ret << 60;
271

    
272
        switch (ret) {
273
        case REMOVE_SUCCESS:
274
            *tsh |= (r & (HPTE_R_C | HPTE_R_R)) << 43;
275
            break;
276

    
277
        case REMOVE_PARM:
278
            return H_PARAMETER;
279

    
280
        case REMOVE_HW:
281
            return H_HARDWARE;
282
        }
283
    }
284

    
285
    return H_SUCCESS;
286
}
287

    
288
static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr,
289
                              target_ulong opcode, target_ulong *args)
290
{
291
    CPUPPCState *env = &cpu->env;
292
    target_ulong flags = args[0];
293
    target_ulong pte_index = args[1];
294
    target_ulong avpn = args[2];
295
    uint8_t *hpte;
296
    target_ulong v, r, rb;
297

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

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

    
304
    v = ldq_p(hpte);
305
    r = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
306

    
307
    if ((v & HPTE_V_VALID) == 0 ||
308
        ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
309
        return H_NOT_FOUND;
310
    }
311

    
312
    r &= ~(HPTE_R_PP0 | HPTE_R_PP | HPTE_R_N |
313
           HPTE_R_KEY_HI | HPTE_R_KEY_LO);
314
    r |= (flags << 55) & HPTE_R_PP0;
315
    r |= (flags << 48) & HPTE_R_KEY_HI;
316
    r |= flags & (HPTE_R_PP | HPTE_R_N | HPTE_R_KEY_LO);
317
    rb = compute_tlbie_rb(v, r, pte_index);
318
    stq_p(hpte, v & ~HPTE_V_VALID);
319
    ppc_tlb_invalidate_one(env, rb);
320
    stq_p(hpte + (HASH_PTE_SIZE_64/2), r);
321
    /* Don't need a memory barrier, due to qemu's global lock */
322
    stq_p(hpte, v);
323
    return H_SUCCESS;
324
}
325

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

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

    
340
#define VPA_MIN_SIZE           640
341
#define VPA_SIZE_OFFSET        0x4
342
#define VPA_SHARED_PROC_OFFSET 0x9
343
#define VPA_SHARED_PROC_VAL    0x2
344

    
345
static target_ulong register_vpa(CPUPPCState *env, target_ulong vpa)
346
{
347
    uint16_t size;
348
    uint8_t tmp;
349

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

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

    
360
    size = lduw_be_phys(vpa + 0x4);
361

    
362
    if (size < VPA_MIN_SIZE) {
363
        return H_PARAMETER;
364
    }
365

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

    
371
    env->vpa_addr = vpa;
372

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

    
377
    return H_SUCCESS;
378
}
379

    
380
static target_ulong deregister_vpa(CPUPPCState *env, target_ulong vpa)
381
{
382
    if (env->slb_shadow_addr) {
383
        return H_RESOURCE;
384
    }
385

    
386
    if (env->dtl_addr) {
387
        return H_RESOURCE;
388
    }
389

    
390
    env->vpa_addr = 0;
391
    return H_SUCCESS;
392
}
393

    
394
static target_ulong register_slb_shadow(CPUPPCState *env, target_ulong addr)
395
{
396
    uint32_t size;
397

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

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

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

    
412
    if (!env->vpa_addr) {
413
        return H_RESOURCE;
414
    }
415

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

    
419
    return H_SUCCESS;
420
}
421

    
422
static target_ulong deregister_slb_shadow(CPUPPCState *env, target_ulong addr)
423
{
424
    env->slb_shadow_addr = 0;
425
    env->slb_shadow_size = 0;
426
    return H_SUCCESS;
427
}
428

    
429
static target_ulong register_dtl(CPUPPCState *env, target_ulong addr)
430
{
431
    uint32_t size;
432

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

    
438
    size = ldl_be_phys(addr + 0x4);
439

    
440
    if (size < 48) {
441
        return H_PARAMETER;
442
    }
443

    
444
    if (!env->vpa_addr) {
445
        return H_RESOURCE;
446
    }
447

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

    
451
    return H_SUCCESS;
452
}
453

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

    
459
    return H_SUCCESS;
460
}
461

    
462
static target_ulong h_register_vpa(PowerPCCPU *cpu, sPAPREnvironment *spapr,
463
                                   target_ulong opcode, target_ulong *args)
464
{
465
    target_ulong flags = args[0];
466
    target_ulong procno = args[1];
467
    target_ulong vpa = args[2];
468
    target_ulong ret = H_PARAMETER;
469
    CPUPPCState *tenv;
470

    
471
    for (tenv = first_cpu; tenv; tenv = tenv->next_cpu) {
472
        if (tenv->cpu_index == procno) {
473
            break;
474
        }
475
    }
476

    
477
    if (!tenv) {
478
        return H_PARAMETER;
479
    }
480

    
481
    switch (flags) {
482
    case FLAGS_REGISTER_VPA:
483
        ret = register_vpa(tenv, vpa);
484
        break;
485

    
486
    case FLAGS_DEREGISTER_VPA:
487
        ret = deregister_vpa(tenv, vpa);
488
        break;
489

    
490
    case FLAGS_REGISTER_SLBSHADOW:
491
        ret = register_slb_shadow(tenv, vpa);
492
        break;
493

    
494
    case FLAGS_DEREGISTER_SLBSHADOW:
495
        ret = deregister_slb_shadow(tenv, vpa);
496
        break;
497

    
498
    case FLAGS_REGISTER_DTL:
499
        ret = register_dtl(tenv, vpa);
500
        break;
501

    
502
    case FLAGS_DEREGISTER_DTL:
503
        ret = deregister_dtl(tenv, vpa);
504
        break;
505
    }
506

    
507
    return ret;
508
}
509

    
510
static target_ulong h_cede(PowerPCCPU *cpu, sPAPREnvironment *spapr,
511
                           target_ulong opcode, target_ulong *args)
512
{
513
    CPUPPCState *env = &cpu->env;
514

    
515
    env->msr |= (1ULL << MSR_EE);
516
    hreg_compute_hflags(env);
517
    if (!cpu_has_work(CPU(cpu))) {
518
        env->halted = 1;
519
        env->exception_index = EXCP_HLT;
520
        env->exit_request = 1;
521
    }
522
    return H_SUCCESS;
523
}
524

    
525
static target_ulong h_rtas(PowerPCCPU *cpu, sPAPREnvironment *spapr,
526
                           target_ulong opcode, target_ulong *args)
527
{
528
    target_ulong rtas_r3 = args[0];
529
    uint32_t token = ldl_be_phys(rtas_r3);
530
    uint32_t nargs = ldl_be_phys(rtas_r3 + 4);
531
    uint32_t nret = ldl_be_phys(rtas_r3 + 8);
532

    
533
    return spapr_rtas_call(spapr, token, nargs, rtas_r3 + 12,
534
                           nret, rtas_r3 + 12 + 4*nargs);
535
}
536

    
537
static target_ulong h_logical_load(PowerPCCPU *cpu, sPAPREnvironment *spapr,
538
                                   target_ulong opcode, target_ulong *args)
539
{
540
    target_ulong size = args[0];
541
    target_ulong addr = args[1];
542

    
543
    switch (size) {
544
    case 1:
545
        args[0] = ldub_phys(addr);
546
        return H_SUCCESS;
547
    case 2:
548
        args[0] = lduw_phys(addr);
549
        return H_SUCCESS;
550
    case 4:
551
        args[0] = ldl_phys(addr);
552
        return H_SUCCESS;
553
    case 8:
554
        args[0] = ldq_phys(addr);
555
        return H_SUCCESS;
556
    }
557
    return H_PARAMETER;
558
}
559

    
560
static target_ulong h_logical_store(PowerPCCPU *cpu, sPAPREnvironment *spapr,
561
                                    target_ulong opcode, target_ulong *args)
562
{
563
    target_ulong size = args[0];
564
    target_ulong addr = args[1];
565
    target_ulong val  = args[2];
566

    
567
    switch (size) {
568
    case 1:
569
        stb_phys(addr, val);
570
        return H_SUCCESS;
571
    case 2:
572
        stw_phys(addr, val);
573
        return H_SUCCESS;
574
    case 4:
575
        stl_phys(addr, val);
576
        return H_SUCCESS;
577
    case 8:
578
        stq_phys(addr, val);
579
        return H_SUCCESS;
580
    }
581
    return H_PARAMETER;
582
}
583

    
584
static target_ulong h_logical_memop(PowerPCCPU *cpu, sPAPREnvironment *spapr,
585
                                    target_ulong opcode, target_ulong *args)
586
{
587
    target_ulong dst   = args[0]; /* Destination address */
588
    target_ulong src   = args[1]; /* Source address */
589
    target_ulong esize = args[2]; /* Element size (0=1,1=2,2=4,3=8) */
590
    target_ulong count = args[3]; /* Element count */
591
    target_ulong op    = args[4]; /* 0 = copy, 1 = invert */
592
    uint64_t tmp;
593
    unsigned int mask = (1 << esize) - 1;
594
    int step = 1 << esize;
595

    
596
    if (count > 0x80000000) {
597
        return H_PARAMETER;
598
    }
599

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

    
604
    if (dst >= src && dst < (src + (count << esize))) {
605
            dst = dst + ((count - 1) << esize);
606
            src = src + ((count - 1) << esize);
607
            step = -step;
608
    }
609

    
610
    while (count--) {
611
        switch (esize) {
612
        case 0:
613
            tmp = ldub_phys(src);
614
            break;
615
        case 1:
616
            tmp = lduw_phys(src);
617
            break;
618
        case 2:
619
            tmp = ldl_phys(src);
620
            break;
621
        case 3:
622
            tmp = ldq_phys(src);
623
            break;
624
        default:
625
            return H_PARAMETER;
626
        }
627
        if (op == 1) {
628
            tmp = ~tmp;
629
        }
630
        switch (esize) {
631
        case 0:
632
            stb_phys(dst, tmp);
633
            break;
634
        case 1:
635
            stw_phys(dst, tmp);
636
            break;
637
        case 2:
638
            stl_phys(dst, tmp);
639
            break;
640
        case 3:
641
            stq_phys(dst, tmp);
642
            break;
643
        }
644
        dst = dst + step;
645
        src = src + step;
646
    }
647

    
648
    return H_SUCCESS;
649
}
650

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

    
658
static target_ulong h_logical_dcbf(PowerPCCPU *cpu, sPAPREnvironment *spapr,
659
                                   target_ulong opcode, target_ulong *args)
660
{
661
    /* Nothing to do on emulation, KVM will trap this in the kernel */
662
    return H_SUCCESS;
663
}
664

    
665
static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
666
static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1];
667

    
668
void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
669
{
670
    spapr_hcall_fn *slot;
671

    
672
    if (opcode <= MAX_HCALL_OPCODE) {
673
        assert((opcode & 0x3) == 0);
674

    
675
        slot = &papr_hypercall_table[opcode / 4];
676
    } else {
677
        assert((opcode >= KVMPPC_HCALL_BASE) && (opcode <= KVMPPC_HCALL_MAX));
678

    
679
        slot = &kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
680
    }
681

    
682
    assert(!(*slot));
683
    *slot = fn;
684
}
685

    
686
target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
687
                             target_ulong *args)
688
{
689
    if ((opcode <= MAX_HCALL_OPCODE)
690
        && ((opcode & 0x3) == 0)) {
691
        spapr_hcall_fn fn = papr_hypercall_table[opcode / 4];
692

    
693
        if (fn) {
694
            return fn(cpu, spapr, opcode, args);
695
        }
696
    } else if ((opcode >= KVMPPC_HCALL_BASE) &&
697
               (opcode <= KVMPPC_HCALL_MAX)) {
698
        spapr_hcall_fn fn = kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
699

    
700
        if (fn) {
701
            return fn(cpu, spapr, opcode, args);
702
        }
703
    }
704

    
705
    hcall_dprintf("Unimplemented hcall 0x" TARGET_FMT_lx "\n", opcode);
706
    return H_FUNCTION;
707
}
708

    
709
static void hypercall_register_types(void)
710
{
711
    /* hcall-pft */
712
    spapr_register_hypercall(H_ENTER, h_enter);
713
    spapr_register_hypercall(H_REMOVE, h_remove);
714
    spapr_register_hypercall(H_PROTECT, h_protect);
715

    
716
    /* hcall-bulk */
717
    spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove);
718

    
719
    /* hcall-dabr */
720
    spapr_register_hypercall(H_SET_DABR, h_set_dabr);
721

    
722
    /* hcall-splpar */
723
    spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa);
724
    spapr_register_hypercall(H_CEDE, h_cede);
725

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

    
739
    /* qemu/KVM-PPC specific hcalls */
740
    spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
741
}
742

    
743
type_init(hypercall_register_types)