~ubuntu-branches/ubuntu/saucy/qemu/saucy-proposed

« back to all changes in this revision

Viewing changes to hw/spapr_hcall.c

  • Committer: Package Import Robot
  • Author(s): Serge Hallyn
  • Date: 2013-05-28 08:18:30 UTC
  • mfrom: (1.8.2) (10.1.37 sid)
  • Revision ID: package-import@ubuntu.com-20130528081830-87xl2z9fq516a814
Tags: 1.5.0+dfsg-2ubuntu1
* Merge 1.5.0+dfs-2 from debian unstable.  Remaining changes:
  - debian/control
    * update maintainer
    * remove libiscsi, usb-redir, vde, vnc-jpeg, and libssh2-1-dev
      from build-deps
    * enable rbd
    * add qemu-system and qemu-common B/R to qemu-keymaps
    * add D:udev, R:qemu, R:qemu-common and B:qemu-common to
      qemu-system-common
    * qemu-system-arm, qemu-system-ppc, qemu-system-sparc:
      - add qemu-kvm to Provides
      - add qemu-common, qemu-kvm, kvm to B/R
      - remove openbios-sparc from qemu-system-sparc D
    * qemu-system-x86:
      - add qemu-common to Breaks/Replaces.
      - add cpu-checker to Recommends.
    * qemu-user: add B/R:qemu-kvm
    * qemu-kvm:
      - add armhf armel powerpc sparc to Architecture
      - C/R/P: qemu-kvm-spice
    * add qemu-common package
    * drop qemu-slof which is not packaged in ubuntu
  - add qemu-system-common.links for tap ifup/down scripts and OVMF link.
  - qemu-system-x86.links:
    * remove pxe rom links which are in kvm-ipxe
    * add symlink for kvm.1 manpage
  - debian/rules
    * add kvm-spice symlink to qemu-kvm
    * call dh_installmodules for qemu-system-x86
    * update dh_installinit to install upstart script
    * run dh_installman (Closes: #709241) (cherrypicked from 1.5.0+dfsg-2)
  - Add qemu-utils.links for kvm-* symlinks.
  - Add qemu-system-x86.qemu-kvm.upstart and .default
  - Add qemu-system-x86.modprobe to set nesting=1
  - Add qemu-system-common.preinst to add kvm group
  - qemu-system-common.postinst: remove bad group acl if there, then have
    udev relabel /dev/kvm.
  - Dropped patches:
    * 0001-fix-wrong-output-with-info-chardev-for-tcp-socket.patch
  - Kept patches:
    * expose_vms_qemu64cpu.patch - updated
    * gridcentric patch - updated
    * linaro arm patches from qemu-linaro rebasing branch

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
    CPUState *tcpu;
471
 
 
472
 
    for (tenv = first_cpu; tenv; tenv = tenv->next_cpu) {
473
 
        tcpu = CPU(ppc_env_get_cpu(tenv));
474
 
        if (tcpu->cpu_index == procno) {
475
 
            break;
476
 
        }
477
 
    }
478
 
 
479
 
    if (!tenv) {
480
 
        return H_PARAMETER;
481
 
    }
482
 
 
483
 
    switch (flags) {
484
 
    case FLAGS_REGISTER_VPA:
485
 
        ret = register_vpa(tenv, vpa);
486
 
        break;
487
 
 
488
 
    case FLAGS_DEREGISTER_VPA:
489
 
        ret = deregister_vpa(tenv, vpa);
490
 
        break;
491
 
 
492
 
    case FLAGS_REGISTER_SLBSHADOW:
493
 
        ret = register_slb_shadow(tenv, vpa);
494
 
        break;
495
 
 
496
 
    case FLAGS_DEREGISTER_SLBSHADOW:
497
 
        ret = deregister_slb_shadow(tenv, vpa);
498
 
        break;
499
 
 
500
 
    case FLAGS_REGISTER_DTL:
501
 
        ret = register_dtl(tenv, vpa);
502
 
        break;
503
 
 
504
 
    case FLAGS_DEREGISTER_DTL:
505
 
        ret = deregister_dtl(tenv, vpa);
506
 
        break;
507
 
    }
508
 
 
509
 
    return ret;
510
 
}
511
 
 
512
 
static target_ulong h_cede(PowerPCCPU *cpu, sPAPREnvironment *spapr,
513
 
                           target_ulong opcode, target_ulong *args)
514
 
