Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 351181
b: refs/heads/master
c: 5b3e5e5
h: refs/heads/master
i:
  351179: 44aa3da
v: v3
  • Loading branch information
Christoffer Dall committed Jan 23, 2013
1 parent a86ed24 commit 2fa4e75
Show file tree
Hide file tree
Showing 12 changed files with 1,161 additions and 5 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: f7ed45be3ba524e06a6d933f0517dc7ad2d06703
refs/heads/master: 5b3e5e5bf230f56309706dfc05fc0cb173cc83aa
11 changes: 11 additions & 0 deletions trunk/arch/arm/include/asm/kvm_arm.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@
HCR_SWIO | HCR_TIDCP)
#define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)

/* System Control Register (SCTLR) bits */
#define SCTLR_TE (1 << 30)
#define SCTLR_EE (1 << 25)
#define SCTLR_V (1 << 13)

/* Hyp System Control Register (HSCTLR) bits */
#define HSCTLR_TE (1 << 30)
#define HSCTLR_EE (1 << 25)
Expand Down Expand Up @@ -171,6 +176,10 @@
#define HSR_FSC (0x3f)
#define HSR_FSC_TYPE (0x3c)
#define HSR_WNR (1 << 6)
#define HSR_CV_SHIFT (24)
#define HSR_CV (1U << HSR_CV_SHIFT)
#define HSR_COND_SHIFT (20)
#define HSR_COND (0xfU << HSR_COND_SHIFT)

#define FSC_FAULT (0x04)
#define FSC_PERM (0x0c)
Expand All @@ -197,4 +206,6 @@
#define HSR_EC_DABT (0x24)
#define HSR_EC_DABT_HYP (0x25)

#define HSR_HVC_IMM_MASK ((1UL << 16) - 1)

#endif /* __ARM_KVM_ARM_H__ */
14 changes: 14 additions & 0 deletions trunk/arch/arm/include/asm/kvm_coproc.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,18 @@

void kvm_reset_coprocs(struct kvm_vcpu *vcpu);

struct kvm_coproc_target_table {
unsigned target;
const struct coproc_reg *table;
size_t num;
};
void kvm_register_target_coproc_table(struct kvm_coproc_target_table *table);

int kvm_handle_cp10_id(struct kvm_vcpu *vcpu, struct kvm_run *run);
int kvm_handle_cp_0_13_access(struct kvm_vcpu *vcpu, struct kvm_run *run);
int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run);
int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run);
int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run);
int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run);
void kvm_coproc_table_init(void);
#endif /* __ARM_KVM_COPROC_H__ */
6 changes: 6 additions & 0 deletions trunk/arch/arm/include/asm/kvm_emulate.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@
u32 *vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num);
u32 *vcpu_spsr(struct kvm_vcpu *vcpu);

int kvm_handle_wfi(struct kvm_vcpu *vcpu, struct kvm_run *run);
void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr);
void kvm_inject_undefined(struct kvm_vcpu *vcpu);
void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr);
void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr);

