Revision ed120055 hw/spapr_hcall.c

b/hw/spapr_hcall.c
4 4
#include "sysemu.h"
5 5
#include "qemu-char.h"
6 6
#include "exec-all.h"
7
#include "exec.h"
8
#include "helper_regs.h"
7 9
#include "hw/spapr.h"
8 10

  
9 11
#define HPTES_PER_GROUP 8
......
255 257
    return H_HARDWARE;
256 258
}
257 259

  
260
#define FLAGS_REGISTER_VPA         0x0000200000000000ULL
261
#define FLAGS_REGISTER_DTL         0x0000400000000000ULL
262
#define FLAGS_REGISTER_SLBSHADOW   0x0000600000000000ULL
263
#define FLAGS_DEREGISTER_VPA       0x0000a00000000000ULL
264
#define FLAGS_DEREGISTER_DTL       0x0000c00000000000ULL
265
#define FLAGS_DEREGISTER_SLBSHADOW 0x0000e00000000000ULL
266

  
267
#define VPA_MIN_SIZE           640
268
#define VPA_SIZE_OFFSET        0x4
269
#define VPA_SHARED_PROC_OFFSET 0x9
270
#define VPA_SHARED_PROC_VAL    0x2
271

  
272
static target_ulong register_vpa(CPUState *env, target_ulong vpa)
273
{
274
    uint16_t size;
275
    uint8_t tmp;
276

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

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

  
287
    size = lduw_phys(vpa + 0x4);
288

  
289
    if (size < VPA_MIN_SIZE) {
290
        return H_PARAMETER;
291
    }
292

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

  
298
    env->vpa = vpa;
299

  
300
    tmp = ldub_phys(env->vpa + VPA_SHARED_PROC_OFFSET);
301
    tmp |= VPA_SHARED_PROC_VAL;
302
    stb_phys(env->vpa + VPA_SHARED_PROC_OFFSET, tmp);
303

  
304
    return H_SUCCESS;
305
}
306

  
307
static target_ulong deregister_vpa(CPUState *env, target_ulong vpa)
308
{
309
    if (env->slb_shadow) {
310
        return H_RESOURCE;
311
    }
312

  
313
    if (env->dispatch_trace_log) {
314
        return H_RESOURCE;
315
    }
316

  
317
    env->vpa = 0;
318
    return H_SUCCESS;
319
}
320

  
321
static target_ulong register_slb_shadow(CPUState *env, target_ulong addr)
322
{
323
    uint32_t size;
324

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

  
330
    size = ldl_phys(addr + 0x4);
331
    if (size < 0x8) {
332
        return H_PARAMETER;
333
    }
334

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

  
339
    if (!env->vpa) {
340
        return H_RESOURCE;
341
    }
342

  
343
    env->slb_shadow = addr;
344

  
345
    return H_SUCCESS;
346
}
347

  
348
static target_ulong deregister_slb_shadow(CPUState *env, target_ulong addr)
349
{
350
    env->slb_shadow = 0;
351
    return H_SUCCESS;
352
}
353

  
354
static target_ulong register_dtl(CPUState *env, target_ulong addr)
355
{
356
    uint32_t size;
357

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

  
363
    size = ldl_phys(addr + 0x4);
364

  
365
    if (size < 48) {
366
        return H_PARAMETER;
367
    }
368

  
369
    if (!env->vpa) {
370
        return H_RESOURCE;
371
    }
372

  
373
    env->dispatch_trace_log = addr;
374
    env->dtl_size = size;
375

  
376
    return H_SUCCESS;
377
}
378

  
379
static target_ulong deregister_dtl(CPUState *emv, target_ulong addr)
380
{
381
    env->dispatch_trace_log = 0;
382
    env->dtl_size = 0;
383

  
384
    return H_SUCCESS;
385
}
386

  
387
static target_ulong h_register_vpa(CPUState *env, sPAPREnvironment *spapr,
388
                                   target_ulong opcode, target_ulong *args)
389
{
390
    target_ulong flags = args[0];
391
    target_ulong procno = args[1];
392
    target_ulong vpa = args[2];
393
    target_ulong ret = H_PARAMETER;
394
    CPUState *tenv;
395

  
396
    for (tenv = first_cpu; tenv; tenv = tenv->next_cpu) {
397
        if (tenv->cpu_index == procno) {
398
            break;
399
        }
400
    }
401

  
402
    if (!tenv) {
403
        return H_PARAMETER;
404
    }
405

  
406
    switch (flags) {
407
    case FLAGS_REGISTER_VPA:
408
        ret = register_vpa(tenv, vpa);
409
        break;
410

  
411
    case FLAGS_DEREGISTER_VPA:
412
        ret = deregister_vpa(tenv, vpa);
413
        break;
414

  
415
    case FLAGS_REGISTER_SLBSHADOW:
416
        ret = register_slb_shadow(tenv, vpa);
417
        break;
418

  
419
    case FLAGS_DEREGISTER_SLBSHADOW:
420
        ret = deregister_slb_shadow(tenv, vpa);
421
        break;
422

  
423
    case FLAGS_REGISTER_DTL:
424
        ret = register_dtl(tenv, vpa);
425
        break;
426

  
427
    case FLAGS_DEREGISTER_DTL:
428
        ret = deregister_dtl(tenv, vpa);
429
        break;
430
    }
431

  
432
    return ret;
433
}
434

  
435
static target_ulong h_cede(CPUState *env, sPAPREnvironment *spapr,
436
                           target_ulong opcode, target_ulong *args)
437
{
438
    env->msr |= (1ULL << MSR_EE);
439
    hreg_compute_hflags(env);
440
    if (!cpu_has_work(env)) {
441
        env->halted = 1;
442
    }
443
    return H_SUCCESS;
444
}
445

  
258 446
static target_ulong h_rtas(CPUState *env, sPAPREnvironment *spapr,
259 447
                           target_ulong opcode, target_ulong *args)
260 448
{
......
327 515
    /* hcall-dabr */
328 516
    spapr_register_hypercall(H_SET_DABR, h_set_dabr);
329 517

  
518
    /* hcall-splpar */
519
    spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa);
520
    spapr_register_hypercall(H_CEDE, h_cede);
521

  
330 522
    /* qemu/KVM-PPC specific hcalls */
331 523
    spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
332 524
}

Also available in: Unified diff