{
515
 
    CPUPPCState *env = &cpu->env;
516
 
 
517
 
    env->msr |= (1ULL << MSR_EE);
518
 
    hreg_compute_hflags(env);
519
 
    if (!cpu_has_work(CPU(cpu))) {
520
 
        env->halted = 1;
521
 
        env->exception_index = EXCP_HLT;
522
 
        env->exit_request = 1;
523
 
    }
524
 
    return H_SUCCESS;
525
 
}
526
 
 
527
 
static target_ulong h_rtas(PowerPCCPU *cpu, sPAPREnvironment *spapr,
528
 
                           target_ulong opcode, target_ulong *args)
529
 
{
530
 
    target_ulong rtas_r3 = args[0];
531
 
    uint32_t token = ldl_be_phys(rtas_r3);
532
 
    uint32_t nargs = ldl_be_phys(rtas_r3 + 4);
533
 
    uint32_t nret = ldl_be_phys(rtas_r3 + 8);
534
 
 
535
 
    return spapr_rtas_call(spapr, token, nargs, rtas_r3 + 12,
536
 
                           nret, rtas_r3 + 12 + 4*nargs);
537
 
}
538
 
 
539
 
static target_ulong h_logical_load(PowerPCCPU *cpu, sPAPREnvironment *spapr,
540
 
                                   target_ulong opcode, target_ulong *args)
541
 
{
542
 
    target_ulong size = args[0];
543
 
    target_ulong addr = args[1];
544
 
 
545
 
    switch (size) {
546
 
    case 1:
547
 
        args[0] = ldub_phys(addr);
548
 
        return H_SUCCESS;
549
 
    case 2:
550
 
        args[0] = lduw_phys(addr);
551
 
        return H_SUCCESS;
552
 
    case 4:
553
 
        args[0] = ldl_phys(addr);
554
 
        return H_SUCCESS;
555
 
    case 8:
556
 
        args[0] = ldq_phys(addr);
557
 
        return H_SUCCESS;
558
 
    }
559
 
    return H_PARAMETER;
560
 
}
561
 
 
562
 
static target_ulong h_logical_store(PowerPCCPU *cpu, sPAPREnvironment *spapr,
563
 
                                    target_ulong opcode, target_ulong *args)
564
 
{
565
 
    target_ulong size = args[0];
566
 
    target_ulong addr = args[1];
567
 
    target_ulong val  = args[2];
568
 
 
569
 
    switch (size) {
570
 
    case 1:
571
 
        stb_phys(addr, val);
572
 
        return H_SUCCESS;
573
 
    case 2:
574
 
        stw_phys(addr, val);
575
 
        return H_SUCCESS;
576
 
    case 4:
577
 
        stl_phys(addr, val);
578
 
        return H_SUCCESS;
579
 
    case 8:
580
 
        stq_phys(addr, val);
581
 
        return H_SUCCESS;
582
 
    }
583
 
    return H_PARAMETER;
584
 
}
585
 
 
586
 
static target_ulong h_logical_memop(PowerPCCPU *cpu, sPAPREnvironment *spapr,
587
 
                                    target_ulong opcode, target_ulong *args)
588
 
{
589
 
    target_ulong dst   = args[0]; /* Destination address */
590
 
    target_ulong src   = args[1]; /* Source address */
591
 
    target_ulong esize = args[2]; /* Element size (0=1,1=2,2=4,3=8) */
592
 
    target_ulong count = args[3]; /* Element count */
593
 
    target_ulong op    = args[4]; /* 0 = copy, 1 = invert */
594
 
    uint64_t tmp;
595
 
    unsigned int mask = (1 << esize) - 1;
596
 
    int step = 1 << esize;
597
 
 
598
 
    if (count > 0x80000000) {
599
 
        return H_PARAMETER;
600
 
    }
601
 
 
602
 
    if ((dst & mask) || (src & mask) || (op > 1)) {
603
 
        return H_PARAMETER;
604
 
    }
605
 
 
606
 
    if (dst >= src && dst < (src + (count << esize))) {
607
 
            dst = dst + ((count - 1) << esize);
608
 
            src = src + ((count - 1) << esize);
609
 
            step = -step;
610
 
    }
611
 
 
612
 
    while (count--) {
613
 
        switch (esize) {
614
 
        case 0:
615
 
            tmp = ldub_phys(src);
616
 
            break;
617
 
        case 1:
618
 
            tmp = lduw_phys(src);
619
 
            break;
620
 
        case 2:
621
 
            tmp = ldl_phys(src);
622
 
            break;
623
 
        case 3:
624
 
            tmp = ldq_phys(src);
625
 
            break;
626
 
        default:
627
 
            return H_PARAMETER;
628
 
        }
629
 
        if (op == 1) {
630
 
            tmp = ~tmp;
631
 
        }
632
 
        switch (esize) {
633
 
        case 0:
634
 
            stb_phys(dst, tmp);
635
 
            break;
636
 
        case 1:
637
 
            stw_phys(dst, tmp);
638
 
            break;
639
 
        case 2:
640
 
            stl_phys(dst, tmp);
641
 
            break;
642
 
        case 3:
643
 
            stq_phys(dst, tmp);
644
 
            break;
645
 
        }
646
 
        dst = dst + step;
647
 
        src = src + step;
648
 
    }
649
 
 
650
 
    return H_SUCCESS;
651
 
}
652
 
 
653
 