static inline u32 *vcpu_pc(struct kvm_vcpu *vcpu)
{
return (u32 *)&vcpu->arch.regs.usr_regs.ARM_pc;
Expand Down
4 changes: 4 additions & 0 deletions trunk/arch/arm/include/asm/kvm_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ struct kvm_vcpu_arch {
* Anything that is not used directly from assembly code goes
* here.
*/
/* dcache set/way operation pending */
int last_pcpu;
cpumask_t require_dcache_flush;

/* Interrupt related fields */
u32 irq_lines; /* IRQ and FIQ levels */

Expand Down
2 changes: 1 addition & 1 deletion trunk/arch/arm/kvm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ kvm-arm-y = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o)

obj-y += kvm-arm.o init.o interrupts.o
obj-y += arm.o guest.o mmu.o emulate.o reset.o
obj-y += coproc.o
obj-y += coproc.o coproc_a15.o
169 changes: 166 additions & 3 deletions trunk/arch/arm/kvm/arm.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,14 @@
#include <asm/mman.h>
#include <asm/cputype.h>
#include <asm/tlbflush.h>
#include <asm/cacheflush.h>
#include <asm/virt.h>
#include <asm/kvm_arm.h>
#include <asm/kvm_asm.h>
#include <asm/kvm_mmu.h>
#include <asm/kvm_emulate.h>
#include <asm/kvm_coproc.h>
#include <asm/opcodes.h>

#ifdef REQUIRES_VIRT
__asm__(".arch_extension virt");
Expand Down Expand Up @@ -294,6 +297,15 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
{
vcpu->cpu = cpu;
vcpu->arch.vfp_host = this_cpu_ptr(kvm_host_vfp_state);

/*
* Check whether this vcpu requires the cache to be flushed on
* this physical CPU. This is a consequence of doing dcache
* operations by set/way on this vcpu. We do it here to be in
* a non-preemptible section.
*/
if (cpumask_test_and_clear_cpu(cpu, &vcpu->arch.require_dcache_flush))
flush_cache_all(); /* We'd really want v7_flush_dcache_all() */
}

void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
Expand All @@ -319,9 +331,16 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
return -EINVAL;
}

/**
* kvm_arch_vcpu_runnable - determine if the vcpu can be scheduled
* @v: The VCPU pointer
*
* If the guest CPU is not waiting for interrupts or an interrupt line is
* asserted, the CPU is by definition runnable.
*/
int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
{
return 0;
return !!v->arch.irq_lines;
}

/* Just ensure a guest exit from a particular CPU */
Expand Down Expand Up @@ -411,15 +430,157 @@ static void update_vttbr(struct kvm *kvm)
spin_unlock(&kvm_vmid_lock);
}

static int handle_svc_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
/* SVC called from Hyp mode should never get here */
kvm_debug("SVC called from Hyp mode shouldn't go here\n");
BUG();
return -EINVAL; /* Squash warning */
}

static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
trace_kvm_hvc(*vcpu_pc(vcpu), *vcpu_reg(vcpu, 0),
vcpu->arch.hsr & HSR_HVC_IMM_MASK);

kvm_inject_undefined(vcpu);
return 1;
}

static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
/* We don't support SMC; don't do that. */
kvm_debug("smc: at %08x", *vcpu_pc(vcpu));
kvm_inject_undefined(vcpu);
return 1;
}

static int handle_pabt_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
/* The hypervisor should never cause aborts */
kvm_err("Prefetch Abort taken from Hyp mode at %#08x (HSR: %#08x)\n",
vcpu->arch.hxfar, vcpu->arch.hsr);
return -EFAULT;
}

static int handle_dabt_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
/* This is either an error in the ws. code or an external abort */
kvm_err("Data Abort taken from Hyp mode at %#08x (HSR: %#08x)\n",
vcpu->arch.hxfar, vcpu->arch.hsr);
return -EFAULT;
}

typedef int (*exit_handle_fn)(struct kvm_vcpu *, struct kvm_run *);
static exit_handle_fn arm_exit_handlers[] = {
[HSR_EC_WFI] = kvm_handle_wfi,
[HSR_EC_CP15_32] = kvm_handle_cp15_32,
[HSR_EC_CP15_64] = kvm_handle_cp15_64,
[HSR_EC_CP14_MR] = kvm_handle_cp14_access,
[HSR_EC_CP14_LS] = kvm_handle_cp14_load_store,
[HSR_EC_CP14_64] = kvm_handle_cp14_access,
[HSR_EC_CP_0_13] = kvm_handle_cp_0_13_access,
[HSR_EC_CP10_ID] = kvm_handle_cp10_id,
[HSR_EC_SVC_HYP] = handle_svc_hyp,
[HSR_EC_HVC] = handle_hvc,
[HSR_EC_SMC] = handle_smc,
[HSR_EC_IABT] = kvm_handle_guest_abort,
[HSR_EC_IABT_HYP] = handle_pabt_hyp,
[HSR_EC_DABT] = kvm_handle_guest_abort,
[HSR_EC_DABT_HYP] = handle_dabt_hyp,
};

