Statistics
| Branch: | Revision:

root / hw / spapr_hcall.c @ 06c46bba

History | View | Annotate | Download (14.1 kB)

1
#include "sysemu.h"
2
#include "cpu.h"
3
#include "qemu-char.h"
4
#include "sysemu.h"
5
#include "qemu-char.h"
6
#include "exec.h"
7
#include "helper_regs.h"
8
#include "hw/spapr.h"
9

    
10
#define HPTES_PER_GROUP 8
11

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

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

    
40
#define HPTE_V_1TB_SEG          0x4000000000000000ULL
41
#define HPTE_V_VRMA_MASK        0x4001ffffff000000ULL
42

    
43
#define HPTE_V_HVLOCK           0x40ULL
44

    
45
static inline int lock_hpte(void *hpte, target_ulong bits)
46
{
47
    uint64_t pteh;
48

    
49
    pteh = ldq_p(hpte);
50

    
51
    /* We're protected by qemu's global lock here */
52
    if (pteh & bits) {
53
        return 0;
54
    }
55
    stq_p(hpte, pteh | HPTE_V_HVLOCK);
56
    return 1;
57
}
58

    
59
static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
60
                                     target_ulong pte_index)
61
{
62
    target_ulong rb, va_low;
63

    
64
    rb = (v & ~0x7fULL) << 16; /* AVA field */
65
    va_low = pte_index >> 3;
66
    if (v & HPTE_V_SECONDARY) {
67
        va_low = ~va_low;
68
    }
69
    /* xor vsid from AVA */
70
    if (!(v & HPTE_V_1TB_SEG)) {
71
        va_low ^= v >> 12;
72
    } else {
73
        va_low ^= v >> 24;
74
    }
75
    va_low &= 0x7ff;
76
    if (v & HPTE_V_LARGE) {
77
        rb |= 1;                         /* L field */
78
#if 0 /* Disable that P7 specific bit for now */
79
        if (r & 0xff000) {
80
            /* non-16MB large page, must be 64k */
81
            /* (masks depend on page size) */
82
            rb |= 0x1000;                /* page encoding in LP field */
83
            rb |= (va_low & 0x7f) << 16; /* 7b of VA in AVA/LP field */
84
            rb |= (va_low & 0xfe);       /* AVAL field */
85
        }
86
#endif
87
    } else {
88
        /* 4kB page */
89
        rb |= (va_low & 0x7ff) << 12;   /* remaining 11b of AVA */
90
    }
91
    rb |= (v >> 54) & 0x300;            /* B field */
92
    return rb;
93
}
94

    
95
static target_ulong h_enter(CPUState *env, sPAPREnvironment *spapr,
96
                            target_ulong opcode, target_ulong *args)
97
{
98
    target_ulong flags = args[0];
99
    target_ulong pte_index = args[1];
100
    target_ulong pteh = args[2];
101
    target_ulong ptel = args[3];
102
    target_ulong i;
103
    uint8_t *hpte;
104

    
105
    /* only handle 4k and 16M pages for now */
106
    if (pteh & HPTE_V_LARGE) {
107
#if 0 /* We don't support 64k pages yet */
108
        if ((ptel & 0xf000) == 0x1000) {
109
            /* 64k page */
110
        } else
111
#endif
112
        if ((ptel & 0xff000) == 0) {
113
            /* 16M page */
114
            /* lowest AVA bit must be 0 for 16M pages */
115
            if (pteh & 0x80) {
116
                return H_PARAMETER;
117
            }
118
        } else {
119
            return H_PARAMETER;
120
        }
121
    }
122

    
123
    /* FIXME: bounds check the pa? */
124

    
125
    /* Check WIMG */
126
    if ((ptel & HPTE_R_WIMG) != HPTE_R_M) {
127
        return H_PARAMETER;
128
    }
129
    pteh &= ~0x60ULL;
130

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

    
158
    assert(!(ldq_p(hpte) & HPTE_V_HVLOCK));
159
    args[0] = pte_index + i;
160
    return H_SUCCESS;
161
}
162

    
163
static target_ulong h_remove(CPUState *env, sPAPREnvironment *spapr,
164
                             target_ulong opcode, target_ulong *args)