static target_ulong h_logical_icbi(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_logical_dcbf(PowerPCCPU *cpu, sPAPREnvironment *spapr,
661
 
                                   target_ulong opcode, target_ulong *args)
662
 
{
663
 
    /* Nothing to do on emulation, KVM will trap this in the kernel */
664
 
    return H_SUCCESS;
665
 
}
666
 
 
667
 
static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
668
 
static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1];
669
 
 
670
 
void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
671
 
{
672
 
    spapr_hcall_fn *slot;
673
 
 
674
 
    if (opcode <= MAX_HCALL_OPCODE) {
675
 
        assert((opcode & 0x3) == 0);
676
 
 
677
 
        slot = &papr_hypercall_table[opcode / 4];
678
 
    } else {
679
 
        assert((opcode >= KVMPPC_HCALL_BASE) && (opcode <= KVMPPC_HCALL_MAX));
680
 
 
681
 
        slot = &kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
682
 
    }
683
 
 
684
 
    assert(!(*slot));
685
 
    *slot = fn;
686
 
}
687
 
 
688
 
target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
689
 
                             target_ulong *args)
690
 
{
691
 
    if ((opcode <= MAX_HCALL_OPCODE)
692
 
        && ((opcode & 0x3) == 0)) {
693
 
        spapr_hcall_fn fn = papr_hypercall_table[opcode / 4];
694
 
 
695
 
        if (fn) {
696
 
            return fn(cpu, spapr, opcode, args);
697
 
        }
698
 
    } else if ((opcode >= KVMPPC_HCALL_BASE) &&
699
 
               (opcode <= KVMPPC_HCALL_MAX)) {
700
 
        spapr_hcall_fn fn = kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
701
 
 
702
 
        if (fn) {
703
 
            return fn(cpu, spapr, opcode, args);
704
 
        }
705
 
    }
706
 
 
707
 
    hcall_dprintf("Unimplemented hcall 0x" TARGET_FMT_lx "\n", opcode);
708
 
    return H_FUNCTION;
709
 
}
710
 
 
711
 
static void hypercall_register_types(void)
712
 
{
713
 
    /* hcall-pft */
714
 
    spapr_register_hypercall(H_ENTER, h_enter);
715
 
    spapr_register_hypercall(H_REMOVE, h_remove);
716
 
    spapr_register_hypercall(H_PROTECT, h_protect);
717
 
 
718
 
    /* hcall-bulk */
719
 
    spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove);
720
 
 
721
 
    /* hcall-dabr */
722
 
    spapr_register_hypercall(H_SET_DABR, h_set_dabr);
723
 
 
724
 
    /* hcall-splpar */
725
 
    spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa);
726
 
    spapr_register_hypercall(H_CEDE, h_cede);
727
 
 
728
 
    /* "debugger" hcalls (also used by SLOF). Note: We do -not- differenciate
729
 
     * here between the "CI" and the "CACHE" variants, they will use whatever
730
 
     * mapping attributes qemu is using. When using KVM, the kernel will
731
 
     * enforce the attributes more strongly
732
 
     */
733
 
    spapr_register_hypercall(H_LOGICAL_CI_LOAD, h_logical_load);
734
 
    spapr_register_hypercall(H_LOGICAL_CI_STORE, h_logical_store);
735
 
    spapr_register_hypercall(H_LOGICAL_CACHE_LOAD, h_logical_load);
736
 
    spapr_register_hypercall(H_LOGICAL_CACHE_STORE, h_logical_store);
737
 
    spapr_register_hypercall(H_LOGICAL_ICBI, h_logical_icbi);
738
 
    spapr_register_hypercall(H_LOGICAL_DCBF, h_logical_dcbf);
739
 
    spapr_register_hypercall(KVMPPC_H_LOGICAL_MEMOP, h_logical_memop);
740
 
 
741
 
    /* qemu/KVM-PPC specific hcalls */
742
 
    spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
743
 
}
744
 
 
745
 
type_init(hypercall_register_types)