Commit d76d16501ef27fdf3ac8c1f9b7cf59b59a661ec3

Authored by aurel32
1 parent f652e6af

target-ppc: Enable KVM for ppcemb.

Implement hooks called by generic KVM code.

Also add code that will copy the host's CPU and timebase frequencies to the
guest, which is necessary on KVM because the guest can directly access the
timebase.

Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>
Acked-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6065 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile.target
@@ -659,6 +659,9 @@ ifdef FDT_LIBS @@ -659,6 +659,9 @@ ifdef FDT_LIBS
659 OBJS+= device_tree.o 659 OBJS+= device_tree.o
660 LIBS+= $(FDT_LIBS) 660 LIBS+= $(FDT_LIBS)
661 endif 661 endif
  662 +ifdef CONFIG_KVM
  663 +OBJS+= kvm_ppc.o
  664 +endif
662 # virtio support 665 # virtio support
663 OBJS+= virtio.o virtio-blk.o virtio-balloon.o 666 OBJS+= virtio.o virtio-blk.o virtio-balloon.o
664 endif 667 endif
configure
@@ -1491,6 +1491,7 @@ gdb_xml_files=&quot;&quot; @@ -1491,6 +1491,7 @@ gdb_xml_files=&quot;&quot;
1491 1491
1492 # Make sure the target and host cpus are compatible 1492 # Make sure the target and host cpus are compatible
1493 if test "$kvm" = "yes" -a ! \( "$target_cpu" = "$cpu" -o \ 1493 if test "$kvm" = "yes" -a ! \( "$target_cpu" = "$cpu" -o \
  1494 + \( "$target_cpu" = "ppcemb" -a "$cpu" = "powerpc" \) -o \
1494 \( "$target_cpu" = "x86_64" -a "$cpu" = "i386" \) -o \ 1495 \( "$target_cpu" = "x86_64" -a "$cpu" = "i386" \) -o \
1495 \( "$target_cpu" = "i386" -a "$cpu" = "x86_64" \) \) ; then 1496 \( "$target_cpu" = "i386" -a "$cpu" = "x86_64" \) \) ; then
1496 kvm="no" 1497 kvm="no"
@@ -1585,6 +1586,11 @@ case &quot;$target_cpu&quot; in @@ -1585,6 +1586,11 @@ case &quot;$target_cpu&quot; in
1585 echo "#define TARGET_ARCH \"ppcemb\"" >> $config_h 1586 echo "#define TARGET_ARCH \"ppcemb\"" >> $config_h
1586 echo "#define TARGET_PPC 1" >> $config_h 1587 echo "#define TARGET_PPC 1" >> $config_h
1587 echo "#define TARGET_PPCEMB 1" >> $config_h 1588 echo "#define TARGET_PPCEMB 1" >> $config_h
  1589 + if test "$kvm" = "yes" ; then
  1590 + echo "CONFIG_KVM=yes" >> $config_mak
  1591 + echo "KVM_CFLAGS=$kvm_cflags" >> $config_mak
  1592 + echo "#define CONFIG_KVM 1" >> $config_h
  1593 + fi
1588 ;; 1594 ;;
1589 ppc64) 1595 ppc64)
1590 echo "TARGET_ARCH=ppc64" >> $config_mak 1596 echo "TARGET_ARCH=ppc64" >> $config_mak
target-ppc/helper.c
@@ -29,6 +29,7 @@ @@ -29,6 +29,7 @@
29 #include "exec-all.h" 29 #include "exec-all.h"
30 #include "helper_regs.h" 30 #include "helper_regs.h"
31 #include "qemu-common.h" 31 #include "qemu-common.h"
  32 +#include "kvm.h"
32 33
33 //#define DEBUG_MMU 34 //#define DEBUG_MMU
34 //#define DEBUG_BATS 35 //#define DEBUG_BATS
@@ -2920,6 +2921,10 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model) @@ -2920,6 +2921,10 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model)
2920 env->cpu_model_str = cpu_model; 2921 env->cpu_model_str = cpu_model;
2921 cpu_ppc_register_internal(env, def); 2922 cpu_ppc_register_internal(env, def);
2922 cpu_ppc_reset(env); 2923 cpu_ppc_reset(env);
  2924 +
  2925 + if (kvm_enabled())
  2926 + kvm_init_vcpu(env);
  2927 +
