Statistics
| Branch: | Revision:

root / hw / ppc / spapr_hcall.c @ 42561bf2

History | View | Annotate | Download (21.5 kB)

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

    
7
static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
8
                                     target_ulong pte_index)
9
{
10
    target_ulong rb, va_low;
11

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

    
43
static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
44
                            target_ulong opcode, target_ulong *args)
45
{
46
    CPUPPCState *env = &cpu->env;
47
    target_ulong flags = args[0];
48
    target_ulong pte_index = args[1];
49
    target_ulong pteh = args[2];
50
    target_ulong ptel = args[3];
51
    target_ulong page_shift = 12;
52
    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
#if 0 /* We don't support 64k pages yet */
59
        if ((ptel & 0xf000) == 0x1000) {
60
            /* 64k page */
61
        } else
62
#endif
63
        if ((ptel & 0xff000) == 0) {
64
            /* 16M page */
65
            page_shift = 24;
66
            /* lowest AVA bit must be 0 for 16M pages */
67
            if (pteh & 0x80) {
68
                return H_PARAMETER;
69
            }
70
        } else {
71
            return H_PARAMETER;
72
        }
73
    }
74

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

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

    
92
    pteh &= ~0x60ULL;
93

    
94
    if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
95
        return H_PARAMETER;
96
    }
97
    if (likely((flags & H_EXACT) == 0)) {
98
        pte_index &= ~7ULL;
99
        hpte = pte_index * HASH_PTE_SIZE_64;
100
        for (i = 0; ; ++i) {
101
            if (i == 8) {
102
                return H_PTEG_FULL;
103
            }
104
            if ((ppc_hash64_load_hpte0(env, hpte) & HPTE64_V_VALID) == 0) {
105
                break;
106
            }
107
            hpte += HASH_PTE_SIZE_64;
108
        }
109
    } else {
110
        i = 0;
111
        hpte = pte_index * HASH_PTE_SIZE_64;
112
        if (ppc_hash64_load_hpte0(env, hpte) & HPTE64_V_VALID) {
113
            return H_PTEG_FULL;
114
        }
115
    }
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
    args[0] = pte_index + i;
121
    return H_SUCCESS;
122
}
123

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

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

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

    
143
    hpte = ptex * HASH_PTE_SIZE_64;
144

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

    
148
    if ((v & HPTE64_V_VALID) == 0 ||
149
        ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
150
        ((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
    return REMOVE_SUCCESS;
159
}
160

    
161
static target_ulong h_remove(PowerPCCPU *cpu, sPAPREnvironment *spapr,
162
                             target_ulong opcode, target_ulong *args)
163
{
164
    CPUPPCState *env = &cpu->env;
165
    target_ulong flags = args[0];
166
    target_ulong pte_index = args[1];
167
    target_ulong avpn = args[2];
168
    RemoveResult ret;
169

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

    
173
    switch (ret) {
174
    case REMOVE_SUCCESS:
175
        return H_SUCCESS;
176

    
177
    case REMOVE_NOT_FOUND:
178
        return H_NOT_FOUND;
179

    
180
    case REMOVE_PARM:
181
        return H_PARAMETER;
182

    
183
    case REMOVE_HW:
184
        return H_HARDWARE;
185
    }
186

    
187
    g_assert_not_reached();
188
}
189

    
190
#define H_BULK_REMOVE_TYPE             0xc000000000000000ULL
191
#define   H_BULK_REMOVE_REQUEST        0x4000000000000000ULL
192
#define   H_BULK_REMOVE_RESPONSE       0x8000000000000000ULL
193
#define   H_BULK_REMOVE_END            0xc000000000000000ULL
194
#define H_BULK_REMOVE_CODE             0x3000000000000000ULL
195
#define   H_BULK_REMOVE_SUCCESS        0x0000000000000000ULL
196
#define   H_BULK_REMOVE_NOT_FOUND      0x1000000000000000ULL
197
#define   H_BULK_REMOVE_PARM           0x2000000000000000ULL
198
#define   H_BULK_REMOVE_HW             0x3000000000000000ULL
199
#define H_BULK_REMOVE_RC               0x0c00000000000000ULL
200
#define H_BULK_REMOVE_FLAGS            0x0300000000000000ULL
201
#define   H_BULK_REMOVE_ABSOLUTE       0x0000000000000000ULL
202
#define   H_BULK_REMOVE_ANDCOND        0x0100000000000000ULL
203
#define   H_BULK_REMOVE_AVPN           0x0200000000000000ULL
204
#define H_BULK_REMOVE_PTEX             0x00ffffffffffffffULL
205

    
206
#define H_BULK_REMOVE_MAX_BATCH        4
207

    
208
static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPREnvironment *spapr,
209
                                  target_ulong opcode, target_ulong *args)
210
{
211
    CPUPPCState *env = &cpu->env;
212
    int i;
213

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

    
219
        if ((*tsh & H_BULK_REMOVE_TYPE) == H_BULK_REMOVE_END) {
220
            break;
221
        } else if ((*tsh & H_BULK_REMOVE_TYPE) != H_BULK_REMOVE_REQUEST) {
222
            return H_PARAMETER;
223
        }
224

    
225
        *tsh &= H_BULK_REMOVE_PTEX | H_BULK_REMOVE_FLAGS;
226
        *tsh |= H_BULK_REMOVE_RESPONSE;
227

    
228
        if ((*tsh & H_BULK_REMOVE_ANDCOND) && (*tsh & H_BULK_REMOVE_AVPN)) {
229
            *tsh |= H_BULK_REMOVE_PARM;
230
            return H_PARAMETER;
231
        }
232

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

    
237
        *tsh |= ret << 60;
238

    
239
        switch (ret) {
240
        case REMOVE_SUCCESS:
241
            *tsh |= (r & (HPTE64_R_C | HPTE64_R_R)) << 43;
242
            break;
243

    
244
        case REMOVE_PARM:
245
            return H_PARAMETER;
246

    
247
        case REMOVE_HW:
248
            return H_HARDWARE;
249
        }
250
    }
251

    
252
    return H_SUCCESS;
253
}
254

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

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

    
269
    hpte = pte_index * HASH_PTE_SIZE_64;