/*
* A conditional instruction is allowed to trap, even though it
* wouldn't be executed. So let's re-implement the hardware, in
* software!
*/
static bool kvm_condition_valid(struct kvm_vcpu *vcpu)
{
unsigned long cpsr, cond, insn;

/*
* Exception Code 0 can only happen if we set HCR.TGE to 1, to
* catch undefined instructions, and then we won't get past
* the arm_exit_handlers test anyway.
*/
BUG_ON(((vcpu->arch.hsr & HSR_EC) >> HSR_EC_SHIFT) == 0);

/* Top two bits non-zero? Unconditional. */
if (vcpu->arch.hsr >> 30)
return true;

cpsr = *vcpu_cpsr(vcpu);

/* Is condition field valid? */
if ((vcpu->arch.hsr & HSR_CV) >> HSR_CV_SHIFT)
cond = (vcpu->arch.hsr & HSR_COND) >> HSR_COND_SHIFT;
else {
/* This can happen in Thumb mode: examine IT state. */
unsigned long it;

it = ((cpsr >> 8) & 0xFC) | ((cpsr >> 25) & 0x3);

/* it == 0 => unconditional. */
if (it == 0)
return true;

/* The cond for this insn works out as the top 4 bits. */
cond = (it >> 4);
}

/* Shift makes it look like an ARM-mode instruction */
insn = cond << 28;
return arm_check_condition(insn, cpsr) != ARM_OPCODE_CONDTEST_FAIL;
}

/*
* Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on
* proper exit to QEMU.
*/
static int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
int exception_index)
{
run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
return 0;
unsigned long hsr_ec;

switch (exception_index) {
case ARM_EXCEPTION_IRQ:
return 1;
case ARM_EXCEPTION_UNDEFINED:
kvm_err("Undefined exception in Hyp mode at: %#08x\n",
vcpu->arch.hyp_pc);
BUG();
panic("KVM: Hypervisor undefined exception!\n");
case ARM_EXCEPTION_DATA_ABORT:
case ARM_EXCEPTION_PREF_ABORT:
case ARM_EXCEPTION_HVC:
hsr_ec = (vcpu->arch.hsr & HSR_EC) >> HSR_EC_SHIFT;

if (hsr_ec >= ARRAY_SIZE(arm_exit_handlers)
|| !arm_exit_handlers[hsr_ec]) {
kvm_err("Unkown exception class: %#08lx, "
"hsr: %#08x\n", hsr_ec,
(unsigned int)vcpu->arch.hsr);
BUG();
}

/*
* See ARM ARM B1.14.1: "Hyp traps on instructions
* that fail their condition code check"
*/
if (!kvm_condition_valid(vcpu)) {
bool is_wide = vcpu->arch.hsr & HSR_IL;
kvm_skip_instr(vcpu, is_wide);
return 1;
}

return arm_exit_handlers[hsr_ec](vcpu, run);
default:
kvm_pr_unimpl("Unsupported exception type: %d",
exception_index);
run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
return 0;
}
}

static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
Expand Down Expand Up @@ -493,6 +654,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
ret = kvm_call_hyp(__kvm_vcpu_run, vcpu);

vcpu->mode = OUTSIDE_GUEST_MODE;
vcpu->arch.last_pcpu = smp_processor_id();
kvm_guest_exit();
trace_kvm_exit(*vcpu_pc(vcpu));
/*
Expand Down Expand Up @@ -801,6 +963,7 @@ int kvm_arch_init(void *opaque)
if (err)
goto out_err;

kvm_coproc_table_init();
return 0;
out_err:
return err;
Expand Down
Loading

0 comments on commit 2fa4e75

Please sign in to comment.