165
{
166
    target_ulong flags = args[0];
167
    target_ulong pte_index = args[1];
168
    target_ulong avpn = args[2];
169
    uint8_t *hpte;
170
    target_ulong v, r, rb;
171

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

    
176
    hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
177
    while (!lock_hpte(hpte, HPTE_V_HVLOCK)) {
178
        /* We have no real concurrency in qemu soft-emulation, so we
179
         * will never actually have a contested lock */
180
        assert(0);
181
    }
182

    
183
    v = ldq_p(hpte);
184
    r = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
185

    
186
    if ((v & HPTE_V_VALID) == 0 ||
187
        ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
188
        ((flags & H_ANDCOND) && (v & avpn) != 0)) {
189
        stq_p(hpte, v & ~HPTE_V_HVLOCK);
190
        assert(!(ldq_p(hpte) & HPTE_V_HVLOCK));
191
        return H_NOT_FOUND;
192
    }
193
    args[0] = v & ~HPTE_V_HVLOCK;
194
    args[1] = r;
195
    stq_p(hpte, 0);
196
    rb = compute_tlbie_rb(v, r, pte_index);
197
    ppc_tlb_invalidate_one(env, rb);
198
    assert(!(ldq_p(hpte) & HPTE_V_HVLOCK));
199
    return H_SUCCESS;
200
}
201

    
202
static target_ulong h_protect(CPUState *env, sPAPREnvironment *spapr,
203
                              target_ulong opcode, target_ulong *args)
204
{
205
    target_ulong flags = args[0];
206
    target_ulong pte_index = args[1];
207
    target_ulong avpn = args[2];
208
    uint8_t *hpte;
209
    target_ulong v, r, rb;
210

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

    
215
    hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
216
    while (!lock_hpte(hpte, HPTE_V_HVLOCK)) {
217
        /* We have no real concurrency in qemu soft-emulation, so we
218
         * will never actually have a contested lock */
219
        assert(0);
220
    }
221

    
222
    v = ldq_p(hpte);
223
    r = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
224

    
225
    if ((v & HPTE_V_VALID) == 0 ||
226
        ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
227
        stq_p(hpte, v & ~HPTE_V_HVLOCK);
228
        assert(!(ldq_p(hpte) & HPTE_V_HVLOCK));
229
        return H_NOT_FOUND;
230
    }
231

    
232
    r &= ~(HPTE_R_PP0 | HPTE_R_PP | HPTE_R_N |
233
           HPTE_R_KEY_HI | HPTE_R_KEY_LO);
234
    r |= (flags << 55) & HPTE_R_PP0;
235
    r |= (flags << 48) & HPTE_R_KEY_HI;
236
    r |= flags & (HPTE_R_PP | HPTE_R_N | HPTE_R_KEY_LO);
237
    rb = compute_tlbie_rb(v, r, pte_index);
238
    stq_p(hpte, v & ~HPTE_V_VALID);
239
    ppc_tlb_invalidate_one(env, rb);
240
    stq_p(hpte + (HASH_PTE_SIZE_64/2), r);
241
    /* Don't need a memory barrier, due to qemu's global lock */
242
    stq_p(hpte, v & ~HPTE_V_HVLOCK);
243
    assert(!(ldq_p(hpte) & HPTE_V_HVLOCK));
244
    return H_SUCCESS;
245
}
246

    
247
static target_ulong h_set_dabr(CPUState *env, sPAPREnvironment *spapr,
248
                               target_ulong opcode, target_ulong *args)