270

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

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

    
279
    r &= ~(HPTE64_R_PP0 | HPTE64_R_PP | HPTE64_R_N |
280
           HPTE64_R_KEY_HI | HPTE64_R_KEY_LO);
281
    r |= (flags << 55) & HPTE64_R_PP0;
282
    r |= (flags << 48) & HPTE64_R_KEY_HI;
283
    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
    return H_SUCCESS;
291
}
292

    
293
static target_ulong h_read(PowerPCCPU *cpu, sPAPREnvironment *spapr,
294
                           target_ulong opcode, target_ulong *args)
295
{
296
    CPUPPCState *env = &cpu->env;
297
    target_ulong flags = args[0];
298
    target_ulong pte_index = args[1];
299
    uint8_t *hpte;
300
    int i, ridx, n_entries = 1;
301

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

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

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

    
314
    for (i = 0, ridx = 0; i < n_entries; i++) {
315
        args[ridx++] = ldq_p(hpte);
316
        args[ridx++] = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
317
        hpte += HASH_PTE_SIZE_64;
318
    }
319

    
320
    return H_SUCCESS;
321
}
322

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

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

    
337
#define VPA_MIN_SIZE           640
338
#define VPA_SIZE_OFFSET        0x4
339
#define VPA_SHARED_PROC_OFFSET 0x9
340
#define VPA_SHARED_PROC_VAL    0x2
341

    
342
static target_ulong register_vpa(CPUPPCState *env, target_ulong vpa)
343
{
344
    uint16_t size;
345
    uint8_t tmp;
346

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

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

    
357
    size = lduw_be_phys(vpa + 0x4);
358

    
359
    if (size < VPA_MIN_SIZE) {
360
        return H_PARAMETER;
361
    }
362

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

    
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
    return H_SUCCESS;
375
}
376

    
377
static target_ulong deregister_vpa(CPUPPCState *env, target_ulong vpa)
378
{
379
    if (env->slb_shadow_addr) {
380
        return H_RESOURCE;
381
    }
382

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

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

    
391
static target_ulong register_slb_shadow(CPUPPCState *env, target_ulong addr)
392
{
393
    uint32_t size;
394

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

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

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

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

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

    
416
    return H_SUCCESS;
417
}
418

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

    
426
static target_ulong register_dtl(CPUPPCState *env, target_ulong addr)
427
{
428
    uint32_t size;
429

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

    
435
    size = ldl_be_phys(addr + 0x4);
436

    
437
    if (size < 48) {
438
        return H_PARAMETER;
439
    }
440

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

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

    
448
    return H_SUCCESS;
449
}
450

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

    
456
    return H_SUCCESS;
457
}
458

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

    
469
    tcpu = qemu_get_cpu(procno);
