diff options
author | Christoffer Dall <cdall@cs.columbia.edu> | 2011-12-01 21:28:16 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2012-01-30 14:23:40 +0000 |
commit | f3feba70a17bd02cad205b6773ce146e9f111013 (patch) | |
tree | 788414f5aa7c6bc38aec320ac6e65aaa1c6b1ad3 | |
parent | 9679d3dc5dfad47b03d89b2d973da70f623ff715 (diff) |
ARM: KVM: Add support for KVM on ARM architectures
This patch represents work in progress on adding support
for KVM on ARM architectures. Note that it is highly
experimental and is not enabled by default.
TODO: this is Christoffer's patch, but with the configure
script changes redone by me. Needs signed-off-by.
-rwxr-xr-x | configure | 5 | ||||
-rw-r--r-- | hw/arm_pic.c | 4 | ||||
-rw-r--r-- | kvm.h | 2 | ||||
-rw-r--r-- | target-arm/kvm.c | 192 |
4 files changed, 202 insertions, 1 deletions
@@ -3313,6 +3313,9 @@ done if test "$linux" = "yes" ; then mkdir -p linux-headers case "$cpu" in + arm) + symlink $source_path/linux-headers/asm-arm linux-headers/asm + ;; i386|x86_64) symlink $source_path/linux-headers/asm-x86 linux-headers/asm ;; @@ -3566,7 +3569,7 @@ case "$target_arch2" in echo "CONFIG_NO_XEN=y" >> $config_target_mak esac case "$target_arch2" in - i386|x86_64|ppcemb|ppc|ppc64|s390x) + i386|x86_64|ppcemb|ppc|ppc64|s390x|arm) # Make sure the target and host cpus are compatible if test "$kvm" = "yes" -a "$target_softmmu" = "yes" -a \ \( "$target_arch2" = "$cpu" -o \ diff --git a/hw/arm_pic.c b/hw/arm_pic.c index a2e8a7330..51f65ae35 100644 --- a/hw/arm_pic.c +++ b/hw/arm_pic.c @@ -9,6 +9,7 @@ #include "hw.h" #include "arm-misc.h" +#include "kvm.h" /* Input 0 is IRQ and input 1 is FIQ. */ static void arm_pic_cpu_handler(void *opaque, int irq, int level) @@ -30,6 +31,9 @@ static void arm_pic_cpu_handler(void *opaque, int irq, int level) default: hw_error("arm_pic_cpu_handler: Bad interrupt line %d\n", irq); } + + if (kvm_enabled()) + kvm_arch_interrupt(env, irq, level); } qemu_irq *arm_pic_init_cpu(CPUState *env) @@ -125,6 +125,8 @@ int kvm_arch_init_vcpu(CPUState *env); void kvm_arch_reset_vcpu(CPUState *env); +int kvm_arch_interrupt(CPUState *env, int irq, int level); + int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr); int kvm_arch_on_sigbus(int code, void *addr); diff --git a/target-arm/kvm.c b/target-arm/kvm.c new file mode 100644 index 000000000..6ea96e56d --- /dev/null +++ b/target-arm/kvm.c @@ -0,0 +1,192 @@ +/* + * ARM implementation of KVM hooks + * + * Copyright Christoffer Dall 2009-2010 + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/mman.h> + +#include <linux/kvm.h> + +#include "qemu-common.h" +#include "qemu-timer.h" +#include "sysemu.h" +#include "kvm.h" +#include "cpu.h" +#include "device_tree.h" +#include "hw/arm-misc.h" + +const KVMCapabilityInfo kvm_arch_required_capabilities[] = { + KVM_CAP_LAST_INFO +}; + +int kvm_arch_init(KVMState *s) +{ + return 0; +} + +int kvm_arch_init_vcpu(CPUState *env) +{ + return 0; +} + +int kvm_arch_put_registers(CPUState *env, int level) +{ + struct kvm_regs regs; + int ret; + + ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, ®s); + if (ret < 0) + return ret; + + memcpy(regs.regs0_7, env->regs, sizeof(uint32_t) * 8); + memcpy(regs.usr_regs8_12, env->usr_regs, sizeof(uint32_t) * 5); + memcpy(regs.fiq_regs8_12, env->fiq_regs, sizeof(uint32_t) * 5); + regs.reg13[MODE_FIQ] = env->banked_r13[5]; + regs.reg13[MODE_IRQ] = env->banked_r13[4]; + regs.reg13[MODE_SVC] = env->banked_r13[1]; + regs.reg13[MODE_ABT] = env->banked_r13[2]; + regs.reg13[MODE_UND] = env->banked_r13[3]; + regs.reg13[MODE_USR] = env->banked_r13[0]; + regs.reg14[MODE_FIQ] = env->banked_r14[5]; + regs.reg14[MODE_IRQ] = env->banked_r14[4]; + regs.reg14[MODE_SVC] = env->banked_r14[1]; + regs.reg14[MODE_ABT] = env->banked_r14[2]; + regs.reg14[MODE_UND] = env->banked_r14[3]; + regs.reg14[MODE_USR] = env->banked_r14[0]; + regs.reg15 = env->regs[15]; + regs.cpsr = cpsr_read(env); + regs.spsr[MODE_FIQ] = env->banked_spsr[5]; + regs.spsr[MODE_IRQ] = env->banked_spsr[4]; + regs.spsr[MODE_SVC] = env->banked_spsr[1]; + regs.spsr[MODE_ABT] = env->banked_spsr[2]; + regs.spsr[MODE_UND] = env->banked_spsr[3]; + + regs.cp15.c0_midr = env->cp15.c0_cpuid; + regs.cp15.c1_sys = env->cp15.c1_sys; + + ret = kvm_vcpu_ioctl(env, KVM_SET_REGS, ®s); + + return ret; +} + +int kvm_arch_get_registers(CPUState *env) +{ + struct kvm_regs regs; + int32_t ret; + + ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, ®s); + if (ret < 0) + return ret; + memcpy(env->regs, regs.regs0_7, sizeof(uint32_t) * 8); + memcpy(env->usr_regs, regs.usr_regs8_12, sizeof(uint32_t) * 5); + memcpy(env->fiq_regs, regs.fiq_regs8_12, sizeof(uint32_t) * 5); + env->banked_r13[5] = regs.reg13[MODE_FIQ]; + env->banked_r13[4] = regs.reg13[MODE_IRQ]; + env->banked_r13[1] = regs.reg13[MODE_SVC]; + env->banked_r13[2] = regs.reg13[MODE_ABT]; + env->banked_r13[3] = regs.reg13[MODE_UND]; + env->banked_r13[0] = regs.reg13[MODE_USR]; + env->banked_r14[5] = regs.reg14[MODE_FIQ]; + env->banked_r14[4] = regs.reg14[MODE_IRQ]; + env->banked_r14[1] = regs.reg14[MODE_SVC]; + env->banked_r14[2] = regs.reg14[MODE_ABT]; + env->banked_r14[3] = regs.reg14[MODE_UND]; + env->banked_r14[0] = regs.reg14[MODE_USR]; + env->regs[15] = regs.reg15; + cpsr_write(env, regs.cpsr, 0xFFFFFFFF); + env->banked_spsr[5] = regs.spsr[MODE_FIQ]; + env->banked_spsr[4] = regs.spsr[MODE_IRQ]; + env->banked_spsr[1] = regs.spsr[MODE_SVC]; + env->banked_spsr[2] = regs.spsr[MODE_ABT]; + env->banked_spsr[3] = regs.spsr[MODE_UND]; + + //env->cp15.c0_cpuid = regs.cp15.c0_midr; + env->cp15.c1_sys = regs.cp15.c1_sys; + env->cp15.c2_base0 = regs.cp15.c2_base0; + env->cp15.c2_base1 = regs.cp15.c2_base1; + env->cp15.c3 = regs.cp15.c3_dacr; + + return 0; +} + +#define KVM_ARM_EXCEPTION_IRQ 0x02 +#define KVM_ARM_EXCEPTION_FIQ 0x01 +int kvm_arch_interrupt(CPUState *env, int irq, int level) +{ + struct kvm_irq_level irq_level; + int vcpu_idx = 0; /* Assume non-SMP for now */ + KVMState *s = kvm_state; + int ret; + + if (level) + irq_level.level = 1; + else + irq_level.level = 0; + + switch (irq) { + case ARM_PIC_CPU_IRQ: + irq_level.irq = KVM_ARM_IRQ_LINE * vcpu_idx; + break; + case ARM_PIC_CPU_FIQ: + irq_level.irq = (KVM_ARM_FIQ_LINE * vcpu_idx) + 1; + break; + default: + fprintf(stderr, "unsupported ARM irq injection\n"); + abort(); + } + + ret = kvm_vm_ioctl(s, KVM_IRQ_LINE, &irq_level); + if (ret) { + fprintf(stderr, "kvm_vm_ioctl(s, KVM_IRQ_LINE, &irq_level) failed\n"); + abort(); + } + + return 0; +} + +void kvm_arch_pre_run(CPUState *env, struct kvm_run *run) +{ +} + +void kvm_arch_post_run(CPUState *env, struct kvm_run *run) +{ +} + +int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run) +{ + int ret = 0; + + return ret; +} + +void kvm_arch_reset_vcpu(CPUState *env) +{ +} + +bool kvm_arch_stop_on_emulation_error(CPUState *env) +{ + return true; +} + +int kvm_arch_process_async_events(CPUState *env) +{ + return 0; +} + +int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr) +{ + return 1; +} + +int kvm_arch_on_sigbus(int code, void *addr) +{ + return 1; +} |