249
{
250
    /* FIXME: actually implement this */
251
    return H_HARDWARE;
252
}
253

    
254
#define FLAGS_REGISTER_VPA         0x0000200000000000ULL
255
#define FLAGS_REGISTER_DTL         0x0000400000000000ULL
256
#define FLAGS_REGISTER_SLBSHADOW   0x0000600000000000ULL
257
#define FLAGS_DEREGISTER_VPA       0x0000a00000000000ULL
258
#define FLAGS_DEREGISTER_DTL       0x0000c00000000000ULL
259
#define FLAGS_DEREGISTER_SLBSHADOW 0x0000e00000000000ULL
260

    
261
#define VPA_MIN_SIZE           640
262
#define VPA_SIZE_OFFSET        0x4
263
#define VPA_SHARED_PROC_OFFSET 0x9
264
#define VPA_SHARED_PROC_VAL    0x2
265

    
266
static target_ulong register_vpa(CPUState *env, target_ulong vpa)
267
{
268
    uint16_t size;
269
    uint8_t tmp;
270

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

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

    
281
    size = lduw_be_phys(vpa + 0x4);
282

    
283
    if (size < VPA_MIN_SIZE) {
284
        return H_PARAMETER;
285
    }
286

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

    
292
    env->vpa = vpa;
293

    
294
    tmp = ldub_phys(env->vpa + VPA_SHARED_PROC_OFFSET);
295
    tmp |= VPA_SHARED_PROC_VAL;
296
    stb_phys(env->vpa + VPA_SHARED_PROC_OFFSET, tmp);
297

    
298
    return H_SUCCESS;
299
}
300

    
301
static target_ulong deregister_vpa(CPUState *env, target_ulong vpa)
302
{
303
    if (env->slb_shadow) {
304
        return H_RESOURCE;
305
    }
306

    
307
    if (env->dispatch_trace_log) {
308
        return H_RESOURCE;
309
    }
310

    
311
    env->vpa = 0;
312
    return H_SUCCESS;
313
}
314

    
315
static target_ulong register_slb_shadow(CPUState *env, target_ulong addr)
316
{
317
    uint32_t size;
318

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

    
324
    size = ldl_be_phys(addr + 0x4);
325
    if (size < 0x8) {
326
        return H_PARAMETER;
327
    }
328

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

    
333
    if (!env->vpa) {
334
        return H_RESOURCE;
335
    }
336

    
337
    env->slb_shadow = addr;
338

    
339
    return H_SUCCESS;
340
}
341

    
342
static target_ulong deregister_slb_shadow(CPUState *env, target_ulong addr)
343
{
344
    env->slb_shadow = 0;
345
    return H_SUCCESS;
346
}
347

    
348
static target_ulong register_dtl(CPUState *env, target_ulong addr)
349
{
350
    uint32_t size;
351

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

    
357
    size = ldl_be_phys(addr + 0x4);
358

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

    
363
    if (!env->vpa) {
364
        return H_RESOURCE;
365
    }
366

    
367
    env->dispatch_trace_log = addr;
368
    env->dtl_size = size;
369

    
370
    return H_SUCCESS;
371
}
372

    
373
static target_ulong deregister_dtl(CPUState *emv, target_ulong addr)
374
{
375
    env->dispatch_trace_log = 0;
376
    env->dtl_size = 0;
377

    
378
    return H_SUCCESS;
379
}
380

    
381
static target_ulong h_register_vpa(CPUState *env, sPAPREnvironment *spapr,
382
                                   target_ulong opcode, target_ulong *args)
383
{
384
    target_ulong flags = args[0];
385
    target_ulong procno = args[1];
386
    target_ulong vpa = args[2];
387
    target_ulong ret = H_PARAMETER;
388
    CPUState *tenv;
389

    
390
    for (tenv = first_cpu; tenv; tenv = tenv->next_cpu) {
391
        if (tenv->cpu_index == procno) {
392
            break;
393
        }
394
    }
395

    
396
    if (!tenv) {
397
        return H_PARAMETER;
398
    }
399

    
400
    switch (flags) {
401
    case FLAGS_REGISTER_VPA:
402
        ret = register_vpa(tenv, vpa);
403
        break;
404

    
405
    case FLAGS_DEREGISTER_VPA:
406
        ret = deregister_vpa(tenv, vpa);
407
        break;
408

    
409
    case FLAGS_REGISTER_SLBSHADOW:
410
        ret = register_slb_shadow(tenv, vpa);
411
        break;
412

    
413
    case FLAGS_DEREGISTER_SLBSHADOW:
414
        ret = deregister_slb_shadow(tenv, vpa);
415
        break;
416

    
417
    case FLAGS_REGISTER_DTL:
418
        ret = register_dtl(tenv, vpa);
419
        break;
420

    
421
    case FLAGS_DEREGISTER_DTL:
422
        ret = deregister_dtl(tenv, vpa);
423
        break;
424
    }
425

    
426
    return ret;
427
}
428

    
429
static target_ulong h_cede(CPUState *env, sPAPREnvironment *spapr,
430
                           target_ulong opcode, target_ulong *args)