470
    if (!tcpu) {
471
        return H_PARAMETER;
472
    }
473
    tenv = tcpu->env_ptr;
474

    
475
    switch (flags) {
476
    case FLAGS_REGISTER_VPA:
477
        ret = register_vpa(tenv, vpa);
478
        break;
479

    
480
    case FLAGS_DEREGISTER_VPA:
481
        ret = deregister_vpa(tenv, vpa);
482
        break;
483

    
484
    case FLAGS_REGISTER_SLBSHADOW:
485
        ret = register_slb_shadow(tenv, vpa);
486
        break;
487

    
488
    case FLAGS_DEREGISTER_SLBSHADOW:
489
        ret = deregister_slb_shadow(tenv, vpa);
490
        break;
491

    
492
    case FLAGS_REGISTER_DTL:
493
        ret = register_dtl(tenv, vpa);
494
        break;
495

    
496
    case FLAGS_DEREGISTER_DTL:
497
        ret = deregister_dtl(tenv, vpa);
498
        break;
499
    }
500

    
501
    return ret;
502
}
503

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

    
510
    env->msr |= (1ULL << MSR_EE);
511
    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
    return H_SUCCESS;
518
}
519

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

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

    
532
static target_ulong h_logical_load(PowerPCCPU *cpu, sPAPREnvironment *spapr,
533
                                   target_ulong opcode, target_ulong *args)
534
{
535
    target_ulong size = args[0];
536
    target_ulong addr = args[1];
537

    
538
    switch (size) {
539
    case 1:
540
        args[0] = ldub_phys(addr);
541
        return H_SUCCESS;
542
    case 2:
543
        args[0] = lduw_phys(addr);
544
        return H_SUCCESS;
545
    case 4:
546
        args[0] = ldl_phys(addr);
547
        return H_SUCCESS;
548
    case 8:
549
        args[0] = ldq_phys(addr);
550
        return H_SUCCESS;
551
    }
552
    return H_PARAMETER;
553
}
554

    
555
static target_ulong h_logical_store(PowerPCCPU *cpu, sPAPREnvironment *spapr,
556
                                    target_ulong opcode, target_ulong *args)
557
{
558
    target_ulong size = args[0];
559
    target_ulong addr = args[1];
560
    target_ulong val  = args[2];
561

    
562
    switch (size) {
563
    case 1:
564
        stb_phys(addr, val);
565
        return H_SUCCESS;
566
    case 2:
567
        stw_phys(addr, val);
568
        return H_SUCCESS;
569
    case 4:
570
        stl_phys(addr, val);
571
        return H_SUCCESS;
572
    case 8:
573
        stq_phys(addr, val);
574
        return H_SUCCESS;
575
    }
576
    return H_PARAMETER;
577
}
578

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

    
591
    if (count > 0x80000000) {
592
        return H_PARAMETER;
593
    }
594

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

    
599
    if (dst >= src && dst < (src + (count << esize))) {
600
            dst = dst + ((count - 1) << esize);
601
            src = src + ((count - 1) << esize);
602
            step = -step;
603
    }
604

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

    
643
    return H_SUCCESS;
644
}
645

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

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

    
660
static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPREnvironment *spapr,
661
                               target_ulong opcode, target_ulong *args)