2923 return env; 2928 return env;
2924 } 2929 }
2925 2930
target-ppc/kvm.c 0 → 100644
  1 +/*
  2 + * PowerPC implementation of KVM hooks
  3 + *
  4 + * Copyright IBM Corp. 2007
  5 + *
  6 + * Authors:
  7 + * Jerone Young <jyoung5@us.ibm.com>
  8 + * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
  9 + * Hollis Blanchard <hollisb@us.ibm.com>
  10 + *
  11 + * This work is licensed under the terms of the GNU GPL, version 2 or later.
  12 + * See the COPYING file in the top-level directory.
  13 + *
  14 + */
  15 +
  16 +#include <sys/types.h>
  17 +#include <sys/ioctl.h>
  18 +#include <sys/mman.h>
  19 +
  20 +#include <linux/kvm.h>
  21 +
  22 +#include "qemu-common.h"
  23 +#include "qemu-timer.h"
  24 +#include "sysemu.h"
  25 +#include "kvm.h"
  26 +#include "kvm_ppc.h"
  27 +#include "cpu.h"
  28 +#include "device_tree.h"
  29 +
  30 +//#define DEBUG_KVM
  31 +
  32 +#ifdef DEBUG_KVM
  33 +#define dprintf(fmt, ...) \
  34 + do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
  35 +#else
  36 +#define dprintf(fmt, ...) \
  37 + do { } while (0)
  38 +#endif
  39 +
  40 +int kvm_arch_init(KVMState *s, int smp_cpus)
  41 +{
  42 + return 0;
  43 +}
  44 +
  45 +int kvm_arch_init_vcpu(CPUState *cenv)
  46 +{
  47 + return 0;
  48 +}
  49 +
  50 +int kvm_arch_put_registers(CPUState *env)
  51 +{
  52 + struct kvm_regs regs;
  53 + int ret;
  54 + int i;
  55 +
  56 + ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, &regs);
  57 + if (ret < 0)
  58 + return ret;
  59 +
  60 + regs.ctr = env->ctr;
  61 + regs.lr = env->lr;
  62 + regs.xer = env->xer;
  63 + regs.msr = env->msr;
  64 + regs.pc = env->nip;
  65 +
  66 + regs.srr0 = env->spr[SPR_SRR0];
  67 + regs.srr1 = env->spr[SPR_SRR1];
  68 +
  69 + regs.sprg0 = env->spr[SPR_SPRG0];
  70 + regs.sprg1 = env->spr[SPR_SPRG1];
  71 + regs.sprg2 = env->spr[SPR_SPRG2];
  72 + regs.sprg3 = env->spr[SPR_SPRG3];
  73 + regs.sprg4 = env->spr[SPR_SPRG4];
  74 + regs.sprg5 = env->spr[SPR_SPRG5];
  75 + regs.sprg6 = env->spr[SPR_SPRG6];
  76 + regs.sprg7 = env->spr[SPR_SPRG7];
  77 +
  78 + for (i = 0;i < 32; i++)
  79 + regs.gpr[i] = env->gpr[i];
  80 +
  81 + ret = kvm_vcpu_ioctl(env, KVM_SET_REGS, &regs);
  82 + if (ret < 0)
  83 + return ret;
  84 +
  85 + return ret;
  86 +}
  87 +
  88 +int kvm_arch_get_registers(CPUState *env)
  89 +{
  90 + struct kvm_regs regs;
  91 + uint32_t i, ret;
  92 +
  93 + ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, &regs);
  94 + if (ret < 0)
  95 + return ret;
  96 +
  97 + env->ctr = regs.ctr;
  98 + env->lr = regs.lr;
  99 + env->xer = regs.xer;
  100 + env->msr = regs.msr;
  101 + env->nip = regs.pc;
  102 +
  103 + env->spr[SPR_SRR0] = regs.srr0;
  104 + env->spr[SPR_SRR1] = regs.srr1;
  105 +
  106 + env->spr[SPR_SPRG0] = regs.sprg0;
  107 + env->spr[SPR_SPRG1] = regs.sprg1;
  108 + env->spr[SPR_SPRG2] = regs.sprg2;
  109 + env->spr[SPR_SPRG3] = regs.sprg3;
  110 + env->spr[SPR_SPRG4] = regs.sprg4;
  111 + env->spr[SPR_SPRG5] = regs.sprg5;
  112 + env->spr[SPR_SPRG6] = regs.sprg6;
  113 + env->spr[SPR_SPRG7] = regs.sprg7;
  114 +
  115 + for (i = 0;i < 32; i++)
  116 + env->gpr[i] = regs.gpr[i];
  117 +
  118 + return 0;
  119 +}
  120 +
  121 +int kvm_arch_pre_run(CPUState *env, struct kvm_run *run)
  122 +{
  123 + int r;
  124 + unsigned irq;
  125 +
  126 + /* PowerPC Qemu tracks the various core input pins (interrupt, critical
  127 + * interrupt, reset, etc) in PPC-specific env->irq_input_state. */
  128 + if (run->ready_for_interrupt_injection &&
  129 + (env->interrupt_request & CPU_INTERRUPT_HARD) &&
  130 + (env->irq_input_state & (1<<PPC40x_INPUT_INT)))
  131 + {
  132 + /* For now KVM disregards the 'irq' argument. However, in the
  133 + * future KVM could cache it in-kernel to avoid a heavyweight exit
  134 + * when reading the UIC.
  135 + */
  136 + irq = -1U;
  137 +
  138 + dprintf("injected interrupt %d\n", irq);
  139 + r = kvm_vcpu_ioctl(env, KVM_INTERRUPT, &irq);
  140 + if (r < 0)
  141 + printf("cpu %d fail inject %x\n", env->cpu_index, irq);
  142 + }
  143 +
  144 + /* We don't know if there are more interrupts pending after this. However,
  145 + * the guest will return to userspace in the course of handling this one
  146 + * anyways, so we will get a chance to deliver the rest. */
  147 + return 0;
  148 +}
  149 +
  150 +int kvm_arch_post_run(CPUState *env, struct kvm_run *run)
  151 +{
  152 + return 0;
  153 +}
  154 +
  155 +static int kvmppc_handle_halt(CPUState *env)
  156 +{
  157 + if (!(env->interrupt_request & CPU_INTERRUPT_HARD) && (msr_ee)) {
  158 + env->halted = 1;
  159 + env->exception_index = EXCP_HLT;
  160 + }
  161 +
  162 + return 1;
  163 +}
  164 +
  165 +/* map dcr access to existing qemu dcr emulation */
  166 +static int kvmppc_handle_dcr_read(CPUState *env, uint32_t dcrn, uint32_t *data)
  167 +{
  168 + if (ppc_dcr_read(env->dcr_env, dcrn, data) < 0)
  169 + fprintf(stderr, "Read to unhandled DCR (0x%x)\n", dcrn);
  170 +
  171 + return 1;
  172 +}
  173 +
  174 +static int kvmppc_handle_dcr_write(CPUState *env, uint32_t dcrn, uint32_t data)
  175 +{
  176 + if (ppc_dcr_write(env->dcr_env, dcrn, data) < 0)
  177 + fprintf(stderr, "Write to unhandled DCR (0x%x)\n", dcrn);
  178 +
  179 + return 1;
  180 +}
  181 +
  182 +int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)
  183 +{
  184 + int ret = 0;
  185 +
  186 + switch (run->exit_reason) {
  187 + case KVM_EXIT_DCR:
  188 + if (run->dcr.is_write) {
  189 + dprintf("handle dcr write\n");
  190 + ret = kvmppc_handle_dcr_write(env, run->dcr.dcrn, run->dcr.data);
  191 + } else {
  192 + dprintf("handle dcr read\n");
  193 + ret = kvmppc_handle_dcr_read(env, run->dcr.dcrn, &run->dcr.data);
  194 + }
  195 + break;
  196 + case KVM_EXIT_HLT:
  197 + dprintf("handle halt\n");
  198 + ret = kvmppc_handle_halt(env);
  199 + break;
  200 + }
  201 +
  202 + return ret;
  203 +}
  204 +