431
{
432
    env->msr |= (1ULL << MSR_EE);
433
    hreg_compute_hflags(env);
434
    if (!cpu_has_work(env)) {
435
        env->halted = 1;
436
    }
437
    return H_SUCCESS;
438
}
439

    
440
static target_ulong h_rtas(CPUState *env, sPAPREnvironment *spapr,
441
                           target_ulong opcode, target_ulong *args)
442
{
443
    target_ulong rtas_r3 = args[0];
444
    uint32_t token = ldl_be_phys(rtas_r3);
445
    uint32_t nargs = ldl_be_phys(rtas_r3 + 4);
446
    uint32_t nret = ldl_be_phys(rtas_r3 + 8);
447

    
448
    return spapr_rtas_call(spapr, token, nargs, rtas_r3 + 12,
449
                           nret, rtas_r3 + 12 + 4*nargs);
450
}
451

    
452
static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
453
static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1];
454

    
455
void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
456
{
457
    spapr_hcall_fn *slot;
458

    
459
    if (opcode <= MAX_HCALL_OPCODE) {
460
        assert((opcode & 0x3) == 0);
461

    
462
        slot = &papr_hypercall_table[opcode / 4];
463
    } else {
464
        assert((opcode >= KVMPPC_HCALL_BASE) && (opcode <= KVMPPC_HCALL_MAX));
465

    
466

    
467
        slot = &kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
468
    }
469

    
470
    assert(!(*slot) || (fn == *slot));
471
    *slot = fn;
472
}
473

    
474
target_ulong spapr_hypercall(CPUState *env, target_ulong opcode,
475
                             target_ulong *args)
476
{
477
    if (msr_pr) {
478
        hcall_dprintf("Hypercall made with MSR[PR]=1\n");
479
        return H_PRIVILEGE;
480
    }
481

    
482
    if ((opcode <= MAX_HCALL_OPCODE)
483
        && ((opcode & 0x3) == 0)) {
484
        spapr_hcall_fn fn = papr_hypercall_table[opcode / 4];
485

    
486
        if (fn) {
487
            return fn(env, spapr, opcode, args);
488
        }
489
    } else if ((opcode >= KVMPPC_HCALL_BASE) &&
490
               (opcode <= KVMPPC_HCALL_MAX)) {
491
        spapr_hcall_fn fn = kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
492

    
493
        if (fn) {
494
            return fn(env, spapr, opcode, args);
495
        }
496
    }
497

    
498
    hcall_dprintf("Unimplemented hcall 0x" TARGET_FMT_lx "\n", opcode);
499
    return H_FUNCTION;
500
}
501

    
502
static void hypercall_init(void)
503
{
504
    /* hcall-pft */
505
    spapr_register_hypercall(H_ENTER, h_enter);
506
    spapr_register_hypercall(H_REMOVE, h_remove);
507
    spapr_register_hypercall(H_PROTECT, h_protect);
508

    
509
    /* hcall-dabr */
510
    spapr_register_hypercall(H_SET_DABR, h_set_dabr);
511

    
512
    /* hcall-splpar */
513
    spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa);
514
    spapr_register_hypercall(H_CEDE, h_cede);
515

    
516
    /* qemu/KVM-PPC specific hcalls */
517
    spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
518
}
519
device_init(hypercall_init);