mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 02:32:09 -04:00
Here are the PPC and ARM changes for KVM, which I separated because
they had small conflicts (respectively within KVM documentation, and with 3.16-rc changes). Since they were all within the subsystem, I took care of them. Stephen Rothwell reported some snags in PPC builds, but they are all fixed now; the latest linux-next report was clean. New features for ARM include: - KVM VGIC v2 emulation on GICv3 hardware - Big-Endian support for arm/arm64 (guest and host) - Debug Architecture support for arm64 (arm32 is on Christoffer's todo list) And for PPC: - Book3S: Good number of LE host fixes, enable HV on LE - Book3S HV: Add in-guest debug support This release drops support for KVM on the PPC440. As a result, the PPC merge removes more lines than it adds. :) I also included an x86 change, since Davidlohr tied it to an independent bug report and the reporter quickly provided a Tested-by; there was no reason to wait for -rc2. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJT4iIJAAoJEBvWZb6bTYbyZqoP/3Wxy8NWPFJ8HGt81NHlGnDS a9UbL7EibcOEG+aaKqmtBglTD5YDiGBDNCxxiSJaDHt+grLN4fsWIliJob1nJFoO 90f89EWN2XjeCrJXA5nUoeg5tpc5OoYKsiP6pTgzIwkP8vvs/H1+zpcTS/UmYsr/ qipVMMsM+zZeHWZcSbqjW88z7YqIn1sr5282wJ85cbyv4KGizb/G4dyPuDqLb6np hkAD8Ah6VV2suQ2FSy7G2fg20R0vglUi60hkEHLoCBPVqJCl7SmC8MvxNbjBnP8S J36R0R0u1wHYKzAGooLJGVOZ/o/gSiVqKX+++L2EvJBN+kuA6u/7fxLyBT+LwDAE IF/Aln5rpg1fe+eywvhz86WljTVEQ8bO1zVsIQUPY+/ZOPedZHMwyvXft8ogbjSp 2m9OJ/3e8Aggh0OeHpCDoeow+QDUXvX0YdCw+2Yh0p+7VMXqkyp0QEiBu38jrusC rB3VNifJbDSWLKdG9LfCAPHnxZD2XYEwv2WFBo6KQOGMGHfx0GXpCOL/jQihrhA6 HtEG5Bs3lvnHQemdpUZ58xojiABbMaUPdcnPXQQEp23WhZzrfLMLzqVG0VYnhSsC 9pi7MJj8c31rqx5WU2oRM28i/BvNxN0NCtkDpineO5s3f89Ws1xnwxqlm38AKP0J irJQTYFEqec+GM9JK1rG =hyQP -----END PGP SIGNATURE----- Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm Pull second round of KVM changes from Paolo Bonzini: "Here are the PPC and ARM changes for KVM, which I separated because they had small conflicts (respectively within KVM documentation, and with 3.16-rc changes). Since they were all within the subsystem, I took care of them. Stephen Rothwell reported some snags in PPC builds, but they are all fixed now; the latest linux-next report was clean. New features for ARM include: - KVM VGIC v2 emulation on GICv3 hardware - Big-Endian support for arm/arm64 (guest and host) - Debug Architecture support for arm64 (arm32 is on Christoffer's todo list) And for PPC: - Book3S: Good number of LE host fixes, enable HV on LE - Book3S HV: Add in-guest debug support This release drops support for KVM on the PPC440. As a result, the PPC merge removes more lines than it adds. :) I also included an x86 change, since Davidlohr tied it to an independent bug report and the reporter quickly provided a Tested-by; there was no reason to wait for -rc2" * tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm: (122 commits) KVM: Move more code under CONFIG_HAVE_KVM_IRQFD KVM: nVMX: fix "acknowledge interrupt on exit" when APICv is in use KVM: nVMX: Fix nested vmexit ack intr before load vmcs01 KVM: PPC: Enable IRQFD support for the XICS interrupt controller KVM: Give IRQFD its own separate enabling Kconfig option KVM: Move irq notifier implementation into eventfd.c KVM: Move all accesses to kvm::irq_routing into irqchip.c KVM: irqchip: Provide and use accessors for irq routing table KVM: Don't keep reference to irq routing table in irqfd struct KVM: PPC: drop duplicate tracepoint arm64: KVM: fix 64bit CP15 VM access for 32bit guests KVM: arm64: GICv3: mandate page-aligned GICV region arm64: KVM: GICv3: move system register access to msr_s/mrs_s KVM: PPC: PR: Handle FSCR feature deselects KVM: PPC: HV: Remove generic instruction emulation KVM: PPC: BOOKEHV: rename e500hv_spr to bookehv_spr KVM: PPC: Remove DCR handling KVM: PPC: Expose helper functions for data/inst faults KVM: PPC: Separate loadstore emulation from priv emulation KVM: PPC: Handle magic page in kvmppc_ld/st ...
This commit is contained in:
commit
66bb0aa077
116 changed files with 5010 additions and 2825 deletions
|
|
@ -18,6 +18,15 @@
|
|||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/* Low-level stepping controls. */
|
||||
#define DBG_MDSCR_SS (1 << 0)
|
||||
#define DBG_SPSR_SS (1 << 21)
|
||||
|
||||
/* MDSCR_EL1 enabling bits */
|
||||
#define DBG_MDSCR_KDE (1 << 13)
|
||||
#define DBG_MDSCR_MDE (1 << 15)
|
||||
#define DBG_MDSCR_MASK ~(DBG_MDSCR_KDE | DBG_MDSCR_MDE)
|
||||
|
||||
#define DBG_ESR_EVT(x) (((x) >> 27) & 0x7)
|
||||
|
||||
/* AArch64 */
|
||||
|
|
@ -73,11 +82,6 @@
|
|||
|
||||
#define CACHE_FLUSH_IS_SAFE 1
|
||||
|
||||
enum debug_el {
|
||||
DBG_ACTIVE_EL0 = 0,
|
||||
DBG_ACTIVE_EL1,
|
||||
};
|
||||
|
||||
/* AArch32 */
|
||||
#define DBG_ESR_EVT_BKPT 0x4
|
||||
#define DBG_ESR_EVT_VECC 0x5
|
||||
|
|
@ -115,6 +119,11 @@ void unregister_break_hook(struct break_hook *hook);
|
|||
|
||||
u8 debug_monitors_arch(void);
|
||||
|
||||
enum debug_el {
|
||||
DBG_ACTIVE_EL0 = 0,
|
||||
DBG_ACTIVE_EL1,
|
||||
};
|
||||
|
||||
void enable_debug_monitors(enum debug_el el);
|
||||
void disable_debug_monitors(enum debug_el el);
|
||||
|
||||
|
|
|
|||
|
|
@ -76,9 +76,10 @@
|
|||
*/
|
||||
#define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWE | HCR_TWI | HCR_VM | \
|
||||
HCR_TVM | HCR_BSU_IS | HCR_FB | HCR_TAC | \
|
||||
HCR_AMO | HCR_IMO | HCR_FMO | \
|
||||
HCR_SWIO | HCR_TIDCP | HCR_RW)
|
||||
HCR_AMO | HCR_SWIO | HCR_TIDCP | HCR_RW)
|
||||
#define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
|
||||
#define HCR_INT_OVERRIDE (HCR_FMO | HCR_IMO)
|
||||
|
||||
|
||||
/* Hyp System Control Register (SCTLR_EL2) bits */
|
||||
#define SCTLR_EL2_EE (1 << 25)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@
|
|||
#ifndef __ARM_KVM_ASM_H__
|
||||
#define __ARM_KVM_ASM_H__
|
||||
|
||||
#include <asm/virt.h>
|
||||
|
||||
/*
|
||||
* 0 is reserved as an invalid value.
|
||||
* Order *must* be kept in sync with the hyp switch code.
|
||||
|
|
@ -43,14 +45,25 @@
|
|||
#define AMAIR_EL1 19 /* Aux Memory Attribute Indirection Register */
|
||||
#define CNTKCTL_EL1 20 /* Timer Control Register (EL1) */
|
||||
#define PAR_EL1 21 /* Physical Address Register */
|
||||
#define MDSCR_EL1 22 /* Monitor Debug System Control Register */
|
||||
#define DBGBCR0_EL1 23 /* Debug Breakpoint Control Registers (0-15) */
|
||||
#define DBGBCR15_EL1 38
|
||||
#define DBGBVR0_EL1 39 /* Debug Breakpoint Value Registers (0-15) */
|
||||
#define DBGBVR15_EL1 54
|
||||
#define DBGWCR0_EL1 55 /* Debug Watchpoint Control Registers (0-15) */
|
||||
#define DBGWCR15_EL1 70
|
||||
#define DBGWVR0_EL1 71 /* Debug Watchpoint Value Registers (0-15) */
|
||||
#define DBGWVR15_EL1 86
|
||||
#define MDCCINT_EL1 87 /* Monitor Debug Comms Channel Interrupt Enable Reg */
|
||||
|
||||
/* 32bit specific registers. Keep them at the end of the range */
|
||||
#define DACR32_EL2 22 /* Domain Access Control Register */
|
||||
#define IFSR32_EL2 23 /* Instruction Fault Status Register */
|
||||
#define FPEXC32_EL2 24 /* Floating-Point Exception Control Register */
|
||||
#define DBGVCR32_EL2 25 /* Debug Vector Catch Register */
|
||||
#define TEECR32_EL1 26 /* ThumbEE Configuration Register */
|
||||
#define TEEHBR32_EL1 27 /* ThumbEE Handler Base Register */
|
||||
#define NR_SYS_REGS 28
|
||||
#define DACR32_EL2 88 /* Domain Access Control Register */
|
||||
#define IFSR32_EL2 89 /* Instruction Fault Status Register */
|
||||
#define FPEXC32_EL2 90 /* Floating-Point Exception Control Register */
|
||||
#define DBGVCR32_EL2 91 /* Debug Vector Catch Register */
|
||||
#define TEECR32_EL1 92 /* ThumbEE Configuration Register */
|
||||
#define TEEHBR32_EL1 93 /* ThumbEE Handler Base Register */
|
||||
#define NR_SYS_REGS 94
|
||||
|
||||
/* 32bit mapping */
|
||||
#define c0_MPIDR (MPIDR_EL1 * 2) /* MultiProcessor ID Register */
|
||||
|
|
@ -82,11 +95,23 @@
|
|||
#define c10_AMAIR0 (AMAIR_EL1 * 2) /* Aux Memory Attr Indirection Reg */
|
||||
#define c10_AMAIR1 (c10_AMAIR0 + 1)/* Aux Memory Attr Indirection Reg */
|
||||
#define c14_CNTKCTL (CNTKCTL_EL1 * 2) /* Timer Control Register (PL1) */
|
||||
#define NR_CP15_REGS (NR_SYS_REGS * 2)
|
||||
|
||||
#define cp14_DBGDSCRext (MDSCR_EL1 * 2)
|
||||
#define cp14_DBGBCR0 (DBGBCR0_EL1 * 2)
|
||||
#define cp14_DBGBVR0 (DBGBVR0_EL1 * 2)
|
||||
#define cp14_DBGBXVR0 (cp14_DBGBVR0 + 1)
|
||||
#define cp14_DBGWCR0 (DBGWCR0_EL1 * 2)
|
||||
#define cp14_DBGWVR0 (DBGWVR0_EL1 * 2)
|
||||
#define cp14_DBGDCCINT (MDCCINT_EL1 * 2)
|
||||
|
||||
#define NR_COPRO_REGS (NR_SYS_REGS * 2)
|
||||
|
||||
#define ARM_EXCEPTION_IRQ 0
|
||||
#define ARM_EXCEPTION_TRAP 1
|
||||
|
||||
#define KVM_ARM64_DEBUG_DIRTY_SHIFT 0
|
||||
#define KVM_ARM64_DEBUG_DIRTY (1 << KVM_ARM64_DEBUG_DIRTY_SHIFT)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
struct kvm;
|
||||
struct kvm_vcpu;
|
||||
|
|
@ -96,13 +121,21 @@ extern char __kvm_hyp_init_end[];
|
|||
|
||||
extern char __kvm_hyp_vector[];
|
||||
|
||||
extern char __kvm_hyp_code_start[];
|
||||
extern char __kvm_hyp_code_end[];
|
||||
#define __kvm_hyp_code_start __hyp_text_start
|
||||
#define __kvm_hyp_code_end __hyp_text_end
|
||||
|
||||
extern void __kvm_flush_vm_context(void);
|
||||
extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
|
||||
|
||||
extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
|
||||
|
||||
extern u64 __vgic_v3_get_ich_vtr_el2(void);
|
||||
|
||||
extern char __save_vgic_v2_state[];
|
||||
extern char __restore_vgic_v2_state[];
|
||||
extern char __save_vgic_v3_state[];
|
||||
extern char __restore_vgic_v3_state[];
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __ARM_KVM_ASM_H__ */
|
||||
|
|
|
|||
|
|
@ -39,7 +39,8 @@ void kvm_register_target_sys_reg_table(unsigned int target,
|
|||
struct kvm_sys_reg_target_table *table);
|
||||
|
||||
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_cp14_32(struct kvm_vcpu *vcpu, struct kvm_run *run);
|
||||
int kvm_handle_cp14_64(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);
|
||||
int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run);
|
||||
|
|
|
|||
|
|
@ -213,6 +213,17 @@ static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,
|
|||
default:
|
||||
return be64_to_cpu(data);
|
||||
}
|
||||
} else {
|
||||
switch (len) {
|
||||
case 1:
|
||||
return data & 0xff;
|
||||
case 2:
|
||||
return le16_to_cpu(data & 0xffff);
|
||||
case 4:
|
||||
return le32_to_cpu(data & 0xffffffff);
|
||||
default:
|
||||
return le64_to_cpu(data);
|
||||
}
|
||||
}
|
||||
|
||||
return data; /* Leave LE untouched */
|
||||
|
|
@ -233,6 +244,17 @@ static inline unsigned long vcpu_data_host_to_guest(struct kvm_vcpu *vcpu,
|
|||
default:
|
||||
return cpu_to_be64(data);
|
||||
}
|
||||
} else {
|
||||
switch (len) {
|
||||
case 1:
|
||||
return data & 0xff;
|
||||
case 2:
|
||||
return cpu_to_le16(data & 0xffff);
|
||||
case 4:
|
||||
return cpu_to_le32(data & 0xffffffff);
|
||||
default:
|
||||
return cpu_to_le64(data);
|
||||
}
|
||||
}
|
||||
|
||||
return data; /* Leave LE untouched */
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ struct kvm_cpu_context {
|
|||
struct kvm_regs gp_regs;
|
||||
union {
|
||||
u64 sys_regs[NR_SYS_REGS];
|
||||
u32 cp15[NR_CP15_REGS];
|
||||
u32 copro[NR_COPRO_REGS];
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -101,6 +101,9 @@ struct kvm_vcpu_arch {
|
|||
/* Exception Information */
|
||||
struct kvm_vcpu_fault_info fault;
|
||||
|
||||
/* Debug state */
|
||||
u64 debug_flags;
|
||||
|
||||
/* Pointer to host CPU context */
|
||||
kvm_cpu_context_t *host_cpu_context;
|
||||
|
||||
|
|
@ -138,7 +141,20 @@ struct kvm_vcpu_arch {
|
|||
|
||||
#define vcpu_gp_regs(v) (&(v)->arch.ctxt.gp_regs)
|
||||
#define vcpu_sys_reg(v,r) ((v)->arch.ctxt.sys_regs[(r)])
|
||||
#define vcpu_cp15(v,r) ((v)->arch.ctxt.cp15[(r)])
|
||||
/*
|
||||
* CP14 and CP15 live in the same array, as they are backed by the
|
||||
* same system registers.
|
||||
*/
|
||||
#define vcpu_cp14(v,r) ((v)->arch.ctxt.copro[(r)])
|
||||
#define vcpu_cp15(v,r) ((v)->arch.ctxt.copro[(r)])
|
||||
|
||||
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||
#define vcpu_cp15_64_high(v,r) vcpu_cp15((v),(r))
|
||||
#define vcpu_cp15_64_low(v,r) vcpu_cp15((v),(r) + 1)
|
||||
#else
|
||||
#define vcpu_cp15_64_high(v,r) vcpu_cp15((v),(r) + 1)
|
||||
#define vcpu_cp15_64_low(v,r) vcpu_cp15((v),(r))
|
||||
#endif
|
||||
|
||||
struct kvm_vm_stat {
|
||||
u32 remote_tlb_flush;
|
||||
|
|
@ -200,4 +216,32 @@ static inline void __cpu_init_hyp_mode(phys_addr_t boot_pgd_ptr,
|
|||
hyp_stack_ptr, vector_ptr);
|
||||
}
|
||||
|
||||
struct vgic_sr_vectors {
|
||||
void *save_vgic;
|
||||
void *restore_vgic;
|
||||
};
|
||||
|
||||
static inline void vgic_arch_setup(const struct vgic_params *vgic)
|
||||
{
|
||||
extern struct vgic_sr_vectors __vgic_sr_vectors;
|
||||
|
||||
switch(vgic->type)
|
||||
{
|
||||
case VGIC_V2:
|
||||
__vgic_sr_vectors.save_vgic = __save_vgic_v2_state;
|
||||
__vgic_sr_vectors.restore_vgic = __restore_vgic_v2_state;
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_ARM_GIC_V3
|
||||
case VGIC_V3:
|
||||
__vgic_sr_vectors.save_vgic = __save_vgic_v3_state;
|
||||
__vgic_sr_vectors.restore_vgic = __restore_vgic_v3_state;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __ARM64_KVM_HOST_H__ */
|
||||
|
|
|
|||
|
|
@ -125,6 +125,21 @@ static inline void kvm_set_s2pmd_writable(pmd_t *pmd)
|
|||
#define kvm_pud_addr_end(addr, end) pud_addr_end(addr, end)
|
||||
#define kvm_pmd_addr_end(addr, end) pmd_addr_end(addr, end)
|
||||
|
||||
static inline bool kvm_page_empty(void *ptr)
|
||||
{
|
||||
struct page *ptr_page = virt_to_page(ptr);
|
||||
return page_count(ptr_page) == 1;
|
||||
}
|
||||
|
||||
#define kvm_pte_table_empty(ptep) kvm_page_empty(ptep)
|
||||
#ifndef CONFIG_ARM64_64K_PAGES
|
||||
#define kvm_pmd_table_empty(pmdp) kvm_page_empty(pmdp)
|
||||
#else
|
||||
#define kvm_pmd_table_empty(pmdp) (0)
|
||||
#endif
|
||||
#define kvm_pud_table_empty(pudp) (0)
|
||||
|
||||
|
||||
struct kvm;
|
||||
|
||||
#define kvm_flush_dcache_to_poc(a,l) __flush_dcache_area((a), (l))
|
||||
|
|
|
|||
|
|
@ -50,6 +50,10 @@ static inline bool is_hyp_mode_mismatched(void)
|
|||
return __boot_cpu_mode[0] != __boot_cpu_mode[1];
|
||||
}
|
||||
|
||||
/* The section containing the hypervisor text */
|
||||
extern char __hyp_text_start[];
|
||||
extern char __hyp_text_end[];
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* ! __ASM__VIRT_H */
|
||||
|
|
|
|||
|
|
@ -120,6 +120,7 @@ int main(void)
|
|||
DEFINE(VCPU_ESR_EL2, offsetof(struct kvm_vcpu, arch.fault.esr_el2));
|
||||
DEFINE(VCPU_FAR_EL2, offsetof(struct kvm_vcpu, arch.fault.far_el2));
|
||||
DEFINE(VCPU_HPFAR_EL2, offsetof(struct kvm_vcpu, arch.fault.hpfar_el2));
|
||||
DEFINE(VCPU_DEBUG_FLAGS, offsetof(struct kvm_vcpu, arch.debug_flags));
|
||||
DEFINE(VCPU_HCR_EL2, offsetof(struct kvm_vcpu, arch.hcr_el2));
|
||||
DEFINE(VCPU_IRQ_LINES, offsetof(struct kvm_vcpu, arch.irq_lines));
|
||||
DEFINE(VCPU_HOST_CONTEXT, offsetof(struct kvm_vcpu, arch.host_cpu_context));
|
||||
|
|
@ -129,13 +130,24 @@ int main(void)
|
|||
DEFINE(KVM_TIMER_ENABLED, offsetof(struct kvm, arch.timer.enabled));
|
||||
DEFINE(VCPU_KVM, offsetof(struct kvm_vcpu, kvm));
|
||||
DEFINE(VCPU_VGIC_CPU, offsetof(struct kvm_vcpu, arch.vgic_cpu));
|
||||
DEFINE(VGIC_CPU_HCR, offsetof(struct vgic_cpu, vgic_hcr));
|
||||
DEFINE(VGIC_CPU_VMCR, offsetof(struct vgic_cpu, vgic_vmcr));
|
||||
DEFINE(VGIC_CPU_MISR, offsetof(struct vgic_cpu, vgic_misr));
|
||||
DEFINE(VGIC_CPU_EISR, offsetof(struct vgic_cpu, vgic_eisr));
|
||||
DEFINE(VGIC_CPU_ELRSR, offsetof(struct vgic_cpu, vgic_elrsr));
|
||||
DEFINE(VGIC_CPU_APR, offsetof(struct vgic_cpu, vgic_apr));
|
||||
DEFINE(VGIC_CPU_LR, offsetof(struct vgic_cpu, vgic_lr));
|
||||
DEFINE(VGIC_SAVE_FN, offsetof(struct vgic_sr_vectors, save_vgic));
|
||||
DEFINE(VGIC_RESTORE_FN, offsetof(struct vgic_sr_vectors, restore_vgic));
|
||||
DEFINE(VGIC_SR_VECTOR_SZ, sizeof(struct vgic_sr_vectors));
|
||||
DEFINE(VGIC_V2_CPU_HCR, offsetof(struct vgic_cpu, vgic_v2.vgic_hcr));
|
||||
DEFINE(VGIC_V2_CPU_VMCR, offsetof(struct vgic_cpu, vgic_v2.vgic_vmcr));
|
||||
DEFINE(VGIC_V2_CPU_MISR, offsetof(struct vgic_cpu, vgic_v2.vgic_misr));
|
||||
DEFINE(VGIC_V2_CPU_EISR, offsetof(struct vgic_cpu, vgic_v2.vgic_eisr));
|
||||
DEFINE(VGIC_V2_CPU_ELRSR, offsetof(struct vgic_cpu, vgic_v2.vgic_elrsr));
|
||||
DEFINE(VGIC_V2_CPU_APR, offsetof(struct vgic_cpu, vgic_v2.vgic_apr));
|
||||
DEFINE(VGIC_V2_CPU_LR, offsetof(struct vgic_cpu, vgic_v2.vgic_lr));
|
||||
DEFINE(VGIC_V3_CPU_HCR, offsetof(struct vgic_cpu, vgic_v3.vgic_hcr));
|
||||
DEFINE(VGIC_V3_CPU_VMCR, offsetof(struct vgic_cpu, vgic_v3.vgic_vmcr));
|
||||
DEFINE(VGIC_V3_CPU_MISR, offsetof(struct vgic_cpu, vgic_v3.vgic_misr));
|
||||
DEFINE(VGIC_V3_CPU_EISR, offsetof(struct vgic_cpu, vgic_v3.vgic_eisr));
|
||||
DEFINE(VGIC_V3_CPU_ELRSR, offsetof(struct vgic_cpu, vgic_v3.vgic_elrsr));
|
||||
DEFINE(VGIC_V3_CPU_AP0R, offsetof(struct vgic_cpu, vgic_v3.vgic_ap0r));
|
||||
DEFINE(VGIC_V3_CPU_AP1R, offsetof(struct vgic_cpu, vgic_v3.vgic_ap1r));
|
||||
DEFINE(VGIC_V3_CPU_LR, offsetof(struct vgic_cpu, vgic_v3.vgic_lr));
|
||||
DEFINE(VGIC_CPU_NR_LR, offsetof(struct vgic_cpu, nr_lr));
|
||||
DEFINE(KVM_VTTBR, offsetof(struct kvm, arch.vttbr));
|
||||
DEFINE(KVM_VGIC_VCTRL, offsetof(struct kvm, arch.vgic.vctrl_base));
|
||||
|
|
|
|||
|
|
@ -30,15 +30,6 @@
|
|||
#include <asm/cputype.h>
|
||||
#include <asm/system_misc.h>
|
||||
|
||||
/* Low-level stepping controls. */
|
||||
#define DBG_MDSCR_SS (1 << 0)
|
||||
#define DBG_SPSR_SS (1 << 21)
|
||||
|
||||
/* MDSCR_EL1 enabling bits */
|
||||
#define DBG_MDSCR_KDE (1 << 13)
|
||||
#define DBG_MDSCR_MDE (1 << 15)
|
||||
#define DBG_MDSCR_MASK ~(DBG_MDSCR_KDE | DBG_MDSCR_MDE)
|
||||
|
||||
/* Determine debug architecture. */
|
||||
u8 debug_monitors_arch(void)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -20,4 +20,8 @@ kvm-$(CONFIG_KVM_ARM_HOST) += hyp.o hyp-init.o handle_exit.o
|
|||
kvm-$(CONFIG_KVM_ARM_HOST) += guest.o reset.o sys_regs.o sys_regs_generic_v8.o
|
||||
|
||||
kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic.o
|
||||
kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v2.o
|
||||
kvm-$(CONFIG_KVM_ARM_VGIC) += vgic-v2-switch.o
|
||||
kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v3.o
|
||||
kvm-$(CONFIG_KVM_ARM_VGIC) += vgic-v3-switch.o
|
||||
kvm-$(CONFIG_KVM_ARM_TIMER) += $(KVM)/arm/arch_timer.o
|
||||
|
|
|
|||
|
|
@ -135,6 +135,59 @@ static unsigned long num_core_regs(void)
|
|||
return sizeof(struct kvm_regs) / sizeof(__u32);
|
||||
}
|
||||
|
||||
/**
|
||||
* ARM64 versions of the TIMER registers, always available on arm64
|
||||
*/
|
||||
|
||||
#define NUM_TIMER_REGS 3
|
||||
|
||||
static bool is_timer_reg(u64 index)
|
||||
{
|
||||
switch (index) {
|
||||
case KVM_REG_ARM_TIMER_CTL:
|
||||
case KVM_REG_ARM_TIMER_CNT:
|
||||
case KVM_REG_ARM_TIMER_CVAL:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
|
||||
{
|
||||
if (put_user(KVM_REG_ARM_TIMER_CTL, uindices))
|
||||
return -EFAULT;
|
||||
uindices++;
|
||||
if (put_user(KVM_REG_ARM_TIMER_CNT, uindices))
|
||||
return -EFAULT;
|
||||
uindices++;
|
||||
if (put_user(KVM_REG_ARM_TIMER_CVAL, uindices))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
||||
{
|
||||
void __user *uaddr = (void __user *)(long)reg->addr;
|
||||
u64 val;
|
||||
int ret;
|
||||
|
||||
ret = copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id));
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
return kvm_arm_timer_set_reg(vcpu, reg->id, val);
|
||||
}
|
||||
|
||||
static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
||||
{
|
||||
void __user *uaddr = (void __user *)(long)reg->addr;
|
||||
u64 val;
|
||||
|
||||
val = kvm_arm_timer_get_reg(vcpu, reg->id);
|
||||
return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_arm_num_regs - how many registers do we present via KVM_GET_ONE_REG
|
||||
*
|
||||
|
|
@ -142,7 +195,8 @@ static unsigned long num_core_regs(void)
|
|||
*/
|
||||
unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return num_core_regs() + kvm_arm_num_sys_reg_descs(vcpu);
|
||||
return num_core_regs() + kvm_arm_num_sys_reg_descs(vcpu)
|
||||
+ NUM_TIMER_REGS;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -154,6 +208,7 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
|
|||
{
|
||||
unsigned int i;
|
||||
const u64 core_reg = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) {
|
||||
if (put_user(core_reg | i, uindices))
|
||||
|
|
@ -161,6 +216,11 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
|
|||
uindices++;
|
||||
}
|
||||
|
||||
ret = copy_timer_indices(vcpu, uindices);
|
||||
if (ret)
|
||||
return ret;
|
||||
uindices += NUM_TIMER_REGS;
|
||||
|
||||
return kvm_arm_copy_sys_reg_indices(vcpu, uindices);
|
||||
}
|
||||
|
||||
|
|
@ -174,6 +234,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
|||
if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
|
||||
return get_core_reg(vcpu, reg);
|
||||
|
||||
if (is_timer_reg(reg->id))
|
||||
return get_timer_reg(vcpu, reg);
|
||||
|
||||
return kvm_arm_sys_reg_get_reg(vcpu, reg);
|
||||
}
|
||||
|
||||
|
|
@ -187,6 +250,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
|||
if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
|
||||
return set_core_reg(vcpu, reg);
|
||||
|
||||
if (is_timer_reg(reg->id))
|
||||
return set_timer_reg(vcpu, reg);
|
||||
|
||||
return kvm_arm_sys_reg_set_reg(vcpu, reg);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -73,9 +73,9 @@ static exit_handle_fn arm_exit_handlers[] = {
|
|||
[ESR_EL2_EC_WFI] = kvm_handle_wfx,
|
||||
[ESR_EL2_EC_CP15_32] = kvm_handle_cp15_32,
|
||||
[ESR_EL2_EC_CP15_64] = kvm_handle_cp15_64,
|
||||
[ESR_EL2_EC_CP14_MR] = kvm_handle_cp14_access,
|
||||
[ESR_EL2_EC_CP14_MR] = kvm_handle_cp14_32,
|
||||
[ESR_EL2_EC_CP14_LS] = kvm_handle_cp14_load_store,
|
||||
[ESR_EL2_EC_CP14_64] = kvm_handle_cp14_access,
|
||||
[ESR_EL2_EC_CP14_64] = kvm_handle_cp14_64,
|
||||
[ESR_EL2_EC_HVC32] = handle_hvc,
|
||||
[ESR_EL2_EC_SMC32] = handle_smc,
|
||||
[ESR_EL2_EC_HVC64] = handle_hvc,
|
||||
|
|
|
|||
|
|
@ -16,11 +16,11 @@
|
|||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/irqchip/arm-gic.h>
|
||||
|
||||
#include <asm/assembler.h>
|
||||
#include <asm/memory.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm/debug-monitors.h>
|
||||
#include <asm/fpsimdmacros.h>
|
||||
#include <asm/kvm.h>
|
||||
#include <asm/kvm_asm.h>
|
||||
|
|
@ -36,9 +36,6 @@
|
|||
.pushsection .hyp.text, "ax"
|
||||
.align PAGE_SHIFT
|
||||
|
||||
__kvm_hyp_code_start:
|
||||
.globl __kvm_hyp_code_start
|
||||
|
||||
.macro save_common_regs
|
||||
// x2: base address for cpu context
|
||||
// x3: tmp register
|
||||
|
|
@ -215,6 +212,7 @@ __kvm_hyp_code_start:
|
|||
mrs x22, amair_el1
|
||||
mrs x23, cntkctl_el1
|
||||
mrs x24, par_el1
|
||||
mrs x25, mdscr_el1
|
||||
|
||||
stp x4, x5, [x3]
|
||||
stp x6, x7, [x3, #16]
|
||||
|
|
@ -226,7 +224,202 @@ __kvm_hyp_code_start:
|
|||
stp x18, x19, [x3, #112]
|
||||
stp x20, x21, [x3, #128]
|
||||
stp x22, x23, [x3, #144]
|
||||
str x24, [x3, #160]
|
||||
stp x24, x25, [x3, #160]
|
||||
.endm
|
||||
|
||||
.macro save_debug
|
||||
// x2: base address for cpu context
|
||||
// x3: tmp register
|
||||
|
||||
mrs x26, id_aa64dfr0_el1
|
||||
ubfx x24, x26, #12, #4 // Extract BRPs
|
||||
ubfx x25, x26, #20, #4 // Extract WRPs
|
||||
mov w26, #15
|
||||
sub w24, w26, w24 // How many BPs to skip
|
||||
sub w25, w26, w25 // How many WPs to skip
|
||||
|
||||
add x3, x2, #CPU_SYSREG_OFFSET(DBGBCR0_EL1)
|
||||
|
||||
adr x26, 1f
|
||||
add x26, x26, x24, lsl #2
|
||||
br x26
|
||||
1:
|
||||
mrs x20, dbgbcr15_el1
|
||||
mrs x19, dbgbcr14_el1
|
||||
mrs x18, dbgbcr13_el1
|
||||
mrs x17, dbgbcr12_el1
|
||||
mrs x16, dbgbcr11_el1
|
||||
mrs x15, dbgbcr10_el1
|
||||
mrs x14, dbgbcr9_el1
|
||||
mrs x13, dbgbcr8_el1
|
||||
mrs x12, dbgbcr7_el1
|
||||
mrs x11, dbgbcr6_el1
|
||||
mrs x10, dbgbcr5_el1
|
||||
mrs x9, dbgbcr4_el1
|
||||
mrs x8, dbgbcr3_el1
|
||||
mrs x7, dbgbcr2_el1
|
||||
mrs x6, dbgbcr1_el1
|
||||
mrs x5, dbgbcr0_el1
|
||||
|
||||
adr x26, 1f
|
||||
add x26, x26, x24, lsl #2
|
||||
br x26
|
||||
|
||||
1:
|
||||
str x20, [x3, #(15 * 8)]
|
||||
str x19, [x3, #(14 * 8)]
|
||||
str x18, [x3, #(13 * 8)]
|
||||
str x17, [x3, #(12 * 8)]
|
||||
str x16, [x3, #(11 * 8)]
|
||||
str x15, [x3, #(10 * 8)]
|
||||
str x14, [x3, #(9 * 8)]
|
||||
str x13, [x3, #(8 * 8)]
|
||||
str x12, [x3, #(7 * 8)]
|
||||
str x11, [x3, #(6 * 8)]
|
||||
str x10, [x3, #(5 * 8)]
|
||||
str x9, [x3, #(4 * 8)]
|
||||
str x8, [x3, #(3 * 8)]
|
||||
str x7, [x3, #(2 * 8)]
|
||||
str x6, [x3, #(1 * 8)]
|
||||
str x5, [x3, #(0 * 8)]
|
||||
|
||||
add x3, x2, #CPU_SYSREG_OFFSET(DBGBVR0_EL1)
|
||||
|
||||
adr x26, 1f
|
||||
add x26, x26, x24, lsl #2
|
||||
br x26
|
||||
1:
|
||||
mrs x20, dbgbvr15_el1
|
||||
mrs x19, dbgbvr14_el1
|
||||
mrs x18, dbgbvr13_el1
|
||||
mrs x17, dbgbvr12_el1
|
||||
mrs x16, dbgbvr11_el1
|
||||
mrs x15, dbgbvr10_el1
|
||||
mrs x14, dbgbvr9_el1
|
||||
mrs x13, dbgbvr8_el1
|
||||
mrs x12, dbgbvr7_el1
|
||||
mrs x11, dbgbvr6_el1
|
||||
mrs x10, dbgbvr5_el1
|
||||
mrs x9, dbgbvr4_el1
|
||||
mrs x8, dbgbvr3_el1
|
||||
mrs x7, dbgbvr2_el1
|
||||
mrs x6, dbgbvr1_el1
|
||||
mrs x5, dbgbvr0_el1
|
||||
|
||||
adr x26, 1f
|
||||
add x26, x26, x24, lsl #2
|
||||
br x26
|
||||
|
||||
1:
|
||||
str x20, [x3, #(15 * 8)]
|
||||
str x19, [x3, #(14 * 8)]
|
||||
str x18, [x3, #(13 * 8)]
|
||||
str x17, [x3, #(12 * 8)]
|
||||
str x16, [x3, #(11 * 8)]
|
||||
str x15, [x3, #(10 * 8)]
|
||||
str x14, [x3, #(9 * 8)]
|
||||
str x13, [x3, #(8 * 8)]
|
||||
str x12, [x3, #(7 * 8)]
|
||||
str x11, [x3, #(6 * 8)]
|
||||
str x10, [x3, #(5 * 8)]
|
||||
str x9, [x3, #(4 * 8)]
|
||||
str x8, [x3, #(3 * 8)]
|
||||
str x7, [x3, #(2 * 8)]
|
||||
str x6, [x3, #(1 * 8)]
|
||||
str x5, [x3, #(0 * 8)]
|
||||
|
||||
add x3, x2, #CPU_SYSREG_OFFSET(DBGWCR0_EL1)
|
||||
|
||||
adr x26, 1f
|
||||
add x26, x26, x25, lsl #2
|
||||
br x26
|
||||
1:
|
||||
mrs x20, dbgwcr15_el1
|
||||
mrs x19, dbgwcr14_el1
|
||||
mrs x18, dbgwcr13_el1
|
||||
mrs x17, dbgwcr12_el1
|
||||
mrs x16, dbgwcr11_el1
|
||||
mrs x15, dbgwcr10_el1
|
||||
mrs x14, dbgwcr9_el1
|
||||
mrs x13, dbgwcr8_el1
|
||||
mrs x12, dbgwcr7_el1
|
||||
mrs x11, dbgwcr6_el1
|
||||
mrs x10, dbgwcr5_el1
|
||||
mrs x9, dbgwcr4_el1
|
||||
mrs x8, dbgwcr3_el1
|
||||
mrs x7, dbgwcr2_el1
|
||||
mrs x6, dbgwcr1_el1
|
||||
mrs x5, dbgwcr0_el1
|
||||
|
||||
adr x26, 1f
|
||||
add x26, x26, x25, lsl #2
|
||||
br x26
|
||||
|
||||
1:
|
||||
str x20, [x3, #(15 * 8)]
|
||||
str x19, [x3, #(14 * 8)]
|
||||
str x18, [x3, #(13 * 8)]
|
||||
str x17, [x3, #(12 * 8)]
|
||||
str x16, [x3, #(11 * 8)]
|
||||
str x15, [x3, #(10 * 8)]
|
||||
str x14, [x3, #(9 * 8)]
|
||||
str x13, [x3, #(8 * 8)]
|
||||
str x12, [x3, #(7 * 8)]
|
||||
str x11, [x3, #(6 * 8)]
|
||||
str x10, [x3, #(5 * 8)]
|
||||
str x9, [x3, #(4 * 8)]
|
||||
str x8, [x3, #(3 * 8)]
|
||||
str x7, [x3, #(2 * 8)]
|
||||
str x6, [x3, #(1 * 8)]
|
||||
str x5, [x3, #(0 * 8)]
|
||||
|
||||
add x3, x2, #CPU_SYSREG_OFFSET(DBGWVR0_EL1)
|
||||
|
||||
adr x26, 1f
|
||||
add x26, x26, x25, lsl #2
|
||||
br x26
|
||||
1:
|
||||
mrs x20, dbgwvr15_el1
|
||||
mrs x19, dbgwvr14_el1
|
||||
mrs x18, dbgwvr13_el1
|
||||
mrs x17, dbgwvr12_el1
|
||||
mrs x16, dbgwvr11_el1
|
||||
mrs x15, dbgwvr10_el1
|
||||
mrs x14, dbgwvr9_el1
|
||||
mrs x13, dbgwvr8_el1
|
||||
mrs x12, dbgwvr7_el1
|
||||
mrs x11, dbgwvr6_el1
|
||||
mrs x10, dbgwvr5_el1
|
||||
mrs x9, dbgwvr4_el1
|
||||
mrs x8, dbgwvr3_el1
|
||||
mrs x7, dbgwvr2_el1
|
||||
mrs x6, dbgwvr1_el1
|
||||
mrs x5, dbgwvr0_el1
|
||||
|
||||
adr x26, 1f
|
||||
add x26, x26, x25, lsl #2
|
||||
br x26
|
||||
|
||||
1:
|
||||
str x20, [x3, #(15 * 8)]
|
||||
str x19, [x3, #(14 * 8)]
|
||||
str x18, [x3, #(13 * 8)]
|
||||
str x17, [x3, #(12 * 8)]
|
||||
str x16, [x3, #(11 * 8)]
|
||||
str x15, [x3, #(10 * 8)]
|
||||
str x14, [x3, #(9 * 8)]
|
||||
str x13, [x3, #(8 * 8)]
|
||||
str x12, [x3, #(7 * 8)]
|
||||
str x11, [x3, #(6 * 8)]
|
||||
str x10, [x3, #(5 * 8)]
|
||||
str x9, [x3, #(4 * 8)]
|
||||
str x8, [x3, #(3 * 8)]
|
||||
str x7, [x3, #(2 * 8)]
|
||||
str x6, [x3, #(1 * 8)]
|
||||
str x5, [x3, #(0 * 8)]
|
||||
|
||||
mrs x21, mdccint_el1
|
||||
str x21, [x2, #CPU_SYSREG_OFFSET(MDCCINT_EL1)]
|
||||
.endm
|
||||
|
||||
.macro restore_sysregs
|
||||
|
|
@ -245,7 +438,7 @@ __kvm_hyp_code_start:
|
|||
ldp x18, x19, [x3, #112]
|
||||
ldp x20, x21, [x3, #128]
|
||||
ldp x22, x23, [x3, #144]
|
||||
ldr x24, [x3, #160]
|
||||
ldp x24, x25, [x3, #160]
|
||||
|
||||
msr vmpidr_el2, x4
|
||||
msr csselr_el1, x5
|
||||
|
|
@ -268,6 +461,198 @@ __kvm_hyp_code_start:
|
|||
msr amair_el1, x22
|
||||
msr cntkctl_el1, x23
|
||||
msr par_el1, x24
|
||||
msr mdscr_el1, x25
|
||||
.endm
|
||||
|
||||
.macro restore_debug
|
||||
// x2: base address for cpu context
|
||||
// x3: tmp register
|
||||
|
||||
mrs x26, id_aa64dfr0_el1
|
||||
ubfx x24, x26, #12, #4 // Extract BRPs
|
||||
ubfx x25, x26, #20, #4 // Extract WRPs
|
||||
mov w26, #15
|
||||
sub w24, w26, w24 // How many BPs to skip
|
||||
sub w25, w26, w25 // How many WPs to skip
|
||||
|
||||
add x3, x2, #CPU_SYSREG_OFFSET(DBGBCR0_EL1)
|
||||
|
||||
adr x26, 1f
|
||||
add x26, x26, x24, lsl #2
|
||||
br x26
|
||||
1:
|
||||
ldr x20, [x3, #(15 * 8)]
|
||||
ldr x19, [x3, #(14 * 8)]
|
||||
ldr x18, [x3, #(13 * 8)]
|
||||
ldr x17, [x3, #(12 * 8)]
|
||||
ldr x16, [x3, #(11 * 8)]
|
||||
ldr x15, [x3, #(10 * 8)]
|
||||
ldr x14, [x3, #(9 * 8)]
|
||||
ldr x13, [x3, #(8 * 8)]
|
||||
ldr x12, [x3, #(7 * 8)]
|
||||
ldr x11, [x3, #(6 * 8)]
|
||||
ldr x10, [x3, #(5 * 8)]
|
||||
ldr x9, [x3, #(4 * 8)]
|
||||
ldr x8, [x3, #(3 * 8)]
|
||||
ldr x7, [x3, #(2 * 8)]
|
||||
ldr x6, [x3, #(1 * 8)]
|
||||
ldr x5, [x3, #(0 * 8)]
|
||||
|
||||
adr x26, 1f
|
||||
add x26, x26, x24, lsl #2
|
||||
br x26
|
||||
1:
|
||||
msr dbgbcr15_el1, x20
|
||||
msr dbgbcr14_el1, x19
|
||||
msr dbgbcr13_el1, x18
|
||||
msr dbgbcr12_el1, x17
|
||||
msr dbgbcr11_el1, x16
|
||||
msr dbgbcr10_el1, x15
|
||||
msr dbgbcr9_el1, x14
|
||||
msr dbgbcr8_el1, x13
|
||||
msr dbgbcr7_el1, x12
|
||||
msr dbgbcr6_el1, x11
|
||||
msr dbgbcr5_el1, x10
|
||||
msr dbgbcr4_el1, x9
|
||||
msr dbgbcr3_el1, x8
|
||||
msr dbgbcr2_el1, x7
|
||||
msr dbgbcr1_el1, x6
|
||||
msr dbgbcr0_el1, x5
|
||||
|
||||
add x3, x2, #CPU_SYSREG_OFFSET(DBGBVR0_EL1)
|
||||
|
||||
adr x26, 1f
|
||||
add x26, x26, x24, lsl #2
|
||||
br x26
|
||||
1:
|
||||
ldr x20, [x3, #(15 * 8)]
|
||||
ldr x19, [x3, #(14 * 8)]
|
||||
ldr x18, [x3, #(13 * 8)]
|
||||
ldr x17, [x3, #(12 * 8)]
|
||||
ldr x16, [x3, #(11 * 8)]
|
||||
ldr x15, [x3, #(10 * 8)]
|
||||
ldr x14, [x3, #(9 * 8)]
|
||||
ldr x13, [x3, #(8 * 8)]
|
||||
ldr x12, [x3, #(7 * 8)]
|
||||
ldr x11, [x3, #(6 * 8)]
|
||||
ldr x10, [x3, #(5 * 8)]
|
||||
ldr x9, [x3, #(4 * 8)]
|
||||
ldr x8, [x3, #(3 * 8)]
|
||||
ldr x7, [x3, #(2 * 8)]
|
||||
ldr x6, [x3, #(1 * 8)]
|
||||
ldr x5, [x3, #(0 * 8)]
|
||||
|
||||
adr x26, 1f
|
||||
add x26, x26, x24, lsl #2
|
||||
br x26
|
||||
1:
|
||||
msr dbgbvr15_el1, x20
|
||||
msr dbgbvr14_el1, x19
|
||||
msr dbgbvr13_el1, x18
|
||||
msr dbgbvr12_el1, x17
|
||||
msr dbgbvr11_el1, x16
|
||||
msr dbgbvr10_el1, x15
|
||||
msr dbgbvr9_el1, x14
|
||||
msr dbgbvr8_el1, x13
|
||||
msr dbgbvr7_el1, x12
|
||||
msr dbgbvr6_el1, x11
|
||||
msr dbgbvr5_el1, x10
|
||||
msr dbgbvr4_el1, x9
|
||||
msr dbgbvr3_el1, x8
|
||||
msr dbgbvr2_el1, x7
|
||||
msr dbgbvr1_el1, x6
|
||||
msr dbgbvr0_el1, x5
|
||||
|
||||
add x3, x2, #CPU_SYSREG_OFFSET(DBGWCR0_EL1)
|
||||
|
||||
adr x26, 1f
|
||||
add x26, x26, x25, lsl #2
|
||||
br x26
|
||||
1:
|
||||
ldr x20, [x3, #(15 * 8)]
|
||||
ldr x19, [x3, #(14 * 8)]
|
||||
ldr x18, [x3, #(13 * 8)]
|
||||
ldr x17, [x3, #(12 * 8)]
|
||||
ldr x16, [x3, #(11 * 8)]
|
||||
ldr x15, [x3, #(10 * 8)]
|
||||
ldr x14, [x3, #(9 * 8)]
|
||||
ldr x13, [x3, #(8 * 8)]
|
||||
ldr x12, [x3, #(7 * 8)]
|
||||
ldr x11, [x3, #(6 * 8)]
|
||||
ldr x10, [x3, #(5 * 8)]
|
||||
ldr x9, [x3, #(4 * 8)]
|
||||
ldr x8, [x3, #(3 * 8)]
|
||||
ldr x7, [x3, #(2 * 8)]
|
||||
ldr x6, [x3, #(1 * 8)]
|
||||
ldr x5, [x3, #(0 * 8)]
|
||||
|
||||
adr x26, 1f
|
||||
add x26, x26, x25, lsl #2
|
||||
br x26
|
||||
1:
|
||||
msr dbgwcr15_el1, x20
|
||||
msr dbgwcr14_el1, x19
|
||||
msr dbgwcr13_el1, x18
|
||||
msr dbgwcr12_el1, x17
|
||||
msr dbgwcr11_el1, x16
|
||||
msr dbgwcr10_el1, x15
|
||||
msr dbgwcr9_el1, x14
|
||||
msr dbgwcr8_el1, x13
|
||||
msr dbgwcr7_el1, x12
|
||||
msr dbgwcr6_el1, x11
|
||||
msr dbgwcr5_el1, x10
|
||||
msr dbgwcr4_el1, x9
|
||||
msr dbgwcr3_el1, x8
|
||||
msr dbgwcr2_el1, x7
|
||||
msr dbgwcr1_el1, x6
|
||||
msr dbgwcr0_el1, x5
|
||||
|
||||
add x3, x2, #CPU_SYSREG_OFFSET(DBGWVR0_EL1)
|
||||
|
||||
adr x26, 1f
|
||||
add x26, x26, x25, lsl #2
|
||||
br x26
|
||||
1:
|
||||
ldr x20, [x3, #(15 * 8)]
|
||||
ldr x19, [x3, #(14 * 8)]
|
||||
ldr x18, [x3, #(13 * 8)]
|
||||
ldr x17, [x3, #(12 * 8)]
|
||||
ldr x16, [x3, #(11 * 8)]
|
||||
ldr x15, [x3, #(10 * 8)]
|
||||
ldr x14, [x3, #(9 * 8)]
|
||||
ldr x13, [x3, #(8 * 8)]
|
||||
ldr x12, [x3, #(7 * 8)]
|
||||
ldr x11, [x3, #(6 * 8)]
|
||||
ldr x10, [x3, #(5 * 8)]
|
||||
ldr x9, [x3, #(4 * 8)]
|
||||
ldr x8, [x3, #(3 * 8)]
|
||||
ldr x7, [x3, #(2 * 8)]
|
||||
ldr x6, [x3, #(1 * 8)]
|
||||
ldr x5, [x3, #(0 * 8)]
|
||||
|
||||
adr x26, 1f
|
||||
add x26, x26, x25, lsl #2
|
||||
br x26
|
||||
1:
|
||||
msr dbgwvr15_el1, x20
|
||||
msr dbgwvr14_el1, x19
|
||||
msr dbgwvr13_el1, x18
|
||||
msr dbgwvr12_el1, x17
|
||||
msr dbgwvr11_el1, x16
|
||||
msr dbgwvr10_el1, x15
|
||||
msr dbgwvr9_el1, x14
|
||||
msr dbgwvr8_el1, x13
|
||||
msr dbgwvr7_el1, x12
|
||||
msr dbgwvr6_el1, x11
|
||||
msr dbgwvr5_el1, x10
|
||||
msr dbgwvr4_el1, x9
|
||||
msr dbgwvr3_el1, x8
|
||||
msr dbgwvr2_el1, x7
|
||||
msr dbgwvr1_el1, x6
|
||||
msr dbgwvr0_el1, x5
|
||||
|
||||
ldr x21, [x2, #CPU_SYSREG_OFFSET(MDCCINT_EL1)]
|
||||
msr mdccint_el1, x21
|
||||
.endm
|
||||
|
||||
.macro skip_32bit_state tmp, target
|
||||
|
|
@ -282,6 +667,35 @@ __kvm_hyp_code_start:
|
|||
tbz \tmp, #12, \target
|
||||
.endm
|
||||
|
||||
.macro skip_debug_state tmp, target
|
||||
ldr \tmp, [x0, #VCPU_DEBUG_FLAGS]
|
||||
tbz \tmp, #KVM_ARM64_DEBUG_DIRTY_SHIFT, \target
|
||||
.endm
|
||||
|
||||
.macro compute_debug_state target
|
||||
// Compute debug state: If any of KDE, MDE or KVM_ARM64_DEBUG_DIRTY
|
||||
// is set, we do a full save/restore cycle and disable trapping.
|
||||
add x25, x0, #VCPU_CONTEXT
|
||||
|
||||
// Check the state of MDSCR_EL1
|
||||
ldr x25, [x25, #CPU_SYSREG_OFFSET(MDSCR_EL1)]
|
||||
and x26, x25, #DBG_MDSCR_KDE
|
||||
and x25, x25, #DBG_MDSCR_MDE
|
||||
adds xzr, x25, x26
|
||||
b.eq 9998f // Nothing to see there
|
||||
|
||||
// If any interesting bits was set, we must set the flag
|
||||
mov x26, #KVM_ARM64_DEBUG_DIRTY
|
||||
str x26, [x0, #VCPU_DEBUG_FLAGS]
|
||||
b 9999f // Don't skip restore
|
||||
|
||||
9998:
|
||||
// Otherwise load the flags from memory in case we recently
|
||||
// trapped
|
||||
skip_debug_state x25, \target
|
||||
9999:
|
||||
.endm
|
||||
|
||||
.macro save_guest_32bit_state
|
||||
skip_32bit_state x3, 1f
|
||||
|
||||
|
|
@ -297,10 +711,13 @@ __kvm_hyp_code_start:
|
|||
mrs x4, dacr32_el2
|
||||
mrs x5, ifsr32_el2
|
||||
mrs x6, fpexc32_el2
|
||||
mrs x7, dbgvcr32_el2
|
||||
stp x4, x5, [x3]
|
||||
stp x6, x7, [x3, #16]
|
||||
str x6, [x3, #16]
|
||||
|
||||
skip_debug_state x8, 2f
|
||||
mrs x7, dbgvcr32_el2
|
||||
str x7, [x3, #24]
|
||||
2:
|
||||
skip_tee_state x8, 1f
|
||||
|
||||
add x3, x2, #CPU_SYSREG_OFFSET(TEECR32_EL1)
|
||||
|
|
@ -323,12 +740,15 @@ __kvm_hyp_code_start:
|
|||
|
||||
add x3, x2, #CPU_SYSREG_OFFSET(DACR32_EL2)
|
||||
ldp x4, x5, [x3]
|
||||
ldp x6, x7, [x3, #16]
|
||||
ldr x6, [x3, #16]
|
||||
msr dacr32_el2, x4
|
||||
msr ifsr32_el2, x5
|
||||
msr fpexc32_el2, x6
|
||||
msr dbgvcr32_el2, x7
|
||||
|
||||
skip_debug_state x8, 2f
|
||||
ldr x7, [x3, #24]
|
||||
msr dbgvcr32_el2, x7
|
||||
2:
|
||||
skip_tee_state x8, 1f
|
||||
|
||||
add x3, x2, #CPU_SYSREG_OFFSET(TEECR32_EL1)
|
||||
|
|
@ -339,11 +759,8 @@ __kvm_hyp_code_start:
|
|||
.endm
|
||||
|
||||
.macro activate_traps
|
||||
ldr x2, [x0, #VCPU_IRQ_LINES]
|
||||
ldr x1, [x0, #VCPU_HCR_EL2]
|
||||
orr x2, x2, x1
|
||||
msr hcr_el2, x2
|
||||
|
||||
ldr x2, [x0, #VCPU_HCR_EL2]
|
||||
msr hcr_el2, x2
|
||||
ldr x2, =(CPTR_EL2_TTA)
|
||||
msr cptr_el2, x2
|
||||
|
||||
|
|
@ -353,6 +770,14 @@ __kvm_hyp_code_start:
|
|||
mrs x2, mdcr_el2
|
||||
and x2, x2, #MDCR_EL2_HPMN_MASK
|
||||
orr x2, x2, #(MDCR_EL2_TPM | MDCR_EL2_TPMCR)
|
||||
orr x2, x2, #(MDCR_EL2_TDRA | MDCR_EL2_TDOSA)
|
||||
|
||||
// Check for KVM_ARM64_DEBUG_DIRTY, and set debug to trap
|
||||
// if not dirty.
|
||||
ldr x3, [x0, #VCPU_DEBUG_FLAGS]
|
||||
tbnz x3, #KVM_ARM64_DEBUG_DIRTY_SHIFT, 1f
|
||||
orr x2, x2, #MDCR_EL2_TDA
|
||||
1:
|
||||
msr mdcr_el2, x2
|
||||
.endm
|
||||
|
||||
|
|
@ -379,100 +804,33 @@ __kvm_hyp_code_start:
|
|||
.endm
|
||||
|
||||
/*
|
||||
* Save the VGIC CPU state into memory
|
||||
* x0: Register pointing to VCPU struct
|
||||
* Do not corrupt x1!!!
|
||||
* Call into the vgic backend for state saving
|
||||
*/
|
||||
.macro save_vgic_state
|
||||
/* Get VGIC VCTRL base into x2 */
|
||||
ldr x2, [x0, #VCPU_KVM]
|
||||
kern_hyp_va x2
|
||||
ldr x2, [x2, #KVM_VGIC_VCTRL]
|
||||
kern_hyp_va x2
|
||||
cbz x2, 2f // disabled
|
||||
|
||||
/* Compute the address of struct vgic_cpu */
|
||||
add x3, x0, #VCPU_VGIC_CPU
|
||||
|
||||
/* Save all interesting registers */
|
||||
ldr w4, [x2, #GICH_HCR]
|
||||
ldr w5, [x2, #GICH_VMCR]
|
||||
ldr w6, [x2, #GICH_MISR]
|
||||
ldr w7, [x2, #GICH_EISR0]
|
||||
ldr w8, [x2, #GICH_EISR1]
|
||||
ldr w9, [x2, #GICH_ELRSR0]
|
||||
ldr w10, [x2, #GICH_ELRSR1]
|
||||
ldr w11, [x2, #GICH_APR]
|
||||
CPU_BE( rev w4, w4 )
|
||||
CPU_BE( rev w5, w5 )
|
||||
CPU_BE( rev w6, w6 )
|
||||
CPU_BE( rev w7, w7 )
|
||||
CPU_BE( rev w8, w8 )
|
||||
CPU_BE( rev w9, w9 )
|
||||
CPU_BE( rev w10, w10 )
|
||||
CPU_BE( rev w11, w11 )
|
||||
|
||||
str w4, [x3, #VGIC_CPU_HCR]
|
||||
str w5, [x3, #VGIC_CPU_VMCR]
|
||||
str w6, [x3, #VGIC_CPU_MISR]
|
||||
str w7, [x3, #VGIC_CPU_EISR]
|
||||
str w8, [x3, #(VGIC_CPU_EISR + 4)]
|
||||
str w9, [x3, #VGIC_CPU_ELRSR]
|
||||
str w10, [x3, #(VGIC_CPU_ELRSR + 4)]
|
||||
str w11, [x3, #VGIC_CPU_APR]
|
||||
|
||||
/* Clear GICH_HCR */
|
||||
str wzr, [x2, #GICH_HCR]
|
||||
|
||||
/* Save list registers */
|
||||
add x2, x2, #GICH_LR0
|
||||
ldr w4, [x3, #VGIC_CPU_NR_LR]
|
||||
add x3, x3, #VGIC_CPU_LR
|
||||
1: ldr w5, [x2], #4
|
||||
CPU_BE( rev w5, w5 )
|
||||
str w5, [x3], #4
|
||||
sub w4, w4, #1
|
||||
cbnz w4, 1b
|
||||
2:
|
||||
adr x24, __vgic_sr_vectors
|
||||
ldr x24, [x24, VGIC_SAVE_FN]
|
||||
kern_hyp_va x24
|
||||
blr x24
|
||||
mrs x24, hcr_el2
|
||||
mov x25, #HCR_INT_OVERRIDE
|
||||
neg x25, x25
|
||||
and x24, x24, x25
|
||||
msr hcr_el2, x24
|
||||
.endm
|
||||
|
||||
/*
|
||||
* Restore the VGIC CPU state from memory
|
||||
* x0: Register pointing to VCPU struct
|
||||
* Call into the vgic backend for state restoring
|
||||
*/
|
||||
.macro restore_vgic_state
|
||||
/* Get VGIC VCTRL base into x2 */
|
||||
ldr x2, [x0, #VCPU_KVM]
|
||||
kern_hyp_va x2
|
||||
ldr x2, [x2, #KVM_VGIC_VCTRL]
|
||||
kern_hyp_va x2
|
||||
cbz x2, 2f // disabled
|
||||
|
||||
/* Compute the address of struct vgic_cpu */
|
||||
add x3, x0, #VCPU_VGIC_CPU
|
||||
|
||||
/* We only restore a minimal set of registers */
|
||||
ldr w4, [x3, #VGIC_CPU_HCR]
|
||||
ldr w5, [x3, #VGIC_CPU_VMCR]
|
||||
ldr w6, [x3, #VGIC_CPU_APR]
|
||||
CPU_BE( rev w4, w4 )
|
||||
CPU_BE( rev w5, w5 )
|
||||
CPU_BE( rev w6, w6 )
|
||||
|
||||
str w4, [x2, #GICH_HCR]
|
||||
str w5, [x2, #GICH_VMCR]
|
||||
str w6, [x2, #GICH_APR]
|
||||
|
||||
/* Restore list registers */
|
||||
add x2, x2, #GICH_LR0
|
||||
ldr w4, [x3, #VGIC_CPU_NR_LR]
|
||||
add x3, x3, #VGIC_CPU_LR
|
||||
1: ldr w5, [x3], #4
|
||||
CPU_BE( rev w5, w5 )
|
||||
str w5, [x2], #4
|
||||
sub w4, w4, #1
|
||||
cbnz w4, 1b
|
||||
2:
|
||||
mrs x24, hcr_el2
|
||||
ldr x25, [x0, #VCPU_IRQ_LINES]
|
||||
orr x24, x24, #HCR_INT_OVERRIDE
|
||||
orr x24, x24, x25
|
||||
msr hcr_el2, x24
|
||||
adr x24, __vgic_sr_vectors
|
||||
ldr x24, [x24, #VGIC_RESTORE_FN]
|
||||
kern_hyp_va x24
|
||||
blr x24
|
||||
.endm
|
||||
|
||||
.macro save_timer_state
|
||||
|
|
@ -537,6 +895,14 @@ __restore_sysregs:
|
|||
restore_sysregs
|
||||
ret
|
||||
|
||||
__save_debug:
|
||||
save_debug
|
||||
ret
|
||||
|
||||
__restore_debug:
|
||||
restore_debug
|
||||
ret
|
||||
|
||||
__save_fpsimd:
|
||||
save_fpsimd
|
||||
ret
|
||||
|
|
@ -568,6 +934,9 @@ ENTRY(__kvm_vcpu_run)
|
|||
bl __save_fpsimd
|
||||
bl __save_sysregs
|
||||
|
||||
compute_debug_state 1f
|
||||
bl __save_debug
|
||||
1:
|
||||
activate_traps
|
||||
activate_vm
|
||||
|
||||
|
|
@ -579,6 +948,10 @@ ENTRY(__kvm_vcpu_run)
|
|||
|
||||
bl __restore_sysregs
|
||||
bl __restore_fpsimd
|
||||
|
||||
skip_debug_state x3, 1f
|
||||
bl __restore_debug
|
||||
1:
|
||||
restore_guest_32bit_state
|
||||
restore_guest_regs
|
||||
|
||||
|
|
@ -595,6 +968,10 @@ __kvm_vcpu_return:
|
|||
save_guest_regs
|
||||
bl __save_fpsimd
|
||||
bl __save_sysregs
|
||||
|
||||
skip_debug_state x3, 1f
|
||||
bl __save_debug
|
||||
1:
|
||||
save_guest_32bit_state
|
||||
|
||||
save_timer_state
|
||||
|
|
@ -609,6 +986,14 @@ __kvm_vcpu_return:
|
|||
|
||||
bl __restore_sysregs
|
||||
bl __restore_fpsimd
|
||||
|
||||
skip_debug_state x3, 1f
|
||||
// Clear the dirty flag for the next run, as all the state has
|
||||
// already been saved. Note that we nuke the whole 64bit word.
|
||||
// If we ever add more flags, we'll have to be more careful...
|
||||
str xzr, [x0, #VCPU_DEBUG_FLAGS]
|
||||
bl __restore_debug
|
||||
1:
|
||||
restore_host_regs
|
||||
|
||||
mov x0, x1
|
||||
|
|
@ -653,6 +1038,12 @@ ENTRY(__kvm_flush_vm_context)
|
|||
ret
|
||||
ENDPROC(__kvm_flush_vm_context)
|
||||
|
||||
// struct vgic_sr_vectors __vgi_sr_vectors;
|
||||
.align 3
|
||||
ENTRY(__vgic_sr_vectors)
|
||||
.skip VGIC_SR_VECTOR_SZ
|
||||
ENDPROC(__vgic_sr_vectors)
|
||||
|
||||
__kvm_hyp_panic:
|
||||
// Guess the context by looking at VTTBR:
|
||||
// If zero, then we're already a host.
|
||||
|
|
@ -830,7 +1221,7 @@ el1_trap:
|
|||
mrs x2, far_el2
|
||||
|
||||
2: mrs x0, tpidr_el2
|
||||
str x1, [x0, #VCPU_ESR_EL2]
|
||||
str w1, [x0, #VCPU_ESR_EL2]
|
||||
str x2, [x0, #VCPU_FAR_EL2]
|
||||
str x3, [x0, #VCPU_HPFAR_EL2]
|
||||
|
||||
|
|
@ -880,7 +1271,4 @@ ENTRY(__kvm_hyp_vector)
|
|||
ventry el1_error_invalid // Error 32-bit EL1
|
||||
ENDPROC(__kvm_hyp_vector)
|
||||
|
||||
__kvm_hyp_code_end:
|
||||
.globl __kvm_hyp_code_end
|
||||
|
||||
.popsection
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include <asm/kvm_mmu.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/cputype.h>
|
||||
#include <asm/debug-monitors.h>
|
||||
#include <trace/events/kvm.h>
|
||||
|
||||
#include "sys_regs.h"
|
||||
|
|
@ -137,10 +138,11 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu,
|
|||
if (!p->is_aarch32) {
|
||||
vcpu_sys_reg(vcpu, r->reg) = val;
|
||||
} else {
|
||||
vcpu_cp15(vcpu, r->reg) = val & 0xffffffffUL;
|
||||
if (!p->is_32bit)
|
||||
vcpu_cp15(vcpu, r->reg + 1) = val >> 32;
|
||||
vcpu_cp15_64_high(vcpu, r->reg) = val >> 32;
|
||||
vcpu_cp15_64_low(vcpu, r->reg) = val & 0xffffffffUL;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -163,18 +165,9 @@ static bool access_sctlr(struct kvm_vcpu *vcpu,
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* We could trap ID_DFR0 and tell the guest we don't support performance
|
||||
* monitoring. Unfortunately the patch to make the kernel check ID_DFR0 was
|
||||
* NAKed, so it will read the PMCR anyway.
|
||||
*
|
||||
* Therefore we tell the guest we have 0 counters. Unfortunately, we
|
||||
* must always support PMCCNTR (the cycle counter): we just RAZ/WI for
|
||||
* all PM registers, which doesn't crash the guest kernel at least.
|
||||
*/
|
||||
static bool pm_fake(struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
static bool trap_raz_wi(struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
if (p->is_write)
|
||||
return ignore_write(vcpu, p);
|
||||
|
|
@ -182,6 +175,73 @@ static bool pm_fake(struct kvm_vcpu *vcpu,
|
|||
return read_zero(vcpu, p);
|
||||
}
|
||||
|
||||
static bool trap_oslsr_el1(struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
if (p->is_write) {
|
||||
return ignore_write(vcpu, p);
|
||||
} else {
|
||||
*vcpu_reg(vcpu, p->Rt) = (1 << 3);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool trap_dbgauthstatus_el1(struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
if (p->is_write) {
|
||||
return ignore_write(vcpu, p);
|
||||
} else {
|
||||
u32 val;
|
||||
asm volatile("mrs %0, dbgauthstatus_el1" : "=r" (val));
|
||||
*vcpu_reg(vcpu, p->Rt) = val;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We want to avoid world-switching all the DBG registers all the
|
||||
* time:
|
||||
*
|
||||
* - If we've touched any debug register, it is likely that we're
|
||||
* going to touch more of them. It then makes sense to disable the
|
||||
* traps and start doing the save/restore dance
|
||||
* - If debug is active (DBG_MDSCR_KDE or DBG_MDSCR_MDE set), it is
|
||||
* then mandatory to save/restore the registers, as the guest
|
||||
* depends on them.
|
||||
*
|
||||
* For this, we use a DIRTY bit, indicating the guest has modified the
|
||||
* debug registers, used as follow:
|
||||
*
|
||||
* On guest entry:
|
||||
* - If the dirty bit is set (because we're coming back from trapping),
|
||||
* disable the traps, save host registers, restore guest registers.
|
||||
* - If debug is actively in use (DBG_MDSCR_KDE or DBG_MDSCR_MDE set),
|
||||
* set the dirty bit, disable the traps, save host registers,
|
||||
* restore guest registers.
|
||||
* - Otherwise, enable the traps
|
||||
*
|
||||
* On guest exit:
|
||||
* - If the dirty bit is set, save guest registers, restore host
|
||||
* registers and clear the dirty bit. This ensure that the host can
|
||||
* now use the debug registers.
|
||||
*/
|
||||
static bool trap_debug_regs(struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
if (p->is_write) {
|
||||
vcpu_sys_reg(vcpu, r->reg) = *vcpu_reg(vcpu, p->Rt);
|
||||
vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
|
||||
} else {
|
||||
*vcpu_reg(vcpu, p->Rt) = vcpu_sys_reg(vcpu, r->reg);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void reset_amair_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
|
||||
{
|
||||
u64 amair;
|
||||
|
|
@ -198,9 +258,39 @@ static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
|
|||
vcpu_sys_reg(vcpu, MPIDR_EL1) = (1UL << 31) | (vcpu->vcpu_id & 0xff);
|
||||
}
|
||||
|
||||
/* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
|
||||
#define DBG_BCR_BVR_WCR_WVR_EL1(n) \
|
||||
/* DBGBVRn_EL1 */ \
|
||||
{ Op0(0b10), Op1(0b000), CRn(0b0000), CRm((n)), Op2(0b100), \
|
||||
trap_debug_regs, reset_val, (DBGBVR0_EL1 + (n)), 0 }, \
|
||||
/* DBGBCRn_EL1 */ \
|
||||
{ Op0(0b10), Op1(0b000), CRn(0b0000), CRm((n)), Op2(0b101), \
|
||||
trap_debug_regs, reset_val, (DBGBCR0_EL1 + (n)), 0 }, \
|
||||
/* DBGWVRn_EL1 */ \
|
||||
{ Op0(0b10), Op1(0b000), CRn(0b0000), CRm((n)), Op2(0b110), \
|
||||
trap_debug_regs, reset_val, (DBGWVR0_EL1 + (n)), 0 }, \
|
||||
/* DBGWCRn_EL1 */ \
|
||||
{ Op0(0b10), Op1(0b000), CRn(0b0000), CRm((n)), Op2(0b111), \
|
||||
trap_debug_regs, reset_val, (DBGWCR0_EL1 + (n)), 0 }
|
||||
|
||||
/*
|
||||
* Architected system registers.
|
||||
* Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2
|
||||
*
|
||||
* We could trap ID_DFR0 and tell the guest we don't support performance
|
||||
* monitoring. Unfortunately the patch to make the kernel check ID_DFR0 was
|
||||
* NAKed, so it will read the PMCR anyway.
|
||||
*
|
||||
* Therefore we tell the guest we have 0 counters. Unfortunately, we
|
||||
* must always support PMCCNTR (the cycle counter): we just RAZ/WI for
|
||||
* all PM registers, which doesn't crash the guest kernel at least.
|
||||
*
|
||||
* Debug handling: We do trap most, if not all debug related system
|
||||
* registers. The implementation is good enough to ensure that a guest
|
||||
* can use these with minimal performance degradation. The drawback is
|
||||
* that we don't implement any of the external debug, none of the
|
||||
* OSlock protocol. This should be revisited if we ever encounter a
|
||||
* more demanding guest...
|
||||
*/
|
||||
static const struct sys_reg_desc sys_reg_descs[] = {
|
||||
/* DC ISW */
|
||||
|
|
@ -213,12 +303,71 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
|||
{ Op0(0b01), Op1(0b000), CRn(0b0111), CRm(0b1110), Op2(0b010),
|
||||
access_dcsw },
|
||||
|
||||
DBG_BCR_BVR_WCR_WVR_EL1(0),
|
||||
DBG_BCR_BVR_WCR_WVR_EL1(1),
|
||||
/* MDCCINT_EL1 */
|
||||
{ Op0(0b10), Op1(0b000), CRn(0b0000), CRm(0b0010), Op2(0b000),
|
||||
trap_debug_regs, reset_val, MDCCINT_EL1, 0 },
|
||||
/* MDSCR_EL1 */
|
||||
{ Op0(0b10), Op1(0b000), CRn(0b0000), CRm(0b0010), Op2(0b010),
|
||||
trap_debug_regs, reset_val, MDSCR_EL1, 0 },
|
||||
DBG_BCR_BVR_WCR_WVR_EL1(2),
|
||||
DBG_BCR_BVR_WCR_WVR_EL1(3),
|
||||
DBG_BCR_BVR_WCR_WVR_EL1(4),
|
||||
DBG_BCR_BVR_WCR_WVR_EL1(5),
|
||||
DBG_BCR_BVR_WCR_WVR_EL1(6),
|
||||
DBG_BCR_BVR_WCR_WVR_EL1(7),
|
||||
DBG_BCR_BVR_WCR_WVR_EL1(8),
|
||||
DBG_BCR_BVR_WCR_WVR_EL1(9),
|
||||
DBG_BCR_BVR_WCR_WVR_EL1(10),
|
||||
DBG_BCR_BVR_WCR_WVR_EL1(11),
|
||||
DBG_BCR_BVR_WCR_WVR_EL1(12),
|
||||
DBG_BCR_BVR_WCR_WVR_EL1(13),
|
||||
DBG_BCR_BVR_WCR_WVR_EL1(14),
|
||||
DBG_BCR_BVR_WCR_WVR_EL1(15),
|
||||
|
||||
/* MDRAR_EL1 */
|
||||
{ Op0(0b10), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b000),
|
||||
trap_raz_wi },
|
||||
/* OSLAR_EL1 */
|
||||
{ Op0(0b10), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b100),
|
||||
trap_raz_wi },
|
||||
/* OSLSR_EL1 */
|
||||
{ Op0(0b10), Op1(0b000), CRn(0b0001), CRm(0b0001), Op2(0b100),
|
||||
trap_oslsr_el1 },
|
||||
/* OSDLR_EL1 */
|
||||
{ Op0(0b10), Op1(0b000), CRn(0b0001), CRm(0b0011), Op2(0b100),
|
||||
trap_raz_wi },
|
||||
/* DBGPRCR_EL1 */
|
||||
{ Op0(0b10), Op1(0b000), CRn(0b0001), CRm(0b0100), Op2(0b100),
|
||||
trap_raz_wi },
|
||||
/* DBGCLAIMSET_EL1 */
|
||||
{ Op0(0b10), Op1(0b000), CRn(0b0111), CRm(0b1000), Op2(0b110),
|
||||
trap_raz_wi },
|
||||
/* DBGCLAIMCLR_EL1 */
|
||||
{ Op0(0b10), Op1(0b000), CRn(0b0111), CRm(0b1001), Op2(0b110),
|
||||
trap_raz_wi },
|
||||
/* DBGAUTHSTATUS_EL1 */
|
||||
{ Op0(0b10), Op1(0b000), CRn(0b0111), CRm(0b1110), Op2(0b110),
|
||||
trap_dbgauthstatus_el1 },
|
||||
|
||||
/* TEECR32_EL1 */
|
||||
{ Op0(0b10), Op1(0b010), CRn(0b0000), CRm(0b0000), Op2(0b000),
|
||||
NULL, reset_val, TEECR32_EL1, 0 },
|
||||
/* TEEHBR32_EL1 */
|
||||
{ Op0(0b10), Op1(0b010), CRn(0b0001), CRm(0b0000), Op2(0b000),
|
||||
NULL, reset_val, TEEHBR32_EL1, 0 },
|
||||
|
||||
/* MDCCSR_EL1 */
|
||||
{ Op0(0b10), Op1(0b011), CRn(0b0000), CRm(0b0001), Op2(0b000),
|
||||
trap_raz_wi },
|
||||
/* DBGDTR_EL0 */
|
||||
{ Op0(0b10), Op1(0b011), CRn(0b0000), CRm(0b0100), Op2(0b000),
|
||||
trap_raz_wi },
|
||||
/* DBGDTR[TR]X_EL0 */
|
||||
{ Op0(0b10), Op1(0b011), CRn(0b0000), CRm(0b0101), Op2(0b000),
|
||||
trap_raz_wi },
|
||||
|
||||
/* DBGVCR32_EL2 */
|
||||
{ Op0(0b10), Op1(0b100), CRn(0b0000), CRm(0b0111), Op2(0b000),
|
||||
NULL, reset_val, DBGVCR32_EL2, 0 },
|
||||
|
|
@ -260,10 +409,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
|||
|
||||
/* PMINTENSET_EL1 */
|
||||
{ Op0(0b11), Op1(0b000), CRn(0b1001), CRm(0b1110), Op2(0b001),
|
||||
pm_fake },
|
||||
trap_raz_wi },
|
||||
/* PMINTENCLR_EL1 */
|
||||
{ Op0(0b11), Op1(0b000), CRn(0b1001), CRm(0b1110), Op2(0b010),
|
||||
pm_fake },
|
||||
trap_raz_wi },
|
||||
|
||||
/* MAIR_EL1 */
|
||||
{ Op0(0b11), Op1(0b000), CRn(0b1010), CRm(0b0010), Op2(0b000),
|
||||
|
|
@ -292,43 +441,43 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
|||
|
||||
/* PMCR_EL0 */
|
||||
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b000),
|
||||
pm_fake },
|
||||
trap_raz_wi },
|
||||
/* PMCNTENSET_EL0 */
|
||||
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b001),
|
||||
pm_fake },
|
||||
trap_raz_wi },
|
||||
/* PMCNTENCLR_EL0 */
|
||||
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b010),
|
||||
pm_fake },
|
||||
trap_raz_wi },
|
||||
/* PMOVSCLR_EL0 */
|
||||
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b011),
|
||||
pm_fake },
|
||||
trap_raz_wi },
|
||||
/* PMSWINC_EL0 */
|
||||
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b100),
|
||||
pm_fake },
|
||||
trap_raz_wi },
|
||||
/* PMSELR_EL0 */
|
||||
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b101),
|
||||
pm_fake },
|
||||
trap_raz_wi },
|
||||
/* PMCEID0_EL0 */
|
||||
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b110),
|
||||
pm_fake },
|
||||
trap_raz_wi },
|
||||
/* PMCEID1_EL0 */
|
||||
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b111),
|
||||
pm_fake },
|
||||
trap_raz_wi },
|
||||
/* PMCCNTR_EL0 */
|
||||
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b000),
|
||||
pm_fake },
|
||||
trap_raz_wi },
|
||||
/* PMXEVTYPER_EL0 */
|
||||
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b001),
|
||||
pm_fake },
|
||||
trap_raz_wi },
|
||||
/* PMXEVCNTR_EL0 */
|
||||
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b010),
|
||||
pm_fake },
|
||||
trap_raz_wi },
|
||||
/* PMUSERENR_EL0 */
|
||||
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b000),
|
||||
pm_fake },
|
||||
trap_raz_wi },
|
||||
/* PMOVSSET_EL0 */
|
||||
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b011),
|
||||
pm_fake },
|
||||
trap_raz_wi },
|
||||
|
||||
/* TPIDR_EL0 */
|
||||
{ Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b0000), Op2(0b010),
|
||||
|
|
@ -348,13 +497,161 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
|||
NULL, reset_val, FPEXC32_EL2, 0x70 },
|
||||
};
|
||||
|
||||
static bool trap_dbgidr(struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
if (p->is_write) {
|
||||
return ignore_write(vcpu, p);
|
||||
} else {
|
||||
u64 dfr = read_cpuid(ID_AA64DFR0_EL1);
|
||||
u64 pfr = read_cpuid(ID_AA64PFR0_EL1);
|
||||
u32 el3 = !!((pfr >> 12) & 0xf);
|
||||
|
||||
*vcpu_reg(vcpu, p->Rt) = ((((dfr >> 20) & 0xf) << 28) |
|
||||
(((dfr >> 12) & 0xf) << 24) |
|
||||
(((dfr >> 28) & 0xf) << 20) |
|
||||
(6 << 16) | (el3 << 14) | (el3 << 12));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool trap_debug32(struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
if (p->is_write) {
|
||||
vcpu_cp14(vcpu, r->reg) = *vcpu_reg(vcpu, p->Rt);
|
||||
vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
|
||||
} else {
|
||||
*vcpu_reg(vcpu, p->Rt) = vcpu_cp14(vcpu, r->reg);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define DBG_BCR_BVR_WCR_WVR(n) \
|
||||
/* DBGBVRn */ \
|
||||
{ Op1( 0), CRn( 0), CRm((n)), Op2( 4), trap_debug32, \
|
||||
NULL, (cp14_DBGBVR0 + (n) * 2) }, \
|
||||
/* DBGBCRn */ \
|
||||
{ Op1( 0), CRn( 0), CRm((n)), Op2( 5), trap_debug32, \
|
||||
NULL, (cp14_DBGBCR0 + (n) * 2) }, \
|
||||
/* DBGWVRn */ \
|
||||
{ Op1( 0), CRn( 0), CRm((n)), Op2( 6), trap_debug32, \
|
||||
NULL, (cp14_DBGWVR0 + (n) * 2) }, \
|
||||
/* DBGWCRn */ \
|
||||
{ Op1( 0), CRn( 0), CRm((n)), Op2( 7), trap_debug32, \
|
||||
NULL, (cp14_DBGWCR0 + (n) * 2) }
|
||||
|
||||
#define DBGBXVR(n) \
|
||||
{ Op1( 0), CRn( 1), CRm((n)), Op2( 1), trap_debug32, \
|
||||
NULL, cp14_DBGBXVR0 + n * 2 }
|
||||
|
||||
/*
|
||||
* Trapped cp14 registers. We generally ignore most of the external
|
||||
* debug, on the principle that they don't really make sense to a
|
||||
* guest. Revisit this one day, whould this principle change.
|
||||
*/
|
||||
static const struct sys_reg_desc cp14_regs[] = {
|
||||
/* DBGIDR */
|
||||
{ Op1( 0), CRn( 0), CRm( 0), Op2( 0), trap_dbgidr },
|
||||
/* DBGDTRRXext */
|
||||
{ Op1( 0), CRn( 0), CRm( 0), Op2( 2), trap_raz_wi },
|
||||
|
||||
DBG_BCR_BVR_WCR_WVR(0),
|
||||
/* DBGDSCRint */
|
||||
{ Op1( 0), CRn( 0), CRm( 1), Op2( 0), trap_raz_wi },
|
||||
DBG_BCR_BVR_WCR_WVR(1),
|
||||
/* DBGDCCINT */
|
||||
{ Op1( 0), CRn( 0), CRm( 2), Op2( 0), trap_debug32 },
|
||||
/* DBGDSCRext */
|
||||
{ Op1( 0), CRn( 0), CRm( 2), Op2( 2), trap_debug32 },
|
||||
DBG_BCR_BVR_WCR_WVR(2),
|
||||
/* DBGDTR[RT]Xint */
|
||||
{ Op1( 0), CRn( 0), CRm( 3), Op2( 0), trap_raz_wi },
|
||||
/* DBGDTR[RT]Xext */
|
||||
{ Op1( 0), CRn( 0), CRm( 3), Op2( 2), trap_raz_wi },
|
||||
DBG_BCR_BVR_WCR_WVR(3),
|
||||
DBG_BCR_BVR_WCR_WVR(4),
|
||||
DBG_BCR_BVR_WCR_WVR(5),
|
||||
/* DBGWFAR */
|
||||
{ Op1( 0), CRn( 0), CRm( 6), Op2( 0), trap_raz_wi },
|
||||
/* DBGOSECCR */
|
||||
{ Op1( 0), CRn( 0), CRm( 6), Op2( 2), trap_raz_wi },
|
||||
DBG_BCR_BVR_WCR_WVR(6),
|
||||
/* DBGVCR */
|
||||
{ Op1( 0), CRn( 0), CRm( 7), Op2( 0), trap_debug32 },
|
||||
DBG_BCR_BVR_WCR_WVR(7),
|
||||
DBG_BCR_BVR_WCR_WVR(8),
|
||||
DBG_BCR_BVR_WCR_WVR(9),
|
||||
DBG_BCR_BVR_WCR_WVR(10),
|
||||
DBG_BCR_BVR_WCR_WVR(11),
|
||||
DBG_BCR_BVR_WCR_WVR(12),
|
||||
DBG_BCR_BVR_WCR_WVR(13),
|
||||
DBG_BCR_BVR_WCR_WVR(14),
|
||||
DBG_BCR_BVR_WCR_WVR(15),
|
||||
|
||||
/* DBGDRAR (32bit) */
|
||||
{ Op1( 0), CRn( 1), CRm( 0), Op2( 0), trap_raz_wi },
|
||||
|
||||
DBGBXVR(0),
|
||||
/* DBGOSLAR */
|
||||
{ Op1( 0), CRn( 1), CRm( 0), Op2( 4), trap_raz_wi },
|
||||
DBGBXVR(1),
|
||||
/* DBGOSLSR */
|
||||
{ Op1( 0), CRn( 1), CRm( 1), Op2( 4), trap_oslsr_el1 },
|
||||
DBGBXVR(2),
|
||||
DBGBXVR(3),
|
||||
/* DBGOSDLR */
|
||||
{ Op1( 0), CRn( 1), CRm( 3), Op2( 4), trap_raz_wi },
|
||||
DBGBXVR(4),
|
||||
/* DBGPRCR */
|
||||
{ Op1( 0), CRn( 1), CRm( 4), Op2( 4), trap_raz_wi },
|
||||
DBGBXVR(5),
|
||||
DBGBXVR(6),
|
||||
DBGBXVR(7),
|
||||
DBGBXVR(8),
|
||||
DBGBXVR(9),
|
||||
DBGBXVR(10),
|
||||
DBGBXVR(11),
|
||||
DBGBXVR(12),
|
||||
DBGBXVR(13),
|
||||
DBGBXVR(14),
|
||||
DBGBXVR(15),
|
||||
|
||||
/* DBGDSAR (32bit) */
|
||||
{ Op1( 0), CRn( 2), CRm( 0), Op2( 0), trap_raz_wi },
|
||||
|
||||
/* DBGDEVID2 */
|
||||
{ Op1( 0), CRn( 7), CRm( 0), Op2( 7), trap_raz_wi },
|
||||
/* DBGDEVID1 */
|
||||
{ Op1( 0), CRn( 7), CRm( 1), Op2( 7), trap_raz_wi },
|
||||
/* DBGDEVID */
|
||||
{ Op1( 0), CRn( 7), CRm( 2), Op2( 7), trap_raz_wi },
|
||||
/* DBGCLAIMSET */
|
||||
{ Op1( 0), CRn( 7), CRm( 8), Op2( 6), trap_raz_wi },
|
||||
/* DBGCLAIMCLR */
|
||||
{ Op1( 0), CRn( 7), CRm( 9), Op2( 6), trap_raz_wi },
|
||||
/* DBGAUTHSTATUS */
|
||||
{ Op1( 0), CRn( 7), CRm(14), Op2( 6), trap_dbgauthstatus_el1 },
|
||||
};
|
||||
|
||||
/* Trapped cp14 64bit registers */
|
||||
static const struct sys_reg_desc cp14_64_regs[] = {
|
||||
/* DBGDRAR (64bit) */
|
||||
{ Op1( 0), CRm( 1), .access = trap_raz_wi },
|
||||
|
||||
/* DBGDSAR (64bit) */
|
||||
{ Op1( 0), CRm( 2), .access = trap_raz_wi },
|
||||
};
|
||||
|
||||
/*
|
||||
* Trapped cp15 registers. TTBR0/TTBR1 get a double encoding,
|
||||
* depending on the way they are accessed (as a 32bit or a 64bit
|
||||
* register).
|
||||
*/
|
||||
static const struct sys_reg_desc cp15_regs[] = {
|
||||
{ Op1( 0), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, c2_TTBR0 },
|
||||
{ Op1( 0), CRn( 1), CRm( 0), Op2( 0), access_sctlr, NULL, c1_SCTLR },
|
||||
{ Op1( 0), CRn( 2), CRm( 0), Op2( 0), access_vm_reg, NULL, c2_TTBR0 },
|
||||
{ Op1( 0), CRn( 2), CRm( 0), Op2( 1), access_vm_reg, NULL, c2_TTBR1 },
|
||||
|
|
@ -374,26 +671,30 @@ static const struct sys_reg_desc cp15_regs[] = {
|
|||
{ Op1( 0), CRn( 7), CRm(10), Op2( 2), access_dcsw },
|
||||
{ Op1( 0), CRn( 7), CRm(14), Op2( 2), access_dcsw },
|
||||
|
||||
{ Op1( 0), CRn( 9), CRm(12), Op2( 0), pm_fake },
|
||||
{ Op1( 0), CRn( 9), CRm(12), Op2( 1), pm_fake },
|
||||
{ Op1( 0), CRn( 9), CRm(12), Op2( 2), pm_fake },
|
||||
{ Op1( 0), CRn( 9), CRm(12), Op2( 3), pm_fake },
|
||||
{ Op1( 0), CRn( 9), CRm(12), Op2( 5), pm_fake },
|
||||
{ Op1( 0), CRn( 9), CRm(12), Op2( 6), pm_fake },
|
||||
{ Op1( 0), CRn( 9), CRm(12), Op2( 7), pm_fake },
|
||||
{ Op1( 0), CRn( 9), CRm(13), Op2( 0), pm_fake },
|
||||
{ Op1( 0), CRn( 9), CRm(13), Op2( 1), pm_fake },
|
||||
{ Op1( 0), CRn( 9), CRm(13), Op2( 2), pm_fake },
|
||||
{ Op1( 0), CRn( 9), CRm(14), Op2( 0), pm_fake },
|
||||
{ Op1( 0), CRn( 9), CRm(14), Op2( 1), pm_fake },
|
||||
{ Op1( 0), CRn( 9), CRm(14), Op2( 2), pm_fake },
|
||||
/* PMU */
|
||||
{ Op1( 0), CRn( 9), CRm(12), Op2( 0), trap_raz_wi },
|
||||
{ Op1( 0), CRn( 9), CRm(12), Op2( 1), trap_raz_wi },
|
||||
{ Op1( 0), CRn( 9), CRm(12), Op2( 2), trap_raz_wi },
|
||||
{ Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
|
||||
{ Op1( 0), CRn( 9), CRm(12), Op2( 5), trap_raz_wi },
|
||||
{ Op1( 0), CRn( 9), CRm(12), Op2( 6), trap_raz_wi },
|
||||
{ Op1( 0), CRn( 9), CRm(12), Op2( 7), trap_raz_wi },
|
||||
{ Op1( 0), CRn( 9), CRm(13), Op2( 0), trap_raz_wi },
|
||||
{ Op1( 0), CRn( 9), CRm(13), Op2( 1), trap_raz_wi },
|
||||
{ Op1( 0), CRn( 9), CRm(13), Op2( 2), trap_raz_wi },
|
||||
{ Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
|
||||
{ Op1( 0), CRn( 9), CRm(14), Op2( 1), trap_raz_wi },
|
||||
{ Op1( 0), CRn( 9), CRm(14), Op2( 2), trap_raz_wi },
|
||||
|
||||
{ Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, c10_PRRR },
|
||||
{ Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR },
|
||||
{ Op1( 0), CRn(10), CRm( 3), Op2( 0), access_vm_reg, NULL, c10_AMAIR0 },
|
||||
{ Op1( 0), CRn(10), CRm( 3), Op2( 1), access_vm_reg, NULL, c10_AMAIR1 },
|
||||
{ Op1( 0), CRn(13), CRm( 0), Op2( 1), access_vm_reg, NULL, c13_CID },
|
||||
};
|
||||
|
||||
static const struct sys_reg_desc cp15_64_regs[] = {
|
||||
{ Op1( 0), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, c2_TTBR0 },
|
||||
{ Op1( 1), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, c2_TTBR1 },
|
||||
};
|
||||
|
||||
|
|
@ -454,26 +755,29 @@ int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|||
return 1;
|
||||
}
|
||||
|
||||
int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
/*
|
||||
* emulate_cp -- tries to match a sys_reg access in a handling table, and
|
||||
* call the corresponding trap handler.
|
||||
*
|
||||
* @params: pointer to the descriptor of the access
|
||||
* @table: array of trap descriptors
|
||||
* @num: size of the trap descriptor array
|
||||
*
|
||||
* Return 0 if the access has been handled, and -1 if not.
|
||||
*/
|
||||
static int emulate_cp(struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_params *params,
|
||||
const struct sys_reg_desc *table,
|
||||
size_t num)
|
||||
{
|
||||
kvm_inject_undefined(vcpu);
|
||||
return 1;
|
||||
}
|
||||
const struct sys_reg_desc *r;
|
||||
|
||||
static void emulate_cp15(struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_params *params)
|
||||
{
|
||||
size_t num;
|
||||
const struct sys_reg_desc *table, *r;
|
||||
if (!table)
|
||||
return -1; /* Not handled */
|
||||
|
||||
table = get_target_table(vcpu->arch.target, false, &num);
|
||||
|
||||
/* Search target-specific then generic table. */
|
||||
r = find_reg(params, table, num);
|
||||
if (!r)
|
||||
r = find_reg(params, cp15_regs, ARRAY_SIZE(cp15_regs));
|
||||
|
||||
if (likely(r)) {
|
||||
if (r) {
|
||||
/*
|
||||
* Not having an accessor means that we have
|
||||
* configured a trap that we don't know how to
|
||||
|
|
@ -485,22 +789,51 @@ static void emulate_cp15(struct kvm_vcpu *vcpu,
|
|||
if (likely(r->access(vcpu, params, r))) {
|
||||
/* Skip instruction, since it was emulated */
|
||||
kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
|
||||
return;
|
||||
}
|
||||
/* If access function fails, it should complain. */
|
||||
|
||||
/* Handled */
|
||||
return 0;
|
||||
}
|
||||
|
||||
kvm_err("Unsupported guest CP15 access at: %08lx\n", *vcpu_pc(vcpu));
|
||||
/* Not handled */
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void unhandled_cp_access(struct kvm_vcpu *vcpu,
|
||||
struct sys_reg_params *params)
|
||||
{
|
||||
u8 hsr_ec = kvm_vcpu_trap_get_class(vcpu);
|
||||
int cp;
|
||||
|
||||
switch(hsr_ec) {
|
||||
case ESR_EL2_EC_CP15_32:
|
||||
case ESR_EL2_EC_CP15_64:
|
||||
cp = 15;
|
||||
break;
|
||||
case ESR_EL2_EC_CP14_MR:
|
||||
case ESR_EL2_EC_CP14_64:
|
||||
cp = 14;
|
||||
break;
|
||||
default:
|
||||
WARN_ON((cp = -1));
|
||||
}
|
||||
|
||||
kvm_err("Unsupported guest CP%d access at: %08lx\n",
|
||||
cp, *vcpu_pc(vcpu));
|
||||
print_sys_reg_instr(params);
|
||||
kvm_inject_undefined(vcpu);
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_handle_cp15_64 -- handles a mrrc/mcrr trap on a guest CP15 access
|
||||
* kvm_handle_cp_64 -- handles a mrrc/mcrr trap on a guest CP15 access
|
||||
* @vcpu: The VCPU pointer
|
||||
* @run: The kvm_run struct
|
||||
*/
|
||||
int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
static int kvm_handle_cp_64(struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_desc *global,
|
||||
size_t nr_global,
|
||||
const struct sys_reg_desc *target_specific,
|
||||
size_t nr_specific)
|
||||
{
|
||||
struct sys_reg_params params;
|
||||
u32 hsr = kvm_vcpu_get_hsr(vcpu);
|
||||
|
|
@ -529,8 +862,14 @@ int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|||
*vcpu_reg(vcpu, params.Rt) = val;
|
||||
}
|
||||
|
||||
emulate_cp15(vcpu, ¶ms);
|
||||
if (!emulate_cp(vcpu, ¶ms, target_specific, nr_specific))
|
||||
goto out;
|
||||
if (!emulate_cp(vcpu, ¶ms, global, nr_global))
|
||||
goto out;
|
||||
|
||||
unhandled_cp_access(vcpu, ¶ms);
|
||||
|
||||
out:
|
||||
/* Do the opposite hack for the read side */
|
||||
if (!params.is_write) {
|
||||
u64 val = *vcpu_reg(vcpu, params.Rt);
|
||||
|
|
@ -546,7 +885,11 @@ int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|||
* @vcpu: The VCPU pointer
|
||||
* @run: The kvm_run struct
|
||||
*/
|
||||
int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
static int kvm_handle_cp_32(struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_desc *global,
|
||||
size_t nr_global,
|
||||
const struct sys_reg_desc *target_specific,
|
||||
size_t nr_specific)
|
||||
{
|
||||
struct sys_reg_params params;
|
||||
u32 hsr = kvm_vcpu_get_hsr(vcpu);
|
||||
|
|
@ -561,10 +904,51 @@ int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|||
params.Op1 = (hsr >> 14) & 0x7;
|
||||
params.Op2 = (hsr >> 17) & 0x7;
|
||||
|
||||
emulate_cp15(vcpu, ¶ms);
|
||||
if (!emulate_cp(vcpu, ¶ms, target_specific, nr_specific))
|
||||
return 1;
|
||||
if (!emulate_cp(vcpu, ¶ms, global, nr_global))
|
||||
return 1;
|
||||
|
||||
unhandled_cp_access(vcpu, ¶ms);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
{
|
||||
const struct sys_reg_desc *target_specific;
|
||||
size_t num;
|
||||
|
||||
target_specific = get_target_table(vcpu->arch.target, false, &num);
|
||||
return kvm_handle_cp_64(vcpu,
|
||||
cp15_64_regs, ARRAY_SIZE(cp15_64_regs),
|
||||
target_specific, num);
|
||||
}
|
||||
|
||||
int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
{
|
||||
const struct sys_reg_desc *target_specific;
|
||||
size_t num;
|
||||
|
||||
target_specific = get_target_table(vcpu->arch.target, false, &num);
|
||||
return kvm_handle_cp_32(vcpu,
|
||||
cp15_regs, ARRAY_SIZE(cp15_regs),
|
||||
target_specific, num);
|
||||
}
|
||||
|
||||
int kvm_handle_cp14_64(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
{
|
||||
return kvm_handle_cp_64(vcpu,
|
||||
cp14_64_regs, ARRAY_SIZE(cp14_64_regs),
|
||||
NULL, 0);
|
||||
}
|
||||
|
||||
int kvm_handle_cp14_32(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
{
|
||||
return kvm_handle_cp_32(vcpu,
|
||||
cp14_regs, ARRAY_SIZE(cp14_regs),
|
||||
NULL, 0);
|
||||
}
|
||||
|
||||
static int emulate_sys_reg(struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_params *params)
|
||||
{
|
||||
|
|
@ -776,17 +1160,15 @@ static struct sys_reg_desc invariant_sys_regs[] = {
|
|||
NULL, get_ctr_el0 },
|
||||
};
|
||||
|
||||
static int reg_from_user(void *val, const void __user *uaddr, u64 id)
|
||||
static int reg_from_user(u64 *val, const void __user *uaddr, u64 id)
|
||||
{
|
||||
/* This Just Works because we are little endian. */
|
||||
if (copy_from_user(val, uaddr, KVM_REG_SIZE(id)) != 0)
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reg_to_user(void __user *uaddr, const void *val, u64 id)
|
||||
static int reg_to_user(void __user *uaddr, const u64 *val, u64 id)
|
||||
{
|
||||
/* This Just Works because we are little endian. */
|
||||
if (copy_to_user(uaddr, val, KVM_REG_SIZE(id)) != 0)
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
|
|
@ -962,7 +1344,7 @@ static unsigned int num_demux_regs(void)
|
|||
|
||||
static int write_demux_regids(u64 __user *uindices)
|
||||
{
|
||||
u64 val = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_DEMUX;
|
||||
u64 val = KVM_REG_ARM64 | KVM_REG_SIZE_U32 | KVM_REG_ARM_DEMUX;
|
||||
unsigned int i;
|
||||
|
||||
val |= KVM_REG_ARM_DEMUX_ID_CCSIDR;
|
||||
|
|
@ -1069,14 +1451,32 @@ int kvm_arm_copy_sys_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
|
|||
return write_demux_regids(uindices);
|
||||
}
|
||||
|
||||
static int check_sysreg_table(const struct sys_reg_desc *table, unsigned int n)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 1; i < n; i++) {
|
||||
if (cmp_sys_reg(&table[i-1], &table[i]) >= 0) {
|
||||
kvm_err("sys_reg table %p out of order (%d)\n", table, i - 1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kvm_sys_reg_table_init(void)
|
||||
{
|
||||
unsigned int i;
|
||||
struct sys_reg_desc clidr;
|
||||
|
||||
/* Make sure tables are unique and in order. */
|
||||
for (i = 1; i < ARRAY_SIZE(sys_reg_descs); i++)
|
||||
BUG_ON(cmp_sys_reg(&sys_reg_descs[i-1], &sys_reg_descs[i]) >= 0);
|
||||
BUG_ON(check_sysreg_table(sys_reg_descs, ARRAY_SIZE(sys_reg_descs)));
|
||||
BUG_ON(check_sysreg_table(cp14_regs, ARRAY_SIZE(cp14_regs)));
|
||||
BUG_ON(check_sysreg_table(cp14_64_regs, ARRAY_SIZE(cp14_64_regs)));
|
||||
BUG_ON(check_sysreg_table(cp15_regs, ARRAY_SIZE(cp15_regs)));
|
||||
BUG_ON(check_sysreg_table(cp15_64_regs, ARRAY_SIZE(cp15_64_regs)));
|
||||
BUG_ON(check_sysreg_table(invariant_sys_regs, ARRAY_SIZE(invariant_sys_regs)));
|
||||
|
||||
/* We abuse the reset function to overwrite the table itself. */
|
||||
for (i = 0; i < ARRAY_SIZE(invariant_sys_regs); i++)
|
||||
|
|
|
|||
133
arch/arm64/kvm/vgic-v2-switch.S
Normal file
133
arch/arm64/kvm/vgic-v2-switch.S
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright (C) 2012,2013 - ARM Ltd
|
||||
* Author: Marc Zyngier <marc.zyngier@arm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/irqchip/arm-gic.h>
|
||||
|
||||
#include <asm/assembler.h>
|
||||
#include <asm/memory.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm/kvm.h>
|
||||
#include <asm/kvm_asm.h>
|
||||
#include <asm/kvm_arm.h>
|
||||
#include <asm/kvm_mmu.h>
|
||||
|
||||
.text
|
||||
.pushsection .hyp.text, "ax"
|
||||
|
||||
/*
|
||||
* Save the VGIC CPU state into memory
|
||||
* x0: Register pointing to VCPU struct
|
||||
* Do not corrupt x1!!!
|
||||
*/
|
||||
ENTRY(__save_vgic_v2_state)
|
||||
__save_vgic_v2_state:
|
||||
/* Get VGIC VCTRL base into x2 */
|
||||
ldr x2, [x0, #VCPU_KVM]
|
||||
kern_hyp_va x2
|
||||
ldr x2, [x2, #KVM_VGIC_VCTRL]
|
||||
kern_hyp_va x2
|
||||
cbz x2, 2f // disabled
|
||||
|
||||
/* Compute the address of struct vgic_cpu */
|
||||
add x3, x0, #VCPU_VGIC_CPU
|
||||
|
||||
/* Save all interesting registers */
|
||||
ldr w4, [x2, #GICH_HCR]
|
||||
ldr w5, [x2, #GICH_VMCR]
|
||||
ldr w6, [x2, #GICH_MISR]
|
||||
ldr w7, [x2, #GICH_EISR0]
|
||||
ldr w8, [x2, #GICH_EISR1]
|
||||
ldr w9, [x2, #GICH_ELRSR0]
|
||||
ldr w10, [x2, #GICH_ELRSR1]
|
||||
ldr w11, [x2, #GICH_APR]
|
||||
CPU_BE( rev w4, w4 )
|
||||
CPU_BE( rev w5, w5 )
|
||||
CPU_BE( rev w6, w6 )
|
||||
CPU_BE( rev w7, w7 )
|
||||
CPU_BE( rev w8, w8 )
|
||||
CPU_BE( rev w9, w9 )
|
||||
CPU_BE( rev w10, w10 )
|
||||
CPU_BE( rev w11, w11 )
|
||||
|
||||
str w4, [x3, #VGIC_V2_CPU_HCR]
|
||||
str w5, [x3, #VGIC_V2_CPU_VMCR]
|
||||
str w6, [x3, #VGIC_V2_CPU_MISR]
|
||||
str w7, [x3, #VGIC_V2_CPU_EISR]
|
||||
str w8, [x3, #(VGIC_V2_CPU_EISR + 4)]
|
||||
str w9, [x3, #VGIC_V2_CPU_ELRSR]
|
||||
str w10, [x3, #(VGIC_V2_CPU_ELRSR + 4)]
|
||||
str w11, [x3, #VGIC_V2_CPU_APR]
|
||||
|
||||
/* Clear GICH_HCR */
|
||||
str wzr, [x2, #GICH_HCR]
|
||||
|
||||
/* Save list registers */
|
||||
add x2, x2, #GICH_LR0
|
||||
ldr w4, [x3, #VGIC_CPU_NR_LR]
|
||||
add x3, x3, #VGIC_V2_CPU_LR
|
||||
1: ldr w5, [x2], #4
|
||||
CPU_BE( rev w5, w5 )
|
||||
str w5, [x3], #4
|
||||
sub w4, w4, #1
|
||||
cbnz w4, 1b
|
||||
2:
|
||||
ret
|
||||
ENDPROC(__save_vgic_v2_state)
|
||||
|
||||
/*
|
||||
* Restore the VGIC CPU state from memory
|
||||
* x0: Register pointing to VCPU struct
|
||||
*/
|
||||
ENTRY(__restore_vgic_v2_state)
|
||||
__restore_vgic_v2_state:
|
||||
/* Get VGIC VCTRL base into x2 */
|
||||
ldr x2, [x0, #VCPU_KVM]
|
||||
kern_hyp_va x2
|
||||
ldr x2, [x2, #KVM_VGIC_VCTRL]
|
||||
kern_hyp_va x2
|
||||
cbz x2, 2f // disabled
|
||||
|
||||
/* Compute the address of struct vgic_cpu */
|
||||
add x3, x0, #VCPU_VGIC_CPU
|
||||
|
||||
/* We only restore a minimal set of registers */
|
||||
ldr w4, [x3, #VGIC_V2_CPU_HCR]
|
||||
ldr w5, [x3, #VGIC_V2_CPU_VMCR]
|
||||
ldr w6, [x3, #VGIC_V2_CPU_APR]
|
||||
CPU_BE( rev w4, w4 )
|
||||
CPU_BE( rev w5, w5 )
|
||||
CPU_BE( rev w6, w6 )
|
||||
|
||||
str w4, [x2, #GICH_HCR]
|
||||
str w5, [x2, #GICH_VMCR]
|
||||
str w6, [x2, #GICH_APR]
|
||||
|
||||
/* Restore list registers */
|
||||
add x2, x2, #GICH_LR0
|
||||
ldr w4, [x3, #VGIC_CPU_NR_LR]
|
||||
add x3, x3, #VGIC_V2_CPU_LR
|
||||
1: ldr w5, [x3], #4
|
||||
CPU_BE( rev w5, w5 )
|
||||
str w5, [x2], #4
|
||||
sub w4, w4, #1
|
||||
cbnz w4, 1b
|
||||
2:
|
||||
ret
|
||||
ENDPROC(__restore_vgic_v2_state)
|
||||
|
||||
.popsection
|
||||
267
arch/arm64/kvm/vgic-v3-switch.S
Normal file
267
arch/arm64/kvm/vgic-v3-switch.S
Normal file
|
|
@ -0,0 +1,267 @@
|
|||
/*
|
||||
* Copyright (C) 2012,2013 - ARM Ltd
|
||||
* Author: Marc Zyngier <marc.zyngier@arm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/irqchip/arm-gic-v3.h>
|
||||
|
||||
#include <asm/assembler.h>
|
||||
#include <asm/memory.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm/kvm.h>
|
||||
#include <asm/kvm_asm.h>
|
||||
#include <asm/kvm_arm.h>
|
||||
|
||||
.text
|
||||
.pushsection .hyp.text, "ax"
|
||||
|
||||
/*
|
||||
* We store LRs in reverse order to let the CPU deal with streaming
|
||||
* access. Use this macro to make it look saner...
|
||||
*/
|
||||
#define LR_OFFSET(n) (VGIC_V3_CPU_LR + (15 - n) * 8)
|
||||
|
||||
/*
|
||||
* Save the VGIC CPU state into memory
|
||||
* x0: Register pointing to VCPU struct
|
||||
* Do not corrupt x1!!!
|
||||
*/
|
||||
.macro save_vgic_v3_state
|
||||
// Compute the address of struct vgic_cpu
|
||||
add x3, x0, #VCPU_VGIC_CPU
|
||||
|
||||
// Make sure stores to the GIC via the memory mapped interface
|
||||
// are now visible to the system register interface
|
||||
dsb st
|
||||
|
||||
// Save all interesting registers
|
||||
mrs_s x4, ICH_HCR_EL2
|
||||
mrs_s x5, ICH_VMCR_EL2
|
||||
mrs_s x6, ICH_MISR_EL2
|
||||
mrs_s x7, ICH_EISR_EL2
|
||||
mrs_s x8, ICH_ELSR_EL2
|
||||
|
||||
str w4, [x3, #VGIC_V3_CPU_HCR]
|
||||
str w5, [x3, #VGIC_V3_CPU_VMCR]
|
||||
str w6, [x3, #VGIC_V3_CPU_MISR]
|
||||
str w7, [x3, #VGIC_V3_CPU_EISR]
|
||||
str w8, [x3, #VGIC_V3_CPU_ELRSR]
|
||||
|
||||
msr_s ICH_HCR_EL2, xzr
|
||||
|
||||
mrs_s x21, ICH_VTR_EL2
|
||||
mvn w22, w21
|
||||
ubfiz w23, w22, 2, 4 // w23 = (15 - ListRegs) * 4
|
||||
|
||||
adr x24, 1f
|
||||
add x24, x24, x23
|
||||
br x24
|
||||
|
||||
1:
|
||||
mrs_s x20, ICH_LR15_EL2
|
||||
mrs_s x19, ICH_LR14_EL2
|
||||
mrs_s x18, ICH_LR13_EL2
|
||||
mrs_s x17, ICH_LR12_EL2
|
||||
mrs_s x16, ICH_LR11_EL2
|
||||
mrs_s x15, ICH_LR10_EL2
|
||||
mrs_s x14, ICH_LR9_EL2
|
||||
mrs_s x13, ICH_LR8_EL2
|
||||
mrs_s x12, ICH_LR7_EL2
|
||||
mrs_s x11, ICH_LR6_EL2
|
||||
mrs_s x10, ICH_LR5_EL2
|
||||
mrs_s x9, ICH_LR4_EL2
|
||||
mrs_s x8, ICH_LR3_EL2
|
||||
mrs_s x7, ICH_LR2_EL2
|
||||
mrs_s x6, ICH_LR1_EL2
|
||||
mrs_s x5, ICH_LR0_EL2
|
||||
|
||||
adr x24, 1f
|
||||
add x24, x24, x23
|
||||
br x24
|
||||
|
||||
1:
|
||||
str x20, [x3, #LR_OFFSET(15)]
|
||||
str x19, [x3, #LR_OFFSET(14)]
|
||||
str x18, [x3, #LR_OFFSET(13)]
|
||||
str x17, [x3, #LR_OFFSET(12)]
|
||||
str x16, [x3, #LR_OFFSET(11)]
|
||||
str x15, [x3, #LR_OFFSET(10)]
|
||||
str x14, [x3, #LR_OFFSET(9)]
|
||||
str x13, [x3, #LR_OFFSET(8)]
|
||||
str x12, [x3, #LR_OFFSET(7)]
|
||||
str x11, [x3, #LR_OFFSET(6)]
|
||||
str x10, [x3, #LR_OFFSET(5)]
|
||||
str x9, [x3, #LR_OFFSET(4)]
|
||||
str x8, [x3, #LR_OFFSET(3)]
|
||||
str x7, [x3, #LR_OFFSET(2)]
|
||||
str x6, [x3, #LR_OFFSET(1)]
|
||||
str x5, [x3, #LR_OFFSET(0)]
|
||||
|
||||
tbnz w21, #29, 6f // 6 bits
|
||||
tbz w21, #30, 5f // 5 bits
|
||||
// 7 bits
|
||||
mrs_s x20, ICH_AP0R3_EL2
|
||||
str w20, [x3, #(VGIC_V3_CPU_AP0R + 3*4)]
|
||||
mrs_s x19, ICH_AP0R2_EL2
|
||||
str w19, [x3, #(VGIC_V3_CPU_AP0R + 2*4)]
|
||||
6: mrs_s x18, ICH_AP0R1_EL2
|
||||
str w18, [x3, #(VGIC_V3_CPU_AP0R + 1*4)]
|
||||
5: mrs_s x17, ICH_AP0R0_EL2
|
||||
str w17, [x3, #VGIC_V3_CPU_AP0R]
|
||||
|
||||
tbnz w21, #29, 6f // 6 bits
|
||||
tbz w21, #30, 5f // 5 bits
|
||||
// 7 bits
|
||||
mrs_s x20, ICH_AP1R3_EL2
|
||||
str w20, [x3, #(VGIC_V3_CPU_AP1R + 3*4)]
|
||||
mrs_s x19, ICH_AP1R2_EL2
|
||||
str w19, [x3, #(VGIC_V3_CPU_AP1R + 2*4)]
|
||||
6: mrs_s x18, ICH_AP1R1_EL2
|
||||
str w18, [x3, #(VGIC_V3_CPU_AP1R + 1*4)]
|
||||
5: mrs_s x17, ICH_AP1R0_EL2
|
||||
str w17, [x3, #VGIC_V3_CPU_AP1R]
|
||||
|
||||
// Restore SRE_EL1 access and re-enable SRE at EL1.
|
||||
mrs_s x5, ICC_SRE_EL2
|
||||
orr x5, x5, #ICC_SRE_EL2_ENABLE
|
||||
msr_s ICC_SRE_EL2, x5
|
||||
isb
|
||||
mov x5, #1
|
||||
msr_s ICC_SRE_EL1, x5
|
||||
.endm
|
||||
|
||||
/*
|
||||
* Restore the VGIC CPU state from memory
|
||||
* x0: Register pointing to VCPU struct
|
||||
*/
|
||||
.macro restore_vgic_v3_state
|
||||
// Disable SRE_EL1 access. Necessary, otherwise
|
||||
// ICH_VMCR_EL2.VFIQEn becomes one, and FIQ happens...
|
||||
msr_s ICC_SRE_EL1, xzr
|
||||
isb
|
||||
|
||||
// Compute the address of struct vgic_cpu
|
||||
add x3, x0, #VCPU_VGIC_CPU
|
||||
|
||||
// Restore all interesting registers
|
||||
ldr w4, [x3, #VGIC_V3_CPU_HCR]
|
||||
ldr w5, [x3, #VGIC_V3_CPU_VMCR]
|
||||
|
||||
msr_s ICH_HCR_EL2, x4
|
||||
msr_s ICH_VMCR_EL2, x5
|
||||
|
||||
mrs_s x21, ICH_VTR_EL2
|
||||
|
||||
tbnz w21, #29, 6f // 6 bits
|
||||
tbz w21, #30, 5f // 5 bits
|
||||
// 7 bits
|
||||
ldr w20, [x3, #(VGIC_V3_CPU_AP1R + 3*4)]
|
||||
msr_s ICH_AP1R3_EL2, x20
|
||||
ldr w19, [x3, #(VGIC_V3_CPU_AP1R + 2*4)]
|
||||
msr_s ICH_AP1R2_EL2, x19
|
||||
6: ldr w18, [x3, #(VGIC_V3_CPU_AP1R + 1*4)]
|
||||
msr_s ICH_AP1R1_EL2, x18
|
||||
5: ldr w17, [x3, #VGIC_V3_CPU_AP1R]
|
||||
msr_s ICH_AP1R0_EL2, x17
|
||||
|
||||
tbnz w21, #29, 6f // 6 bits
|
||||
tbz w21, #30, 5f // 5 bits
|
||||
// 7 bits
|
||||
ldr w20, [x3, #(VGIC_V3_CPU_AP0R + 3*4)]
|
||||
msr_s ICH_AP0R3_EL2, x20
|
||||
ldr w19, [x3, #(VGIC_V3_CPU_AP0R + 2*4)]
|
||||
msr_s ICH_AP0R2_EL2, x19
|
||||
6: ldr w18, [x3, #(VGIC_V3_CPU_AP0R + 1*4)]
|
||||
msr_s ICH_AP0R1_EL2, x18
|
||||
5: ldr w17, [x3, #VGIC_V3_CPU_AP0R]
|
||||
msr_s ICH_AP0R0_EL2, x17
|
||||
|
||||
and w22, w21, #0xf
|
||||
mvn w22, w21
|
||||
ubfiz w23, w22, 2, 4 // w23 = (15 - ListRegs) * 4
|
||||
|
||||
adr x24, 1f
|
||||
add x24, x24, x23
|
||||
br x24
|
||||
|
||||
1:
|
||||
ldr x20, [x3, #LR_OFFSET(15)]
|
||||
ldr x19, [x3, #LR_OFFSET(14)]
|
||||
ldr x18, [x3, #LR_OFFSET(13)]
|
||||
ldr x17, [x3, #LR_OFFSET(12)]
|
||||
ldr x16, [x3, #LR_OFFSET(11)]
|
||||
ldr x15, [x3, #LR_OFFSET(10)]
|
||||
ldr x14, [x3, #LR_OFFSET(9)]
|
||||
ldr x13, [x3, #LR_OFFSET(8)]
|
||||
ldr x12, [x3, #LR_OFFSET(7)]
|
||||
ldr x11, [x3, #LR_OFFSET(6)]
|
||||
ldr x10, [x3, #LR_OFFSET(5)]
|
||||
ldr x9, [x3, #LR_OFFSET(4)]
|
||||
ldr x8, [x3, #LR_OFFSET(3)]
|
||||
ldr x7, [x3, #LR_OFFSET(2)]
|
||||
ldr x6, [x3, #LR_OFFSET(1)]
|
||||
ldr x5, [x3, #LR_OFFSET(0)]
|
||||
|
||||
adr x24, 1f
|
||||
add x24, x24, x23
|
||||
br x24
|
||||
|
||||
1:
|
||||
msr_s ICH_LR15_EL2, x20
|
||||
msr_s ICH_LR14_EL2, x19
|
||||
msr_s ICH_LR13_EL2, x18
|
||||
msr_s ICH_LR12_EL2, x17
|
||||
msr_s ICH_LR11_EL2, x16
|
||||
msr_s ICH_LR10_EL2, x15
|
||||
msr_s ICH_LR9_EL2, x14
|
||||
msr_s ICH_LR8_EL2, x13
|
||||
msr_s ICH_LR7_EL2, x12
|
||||
msr_s ICH_LR6_EL2, x11
|
||||
msr_s ICH_LR5_EL2, x10
|
||||
msr_s ICH_LR4_EL2, x9
|
||||
msr_s ICH_LR3_EL2, x8
|
||||
msr_s ICH_LR2_EL2, x7
|
||||
msr_s ICH_LR1_EL2, x6
|
||||
msr_s ICH_LR0_EL2, x5
|
||||
|
||||
// Ensure that the above will have reached the
|
||||
// (re)distributors. This ensure the guest will read
|
||||
// the correct values from the memory-mapped interface.
|
||||
isb
|
||||
dsb sy
|
||||
|
||||
// Prevent the guest from touching the GIC system registers
|
||||
mrs_s x5, ICC_SRE_EL2
|
||||
and x5, x5, #~ICC_SRE_EL2_ENABLE
|
||||
msr_s ICC_SRE_EL2, x5
|
||||
.endm
|
||||
|
||||
ENTRY(__save_vgic_v3_state)
|
||||
save_vgic_v3_state
|
||||
ret
|
||||
ENDPROC(__save_vgic_v3_state)
|
||||
|
||||
ENTRY(__restore_vgic_v3_state)
|
||||
restore_vgic_v3_state
|
||||
ret
|
||||
ENDPROC(__restore_vgic_v3_state)
|
||||
|
||||
ENTRY(__vgic_v3_get_ich_vtr_el2)
|
||||
mrs_s x0, ICH_VTR_EL2
|
||||
ret
|
||||
ENDPROC(__vgic_v3_get_ich_vtr_el2)
|
||||
|
||||
.popsection
|
||||
Loading…
Reference in a new issue