diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2013-03-14 20:14:28 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2013-03-14 20:14:28 -0400 |
commit | 0098fc39e6d575f940487f09f303787efbc7a373 (patch) | |
tree | 051e6aab9bc675f680659e03f07c51e09c2e8dcf /arch/arm/include | |
parent | 73a09d212ec65b7068a283e6034fa05649d3d075 (diff) | |
parent | f42798c6898bf1e536673e798d263e492355162f (diff) |
Merge branch 'kvm-arm-fixes' of git://github.com/columbia/linux-kvm-arm into devel-stable
Diffstat (limited to 'arch/arm/include')
-rw-r--r-- | arch/arm/include/asm/kvm_arm.h | 4 | ||||
-rw-r--r-- | arch/arm/include/asm/kvm_asm.h | 2 | ||||
-rw-r--r-- | arch/arm/include/asm/kvm_emulate.h | 107 | ||||
-rw-r--r-- | arch/arm/include/asm/kvm_host.h | 42 | ||||
-rw-r--r-- | arch/arm/include/asm/kvm_mmu.h | 67 | ||||
-rw-r--r-- | arch/arm/include/asm/kvm_vgic.h | 1 | ||||
-rw-r--r-- | arch/arm/include/uapi/asm/kvm.h | 12 |
7 files changed, 212 insertions, 23 deletions
diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h index 7c3d813e15df..124623e5ef14 100644 --- a/arch/arm/include/asm/kvm_arm.h +++ b/arch/arm/include/asm/kvm_arm.h | |||
@@ -211,4 +211,8 @@ | |||
211 | 211 | ||
212 | #define HSR_HVC_IMM_MASK ((1UL << 16) - 1) | 212 | #define HSR_HVC_IMM_MASK ((1UL << 16) - 1) |
213 | 213 | ||
214 | #define HSR_DABT_S1PTW (1U << 7) | ||
215 | #define HSR_DABT_CM (1U << 8) | ||
216 | #define HSR_DABT_EA (1U << 9) | ||
217 | |||
214 | #endif /* __ARM_KVM_ARM_H__ */ | 218 | #endif /* __ARM_KVM_ARM_H__ */ |
diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h index e4956f4e23e1..18d50322a9e2 100644 --- a/arch/arm/include/asm/kvm_asm.h +++ b/arch/arm/include/asm/kvm_asm.h | |||
@@ -75,7 +75,7 @@ extern char __kvm_hyp_code_end[]; | |||
75 | extern void __kvm_tlb_flush_vmid(struct kvm *kvm); | 75 | extern void __kvm_tlb_flush_vmid(struct kvm *kvm); |
76 | 76 | ||
77 | extern void __kvm_flush_vm_context(void); | 77 | extern void __kvm_flush_vm_context(void); |
78 | extern void __kvm_tlb_flush_vmid(struct kvm *kvm); | 78 | extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa); |
79 | 79 | ||
80 | extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu); | 80 | extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu); |
81 | #endif | 81 | #endif |
diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h index fd611996bfb5..82b4babead2c 100644 --- a/arch/arm/include/asm/kvm_emulate.h +++ b/arch/arm/include/asm/kvm_emulate.h | |||
@@ -22,11 +22,12 @@ | |||
22 | #include <linux/kvm_host.h> | 22 | #include <linux/kvm_host.h> |
23 | #include <asm/kvm_asm.h> | 23 | #include <asm/kvm_asm.h> |
24 | #include <asm/kvm_mmio.h> | 24 | #include <asm/kvm_mmio.h> |
25 | #include <asm/kvm_arm.h> | ||
25 | 26 | ||
26 | u32 *vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num); | 27 | unsigned long *vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num); |
27 | u32 *vcpu_spsr(struct kvm_vcpu *vcpu); | 28 | unsigned long *vcpu_spsr(struct kvm_vcpu *vcpu); |
28 | 29 | ||
29 | int kvm_handle_wfi(struct kvm_vcpu *vcpu, struct kvm_run *run); | 30 | bool kvm_condition_valid(struct kvm_vcpu *vcpu); |
30 | void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr); | 31 | void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr); |
31 | void kvm_inject_undefined(struct kvm_vcpu *vcpu); | 32 | void kvm_inject_undefined(struct kvm_vcpu *vcpu); |
32 | void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr); | 33 | void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr); |
@@ -37,14 +38,14 @@ static inline bool vcpu_mode_is_32bit(struct kvm_vcpu *vcpu) | |||
37 | return 1; | 38 | return 1; |
38 | } | 39 | } |
39 | 40 | ||
40 | static inline u32 *vcpu_pc(struct kvm_vcpu *vcpu) | 41 | static inline unsigned long *vcpu_pc(struct kvm_vcpu *vcpu) |
41 | { | 42 | { |
42 | return (u32 *)&vcpu->arch.regs.usr_regs.ARM_pc; | 43 | return &vcpu->arch.regs.usr_regs.ARM_pc; |
43 | } | 44 | } |
44 | 45 | ||
45 | static inline u32 *vcpu_cpsr(struct kvm_vcpu *vcpu) | 46 | static inline unsigned long *vcpu_cpsr(struct kvm_vcpu *vcpu) |
46 | { | 47 | { |
47 | return (u32 *)&vcpu->arch.regs.usr_regs.ARM_cpsr; | 48 | return &vcpu->arch.regs.usr_regs.ARM_cpsr; |
48 | } | 49 | } |
49 | 50 | ||
50 | static inline void vcpu_set_thumb(struct kvm_vcpu *vcpu) | 51 | static inline void vcpu_set_thumb(struct kvm_vcpu *vcpu) |
@@ -69,4 +70,96 @@ static inline bool kvm_vcpu_reg_is_pc(struct kvm_vcpu *vcpu, int reg) | |||
69 | return reg == 15; | 70 | return reg == 15; |
70 | } | 71 | } |
71 | 72 | ||
73 | static inline u32 kvm_vcpu_get_hsr(struct kvm_vcpu *vcpu) | ||
74 | { | ||
75 | return vcpu->arch.fault.hsr; | ||
76 | } | ||
77 | |||
78 | static inline unsigned long kvm_vcpu_get_hfar(struct kvm_vcpu *vcpu) | ||
79 | { | ||
80 | return vcpu->arch.fault.hxfar; | ||
81 | } | ||
82 | |||
83 | static inline phys_addr_t kvm_vcpu_get_fault_ipa(struct kvm_vcpu *vcpu) | ||
84 | { | ||
85 | return ((phys_addr_t)vcpu->arch.fault.hpfar & HPFAR_MASK) << 8; | ||
86 | } | ||
87 | |||
88 | static inline unsigned long kvm_vcpu_get_hyp_pc(struct kvm_vcpu *vcpu) | ||
89 | { | ||
90 | return vcpu->arch.fault.hyp_pc; | ||
91 | } | ||
92 | |||
93 | static inline bool kvm_vcpu_dabt_isvalid(struct kvm_vcpu *vcpu) | ||
94 | { | ||
95 | return kvm_vcpu_get_hsr(vcpu) & HSR_ISV; | ||
96 | } | ||
97 | |||
98 | static inline bool kvm_vcpu_dabt_iswrite(struct kvm_vcpu *vcpu) | ||
99 | { | ||
100 | return kvm_vcpu_get_hsr(vcpu) & HSR_WNR; | ||
101 | } | ||
102 | |||
103 | static inline bool kvm_vcpu_dabt_issext(struct kvm_vcpu *vcpu) | ||
104 | { | ||
105 | return kvm_vcpu_get_hsr(vcpu) & HSR_SSE; | ||
106 | } | ||
107 | |||
108 | static inline int kvm_vcpu_dabt_get_rd(struct kvm_vcpu *vcpu) | ||
109 | { | ||
110 | return (kvm_vcpu_get_hsr(vcpu) & HSR_SRT_MASK) >> HSR_SRT_SHIFT; | ||
111 | } | ||
112 | |||
113 | static inline bool kvm_vcpu_dabt_isextabt(struct kvm_vcpu *vcpu) | ||
114 | { | ||
115 | return kvm_vcpu_get_hsr(vcpu) & HSR_DABT_EA; | ||
116 | } | ||
117 | |||
118 | static inline bool kvm_vcpu_dabt_iss1tw(struct kvm_vcpu *vcpu) | ||
119 | { | ||
120 | return kvm_vcpu_get_hsr(vcpu) & HSR_DABT_S1PTW; | ||
121 | } | ||
122 | |||
123 | /* Get Access Size from a data abort */ | ||
124 | static inline int kvm_vcpu_dabt_get_as(struct kvm_vcpu *vcpu) | ||
125 | { | ||
126 | switch ((kvm_vcpu_get_hsr(vcpu) >> 22) & 0x3) { | ||
127 | case 0: | ||
128 | return 1; | ||
129 | case 1: | ||
130 | return 2; | ||
131 | case 2: | ||
132 | return 4; | ||
133 | default: | ||
134 | kvm_err("Hardware is weird: SAS 0b11 is reserved\n"); | ||
135 | return -EFAULT; | ||
136 | } | ||
137 | } | ||
138 | |||
139 | /* This one is not specific to Data Abort */ | ||
140 | static inline bool kvm_vcpu_trap_il_is32bit(struct kvm_vcpu *vcpu) | ||
141 | { | ||
142 | return kvm_vcpu_get_hsr(vcpu) & HSR_IL; | ||
143 | } | ||
144 | |||
145 | static inline u8 kvm_vcpu_trap_get_class(struct kvm_vcpu *vcpu) | ||
146 | { | ||
147 | return kvm_vcpu_get_hsr(vcpu) >> HSR_EC_SHIFT; | ||
148 | } | ||
149 | |||
150 | static inline bool kvm_vcpu_trap_is_iabt(struct kvm_vcpu *vcpu) | ||
151 | { | ||
152 | return kvm_vcpu_trap_get_class(vcpu) == HSR_EC_IABT; | ||
153 | } | ||
154 | |||
155 | static inline u8 kvm_vcpu_trap_get_fault(struct kvm_vcpu *vcpu) | ||
156 | { | ||
157 | return kvm_vcpu_get_hsr(vcpu) & HSR_FSC_TYPE; | ||
158 | } | ||
159 | |||
160 | static inline u32 kvm_vcpu_hvc_get_imm(struct kvm_vcpu *vcpu) | ||
161 | { | ||
162 | return kvm_vcpu_get_hsr(vcpu) & HSR_HVC_IMM_MASK; | ||
163 | } | ||
164 | |||
72 | #endif /* __ARM_KVM_EMULATE_H__ */ | 165 | #endif /* __ARM_KVM_EMULATE_H__ */ |
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index d1736a53b12d..0c4e643d939e 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h | |||
@@ -80,6 +80,15 @@ struct kvm_mmu_memory_cache { | |||
80 | void *objects[KVM_NR_MEM_OBJS]; | 80 | void *objects[KVM_NR_MEM_OBJS]; |
81 | }; | 81 | }; |
82 | 82 | ||
83 | struct kvm_vcpu_fault_info { | ||
84 | u32 hsr; /* Hyp Syndrome Register */ | ||
85 | u32 hxfar; /* Hyp Data/Inst. Fault Address Register */ | ||
86 | u32 hpfar; /* Hyp IPA Fault Address Register */ | ||
87 | u32 hyp_pc; /* PC when exception was taken from Hyp mode */ | ||
88 | }; | ||
89 | |||
90 | typedef struct vfp_hard_struct kvm_kernel_vfp_t; | ||
91 | |||
83 | struct kvm_vcpu_arch { | 92 | struct kvm_vcpu_arch { |
84 | struct kvm_regs regs; | 93 | struct kvm_regs regs; |
85 | 94 | ||
@@ -93,13 +102,11 @@ struct kvm_vcpu_arch { | |||
93 | u32 midr; | 102 | u32 midr; |
94 | 103 | ||
95 | /* Exception Information */ | 104 | /* Exception Information */ |
96 | u32 hsr; /* Hyp Syndrome Register */ | 105 | struct kvm_vcpu_fault_info fault; |
97 | u32 hxfar; /* Hyp Data/Inst Fault Address Register */ | ||
98 | u32 hpfar; /* Hyp IPA Fault Address Register */ | ||
99 | 106 | ||
100 | /* Floating point registers (VFP and Advanced SIMD/NEON) */ | 107 | /* Floating point registers (VFP and Advanced SIMD/NEON) */ |
101 | struct vfp_hard_struct vfp_guest; | 108 | kvm_kernel_vfp_t vfp_guest; |
102 | struct vfp_hard_struct *vfp_host; | 109 | kvm_kernel_vfp_t *vfp_host; |
103 | 110 | ||
104 | /* VGIC state */ | 111 | /* VGIC state */ |
105 | struct vgic_cpu vgic_cpu; | 112 | struct vgic_cpu vgic_cpu; |
@@ -122,9 +129,6 @@ struct kvm_vcpu_arch { | |||
122 | /* Interrupt related fields */ | 129 | /* Interrupt related fields */ |
123 | u32 irq_lines; /* IRQ and FIQ levels */ | 130 | u32 irq_lines; /* IRQ and FIQ levels */ |
124 | 131 | ||
125 | /* Hyp exception information */ | ||
126 | u32 hyp_pc; /* PC when exception was taken from Hyp mode */ | ||
127 | |||
128 | /* Cache some mmu pages needed inside spinlock regions */ | 132 | /* Cache some mmu pages needed inside spinlock regions */ |
129 | struct kvm_mmu_memory_cache mmu_page_cache; | 133 | struct kvm_mmu_memory_cache mmu_page_cache; |
130 | 134 | ||
@@ -181,4 +185,26 @@ struct kvm_one_reg; | |||
181 | int kvm_arm_coproc_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *); | 185 | int kvm_arm_coproc_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *); |
182 | int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *); | 186 | int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *); |
183 | 187 | ||
188 | int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, | ||
189 | int exception_index); | ||
190 | |||
191 | static inline void __cpu_init_hyp_mode(unsigned long long pgd_ptr, | ||
192 | unsigned long hyp_stack_ptr, | ||
193 | unsigned long vector_ptr) | ||
194 | { | ||
195 | unsigned long pgd_low, pgd_high; | ||
196 | |||
197 | pgd_low = (pgd_ptr & ((1ULL << 32) - 1)); | ||
198 | pgd_high = (pgd_ptr >> 32ULL); | ||
199 | |||
200 | /* | ||
201 | * Call initialization code, and switch to the full blown | ||
202 | * HYP code. The init code doesn't need to preserve these registers as | ||
203 | * r1-r3 and r12 are already callee save according to the AAPCS. | ||
204 | * Note that we slightly misuse the prototype by casing the pgd_low to | ||
205 | * a void *. | ||
206 | */ | ||
207 | kvm_call_hyp((void *)pgd_low, pgd_high, hyp_stack_ptr, vector_ptr); | ||
208 | } | ||
209 | |||
184 | #endif /* __ARM_KVM_HOST_H__ */ | 210 | #endif /* __ARM_KVM_HOST_H__ */ |
diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h index 421a20b34874..970f3b5fa109 100644 --- a/arch/arm/include/asm/kvm_mmu.h +++ b/arch/arm/include/asm/kvm_mmu.h | |||
@@ -19,6 +19,18 @@ | |||
19 | #ifndef __ARM_KVM_MMU_H__ | 19 | #ifndef __ARM_KVM_MMU_H__ |
20 | #define __ARM_KVM_MMU_H__ | 20 | #define __ARM_KVM_MMU_H__ |
21 | 21 | ||
22 | #include <asm/cacheflush.h> | ||
23 | #include <asm/pgalloc.h> | ||
24 | #include <asm/idmap.h> | ||
25 | |||
26 | /* | ||
27 | * We directly use the kernel VA for the HYP, as we can directly share | ||
28 | * the mapping (HTTBR "covers" TTBR1). | ||
29 | */ | ||
30 | #define HYP_PAGE_OFFSET_MASK (~0UL) | ||
31 | #define HYP_PAGE_OFFSET PAGE_OFFSET | ||
32 | #define KERN_TO_HYP(kva) (kva) | ||
33 | |||
22 | int create_hyp_mappings(void *from, void *to); | 34 | int create_hyp_mappings(void *from, void *to); |
23 | int create_hyp_io_mappings(void *from, void *to, phys_addr_t); | 35 | int create_hyp_io_mappings(void *from, void *to, phys_addr_t); |
24 | void free_hyp_pmds(void); | 36 | void free_hyp_pmds(void); |
@@ -36,6 +48,16 @@ phys_addr_t kvm_mmu_get_httbr(void); | |||
36 | int kvm_mmu_init(void); | 48 | int kvm_mmu_init(void); |
37 | void kvm_clear_hyp_idmap(void); | 49 | void kvm_clear_hyp_idmap(void); |
38 | 50 | ||
51 | static inline void kvm_set_pte(pte_t *pte, pte_t new_pte) | ||
52 | { | ||
53 | pte_val(*pte) = new_pte; | ||
54 | /* | ||
55 | * flush_pmd_entry just takes a void pointer and cleans the necessary | ||
56 | * cache entries, so we can reuse the function for ptes. | ||
57 | */ | ||
58 | flush_pmd_entry(pte); | ||
59 | } | ||
60 | |||
39 | static inline bool kvm_is_write_fault(unsigned long hsr) | 61 | static inline bool kvm_is_write_fault(unsigned long hsr) |
40 | { | 62 | { |
41 | unsigned long hsr_ec = hsr >> HSR_EC_SHIFT; | 63 | unsigned long hsr_ec = hsr >> HSR_EC_SHIFT; |
@@ -47,4 +69,49 @@ static inline bool kvm_is_write_fault(unsigned long hsr) | |||
47 | return true; | 69 | return true; |
48 | } | 70 | } |
49 | 71 | ||
72 | static inline void kvm_clean_pgd(pgd_t *pgd) | ||
73 | { | ||
74 | clean_dcache_area(pgd, PTRS_PER_S2_PGD * sizeof(pgd_t)); | ||
75 | } | ||
76 | |||
77 | static inline void kvm_clean_pmd_entry(pmd_t *pmd) | ||
78 | { | ||
79 | clean_pmd_entry(pmd); | ||
80 | } | ||
81 | |||
82 | static inline void kvm_clean_pte(pte_t *pte) | ||
83 | { | ||
84 | clean_pte_table(pte); | ||
85 | } | ||
86 | |||
87 | static inline void kvm_set_s2pte_writable(pte_t *pte) | ||
88 | { | ||
89 | pte_val(*pte) |= L_PTE_S2_RDWR; | ||
90 | } | ||
91 | |||
92 | struct kvm; | ||
93 | |||
94 | static inline void coherent_icache_guest_page(struct kvm *kvm, gfn_t gfn) | ||
95 | { | ||
96 | /* | ||
97 | * If we are going to insert an instruction page and the icache is | ||
98 | * either VIPT or PIPT, there is a potential problem where the host | ||
99 | * (or another VM) may have used the same page as this guest, and we | ||
100 | * read incorrect data from the icache. If we're using a PIPT cache, | ||
101 | * we can invalidate just that page, but if we are using a VIPT cache | ||
102 | * we need to invalidate the entire icache - damn shame - as written | ||
103 | * in the ARM ARM (DDI 0406C.b - Page B3-1393). | ||
104 | * | ||
105 | * VIVT caches are tagged using both the ASID and the VMID and doesn't | ||
106 | * need any kind of flushing (DDI 0406C.b - Page B3-1392). | ||
107 | */ | ||
108 | if (icache_is_pipt()) { | ||
109 | unsigned long hva = gfn_to_hva(kvm, gfn); | ||
110 | __cpuc_coherent_user_range(hva, hva + PAGE_SIZE); | ||
111 | } else if (!icache_is_vivt_asid_tagged()) { | ||
112 | /* any kind of VIPT cache */ | ||
113 | __flush_icache_all(); | ||
114 | } | ||
115 | } | ||
116 | |||
50 | #endif /* __ARM_KVM_MMU_H__ */ | 117 | #endif /* __ARM_KVM_MMU_H__ */ |
diff --git a/arch/arm/include/asm/kvm_vgic.h b/arch/arm/include/asm/kvm_vgic.h index ab97207d9cd3..343744e4809c 100644 --- a/arch/arm/include/asm/kvm_vgic.h +++ b/arch/arm/include/asm/kvm_vgic.h | |||
@@ -21,7 +21,6 @@ | |||
21 | 21 | ||
22 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
23 | #include <linux/kvm.h> | 23 | #include <linux/kvm.h> |
24 | #include <linux/kvm_host.h> | ||
25 | #include <linux/irqreturn.h> | 24 | #include <linux/irqreturn.h> |
26 | #include <linux/spinlock.h> | 25 | #include <linux/spinlock.h> |
27 | #include <linux/types.h> | 26 | #include <linux/types.h> |
diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h index 023bfeb367bf..c1ee007523d7 100644 --- a/arch/arm/include/uapi/asm/kvm.h +++ b/arch/arm/include/uapi/asm/kvm.h | |||
@@ -53,12 +53,12 @@ | |||
53 | #define KVM_ARM_FIQ_spsr fiq_regs[7] | 53 | #define KVM_ARM_FIQ_spsr fiq_regs[7] |
54 | 54 | ||
55 | struct kvm_regs { | 55 | struct kvm_regs { |
56 | struct pt_regs usr_regs;/* R0_usr - R14_usr, PC, CPSR */ | 56 | struct pt_regs usr_regs; /* R0_usr - R14_usr, PC, CPSR */ |
57 | __u32 svc_regs[3]; /* SP_svc, LR_svc, SPSR_svc */ | 57 | unsigned long svc_regs[3]; /* SP_svc, LR_svc, SPSR_svc */ |
58 | __u32 abt_regs[3]; /* SP_abt, LR_abt, SPSR_abt */ | 58 | unsigned long abt_regs[3]; /* SP_abt, LR_abt, SPSR_abt */ |
59 | __u32 und_regs[3]; /* SP_und, LR_und, SPSR_und */ | 59 | unsigned long und_regs[3]; /* SP_und, LR_und, SPSR_und */ |
60 | __u32 irq_regs[3]; /* SP_irq, LR_irq, SPSR_irq */ | 60 | unsigned long irq_regs[3]; /* SP_irq, LR_irq, SPSR_irq */ |
61 | __u32 fiq_regs[8]; /* R8_fiq - R14_fiq, SPSR_fiq */ | 61 | unsigned long fiq_regs[8]; /* R8_fiq - R14_fiq, SPSR_fiq */ |
62 | }; | 62 | }; |
63 | 63 | ||
64 | /* Supported Processor Types */ | 64 | /* Supported Processor Types */ |