662
{
663
    CPUState *cs;
664
    target_ulong mflags = args[0];
665
    target_ulong resource = args[1];
666
    target_ulong value1 = args[2];
667
    target_ulong value2 = args[3];
668
    target_ulong ret = H_P2;
669

    
670
    if (resource == H_SET_MODE_ENDIAN) {
671
        if (value1) {
672
            ret = H_P3;
673
            goto out;
674
        }
675
        if (value2) {
676
            ret = H_P4;
677
            goto out;
678
        }
679

    
680
        switch (mflags) {
681
        case H_SET_MODE_ENDIAN_BIG:
682
            for (cs = first_cpu; cs != NULL; cs = cs->next_cpu) {
683
                PowerPCCPU *cp = POWERPC_CPU(cs);
684
                CPUPPCState *env = &cp->env;
685
                env->spr[SPR_LPCR] &= ~LPCR_ILE;
686
            }
687
            ret = H_SUCCESS;
688
            break;
689

    
690
        case H_SET_MODE_ENDIAN_LITTLE:
691
            for (cs = first_cpu; cs != NULL; cs = cs->next_cpu) {
692
                PowerPCCPU *cp = POWERPC_CPU(cs);
693
                CPUPPCState *env = &cp->env;
694
                env->spr[SPR_LPCR] |= LPCR_ILE;
695
            }
696
            ret = H_SUCCESS;
697
            break;
698

    
699
        default:
700
            ret = H_UNSUPPORTED_FLAG;
701
        }
702
    }
703

    
704
out:
705
    return ret;
706
}
707

    
708
static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
709
static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1];
710

    
711
void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
712
{
713
    spapr_hcall_fn *slot;
714

    
715
    if (opcode <= MAX_HCALL_OPCODE) {
716
        assert((opcode & 0x3) == 0);
717

    
718
        slot = &papr_hypercall_table[opcode / 4];
719
    } else {
720
        assert((opcode >= KVMPPC_HCALL_BASE) && (opcode <= KVMPPC_HCALL_MAX));
721

    
722
        slot = &kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
723
    }
724

    
725
    assert(!(*slot));
726
    *slot = fn;
727
}
728

    
729
target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
730
                             target_ulong *args)
731
{
732
    if ((opcode <= MAX_HCALL_OPCODE)
733
        && ((opcode & 0x3) == 0)) {
734
        spapr_hcall_fn fn = papr_hypercall_table[opcode / 4];
735

    
736
        if (fn) {
737
            return fn(cpu, spapr, opcode, args);
738
        }
739
    } else if ((opcode >= KVMPPC_HCALL_BASE) &&
740
               (opcode <= KVMPPC_HCALL_MAX)) {
741
        spapr_hcall_fn fn = kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
742

    
743
        if (fn) {
744
            return fn(cpu, spapr, opcode, args);
745
        }
746
    }
747

    
748
    hcall_dprintf("Unimplemented hcall 0x" TARGET_FMT_lx "\n", opcode);
749
    return H_FUNCTION;
750
}
751

    
752
static void hypercall_register_types(void)
753
{
754
    /* hcall-pft */
755
    spapr_register_hypercall(H_ENTER, h_enter);
756
    spapr_register_hypercall(H_REMOVE, h_remove);
757
    spapr_register_hypercall(H_PROTECT, h_protect);
758
    spapr_register_hypercall(H_READ, h_read);
759

    
760
    /* hcall-bulk */
761
    spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove);
762

    
763
    /* hcall-dabr */
764
    spapr_register_hypercall(H_SET_DABR, h_set_dabr);
765

    
766
    /* hcall-splpar */
767
    spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa);
768
    spapr_register_hypercall(H_CEDE, h_cede);
769

    
770
    /* "debugger" hcalls (also used by SLOF). Note: We do -not- differenciate
771
     * here between the "CI" and the "CACHE" variants, they will use whatever
772
     * mapping attributes qemu is using. When using KVM, the kernel will
773
     * enforce the attributes more strongly
774
     */
775
    spapr_register_hypercall(H_LOGICAL_CI_LOAD, h_logical_load);
776
    spapr_register_hypercall(H_LOGICAL_CI_STORE, h_logical_store);
777
    spapr_register_hypercall(H_LOGICAL_CACHE_LOAD, h_logical_load);
778
    spapr_register_hypercall(H_LOGICAL_CACHE_STORE, h_logical_store);
779
    spapr_register_hypercall(H_LOGICAL_ICBI, h_logical_icbi);
780
    spapr_register_hypercall(H_LOGICAL_DCBF, h_logical_dcbf);
781
    spapr_register_hypercall(KVMPPC_H_LOGICAL_MEMOP, h_logical_memop);
782

    
783
    /* qemu/KVM-PPC specific hcalls */
784
    spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
785

    
786
    spapr_register_hypercall(H_SET_MODE, h_set_mode);
787
}
788

    
789
type_init(hypercall_register_types)