target-ppc/kvm_ppc.c 0 → 100644
  1 +/*
  2 + * PowerPC KVM support
  3 + *
  4 + * Copyright IBM Corp. 2008
  5 + *
  6 + * Authors:
  7 + * Hollis Blanchard <hollisb@us.ibm.com>
  8 + *
  9 + * This work is licensed under the terms of the GNU GPL, version 2 or later.
  10 + * See the COPYING file in the top-level directory.
  11 + *
  12 + */
  13 +
  14 +#include "qemu-common.h"
  15 +#include "qemu-timer.h"
  16 +#include "kvm_ppc.h"
  17 +#include "device_tree.h"
  18 +
  19 +#define PROC_DEVTREE_PATH "/proc/device-tree"
  20 +
  21 +static QEMUTimer *kvmppc_timer;
  22 +static unsigned int kvmppc_timer_rate;
  23 +
  24 +#ifdef HAVE_FDT
  25 +static int kvmppc_read_host_property(const char *node_path, const char *prop,
  26 + void *val, size_t len)
  27 +{
  28 + char *path;
  29 + FILE *f;
  30 + int ret;
  31 + int pathlen;
  32 +
  33 + pathlen = snprintf(NULL, 0, "%s/%s/%s", PROC_DEVTREE_PATH, node_path, prop)
  34 + + 1;
  35 + path = qemu_malloc(pathlen);
  36 + if (path == NULL) {
  37 + ret = -ENOMEM;
  38 + goto out;
  39 + }
  40 +
  41 + snprintf(path, pathlen, "%s/%s/%s", PROC_DEVTREE_PATH, node_path, prop);
  42 +
  43 + f = fopen(path, "rb");
  44 + if (f == NULL) {
  45 + ret = errno;
  46 + goto free;
  47 + }
  48 +
  49 + len = fread(val, len, 1, f);
  50 + if (len != 1) {
  51 + ret = ferror(f);
  52 + goto close;
  53 + }
  54 +
  55 +close:
  56 + fclose(f);
  57 +free:
  58 + free(path);
  59 +out:
  60 + return ret;
  61 +}
  62 +
  63 +static int kvmppc_copy_host_cell(void *fdt, const char *node, const char *prop)
  64 +{
  65 + uint32_t cell;
  66 + int ret;
  67 +
  68 + ret = kvmppc_read_host_property(node, prop, &cell, sizeof(cell));
  69 + if (ret < 0) {
  70 + fprintf(stderr, "couldn't read host %s/%s\n", node, prop);
  71 + goto out;
  72 + }
  73 +
  74 + ret = qemu_devtree_setprop_cell(fdt, node, prop, cell);
  75 + if (ret < 0) {
  76 + fprintf(stderr, "couldn't set guest %s/%s\n", node, prop);
  77 + goto out;
  78 + }
  79 +
  80 +out:
  81 + return ret;
  82 +}
  83 +
  84 +void kvmppc_fdt_update(void *fdt)
  85 +{
  86 + /* Copy data from the host device tree into the guest. Since the guest can
  87 + * directly access the timebase without host involvement, we must expose
  88 + * the correct frequencies. */
  89 + kvmppc_copy_host_cell(fdt, "/cpus/cpu@0", "clock-frequency");
  90 + kvmppc_copy_host_cell(fdt, "/cpus/cpu@0", "timebase-frequency");
  91 +}
  92 +#endif
  93 +
  94 +static void kvmppc_timer_hack(void *opaque)
  95 +{
  96 + qemu_service_io();
  97 + qemu_mod_timer(kvmppc_timer, qemu_get_clock(vm_clock) + kvmppc_timer_rate);
  98 +}
  99 +
  100 +void kvmppc_init(void)
  101 +{
  102 + /* XXX The only reason KVM yields control back to qemu is device IO. Since
  103 + * an idle guest does no IO, qemu's device model will never get a chance to
  104 + * run. So, until Qemu gains IO threads, we create this timer to ensure
  105 + * that the device model gets a chance to run. */
  106 + kvmppc_timer_rate = ticks_per_sec / 10;
  107 + kvmppc_timer = qemu_new_timer(vm_clock, &kvmppc_timer_hack, NULL);
  108 + qemu_mod_timer(kvmppc_timer, qemu_get_clock(vm_clock) + kvmppc_timer_rate);
  109 +}
  110 +
target-ppc/kvm_ppc.h 0 → 100644
  1 +/*
  2 + * Copyright 2008 IBM Corporation.
  3 + * Authors: Hollis Blanchard <hollisb@us.ibm.com>
  4 + *
  5 + * This work is licensed under the GNU GPL license version 2 or later.
  6 + *
  7 + */
  8 +
  9 +#ifndef __KVM_PPC_H__
  10 +#define __KVM_PPC_H__
  11 +
  12 +void kvmppc_init(void);
  13 +void kvmppc_fdt_update(void *fdt);
  14 +
  15 +#endif /* __KVM_PPC_H__ */