--- target-mips/kvm.c | 292 +++++++++++++++++++++++++++++++++++++++++++++++++ target-mips/kvm_mips.h | 21 ++++ 2 files changed, 313 insertions(+) create mode 100644 target-mips/kvm.c create mode 100644 target-mips/kvm_mips.h diff --git a/target-mips/kvm.c b/target-mips/kvm.c new file mode 100644 index 0000000..7c01c76 --- /dev/null +++ b/target-mips/kvm.c @@ -0,0 +1,292 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * KVM/MIPS: MIPS specific KVM APIs + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + * Authors: Sanjay Lal <sanjayl@xxxxxxxxxxx> +*/ + +#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/sysemu.h" +#include "sysemu/kvm.h" +#include "cpu.h" +#include "sysemu/cpus.h" +#include "kvm_mips.h" + +//#define DEBUG_KVM + +#ifdef DEBUG_KVM +#define dprintf(fmt, ...) \ + do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) +#else +#define dprintf(fmt, ...) \ + do { } while (0) +#endif + +extern int64_t g_kernel_entry; + + +const KVMCapabilityInfo kvm_arch_required_capabilities[] = { + KVM_CAP_LAST_INFO +}; + +unsigned long kvm_arch_vcpu_id(CPUState *cpu) +{ + return cpu->cpu_index; +} + +int kvm_arch_init(KVMState *s) +{ + dprintf("%s\n", __func__); + return 0; +} + +int kvm_arch_init_vcpu(CPUState *env) +{ + int ret = 0; + dprintf("%s\n", __func__); + return ret; +} + +void kvm_arch_reset_vcpu(CPUState *env) +{ + dprintf("%s\n", __func__); +#ifdef notyet + int ret; + + ret = kvm_vcpu_ioctl(env, KVM_NMI); + if (ret < 0) { + fprintf(stderr, "KVM: injection failed, NMI lost (%s)\n", + strerror(-ret)); + } +#endif +} + +int kvm_arch_put_registers(CPUState *cs, int level) +{ + MIPSCPU *cpu = MIPS_CPU(cs); + CPUMIPSState *env = &cpu->env; + struct kvm_regs regs; + int ret; + int i; + + /* Get the current register set as KVM seems it */ + ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, ®s); + if (ret < 0) + return ret; + + /* Now set the registers based on QEMU's view of things */ + for (i = 0;i < 32; i++) + regs.gprs[i] = env->active_tc.gpr[i]; + + regs.hi = env->active_tc.HI[0]; + regs.lo = env->active_tc.LO[0]; + regs.pc = env->active_tc.PC; + + regs.cp0reg[MIPS_CP0_TLB_INDEX][0] = env->CP0_Index; + regs.cp0reg[MIPS_CP0_TLB_CONTEXT][0] = env->CP0_Context; + regs.cp0reg[MIPS_CP0_BAD_VADDR][0] = env->CP0_BadVAddr; + regs.cp0reg[MIPS_CP0_TLB_HI][0] = env->CP0_EntryHi; + regs.cp0reg[MIPS_CP0_EXC_PC][0] = env->CP0_EPC; + + regs.cp0reg[MIPS_CP0_STATUS][0] = env->CP0_Status; + regs.cp0reg[MIPS_CP0_CAUSE][0] = env->CP0_Cause; + regs.cp0reg[MIPS_CP0_TLB_PG_MASK][0] = env->CP0_PageMask; + regs.cp0reg[MIPS_CP0_TLB_WIRED][0] = env->CP0_Wired; + + regs.cp0reg[MIPS_CP0_ERROR_PC][0] = env->CP0_ErrorEPC; + + ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, ®s); + + if (ret < 0) { + return ret; + } + + return ret; +} + +int kvm_arch_get_registers(CPUState *cs) +{ + MIPSCPU *cpu = MIPS_CPU(cs); + CPUMIPSState *env = &cpu->env; + int ret = 0; + struct kvm_regs regs; + int i; + + /* Get the current register set as KVM seems it */ + ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, ®s); + + if (ret < 0) + return ret; + + for (i = 0;i < 32; i++) + env->active_tc.gpr[i] = regs.gprs[i]; + + env->active_tc.HI[0] = regs.hi; + env->active_tc.LO[0] = regs.lo; + env->active_tc.PC = regs.pc; + + env->CP0_Index = regs.cp0reg[MIPS_CP0_TLB_INDEX][0]; + env->CP0_Context = regs.cp0reg[MIPS_CP0_TLB_CONTEXT][0]; + env->CP0_BadVAddr = regs.cp0reg[MIPS_CP0_BAD_VADDR][0]; + env->CP0_EntryHi = regs.cp0reg[MIPS_CP0_TLB_HI][0]; + env->CP0_EPC = regs.cp0reg[MIPS_CP0_EXC_PC][0]; + + env->CP0_Status = regs.cp0reg[MIPS_CP0_STATUS][0]; + env->CP0_Cause = regs.cp0reg[MIPS_CP0_CAUSE][0]; + env->CP0_PageMask = regs.cp0reg[MIPS_CP0_TLB_PG_MASK][0]; + env->CP0_Wired = regs.cp0reg[MIPS_CP0_TLB_WIRED][0]; + env->CP0_ErrorEPC= regs.cp0reg[MIPS_CP0_ERROR_PC][0]; + + return ret; +} + +int kvm_arch_insert_sw_breakpoint(CPUState *env, struct kvm_sw_breakpoint *bp) +{ + dprintf("%s\n", __func__); + return 0; +} + +int kvm_arch_remove_sw_breakpoint(CPUState *env, struct kvm_sw_breakpoint *bp) +{ + dprintf("%s\n", __func__); + return 0; +} + +static inline int cpu_mips_io_interrupts_pending(CPUArchState *env) +{ + dprintf("%s: %#x\n", __func__, env->CP0_Cause & (1 << (2 + CP0Ca_IP))); + return(env->CP0_Cause & (0x1 << (2 + CP0Ca_IP))); +} + + +void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) +{ + MIPSCPU *cpu = MIPS_CPU(cs); + CPUMIPSState *env = &cpu->env; + int r; + struct kvm_mips_interrupt intr; + + if (env->interrupt_request & CPU_INTERRUPT_HARD && + cpu_mips_io_interrupts_pending(env)) + { + intr.cpu = -1; + intr.irq = 2; + r = kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &intr); + if (r < 0) + printf("cpu %d fail inject %x\n", cs->cpu_index, intr.irq); + } + /* If we have an interrupt but the guest is not ready to receive an + * interrupt, request an interrupt window exit. This will + * cause a return to userspace as soon as the guest is ready to + * receive interrupts. + */ + if ((env->interrupt_request & CPU_INTERRUPT_HARD)) { + run->request_interrupt_window = 1; + } else { + run->request_interrupt_window = 0; + } +} + +void kvm_arch_post_run(CPUState *env, struct kvm_run *run) +{ + dprintf("%s\n", __func__); +} + +int kvm_arch_process_async_events(CPUState *cs) +{ + MIPSCPU *cpu = MIPS_CPU(cs); + CPUMIPSState *env = &cpu->env; + + dprintf("%s\n", __func__); + return env->halted; +} + +int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run) +{ + int ret; + + printf("kvm_arch_handle_exit()\n"); + switch (run->exit_reason) { + default: + fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason); + ret = -1; + break; + } + + return ret; +} + +bool kvm_arch_stop_on_emulation_error(CPUState *env) +{ + dprintf("%s\n", __func__); + return true; +} + +int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr) +{ + dprintf("%s\n", __func__); + return 1; +} + +int kvm_arch_on_sigbus(int code, void *addr) +{ + dprintf("%s\n", __func__); + return 1; +} + +int kvm_mips_set_interrupt(CPUMIPSState *env, int irq, int level) +{ + CPUState *cs = ENV_GET_CPU(env); + struct kvm_mips_interrupt intr; + + if (!kvm_enabled()) { + return 0; + } + + intr.cpu = -1; + + if (level) + intr.irq = irq; + else + intr.irq = -irq; + + kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &intr); + + return 0; +} + +int kvm_mips_set_ipi_interrupt(CPUArchState *env, int irq, int level) +{ + CPUState *cs = ENV_GET_CPU(cpu_single_env); + struct kvm_mips_interrupt intr; + + if (!kvm_enabled()) { + return 0; + } + + intr.cpu = cs->cpu_index; + + if (level) + intr.irq = irq; + else + intr.irq = -irq; + + dprintf("%s: CPU %d, IRQ: %d\n", __func__, intr.cpu, intr.irq); + + kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &intr); + + return 0; +} + + diff --git a/target-mips/kvm_mips.h b/target-mips/kvm_mips.h new file mode 100644 index 0000000..20c3f8c --- /dev/null +++ b/target-mips/kvm_mips.h @@ -0,0 +1,21 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * KVM/MIPS: MIPS specific KVM APIs + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + * Authors: Sanjay Lal <sanjayl@xxxxxxxxxxx> +*/ + +#ifndef __KVM_MIPS_H__ +#define __KVM_MIPS_H__ + + +int kvm_mips_set_interrupt(CPUMIPSState *env, int irq, int level); + +int kvm_mips_set_ipi_interrupt(CPUArchState *env, int irq, int level); + + +#endif /* __KVM_MIPS_H__ */ -- 1.7.11.3 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html