Merge git://git.linaro.org/people/cdall/linux-kvm-arm.git tags/kvm-arm-3.11 into queue
KVM/ARM pull request for 3.11 merge window * tag 'kvm-arm-3.11' of git://git.linaro.org/people/cdall/linux-kvm-arm.git: ARM: kvm: don't include drivers/virtio/Kconfig Update MAINTAINERS: KVM/ARM work now funded by Linaro arm/kvm: Cleanup KVM_ARM_MAX_VCPUS logic ARM: KVM: clear exclusive monitor on all exception returns ARM: KVM: add missing dsb before invalidating Stage-2 TLBs ARM: KVM: perform save/restore of PAR ARM: KVM: get rid of S2_PGD_SIZE ARM: KVM: don't special case PC when doing an MMIO ARM: KVM: use phys_addr_t instead of unsigned long long for HYP PGDs ARM: KVM: remove dead prototype for __kvm_tlb_flush_vmid ARM: KVM: Don't handle PSCI calls via SMC ARM: KVM: Allow host virt timer irq to be different from guest timer virt irq
This commit is contained in:
commit
96f7edf9a5
|
@ -4692,10 +4692,10 @@ F: arch/s390/kvm/
|
||||||
F: drivers/s390/kvm/
|
F: drivers/s390/kvm/
|
||||||
|
|
||||||
KERNEL VIRTUAL MACHINE (KVM) FOR ARM
|
KERNEL VIRTUAL MACHINE (KVM) FOR ARM
|
||||||
M: Christoffer Dall <cdall@cs.columbia.edu>
|
M: Christoffer Dall <christoffer.dall@linaro.org>
|
||||||
L: kvmarm@lists.cs.columbia.edu
|
L: kvmarm@lists.cs.columbia.edu
|
||||||
W: http://systems.cs.columbia.edu/projects/kvm-arm
|
W: http://systems.cs.columbia.edu/projects/kvm-arm
|
||||||
S: Maintained
|
S: Supported
|
||||||
F: arch/arm/include/uapi/asm/kvm*
|
F: arch/arm/include/uapi/asm/kvm*
|
||||||
F: arch/arm/include/asm/kvm*
|
F: arch/arm/include/asm/kvm*
|
||||||
F: arch/arm/kvm/
|
F: arch/arm/kvm/
|
||||||
|
|
|
@ -135,7 +135,6 @@
|
||||||
#define KVM_PHYS_MASK (KVM_PHYS_SIZE - 1ULL)
|
#define KVM_PHYS_MASK (KVM_PHYS_SIZE - 1ULL)
|
||||||
#define PTRS_PER_S2_PGD (1ULL << (KVM_PHYS_SHIFT - 30))
|
#define PTRS_PER_S2_PGD (1ULL << (KVM_PHYS_SHIFT - 30))
|
||||||
#define S2_PGD_ORDER get_order(PTRS_PER_S2_PGD * sizeof(pgd_t))
|
#define S2_PGD_ORDER get_order(PTRS_PER_S2_PGD * sizeof(pgd_t))
|
||||||
#define S2_PGD_SIZE (1 << S2_PGD_ORDER)
|
|
||||||
|
|
||||||
/* Virtualization Translation Control Register (VTCR) bits */
|
/* Virtualization Translation Control Register (VTCR) bits */
|
||||||
#define VTCR_SH0 (3 << 12)
|
#define VTCR_SH0 (3 << 12)
|
||||||
|
|
|
@ -37,16 +37,18 @@
|
||||||
#define c5_AIFSR 15 /* Auxilary Instrunction Fault Status R */
|
#define c5_AIFSR 15 /* Auxilary Instrunction Fault Status R */
|
||||||
#define c6_DFAR 16 /* Data Fault Address Register */
|
#define c6_DFAR 16 /* Data Fault Address Register */
|
||||||
#define c6_IFAR 17 /* Instruction Fault Address Register */
|
#define c6_IFAR 17 /* Instruction Fault Address Register */
|
||||||
#define c9_L2CTLR 18 /* Cortex A15 L2 Control Register */
|
#define c7_PAR 18 /* Physical Address Register */
|
||||||
#define c10_PRRR 19 /* Primary Region Remap Register */
|
#define c7_PAR_high 19 /* PAR top 32 bits */
|
||||||
#define c10_NMRR 20 /* Normal Memory Remap Register */
|
#define c9_L2CTLR 20 /* Cortex A15 L2 Control Register */
|
||||||
#define c12_VBAR 21 /* Vector Base Address Register */
|
#define c10_PRRR 21 /* Primary Region Remap Register */
|
||||||
#define c13_CID 22 /* Context ID Register */
|
#define c10_NMRR 22 /* Normal Memory Remap Register */
|
||||||
#define c13_TID_URW 23 /* Thread ID, User R/W */
|
#define c12_VBAR 23 /* Vector Base Address Register */
|
||||||
#define c13_TID_URO 24 /* Thread ID, User R/O */
|
#define c13_CID 24 /* Context ID Register */
|
||||||
#define c13_TID_PRIV 25 /* Thread ID, Privileged */
|
#define c13_TID_URW 25 /* Thread ID, User R/W */
|
||||||
#define c14_CNTKCTL 26 /* Timer Control Register (PL1) */
|
#define c13_TID_URO 26 /* Thread ID, User R/O */
|
||||||
#define NR_CP15_REGS 27 /* Number of regs (incl. invalid) */
|
#define c13_TID_PRIV 27 /* Thread ID, Privileged */
|
||||||
|
#define c14_CNTKCTL 28 /* Timer Control Register (PL1) */
|
||||||
|
#define NR_CP15_REGS 29 /* Number of regs (incl. invalid) */
|
||||||
|
|
||||||
#define ARM_EXCEPTION_RESET 0
|
#define ARM_EXCEPTION_RESET 0
|
||||||
#define ARM_EXCEPTION_UNDEFINED 1
|
#define ARM_EXCEPTION_UNDEFINED 1
|
||||||
|
@ -72,8 +74,6 @@ extern char __kvm_hyp_vector[];
|
||||||
extern char __kvm_hyp_code_start[];
|
extern char __kvm_hyp_code_start[];
|
||||||
extern char __kvm_hyp_code_end[];
|
extern char __kvm_hyp_code_end[];
|
||||||
|
|
||||||
extern void __kvm_tlb_flush_vmid(struct kvm *kvm);
|
|
||||||
|
|
||||||
extern void __kvm_flush_vm_context(void);
|
extern void __kvm_flush_vm_context(void);
|
||||||
extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
|
extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
|
||||||
|
|
||||||
|
|
|
@ -65,11 +65,6 @@ static inline bool vcpu_mode_priv(struct kvm_vcpu *vcpu)
|
||||||
return cpsr_mode > USR_MODE;;
|
return cpsr_mode > USR_MODE;;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool kvm_vcpu_reg_is_pc(struct kvm_vcpu *vcpu, int reg)
|
|
||||||
{
|
|
||||||
return reg == 15;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline u32 kvm_vcpu_get_hsr(struct kvm_vcpu *vcpu)
|
static inline u32 kvm_vcpu_get_hsr(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
return vcpu->arch.fault.hsr;
|
return vcpu->arch.fault.hsr;
|
||||||
|
|
|
@ -25,7 +25,12 @@
|
||||||
#include <asm/fpstate.h>
|
#include <asm/fpstate.h>
|
||||||
#include <kvm/arm_arch_timer.h>
|
#include <kvm/arm_arch_timer.h>
|
||||||
|
|
||||||
|
#if defined(CONFIG_KVM_ARM_MAX_VCPUS)
|
||||||
#define KVM_MAX_VCPUS CONFIG_KVM_ARM_MAX_VCPUS
|
#define KVM_MAX_VCPUS CONFIG_KVM_ARM_MAX_VCPUS
|
||||||
|
#else
|
||||||
|
#define KVM_MAX_VCPUS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#define KVM_USER_MEM_SLOTS 32
|
#define KVM_USER_MEM_SLOTS 32
|
||||||
#define KVM_PRIVATE_MEM_SLOTS 4
|
#define KVM_PRIVATE_MEM_SLOTS 4
|
||||||
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
|
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
|
||||||
|
@ -190,8 +195,8 @@ int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
|
||||||
int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
|
int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
|
||||||
int exception_index);
|
int exception_index);
|
||||||
|
|
||||||
static inline void __cpu_init_hyp_mode(unsigned long long boot_pgd_ptr,
|
static inline void __cpu_init_hyp_mode(phys_addr_t boot_pgd_ptr,
|
||||||
unsigned long long pgd_ptr,
|
phys_addr_t pgd_ptr,
|
||||||
unsigned long hyp_stack_ptr,
|
unsigned long hyp_stack_ptr,
|
||||||
unsigned long vector_ptr)
|
unsigned long vector_ptr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -41,9 +41,9 @@ config KVM_ARM_HOST
|
||||||
Provides host support for ARM processors.
|
Provides host support for ARM processors.
|
||||||
|
|
||||||
config KVM_ARM_MAX_VCPUS
|
config KVM_ARM_MAX_VCPUS
|
||||||
int "Number maximum supported virtual CPUs per VM" if KVM_ARM_HOST
|
int "Number maximum supported virtual CPUs per VM"
|
||||||
default 4 if KVM_ARM_HOST
|
depends on KVM_ARM_HOST
|
||||||
default 0
|
default 4
|
||||||
help
|
help
|
||||||
Static number of max supported virtual CPUs per VM.
|
Static number of max supported virtual CPUs per VM.
|
||||||
|
|
||||||
|
@ -67,6 +67,4 @@ config KVM_ARM_TIMER
|
||||||
---help---
|
---help---
|
||||||
Adds support for the Architected Timers in virtual machines
|
Adds support for the Architected Timers in virtual machines
|
||||||
|
|
||||||
source drivers/virtio/Kconfig
|
|
||||||
|
|
||||||
endif # VIRTUALIZATION
|
endif # VIRTUALIZATION
|
||||||
|
|
|
@ -789,8 +789,8 @@ long kvm_arch_vm_ioctl(struct file *filp,
|
||||||
|
|
||||||
static void cpu_init_hyp_mode(void *dummy)
|
static void cpu_init_hyp_mode(void *dummy)
|
||||||
{
|
{
|
||||||
unsigned long long boot_pgd_ptr;
|
phys_addr_t boot_pgd_ptr;
|
||||||
unsigned long long pgd_ptr;
|
phys_addr_t pgd_ptr;
|
||||||
unsigned long hyp_stack_ptr;
|
unsigned long hyp_stack_ptr;
|
||||||
unsigned long stack_page;
|
unsigned long stack_page;
|
||||||
unsigned long vector_ptr;
|
unsigned long vector_ptr;
|
||||||
|
@ -798,8 +798,8 @@ static void cpu_init_hyp_mode(void *dummy)
|
||||||
/* Switch from the HYP stub to our own HYP init vector */
|
/* Switch from the HYP stub to our own HYP init vector */
|
||||||
__hyp_set_vectors(kvm_get_idmap_vector());
|
__hyp_set_vectors(kvm_get_idmap_vector());
|
||||||
|
|
||||||
boot_pgd_ptr = (unsigned long long)kvm_mmu_get_boot_httbr();
|
boot_pgd_ptr = kvm_mmu_get_boot_httbr();
|
||||||
pgd_ptr = (unsigned long long)kvm_mmu_get_httbr();
|
pgd_ptr = kvm_mmu_get_httbr();
|
||||||
stack_page = __get_cpu_var(kvm_arm_hyp_stack_page);
|
stack_page = __get_cpu_var(kvm_arm_hyp_stack_page);
|
||||||
hyp_stack_ptr = stack_page + PAGE_SIZE;
|
hyp_stack_ptr = stack_page + PAGE_SIZE;
|
||||||
vector_ptr = (unsigned long)__kvm_hyp_vector;
|
vector_ptr = (unsigned long)__kvm_hyp_vector;
|
||||||
|
|
|
@ -180,6 +180,10 @@ static const struct coproc_reg cp15_regs[] = {
|
||||||
NULL, reset_unknown, c6_DFAR },
|
NULL, reset_unknown, c6_DFAR },
|
||||||
{ CRn( 6), CRm( 0), Op1( 0), Op2( 2), is32,
|
{ CRn( 6), CRm( 0), Op1( 0), Op2( 2), is32,
|
||||||
NULL, reset_unknown, c6_IFAR },
|
NULL, reset_unknown, c6_IFAR },
|
||||||
|
|
||||||
|
/* PAR swapped by interrupt.S */
|
||||||
|
{ CRn( 7), Op1( 0), is64, NULL, reset_unknown64, c7_PAR },
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DC{C,I,CI}SW operations:
|
* DC{C,I,CI}SW operations:
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -52,9 +52,6 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||||
|
|
||||||
static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||||
{
|
{
|
||||||
if (kvm_psci_call(vcpu))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
kvm_inject_undefined(vcpu);
|
kvm_inject_undefined(vcpu);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,7 @@ __kvm_hyp_code_start:
|
||||||
ENTRY(__kvm_tlb_flush_vmid_ipa)
|
ENTRY(__kvm_tlb_flush_vmid_ipa)
|
||||||
push {r2, r3}
|
push {r2, r3}
|
||||||
|
|
||||||
|
dsb ishst
|
||||||
add r0, r0, #KVM_VTTBR
|
add r0, r0, #KVM_VTTBR
|
||||||
ldrd r2, r3, [r0]
|
ldrd r2, r3, [r0]
|
||||||
mcrr p15, 6, r2, r3, c2 @ Write VTTBR
|
mcrr p15, 6, r2, r3, c2 @ Write VTTBR
|
||||||
|
@ -291,6 +292,7 @@ THUMB( orr r2, r2, #PSR_T_BIT )
|
||||||
ldr r2, =BSYM(panic)
|
ldr r2, =BSYM(panic)
|
||||||
msr ELR_hyp, r2
|
msr ELR_hyp, r2
|
||||||
ldr r0, =\panic_str
|
ldr r0, =\panic_str
|
||||||
|
clrex @ Clear exclusive monitor
|
||||||
eret
|
eret
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
@ -414,6 +416,10 @@ guest_trap:
|
||||||
mrcne p15, 4, r2, c6, c0, 4 @ HPFAR
|
mrcne p15, 4, r2, c6, c0, 4 @ HPFAR
|
||||||
bne 3f
|
bne 3f
|
||||||
|
|
||||||
|
/* Preserve PAR */
|
||||||
|
mrrc p15, 0, r0, r1, c7 @ PAR
|
||||||
|
push {r0, r1}
|
||||||
|
|
||||||
/* Resolve IPA using the xFAR */
|
/* Resolve IPA using the xFAR */
|
||||||
mcr p15, 0, r2, c7, c8, 0 @ ATS1CPR
|
mcr p15, 0, r2, c7, c8, 0 @ ATS1CPR
|
||||||
isb
|
isb
|
||||||
|
@ -424,13 +430,20 @@ guest_trap:
|
||||||
lsl r2, r2, #4
|
lsl r2, r2, #4
|
||||||
orr r2, r2, r1, lsl #24
|
orr r2, r2, r1, lsl #24
|
||||||
|
|
||||||
|
/* Restore PAR */
|
||||||
|
pop {r0, r1}
|
||||||
|
mcrr p15, 0, r0, r1, c7 @ PAR
|
||||||
|
|
||||||
3: load_vcpu @ Load VCPU pointer to r0
|
3: load_vcpu @ Load VCPU pointer to r0
|
||||||
str r2, [r0, #VCPU_HPFAR]
|
str r2, [r0, #VCPU_HPFAR]
|
||||||
|
|
||||||
1: mov r1, #ARM_EXCEPTION_HVC
|
1: mov r1, #ARM_EXCEPTION_HVC
|
||||||
b __kvm_vcpu_return
|
b __kvm_vcpu_return
|
||||||
|
|
||||||
4: pop {r0, r1, r2} @ Failed translation, return to guest
|
4: pop {r0, r1} @ Failed translation, return to guest
|
||||||
|
mcrr p15, 0, r0, r1, c7 @ PAR
|
||||||
|
clrex
|
||||||
|
pop {r0, r1, r2}
|
||||||
eret
|
eret
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -456,6 +469,7 @@ switch_to_guest_vfp:
|
||||||
|
|
||||||
pop {r3-r7}
|
pop {r3-r7}
|
||||||
pop {r0-r2}
|
pop {r0-r2}
|
||||||
|
clrex
|
||||||
eret
|
eret
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -302,11 +302,14 @@ vcpu .req r0 @ vcpu pointer always in r0
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
mrc p15, 0, r2, c14, c1, 0 @ CNTKCTL
|
mrc p15, 0, r2, c14, c1, 0 @ CNTKCTL
|
||||||
|
mrrc p15, 0, r4, r5, c7 @ PAR
|
||||||
|
|
||||||
.if \store_to_vcpu == 0
|
.if \store_to_vcpu == 0
|
||||||
push {r2}
|
push {r2,r4-r5}
|
||||||
.else
|
.else
|
||||||
str r2, [vcpu, #CP15_OFFSET(c14_CNTKCTL)]
|
str r2, [vcpu, #CP15_OFFSET(c14_CNTKCTL)]
|
||||||
|
add r12, vcpu, #CP15_OFFSET(c7_PAR)
|
||||||
|
strd r4, r5, [r12]
|
||||||
.endif
|
.endif
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
@ -319,12 +322,15 @@ vcpu .req r0 @ vcpu pointer always in r0
|
||||||
*/
|
*/
|
||||||
.macro write_cp15_state read_from_vcpu
|
.macro write_cp15_state read_from_vcpu
|
||||||
.if \read_from_vcpu == 0
|
.if \read_from_vcpu == 0
|
||||||
pop {r2}
|
pop {r2,r4-r5}
|
||||||
.else
|
.else
|
||||||
ldr r2, [vcpu, #CP15_OFFSET(c14_CNTKCTL)]
|
ldr r2, [vcpu, #CP15_OFFSET(c14_CNTKCTL)]
|
||||||
|
add r12, vcpu, #CP15_OFFSET(c7_PAR)
|
||||||
|
ldrd r4, r5, [r12]
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
mcr p15, 0, r2, c14, c1, 0 @ CNTKCTL
|
mcr p15, 0, r2, c14, c1, 0 @ CNTKCTL
|
||||||
|
mcrr p15, 0, r4, r5, c7 @ PAR
|
||||||
|
|
||||||
.if \read_from_vcpu == 0
|
.if \read_from_vcpu == 0
|
||||||
pop {r2-r12}
|
pop {r2-r12}
|
||||||
|
|
|
@ -86,12 +86,6 @@ static int decode_hsr(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
||||||
sign_extend = kvm_vcpu_dabt_issext(vcpu);
|
sign_extend = kvm_vcpu_dabt_issext(vcpu);
|
||||||
rt = kvm_vcpu_dabt_get_rd(vcpu);
|
rt = kvm_vcpu_dabt_get_rd(vcpu);
|
||||||
|
|
||||||
if (kvm_vcpu_reg_is_pc(vcpu, rt)) {
|
|
||||||
/* IO memory trying to read/write pc */
|
|
||||||
kvm_inject_pabt(vcpu, kvm_vcpu_get_hfar(vcpu));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
mmio->is_write = is_write;
|
mmio->is_write = is_write;
|
||||||
mmio->phys_addr = fault_ipa;
|
mmio->phys_addr = fault_ipa;
|
||||||
mmio->len = len;
|
mmio->len = len;
|
||||||
|
|
|
@ -370,9 +370,6 @@ int kvm_alloc_stage2_pgd(struct kvm *kvm)
|
||||||
if (!pgd)
|
if (!pgd)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* stage-2 pgd must be aligned to its size */
|
|
||||||
VM_BUG_ON((unsigned long)pgd & (S2_PGD_SIZE - 1));
|
|
||||||
|
|
||||||
memset(pgd, 0, PTRS_PER_S2_PGD * sizeof(pgd_t));
|
memset(pgd, 0, PTRS_PER_S2_PGD * sizeof(pgd_t));
|
||||||
kvm_clean_pgd(pgd);
|
kvm_clean_pgd(pgd);
|
||||||
kvm->arch.pgd = pgd;
|
kvm->arch.pgd = pgd;
|
||||||
|
|
|
@ -75,7 +75,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
|
||||||
* kvm_psci_call - handle PSCI call if r0 value is in range
|
* kvm_psci_call - handle PSCI call if r0 value is in range
|
||||||
* @vcpu: Pointer to the VCPU struct
|
* @vcpu: Pointer to the VCPU struct
|
||||||
*
|
*
|
||||||
* Handle PSCI calls from guests through traps from HVC or SMC instructions.
|
* Handle PSCI calls from guests through traps from HVC instructions.
|
||||||
* The calling convention is similar to SMC calls to the secure world where
|
* The calling convention is similar to SMC calls to the secure world where
|
||||||
* the function number is placed in r0 and this function returns true if the
|
* the function number is placed in r0 and this function returns true if the
|
||||||
* function number specified in r0 is withing the PSCI range, and false
|
* function number specified in r0 is withing the PSCI range, and false
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
#include <asm/kvm_arm.h>
|
#include <asm/kvm_arm.h>
|
||||||
#include <asm/kvm_coproc.h>
|
#include <asm/kvm_coproc.h>
|
||||||
|
|
||||||
|
#include <kvm/arm_arch_timer.h>
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Cortex-A15 Reset Values
|
* Cortex-A15 Reset Values
|
||||||
*/
|
*/
|
||||||
|
@ -37,6 +39,11 @@ static struct kvm_regs a15_regs_reset = {
|
||||||
.usr_regs.ARM_cpsr = SVC_MODE | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT,
|
.usr_regs.ARM_cpsr = SVC_MODE | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct kvm_irq_level a15_vtimer_irq = {
|
||||||
|
.irq = 27,
|
||||||
|
.level = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Exported reset function
|
* Exported reset function
|
||||||
|
@ -52,6 +59,7 @@ static struct kvm_regs a15_regs_reset = {
|
||||||
int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
|
int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
struct kvm_regs *cpu_reset;
|
struct kvm_regs *cpu_reset;
|
||||||
|
const struct kvm_irq_level *cpu_vtimer_irq;
|
||||||
|
|
||||||
switch (vcpu->arch.target) {
|
switch (vcpu->arch.target) {
|
||||||
case KVM_ARM_TARGET_CORTEX_A15:
|
case KVM_ARM_TARGET_CORTEX_A15:
|
||||||
|
@ -59,6 +67,7 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
cpu_reset = &a15_regs_reset;
|
cpu_reset = &a15_regs_reset;
|
||||||
vcpu->arch.midr = read_cpuid_id();
|
vcpu->arch.midr = read_cpuid_id();
|
||||||
|
cpu_vtimer_irq = &a15_vtimer_irq;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
@ -70,5 +79,8 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
|
||||||
/* Reset CP15 registers */
|
/* Reset CP15 registers */
|
||||||
kvm_reset_coprocs(vcpu);
|
kvm_reset_coprocs(vcpu);
|
||||||
|
|
||||||
|
/* Reset arch_timer context */
|
||||||
|
kvm_timer_vcpu_reset(vcpu, cpu_vtimer_irq);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,8 @@ struct arch_timer_cpu {
|
||||||
#ifdef CONFIG_KVM_ARM_TIMER
|
#ifdef CONFIG_KVM_ARM_TIMER
|
||||||
int kvm_timer_hyp_init(void);
|
int kvm_timer_hyp_init(void);
|
||||||
int kvm_timer_init(struct kvm *kvm);
|
int kvm_timer_init(struct kvm *kvm);
|
||||||
|
void kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
|
||||||
|
const struct kvm_irq_level *irq);
|
||||||
void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu);
|
void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu);
|
||||||
void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu);
|
void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu);
|
||||||
void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu);
|
void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu);
|
||||||
|
@ -76,6 +78,8 @@ static inline int kvm_timer_init(struct kvm *kvm)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
|
||||||
|
const struct kvm_irq_level *irq) {}
|
||||||
static inline void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu) {}
|
static inline void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu) {}
|
||||||
static inline void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu) {}
|
static inline void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu) {}
|
||||||
static inline void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu) {}
|
static inline void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu) {}
|
||||||
|
|
|
@ -30,9 +30,7 @@
|
||||||
|
|
||||||
static struct timecounter *timecounter;
|
static struct timecounter *timecounter;
|
||||||
static struct workqueue_struct *wqueue;
|
static struct workqueue_struct *wqueue;
|
||||||
static struct kvm_irq_level timer_irq = {
|
static unsigned int host_vtimer_irq;
|
||||||
.level = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
static cycle_t kvm_phys_timer_read(void)
|
static cycle_t kvm_phys_timer_read(void)
|
||||||
{
|
{
|
||||||
|
@ -67,8 +65,8 @@ static void kvm_timer_inject_irq(struct kvm_vcpu *vcpu)
|
||||||
|
|
||||||
timer->cntv_ctl |= ARCH_TIMER_CTRL_IT_MASK;
|
timer->cntv_ctl |= ARCH_TIMER_CTRL_IT_MASK;
|
||||||
kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id,
|
kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id,
|
||||||
vcpu->arch.timer_cpu.irq->irq,
|
timer->irq->irq,
|
||||||
vcpu->arch.timer_cpu.irq->level);
|
timer->irq->level);
|
||||||
}
|
}
|
||||||
|
|
||||||
static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
|
static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
|
||||||
|
@ -156,6 +154,20 @@ void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
|
||||||
timer_arm(timer, ns);
|
timer_arm(timer, ns);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
|
||||||
|
const struct kvm_irq_level *irq)
|
||||||
|
{
|
||||||
|
struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The vcpu timer irq number cannot be determined in
|
||||||
|
* kvm_timer_vcpu_init() because it is called much before
|
||||||
|
* kvm_vcpu_set_target(). To handle this, we determine
|
||||||
|
* vcpu timer irq number when the vcpu is reset.
|
||||||
|
*/
|
||||||
|
timer->irq = irq;
|
||||||
|
}
|
||||||
|
|
||||||
void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
|
void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
|
struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
|
||||||
|
@ -163,12 +175,11 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
|
||||||
INIT_WORK(&timer->expired, kvm_timer_inject_irq_work);
|
INIT_WORK(&timer->expired, kvm_timer_inject_irq_work);
|
||||||
hrtimer_init(&timer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
|
hrtimer_init(&timer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
|
||||||
timer->timer.function = kvm_timer_expire;
|
timer->timer.function = kvm_timer_expire;
|
||||||
timer->irq = &timer_irq;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kvm_timer_init_interrupt(void *info)
|
static void kvm_timer_init_interrupt(void *info)
|
||||||
{
|
{
|
||||||
enable_percpu_irq(timer_irq.irq, 0);
|
enable_percpu_irq(host_vtimer_irq, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -182,7 +193,7 @@ static int kvm_timer_cpu_notify(struct notifier_block *self,
|
||||||
break;
|
break;
|
||||||
case CPU_DYING:
|
case CPU_DYING:
|
||||||
case CPU_DYING_FROZEN:
|
case CPU_DYING_FROZEN:
|
||||||
disable_percpu_irq(timer_irq.irq);
|
disable_percpu_irq(host_vtimer_irq);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,7 +240,7 @@ int kvm_timer_hyp_init(void)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
timer_irq.irq = ppi;
|
host_vtimer_irq = ppi;
|
||||||
|
|
||||||
err = register_cpu_notifier(&kvm_timer_cpu_nb);
|
err = register_cpu_notifier(&kvm_timer_cpu_nb);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
Loading…
Reference in New Issue