diff options
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/include/asm/idmap.h | 1 | ||||
-rw-r--r-- | arch/arm/include/asm/kvm_host.h | 47 | ||||
-rw-r--r-- | arch/arm/include/asm/kvm_mmu.h | 28 | ||||
-rw-r--r-- | arch/arm/kernel/asm-offsets.c | 2 | ||||
-rw-r--r-- | arch/arm/kernel/vmlinux.lds.S | 7 | ||||
-rw-r--r-- | arch/arm/kvm/Kconfig | 6 | ||||
-rw-r--r-- | arch/arm/kvm/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/kvm/arch_timer.c | 7 | ||||
-rw-r--r-- | arch/arm/kvm/arm.c | 129 | ||||
-rw-r--r-- | arch/arm/kvm/init.S | 78 | ||||
-rw-r--r-- | arch/arm/kvm/mmu.c | 455 | ||||
-rw-r--r-- | arch/arm/kvm/perf.c | 68 | ||||
-rw-r--r-- | arch/arm/mm/idmap.c | 32 |
13 files changed, 530 insertions, 332 deletions
diff --git a/arch/arm/include/asm/idmap.h b/arch/arm/include/asm/idmap.h index 1a66f907e5cc..bf863edb517d 100644 --- a/arch/arm/include/asm/idmap.h +++ b/arch/arm/include/asm/idmap.h | |||
@@ -8,7 +8,6 @@ | |||
8 | #define __idmap __section(.idmap.text) noinline notrace | 8 | #define __idmap __section(.idmap.text) noinline notrace |
9 | 9 | ||
10 | extern pgd_t *idmap_pgd; | 10 | extern pgd_t *idmap_pgd; |
11 | extern pgd_t *hyp_pgd; | ||
12 | 11 | ||
13 | void setup_mm_for_reboot(void); | 12 | void setup_mm_for_reboot(void); |
14 | 13 | ||
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index 0c4e643d939e..57cb786a6203 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h | |||
@@ -87,7 +87,7 @@ struct kvm_vcpu_fault_info { | |||
87 | u32 hyp_pc; /* PC when exception was taken from Hyp mode */ | 87 | u32 hyp_pc; /* PC when exception was taken from Hyp mode */ |
88 | }; | 88 | }; |
89 | 89 | ||
90 | typedef struct vfp_hard_struct kvm_kernel_vfp_t; | 90 | typedef struct vfp_hard_struct kvm_cpu_context_t; |
91 | 91 | ||
92 | struct kvm_vcpu_arch { | 92 | struct kvm_vcpu_arch { |
93 | struct kvm_regs regs; | 93 | struct kvm_regs regs; |
@@ -105,8 +105,10 @@ struct kvm_vcpu_arch { | |||
105 | struct kvm_vcpu_fault_info fault; | 105 | struct kvm_vcpu_fault_info fault; |
106 | 106 | ||
107 | /* Floating point registers (VFP and Advanced SIMD/NEON) */ | 107 | /* Floating point registers (VFP and Advanced SIMD/NEON) */ |
108 | kvm_kernel_vfp_t vfp_guest; | 108 | struct vfp_hard_struct vfp_guest; |
109 | kvm_kernel_vfp_t *vfp_host; | 109 | |
110 | /* Host FP context */ | ||
111 | kvm_cpu_context_t *host_cpu_context; | ||
110 | 112 | ||
111 | /* VGIC state */ | 113 | /* VGIC state */ |
112 | struct vgic_cpu vgic_cpu; | 114 | struct vgic_cpu vgic_cpu; |
@@ -188,23 +190,38 @@ int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *); | |||
188 | int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, | 190 | int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, |
189 | int exception_index); | 191 | int exception_index); |
190 | 192 | ||
191 | static inline void __cpu_init_hyp_mode(unsigned long long pgd_ptr, | 193 | static inline void __cpu_init_hyp_mode(unsigned long long boot_pgd_ptr, |
194 | unsigned long long pgd_ptr, | ||
192 | unsigned long hyp_stack_ptr, | 195 | unsigned long hyp_stack_ptr, |
193 | unsigned long vector_ptr) | 196 | unsigned long vector_ptr) |
194 | { | 197 | { |
195 | unsigned long pgd_low, pgd_high; | ||
196 | |||
197 | pgd_low = (pgd_ptr & ((1ULL << 32) - 1)); | ||
198 | pgd_high = (pgd_ptr >> 32ULL); | ||
199 | |||
200 | /* | 198 | /* |
201 | * Call initialization code, and switch to the full blown | 199 | * Call initialization code, and switch to the full blown HYP |
202 | * HYP code. The init code doesn't need to preserve these registers as | 200 | * code. The init code doesn't need to preserve these |
203 | * r1-r3 and r12 are already callee save according to the AAPCS. | 201 | * registers as r0-r3 are already callee saved according to |
204 | * Note that we slightly misuse the prototype by casing the pgd_low to | 202 | * the AAPCS. |
205 | * a void *. | 203 | * Note that we slightly misuse the prototype by casing the |
204 | * stack pointer to a void *. | ||
205 | * | ||
206 | * We don't have enough registers to perform the full init in | ||
207 | * one go. Install the boot PGD first, and then install the | ||
208 | * runtime PGD, stack pointer and vectors. The PGDs are always | ||
209 | * passed as the third argument, in order to be passed into | ||
210 | * r2-r3 to the init code (yes, this is compliant with the | ||
211 | * PCS!). | ||
206 | */ | 212 | */ |
207 | kvm_call_hyp((void *)pgd_low, pgd_high, hyp_stack_ptr, vector_ptr); | 213 | |
214 | kvm_call_hyp(NULL, 0, boot_pgd_ptr); | ||
215 | |||
216 | kvm_call_hyp((void*)hyp_stack_ptr, vector_ptr, pgd_ptr); | ||
208 | } | 217 | } |
209 | 218 | ||
219 | static inline int kvm_arch_dev_ioctl_check_extension(long ext) | ||
220 | { | ||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | int kvm_perf_init(void); | ||
225 | int kvm_perf_teardown(void); | ||
226 | |||
210 | #endif /* __ARM_KVM_HOST_H__ */ | 227 | #endif /* __ARM_KVM_HOST_H__ */ |
diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h index 970f3b5fa109..472ac7091003 100644 --- a/arch/arm/include/asm/kvm_mmu.h +++ b/arch/arm/include/asm/kvm_mmu.h | |||
@@ -19,21 +19,33 @@ | |||
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> | 22 | #include <asm/memory.h> |
23 | #include <asm/pgalloc.h> | 23 | #include <asm/page.h> |
24 | #include <asm/idmap.h> | ||
25 | 24 | ||
26 | /* | 25 | /* |
27 | * We directly use the kernel VA for the HYP, as we can directly share | 26 | * We directly use the kernel VA for the HYP, as we can directly share |
28 | * the mapping (HTTBR "covers" TTBR1). | 27 | * the mapping (HTTBR "covers" TTBR1). |
29 | */ | 28 | */ |
30 | #define HYP_PAGE_OFFSET_MASK (~0UL) | 29 | #define HYP_PAGE_OFFSET_MASK UL(~0) |
31 | #define HYP_PAGE_OFFSET PAGE_OFFSET | 30 | #define HYP_PAGE_OFFSET PAGE_OFFSET |
32 | #define KERN_TO_HYP(kva) (kva) | 31 | #define KERN_TO_HYP(kva) (kva) |
33 | 32 | ||
33 | /* | ||
34 | * Our virtual mapping for the boot-time MMU-enable code. Must be | ||
35 | * shared across all the page-tables. Conveniently, we use the vectors | ||
36 | * page, where no kernel data will ever be shared with HYP. | ||
37 | */ | ||
38 | #define TRAMPOLINE_VA UL(CONFIG_VECTORS_BASE) | ||
39 | |||
40 | #ifndef __ASSEMBLY__ | ||
41 | |||
42 | #include <asm/cacheflush.h> | ||
43 | #include <asm/pgalloc.h> | ||
44 | |||
34 | int create_hyp_mappings(void *from, void *to); | 45 | int create_hyp_mappings(void *from, void *to); |
35 | int create_hyp_io_mappings(void *from, void *to, phys_addr_t); | 46 | int create_hyp_io_mappings(void *from, void *to, phys_addr_t); |
36 | void free_hyp_pmds(void); | 47 | void free_boot_hyp_pgd(void); |
48 | void free_hyp_pgds(void); | ||
37 | 49 | ||
38 | int kvm_alloc_stage2_pgd(struct kvm *kvm); | 50 | int kvm_alloc_stage2_pgd(struct kvm *kvm); |
39 | void kvm_free_stage2_pgd(struct kvm *kvm); | 51 | void kvm_free_stage2_pgd(struct kvm *kvm); |
@@ -45,6 +57,8 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run); | |||
45 | void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu); | 57 | void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu); |
46 | 58 | ||
47 | phys_addr_t kvm_mmu_get_httbr(void); | 59 | phys_addr_t kvm_mmu_get_httbr(void); |
60 | phys_addr_t kvm_mmu_get_boot_httbr(void); | ||
61 | phys_addr_t kvm_get_idmap_vector(void); | ||
48 | int kvm_mmu_init(void); | 62 | int kvm_mmu_init(void); |
49 | void kvm_clear_hyp_idmap(void); | 63 | void kvm_clear_hyp_idmap(void); |
50 | 64 | ||
@@ -114,4 +128,8 @@ static inline void coherent_icache_guest_page(struct kvm *kvm, gfn_t gfn) | |||
114 | } | 128 | } |
115 | } | 129 | } |
116 | 130 | ||
131 | #define kvm_flush_dcache_to_poc(a,l) __cpuc_flush_dcache_area((a), (l)) | ||
132 | |||
133 | #endif /* !__ASSEMBLY__ */ | ||
134 | |||
117 | #endif /* __ARM_KVM_MMU_H__ */ | 135 | #endif /* __ARM_KVM_MMU_H__ */ |
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c index a53efa993690..ee68cce6b48e 100644 --- a/arch/arm/kernel/asm-offsets.c +++ b/arch/arm/kernel/asm-offsets.c | |||
@@ -158,7 +158,7 @@ int main(void) | |||
158 | DEFINE(VCPU_MIDR, offsetof(struct kvm_vcpu, arch.midr)); | 158 | DEFINE(VCPU_MIDR, offsetof(struct kvm_vcpu, arch.midr)); |
159 | DEFINE(VCPU_CP15, offsetof(struct kvm_vcpu, arch.cp15)); | 159 | DEFINE(VCPU_CP15, offsetof(struct kvm_vcpu, arch.cp15)); |
160 | DEFINE(VCPU_VFP_GUEST, offsetof(struct kvm_vcpu, arch.vfp_guest)); | 160 | DEFINE(VCPU_VFP_GUEST, offsetof(struct kvm_vcpu, arch.vfp_guest)); |
161 | DEFINE(VCPU_VFP_HOST, offsetof(struct kvm_vcpu, arch.vfp_host)); | 161 | DEFINE(VCPU_VFP_HOST, offsetof(struct kvm_vcpu, arch.host_cpu_context)); |
162 | DEFINE(VCPU_REGS, offsetof(struct kvm_vcpu, arch.regs)); | 162 | DEFINE(VCPU_REGS, offsetof(struct kvm_vcpu, arch.regs)); |
163 | DEFINE(VCPU_USR_REGS, offsetof(struct kvm_vcpu, arch.regs.usr_regs)); | 163 | DEFINE(VCPU_USR_REGS, offsetof(struct kvm_vcpu, arch.regs.usr_regs)); |
164 | DEFINE(VCPU_SVC_REGS, offsetof(struct kvm_vcpu, arch.regs.svc_regs)); | 164 | DEFINE(VCPU_SVC_REGS, offsetof(struct kvm_vcpu, arch.regs.svc_regs)); |
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index b571484e9f03..a871b8e00fca 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S | |||
@@ -20,7 +20,7 @@ | |||
20 | VMLINUX_SYMBOL(__idmap_text_start) = .; \ | 20 | VMLINUX_SYMBOL(__idmap_text_start) = .; \ |
21 | *(.idmap.text) \ | 21 | *(.idmap.text) \ |
22 | VMLINUX_SYMBOL(__idmap_text_end) = .; \ | 22 | VMLINUX_SYMBOL(__idmap_text_end) = .; \ |
23 | ALIGN_FUNCTION(); \ | 23 | . = ALIGN(32); \ |
24 | VMLINUX_SYMBOL(__hyp_idmap_text_start) = .; \ | 24 | VMLINUX_SYMBOL(__hyp_idmap_text_start) = .; \ |
25 | *(.hyp.idmap.text) \ | 25 | *(.hyp.idmap.text) \ |
26 | VMLINUX_SYMBOL(__hyp_idmap_text_end) = .; | 26 | VMLINUX_SYMBOL(__hyp_idmap_text_end) = .; |
@@ -315,3 +315,8 @@ SECTIONS | |||
315 | */ | 315 | */ |
316 | ASSERT((__proc_info_end - __proc_info_begin), "missing CPU support") | 316 | ASSERT((__proc_info_end - __proc_info_begin), "missing CPU support") |
317 | ASSERT((__arch_info_end - __arch_info_begin), "no machine record defined") | 317 | ASSERT((__arch_info_end - __arch_info_begin), "no machine record defined") |
318 | /* | ||
319 | * The HYP init code can't be more than a page long. | ||
320 | * The above comment applies as well. | ||
321 | */ | ||
322 | ASSERT(((__hyp_idmap_text_end - __hyp_idmap_text_start) <= PAGE_SIZE), "HYP init code too big") | ||
diff --git a/arch/arm/kvm/Kconfig b/arch/arm/kvm/Kconfig index 49dd64e579c2..370e1a8af6ac 100644 --- a/arch/arm/kvm/Kconfig +++ b/arch/arm/kvm/Kconfig | |||
@@ -41,9 +41,9 @@ config KVM_ARM_HOST | |||
41 | Provides host support for ARM processors. | 41 | Provides host support for ARM processors. |
42 | 42 | ||
43 | config KVM_ARM_MAX_VCPUS | 43 | config KVM_ARM_MAX_VCPUS |
44 | int "Number maximum supported virtual CPUs per VM" | 44 | int "Number maximum supported virtual CPUs per VM" if KVM_ARM_HOST |
45 | depends on KVM_ARM_HOST | 45 | default 4 if KVM_ARM_HOST |
46 | default 4 | 46 | default 0 |
47 | help | 47 | help |
48 | Static number of max supported virtual CPUs per VM. | 48 | Static number of max supported virtual CPUs per VM. |
49 | 49 | ||
diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile index 8dc5e76cb789..53c5ed83d16f 100644 --- a/arch/arm/kvm/Makefile +++ b/arch/arm/kvm/Makefile | |||
@@ -18,6 +18,6 @@ kvm-arm-y = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o) | |||
18 | 18 | ||
19 | obj-y += kvm-arm.o init.o interrupts.o | 19 | obj-y += kvm-arm.o init.o interrupts.o |
20 | obj-y += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o | 20 | obj-y += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o |
21 | obj-y += coproc.o coproc_a15.o mmio.o psci.o | 21 | obj-y += coproc.o coproc_a15.o mmio.o psci.o perf.o |
22 | obj-$(CONFIG_KVM_ARM_VGIC) += vgic.o | 22 | obj-$(CONFIG_KVM_ARM_VGIC) += vgic.o |
23 | obj-$(CONFIG_KVM_ARM_TIMER) += arch_timer.o | 23 | obj-$(CONFIG_KVM_ARM_TIMER) += arch_timer.o |
diff --git a/arch/arm/kvm/arch_timer.c b/arch/arm/kvm/arch_timer.c index 6ac938d46297..c55b6089e923 100644 --- a/arch/arm/kvm/arch_timer.c +++ b/arch/arm/kvm/arch_timer.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/kvm_host.h> | 22 | #include <linux/kvm_host.h> |
23 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
24 | 24 | ||
25 | #include <clocksource/arm_arch_timer.h> | ||
25 | #include <asm/arch_timer.h> | 26 | #include <asm/arch_timer.h> |
26 | 27 | ||
27 | #include <asm/kvm_vgic.h> | 28 | #include <asm/kvm_vgic.h> |
@@ -64,7 +65,7 @@ static void kvm_timer_inject_irq(struct kvm_vcpu *vcpu) | |||
64 | { | 65 | { |
65 | struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu; | 66 | struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu; |
66 | 67 | ||
67 | timer->cntv_ctl |= 1 << 1; /* Mask the interrupt in the guest */ | 68 | timer->cntv_ctl |= ARCH_TIMER_CTRL_IT_MASK; |
68 | kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id, | 69 | kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id, |
69 | vcpu->arch.timer_cpu.irq->irq, | 70 | vcpu->arch.timer_cpu.irq->irq, |
70 | vcpu->arch.timer_cpu.irq->level); | 71 | vcpu->arch.timer_cpu.irq->level); |
@@ -133,8 +134,8 @@ void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu) | |||
133 | cycle_t cval, now; | 134 | cycle_t cval, now; |
134 | u64 ns; | 135 | u64 ns; |
135 | 136 | ||
136 | /* Check if the timer is enabled and unmasked first */ | 137 | if ((timer->cntv_ctl & ARCH_TIMER_CTRL_IT_MASK) || |
137 | if ((timer->cntv_ctl & 3) != 1) | 138 | !(timer->cntv_ctl & ARCH_TIMER_CTRL_ENABLE)) |
138 | return; | 139 | return; |
139 | 140 | ||
140 | cval = timer->cntv_cval; | 141 | cval = timer->cntv_cval; |
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index a0dfc2a53f91..37d216d814cd 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c | |||
@@ -16,6 +16,7 @@ | |||
16 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 16 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/cpu.h> | ||
19 | #include <linux/errno.h> | 20 | #include <linux/errno.h> |
20 | #include <linux/err.h> | 21 | #include <linux/err.h> |
21 | #include <linux/kvm_host.h> | 22 | #include <linux/kvm_host.h> |
@@ -48,7 +49,7 @@ __asm__(".arch_extension virt"); | |||
48 | #endif | 49 | #endif |
49 | 50 | ||
50 | static DEFINE_PER_CPU(unsigned long, kvm_arm_hyp_stack_page); | 51 | static DEFINE_PER_CPU(unsigned long, kvm_arm_hyp_stack_page); |
51 | static kvm_kernel_vfp_t __percpu *kvm_host_vfp_state; | 52 | static kvm_cpu_context_t __percpu *kvm_host_cpu_state; |
52 | static unsigned long hyp_default_vectors; | 53 | static unsigned long hyp_default_vectors; |
53 | 54 | ||
54 | /* Per-CPU variable containing the currently running vcpu. */ | 55 | /* Per-CPU variable containing the currently running vcpu. */ |
@@ -206,7 +207,7 @@ int kvm_dev_ioctl_check_extension(long ext) | |||
206 | r = KVM_MAX_VCPUS; | 207 | r = KVM_MAX_VCPUS; |
207 | break; | 208 | break; |
208 | default: | 209 | default: |
209 | r = 0; | 210 | r = kvm_arch_dev_ioctl_check_extension(ext); |
210 | break; | 211 | break; |
211 | } | 212 | } |
212 | return r; | 213 | return r; |
@@ -218,27 +219,18 @@ long kvm_arch_dev_ioctl(struct file *filp, | |||
218 | return -EINVAL; | 219 | return -EINVAL; |
219 | } | 220 | } |
220 | 221 | ||
221 | int kvm_arch_set_memory_region(struct kvm *kvm, | ||
222 | struct kvm_userspace_memory_region *mem, | ||
223 | struct kvm_memory_slot old, | ||
224 | int user_alloc) | ||
225 | { | ||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | int kvm_arch_prepare_memory_region(struct kvm *kvm, | 222 | int kvm_arch_prepare_memory_region(struct kvm *kvm, |
230 | struct kvm_memory_slot *memslot, | 223 | struct kvm_memory_slot *memslot, |
231 | struct kvm_memory_slot old, | ||
232 | struct kvm_userspace_memory_region *mem, | 224 | struct kvm_userspace_memory_region *mem, |
233 | bool user_alloc) | 225 | enum kvm_mr_change change) |
234 | { | 226 | { |
235 | return 0; | 227 | return 0; |
236 | } | 228 | } |
237 | 229 | ||
238 | void kvm_arch_commit_memory_region(struct kvm *kvm, | 230 | void kvm_arch_commit_memory_region(struct kvm *kvm, |
239 | struct kvm_userspace_memory_region *mem, | 231 | struct kvm_userspace_memory_region *mem, |
240 | struct kvm_memory_slot old, | 232 | const struct kvm_memory_slot *old, |
241 | bool user_alloc) | 233 | enum kvm_mr_change change) |
242 | { | 234 | { |
243 | } | 235 | } |
244 | 236 | ||
@@ -326,7 +318,7 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) | |||
326 | void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | 318 | void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) |
327 | { | 319 | { |
328 | vcpu->cpu = cpu; | 320 | vcpu->cpu = cpu; |
329 | vcpu->arch.vfp_host = this_cpu_ptr(kvm_host_vfp_state); | 321 | vcpu->arch.host_cpu_context = this_cpu_ptr(kvm_host_cpu_state); |
330 | 322 | ||
331 | /* | 323 | /* |
332 | * Check whether this vcpu requires the cache to be flushed on | 324 | * Check whether this vcpu requires the cache to be flushed on |
@@ -639,7 +631,8 @@ static int vcpu_interrupt_line(struct kvm_vcpu *vcpu, int number, bool level) | |||
639 | return 0; | 631 | return 0; |
640 | } | 632 | } |
641 | 633 | ||
642 | int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level) | 634 | int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level, |
635 | bool line_status) | ||
643 | { | 636 | { |
644 | u32 irq = irq_level->irq; | 637 | u32 irq = irq_level->irq; |
645 | unsigned int irq_type, vcpu_idx, irq_num; | 638 | unsigned int irq_type, vcpu_idx, irq_num; |
@@ -794,30 +787,48 @@ long kvm_arch_vm_ioctl(struct file *filp, | |||
794 | } | 787 | } |
795 | } | 788 | } |
796 | 789 | ||
797 | static void cpu_init_hyp_mode(void *vector) | 790 | static void cpu_init_hyp_mode(void *dummy) |
798 | { | 791 | { |
792 | unsigned long long boot_pgd_ptr; | ||
799 | unsigned long long pgd_ptr; | 793 | unsigned long long pgd_ptr; |
800 | unsigned long hyp_stack_ptr; | 794 | unsigned long hyp_stack_ptr; |
801 | unsigned long stack_page; | 795 | unsigned long stack_page; |
802 | unsigned long vector_ptr; | 796 | unsigned long vector_ptr; |
803 | 797 | ||
804 | /* Switch from the HYP stub to our own HYP init vector */ | 798 | /* Switch from the HYP stub to our own HYP init vector */ |
805 | __hyp_set_vectors((unsigned long)vector); | 799 | __hyp_set_vectors(kvm_get_idmap_vector()); |
806 | 800 | ||
801 | boot_pgd_ptr = (unsigned long long)kvm_mmu_get_boot_httbr(); | ||
807 | pgd_ptr = (unsigned long long)kvm_mmu_get_httbr(); | 802 | pgd_ptr = (unsigned long long)kvm_mmu_get_httbr(); |
808 | stack_page = __get_cpu_var(kvm_arm_hyp_stack_page); | 803 | stack_page = __get_cpu_var(kvm_arm_hyp_stack_page); |
809 | hyp_stack_ptr = stack_page + PAGE_SIZE; | 804 | hyp_stack_ptr = stack_page + PAGE_SIZE; |
810 | vector_ptr = (unsigned long)__kvm_hyp_vector; | 805 | vector_ptr = (unsigned long)__kvm_hyp_vector; |
811 | 806 | ||
812 | __cpu_init_hyp_mode(pgd_ptr, hyp_stack_ptr, vector_ptr); | 807 | __cpu_init_hyp_mode(boot_pgd_ptr, pgd_ptr, hyp_stack_ptr, vector_ptr); |
808 | } | ||
809 | |||
810 | static int hyp_init_cpu_notify(struct notifier_block *self, | ||
811 | unsigned long action, void *cpu) | ||
812 | { | ||
813 | switch (action) { | ||
814 | case CPU_STARTING: | ||
815 | case CPU_STARTING_FROZEN: | ||
816 | cpu_init_hyp_mode(NULL); | ||
817 | break; | ||
818 | } | ||
819 | |||
820 | return NOTIFY_OK; | ||
813 | } | 821 | } |
814 | 822 | ||
823 | static struct notifier_block hyp_init_cpu_nb = { | ||
824 | .notifier_call = hyp_init_cpu_notify, | ||
825 | }; | ||
826 | |||
815 | /** | 827 | /** |
816 | * Inits Hyp-mode on all online CPUs | 828 | * Inits Hyp-mode on all online CPUs |
817 | */ | 829 | */ |
818 | static int init_hyp_mode(void) | 830 | static int init_hyp_mode(void) |
819 | { | 831 | { |
820 | phys_addr_t init_phys_addr; | ||
821 | int cpu; | 832 | int cpu; |
822 | int err = 0; | 833 | int err = 0; |
823 | 834 | ||
@@ -850,24 +861,6 @@ static int init_hyp_mode(void) | |||
850 | } | 861 | } |
851 | 862 | ||
852 | /* | 863 | /* |
853 | * Execute the init code on each CPU. | ||
854 | * | ||
855 | * Note: The stack is not mapped yet, so don't do anything else than | ||
856 | * initializing the hypervisor mode on each CPU using a local stack | ||
857 | * space for temporary storage. | ||
858 | */ | ||
859 | init_phys_addr = virt_to_phys(__kvm_hyp_init); | ||
860 | for_each_online_cpu(cpu) { | ||
861 | smp_call_function_single(cpu, cpu_init_hyp_mode, | ||
862 | (void *)(long)init_phys_addr, 1); | ||
863 | } | ||
864 | |||
865 | /* | ||
866 | * Unmap the identity mapping | ||
867 | */ | ||
868 | kvm_clear_hyp_idmap(); | ||
869 | |||
870 | /* | ||
871 | * Map the Hyp-code called directly from the host | 864 | * Map the Hyp-code called directly from the host |
872 | */ | 865 | */ |
873 | err = create_hyp_mappings(__kvm_hyp_code_start, __kvm_hyp_code_end); | 866 | err = create_hyp_mappings(__kvm_hyp_code_start, __kvm_hyp_code_end); |
@@ -890,33 +883,38 @@ static int init_hyp_mode(void) | |||
890 | } | 883 | } |
891 | 884 | ||
892 | /* | 885 | /* |
893 | * Map the host VFP structures | 886 | * Map the host CPU structures |
894 | */ | 887 | */ |
895 | kvm_host_vfp_state = alloc_percpu(kvm_kernel_vfp_t); | 888 | kvm_host_cpu_state = alloc_percpu(kvm_cpu_context_t); |
896 | if (!kvm_host_vfp_state) { | 889 | if (!kvm_host_cpu_state) { |
897 | err = -ENOMEM; | 890 | err = -ENOMEM; |
898 | kvm_err("Cannot allocate host VFP state\n"); | 891 | kvm_err("Cannot allocate host CPU state\n"); |
899 | goto out_free_mappings; | 892 | goto out_free_mappings; |
900 | } | 893 | } |
901 | 894 | ||
902 | for_each_possible_cpu(cpu) { | 895 | for_each_possible_cpu(cpu) { |
903 | kvm_kernel_vfp_t *vfp; | 896 | kvm_cpu_context_t *cpu_ctxt; |
904 | 897 | ||
905 | vfp = per_cpu_ptr(kvm_host_vfp_state, cpu); | 898 | cpu_ctxt = per_cpu_ptr(kvm_host_cpu_state, cpu); |
906 | err = create_hyp_mappings(vfp, vfp + 1); | 899 | err = create_hyp_mappings(cpu_ctxt, cpu_ctxt + 1); |
907 | 900 | ||
908 | if (err) { | 901 | if (err) { |
909 | kvm_err("Cannot map host VFP state: %d\n", err); | 902 | kvm_err("Cannot map host CPU state: %d\n", err); |
910 | goto out_free_vfp; | 903 | goto out_free_context; |
911 | } | 904 | } |
912 | } | 905 | } |
913 | 906 | ||
914 | /* | 907 | /* |
908 | * Execute the init code on each CPU. | ||
909 | */ | ||
910 | on_each_cpu(cpu_init_hyp_mode, NULL, 1); | ||
911 | |||
912 | /* | ||
915 | * Init HYP view of VGIC | 913 | * Init HYP view of VGIC |
916 | */ | 914 | */ |
917 | err = kvm_vgic_hyp_init(); | 915 | err = kvm_vgic_hyp_init(); |
918 | if (err) | 916 | if (err) |
919 | goto out_free_vfp; | 917 | goto out_free_context; |
920 | 918 | ||
921 | #ifdef CONFIG_KVM_ARM_VGIC | 919 | #ifdef CONFIG_KVM_ARM_VGIC |
922 | vgic_present = true; | 920 | vgic_present = true; |
@@ -929,12 +927,19 @@ static int init_hyp_mode(void) | |||
929 | if (err) | 927 | if (err) |
930 | goto out_free_mappings; | 928 | goto out_free_mappings; |
931 | 929 | ||
930 | #ifndef CONFIG_HOTPLUG_CPU | ||
931 | free_boot_hyp_pgd(); | ||
932 | #endif | ||
933 | |||
934 | kvm_perf_init(); | ||
935 | |||
932 | kvm_info("Hyp mode initialized successfully\n"); | 936 | kvm_info("Hyp mode initialized successfully\n"); |
937 | |||
933 | return 0; | 938 | return 0; |
934 | out_free_vfp: | 939 | out_free_context: |
935 | free_percpu(kvm_host_vfp_state); | 940 | free_percpu(kvm_host_cpu_state); |
936 | out_free_mappings: | 941 | out_free_mappings: |
937 | free_hyp_pmds(); | 942 | free_hyp_pgds(); |
938 | out_free_stack_pages: | 943 | out_free_stack_pages: |
939 | for_each_possible_cpu(cpu) | 944 | for_each_possible_cpu(cpu) |
940 | free_page(per_cpu(kvm_arm_hyp_stack_page, cpu)); | 945 | free_page(per_cpu(kvm_arm_hyp_stack_page, cpu)); |
@@ -943,27 +948,42 @@ out_err: | |||
943 | return err; | 948 | return err; |
944 | } | 949 | } |
945 | 950 | ||
951 | static void check_kvm_target_cpu(void *ret) | ||
952 | { | ||
953 | *(int *)ret = kvm_target_cpu(); | ||
954 | } | ||
955 | |||
946 | /** | 956 | /** |
947 | * Initialize Hyp-mode and memory mappings on all CPUs. | 957 | * Initialize Hyp-mode and memory mappings on all CPUs. |
948 | */ | 958 | */ |
949 | int kvm_arch_init(void *opaque) | 959 | int kvm_arch_init(void *opaque) |
950 | { | 960 | { |
951 | int err; | 961 | int err; |
962 | int ret, cpu; | ||
952 | 963 | ||
953 | if (!is_hyp_mode_available()) { | 964 | if (!is_hyp_mode_available()) { |
954 | kvm_err("HYP mode not available\n"); | 965 | kvm_err("HYP mode not available\n"); |
955 | return -ENODEV; | 966 | return -ENODEV; |
956 | } | 967 | } |
957 | 968 | ||
958 | if (kvm_target_cpu() < 0) { | 969 | for_each_online_cpu(cpu) { |
959 | kvm_err("Target CPU not supported!\n"); | 970 | smp_call_function_single(cpu, check_kvm_target_cpu, &ret, 1); |
960 | return -ENODEV; | 971 | if (ret < 0) { |
972 | kvm_err("Error, CPU %d not supported!\n", cpu); | ||
973 | return -ENODEV; | ||
974 | } | ||
961 | } | 975 | } |
962 | 976 | ||
963 | err = init_hyp_mode(); | 977 | err = init_hyp_mode(); |
964 | if (err) | 978 | if (err) |
965 | goto out_err; | 979 | goto out_err; |
966 | 980 | ||
981 | err = register_cpu_notifier(&hyp_init_cpu_nb); | ||
982 | if (err) { | ||
983 | kvm_err("Cannot register HYP init CPU notifier (%d)\n", err); | ||
984 | goto out_err; | ||
985 | } | ||
986 | |||
967 | kvm_coproc_table_init(); | 987 | kvm_coproc_table_init(); |
968 | return 0; | 988 | return 0; |
969 | out_err: | 989 | out_err: |
@@ -973,6 +993,7 @@ out_err: | |||
973 | /* NOP: Compiling as a module not supported */ | 993 | /* NOP: Compiling as a module not supported */ |
974 | void kvm_arch_exit(void) | 994 | void kvm_arch_exit(void) |
975 | { | 995 | { |
996 | kvm_perf_teardown(); | ||
976 | } | 997 | } |
977 | 998 | ||
978 | static int arm_init(void) | 999 | static int arm_init(void) |
diff --git a/arch/arm/kvm/init.S b/arch/arm/kvm/init.S index 9f37a79b880b..f048338135f7 100644 --- a/arch/arm/kvm/init.S +++ b/arch/arm/kvm/init.S | |||
@@ -21,13 +21,33 @@ | |||
21 | #include <asm/asm-offsets.h> | 21 | #include <asm/asm-offsets.h> |
22 | #include <asm/kvm_asm.h> | 22 | #include <asm/kvm_asm.h> |
23 | #include <asm/kvm_arm.h> | 23 | #include <asm/kvm_arm.h> |
24 | #include <asm/kvm_mmu.h> | ||
24 | 25 | ||
25 | /******************************************************************** | 26 | /******************************************************************** |
26 | * Hypervisor initialization | 27 | * Hypervisor initialization |
27 | * - should be called with: | 28 | * - should be called with: |
28 | * r0,r1 = Hypervisor pgd pointer | 29 | * r0 = top of Hyp stack (kernel VA) |
29 | * r2 = top of Hyp stack (kernel VA) | 30 | * r1 = pointer to hyp vectors |
30 | * r3 = pointer to hyp vectors | 31 | * r2,r3 = Hypervisor pgd pointer |
32 | * | ||
33 | * The init scenario is: | ||
34 | * - We jump in HYP with four parameters: boot HYP pgd, runtime HYP pgd, | ||
35 | * runtime stack, runtime vectors | ||
36 | * - Enable the MMU with the boot pgd | ||
37 | * - Jump to a target into the trampoline page (remember, this is the same | ||
38 | * physical page!) | ||
39 | * - Now switch to the runtime pgd (same VA, and still the same physical | ||
40 | * page!) | ||
41 | * - Invalidate TLBs | ||
42 | * - Set stack and vectors | ||
43 | * - Profit! (or eret, if you only care about the code). | ||
44 | * | ||
45 | * As we only have four registers available to pass parameters (and we | ||
46 | * need six), we split the init in two phases: | ||
47 | * - Phase 1: r0 = 0, r1 = 0, r2,r3 contain the boot PGD. | ||
48 | * Provides the basic HYP init, and enable the MMU. | ||
49 | * - Phase 2: r0 = ToS, r1 = vectors, r2,r3 contain the runtime PGD. | ||
50 | * Switches to the runtime PGD, set stack and vectors. | ||
31 | */ | 51 | */ |
32 | 52 | ||
33 | .text | 53 | .text |
@@ -47,22 +67,25 @@ __kvm_hyp_init: | |||
47 | W(b) . | 67 | W(b) . |
48 | 68 | ||
49 | __do_hyp_init: | 69 | __do_hyp_init: |
70 | cmp r0, #0 @ We have a SP? | ||
71 | bne phase2 @ Yes, second stage init | ||
72 | |||
50 | @ Set the HTTBR to point to the hypervisor PGD pointer passed | 73 | @ Set the HTTBR to point to the hypervisor PGD pointer passed |
51 | mcrr p15, 4, r0, r1, c2 | 74 | mcrr p15, 4, r2, r3, c2 |
52 | 75 | ||
53 | @ Set the HTCR and VTCR to the same shareability and cacheability | 76 | @ Set the HTCR and VTCR to the same shareability and cacheability |
54 | @ settings as the non-secure TTBCR and with T0SZ == 0. | 77 | @ settings as the non-secure TTBCR and with T0SZ == 0. |
55 | mrc p15, 4, r0, c2, c0, 2 @ HTCR | 78 | mrc p15, 4, r0, c2, c0, 2 @ HTCR |
56 | ldr r12, =HTCR_MASK | 79 | ldr r2, =HTCR_MASK |
57 | bic r0, r0, r12 | 80 | bic r0, r0, r2 |
58 | mrc p15, 0, r1, c2, c0, 2 @ TTBCR | 81 | mrc p15, 0, r1, c2, c0, 2 @ TTBCR |
59 | and r1, r1, #(HTCR_MASK & ~TTBCR_T0SZ) | 82 | and r1, r1, #(HTCR_MASK & ~TTBCR_T0SZ) |
60 | orr r0, r0, r1 | 83 | orr r0, r0, r1 |
61 | mcr p15, 4, r0, c2, c0, 2 @ HTCR | 84 | mcr p15, 4, r0, c2, c0, 2 @ HTCR |
62 | 85 | ||
63 | mrc p15, 4, r1, c2, c1, 2 @ VTCR | 86 | mrc p15, 4, r1, c2, c1, 2 @ VTCR |
64 | ldr r12, =VTCR_MASK | 87 | ldr r2, =VTCR_MASK |
65 | bic r1, r1, r12 | 88 | bic r1, r1, r2 |
66 | bic r0, r0, #(~VTCR_HTCR_SH) @ clear non-reusable HTCR bits | 89 | bic r0, r0, #(~VTCR_HTCR_SH) @ clear non-reusable HTCR bits |
67 | orr r1, r0, r1 | 90 | orr r1, r0, r1 |
68 | orr r1, r1, #(KVM_VTCR_SL0 | KVM_VTCR_T0SZ | KVM_VTCR_S) | 91 | orr r1, r1, #(KVM_VTCR_SL0 | KVM_VTCR_T0SZ | KVM_VTCR_S) |
@@ -85,24 +108,41 @@ __do_hyp_init: | |||
85 | @ - Memory alignment checks: enabled | 108 | @ - Memory alignment checks: enabled |
86 | @ - MMU: enabled (this code must be run from an identity mapping) | 109 | @ - MMU: enabled (this code must be run from an identity mapping) |
87 | mrc p15, 4, r0, c1, c0, 0 @ HSCR | 110 | mrc p15, 4, r0, c1, c0, 0 @ HSCR |
88 | ldr r12, =HSCTLR_MASK | 111 | ldr r2, =HSCTLR_MASK |
89 | bic r0, r0, r12 | 112 | bic r0, r0, r2 |
90 | mrc p15, 0, r1, c1, c0, 0 @ SCTLR | 113 | mrc p15, 0, r1, c1, c0, 0 @ SCTLR |
91 | ldr r12, =(HSCTLR_EE | HSCTLR_FI | HSCTLR_I | HSCTLR_C) | 114 | ldr r2, =(HSCTLR_EE | HSCTLR_FI | HSCTLR_I | HSCTLR_C) |
92 | and r1, r1, r12 | 115 | and r1, r1, r2 |
93 | ARM( ldr r12, =(HSCTLR_M | HSCTLR_A) ) | 116 | ARM( ldr r2, =(HSCTLR_M | HSCTLR_A) ) |
94 | THUMB( ldr r12, =(HSCTLR_M | HSCTLR_A | HSCTLR_TE) ) | 117 | THUMB( ldr r2, =(HSCTLR_M | HSCTLR_A | HSCTLR_TE) ) |
95 | orr r1, r1, r12 | 118 | orr r1, r1, r2 |
96 | orr r0, r0, r1 | 119 | orr r0, r0, r1 |
97 | isb | 120 | isb |
98 | mcr p15, 4, r0, c1, c0, 0 @ HSCR | 121 | mcr p15, 4, r0, c1, c0, 0 @ HSCR |
99 | isb | ||
100 | 122 | ||
101 | @ Set stack pointer and return to the kernel | 123 | @ End of init phase-1 |
102 | mov sp, r2 | 124 | eret |
125 | |||
126 | phase2: | ||
127 | @ Set stack pointer | ||
128 | mov sp, r0 | ||
103 | 129 | ||
104 | @ Set HVBAR to point to the HYP vectors | 130 | @ Set HVBAR to point to the HYP vectors |
105 | mcr p15, 4, r3, c12, c0, 0 @ HVBAR | 131 | mcr p15, 4, r1, c12, c0, 0 @ HVBAR |
132 | |||
133 | @ Jump to the trampoline page | ||
134 | ldr r0, =TRAMPOLINE_VA | ||
135 | adr r1, target | ||
136 | bfi r0, r1, #0, #PAGE_SHIFT | ||
137 | mov pc, r0 | ||
138 | |||
139 | target: @ We're now in the trampoline code, switch page tables | ||
140 | mcrr p15, 4, r2, r3, c2 | ||
141 | isb | ||
142 | |||
143 | @ Invalidate the old TLBs | ||
144 | mcr p15, 4, r0, c8, c7, 0 @ TLBIALLH | ||
145 | dsb | ||
106 | 146 | ||
107 | eret | 147 | eret |
108 | 148 | ||
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c index 2f12e4056408..965706578f13 100644 --- a/arch/arm/kvm/mmu.c +++ b/arch/arm/kvm/mmu.c | |||
@@ -32,8 +32,15 @@ | |||
32 | 32 | ||
33 | extern char __hyp_idmap_text_start[], __hyp_idmap_text_end[]; | 33 | extern char __hyp_idmap_text_start[], __hyp_idmap_text_end[]; |
34 | 34 | ||
35 | static pgd_t *boot_hyp_pgd; | ||
36 | static pgd_t *hyp_pgd; | ||
35 | static DEFINE_MUTEX(kvm_hyp_pgd_mutex); | 37 | static DEFINE_MUTEX(kvm_hyp_pgd_mutex); |
36 | 38 | ||
39 | static void *init_bounce_page; | ||
40 | static unsigned long hyp_idmap_start; | ||
41 | static unsigned long hyp_idmap_end; | ||
42 | static phys_addr_t hyp_idmap_vector; | ||
43 | |||
37 | static void kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa) | 44 | static void kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa) |
38 | { | 45 | { |
39 | kvm_call_hyp(__kvm_tlb_flush_vmid_ipa, kvm, ipa); | 46 | kvm_call_hyp(__kvm_tlb_flush_vmid_ipa, kvm, ipa); |
@@ -71,172 +78,224 @@ static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc) | |||
71 | return p; | 78 | return p; |
72 | } | 79 | } |
73 | 80 | ||
74 | static void free_ptes(pmd_t *pmd, unsigned long addr) | 81 | static void clear_pud_entry(pud_t *pud) |
75 | { | 82 | { |
76 | pte_t *pte; | 83 | pmd_t *pmd_table = pmd_offset(pud, 0); |
77 | unsigned int i; | 84 | pud_clear(pud); |
85 | pmd_free(NULL, pmd_table); | ||
86 | put_page(virt_to_page(pud)); | ||
87 | } | ||
78 | 88 | ||
79 | for (i = 0; i < PTRS_PER_PMD; i++, addr += PMD_SIZE) { | 89 | static void clear_pmd_entry(pmd_t *pmd) |
80 | if (!pmd_none(*pmd) && pmd_table(*pmd)) { | 90 | { |
81 | pte = pte_offset_kernel(pmd, addr); | 91 | pte_t *pte_table = pte_offset_kernel(pmd, 0); |
82 | pte_free_kernel(NULL, pte); | 92 | pmd_clear(pmd); |
83 | } | 93 | pte_free_kernel(NULL, pte_table); |
84 | pmd++; | 94 | put_page(virt_to_page(pmd)); |
95 | } | ||
96 | |||
97 | static bool pmd_empty(pmd_t *pmd) | ||
98 | { | ||
99 | struct page *pmd_page = virt_to_page(pmd); | ||
100 | return page_count(pmd_page) == 1; | ||
101 | } | ||
102 | |||
103 | static void clear_pte_entry(pte_t *pte) | ||
104 | { | ||
105 | if (pte_present(*pte)) { | ||
106 | kvm_set_pte(pte, __pte(0)); | ||
107 | put_page(virt_to_page(pte)); | ||
85 | } | 108 | } |
86 | } | 109 | } |
87 | 110 | ||
88 | static void free_hyp_pgd_entry(unsigned long addr) | 111 | static bool pte_empty(pte_t *pte) |
112 | { | ||
113 | struct page *pte_page = virt_to_page(pte); | ||
114 | return page_count(pte_page) == 1; | ||
115 | } | ||
116 | |||
117 | static void unmap_range(pgd_t *pgdp, unsigned long long start, u64 size) | ||
89 | { | 118 | { |
90 | pgd_t *pgd; | 119 | pgd_t *pgd; |
91 | pud_t *pud; | 120 | pud_t *pud; |
92 | pmd_t *pmd; | 121 | pmd_t *pmd; |
93 | unsigned long hyp_addr = KERN_TO_HYP(addr); | 122 | pte_t *pte; |
123 | unsigned long long addr = start, end = start + size; | ||
124 | u64 range; | ||
125 | |||
126 | while (addr < end) { | ||
127 | pgd = pgdp + pgd_index(addr); | ||
128 | pud = pud_offset(pgd, addr); | ||
129 | if (pud_none(*pud)) { | ||
130 | addr += PUD_SIZE; | ||
131 | continue; | ||
132 | } | ||
94 | 133 | ||
95 | pgd = hyp_pgd + pgd_index(hyp_addr); | 134 | pmd = pmd_offset(pud, addr); |
96 | pud = pud_offset(pgd, hyp_addr); | 135 | if (pmd_none(*pmd)) { |
136 | addr += PMD_SIZE; | ||
137 | continue; | ||
138 | } | ||
97 | 139 | ||
98 | if (pud_none(*pud)) | 140 | pte = pte_offset_kernel(pmd, addr); |
99 | return; | 141 | clear_pte_entry(pte); |
100 | BUG_ON(pud_bad(*pud)); | 142 | range = PAGE_SIZE; |
101 | 143 | ||
102 | pmd = pmd_offset(pud, hyp_addr); | 144 | /* If we emptied the pte, walk back up the ladder */ |
103 | free_ptes(pmd, addr); | 145 | if (pte_empty(pte)) { |
104 | pmd_free(NULL, pmd); | 146 | clear_pmd_entry(pmd); |
105 | pud_clear(pud); | 147 | range = PMD_SIZE; |
148 | if (pmd_empty(pmd)) { | ||
149 | clear_pud_entry(pud); | ||
150 | range = PUD_SIZE; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | addr += range; | ||
155 | } | ||
106 | } | 156 | } |
107 | 157 | ||
108 | /** | 158 | /** |
109 | * free_hyp_pmds - free a Hyp-mode level-2 tables and child level-3 tables | 159 | * free_boot_hyp_pgd - free HYP boot page tables |
110 | * | 160 | * |
111 | * Assumes this is a page table used strictly in Hyp-mode and therefore contains | 161 | * Free the HYP boot page tables. The bounce page is also freed. |
112 | * either mappings in the kernel memory area (above PAGE_OFFSET), or | ||
113 | * device mappings in the vmalloc range (from VMALLOC_START to VMALLOC_END). | ||
114 | */ | 162 | */ |
115 | void free_hyp_pmds(void) | 163 | void free_boot_hyp_pgd(void) |
116 | { | 164 | { |
117 | unsigned long addr; | ||
118 | |||
119 | mutex_lock(&kvm_hyp_pgd_mutex); | 165 | mutex_lock(&kvm_hyp_pgd_mutex); |
120 | for (addr = PAGE_OFFSET; virt_addr_valid(addr); addr += PGDIR_SIZE) | 166 | |
121 | free_hyp_pgd_entry(addr); | 167 | if (boot_hyp_pgd) { |
122 | for (addr = VMALLOC_START; is_vmalloc_addr((void*)addr); addr += PGDIR_SIZE) | 168 | unmap_range(boot_hyp_pgd, hyp_idmap_start, PAGE_SIZE); |
123 | free_hyp_pgd_entry(addr); | 169 | unmap_range(boot_hyp_pgd, TRAMPOLINE_VA, PAGE_SIZE); |
170 | kfree(boot_hyp_pgd); | ||
171 | boot_hyp_pgd = NULL; | ||
172 | } | ||
173 | |||
174 | if (hyp_pgd) | ||
175 | unmap_range(hyp_pgd, TRAMPOLINE_VA, PAGE_SIZE); | ||
176 | |||
177 | kfree(init_bounce_page); | ||
178 | init_bounce_page = NULL; | ||
179 | |||
124 | mutex_unlock(&kvm_hyp_pgd_mutex); | 180 | mutex_unlock(&kvm_hyp_pgd_mutex); |
125 | } | 181 | } |
126 | 182 | ||
127 | static void create_hyp_pte_mappings(pmd_t *pmd, unsigned long start, | 183 | /** |
128 | unsigned long end) | 184 | * free_hyp_pgds - free Hyp-mode page tables |
185 | * | ||
186 | * Assumes hyp_pgd is a page table used strictly in Hyp-mode and | ||
187 | * therefore contains either mappings in the kernel memory area (above | ||
188 | * PAGE_OFFSET), or device mappings in the vmalloc range (from | ||
189 | * VMALLOC_START to VMALLOC_END). | ||
190 | * | ||
191 | * boot_hyp_pgd should only map two pages for the init code. | ||
192 | */ | ||
193 | void free_hyp_pgds(void) | ||
129 | { | 194 | { |
130 | pte_t *pte; | ||
131 | unsigned long addr; | 195 | unsigned long addr; |
132 | struct page *page; | ||
133 | 196 | ||
134 | for (addr = start & PAGE_MASK; addr < end; addr += PAGE_SIZE) { | 197 | free_boot_hyp_pgd(); |
135 | unsigned long hyp_addr = KERN_TO_HYP(addr); | 198 | |
199 | mutex_lock(&kvm_hyp_pgd_mutex); | ||
136 | 200 | ||
137 | pte = pte_offset_kernel(pmd, hyp_addr); | 201 | if (hyp_pgd) { |
138 | BUG_ON(!virt_addr_valid(addr)); | 202 | for (addr = PAGE_OFFSET; virt_addr_valid(addr); addr += PGDIR_SIZE) |
139 | page = virt_to_page(addr); | 203 | unmap_range(hyp_pgd, KERN_TO_HYP(addr), PGDIR_SIZE); |
140 | kvm_set_pte(pte, mk_pte(page, PAGE_HYP)); | 204 | for (addr = VMALLOC_START; is_vmalloc_addr((void*)addr); addr += PGDIR_SIZE) |
205 | unmap_range(hyp_pgd, KERN_TO_HYP(addr), PGDIR_SIZE); | ||
206 | kfree(hyp_pgd); | ||
207 | hyp_pgd = NULL; | ||
141 | } | 208 | } |
209 | |||
210 | mutex_unlock(&kvm_hyp_pgd_mutex); | ||
142 | } | 211 | } |
143 | 212 | ||
144 | static void create_hyp_io_pte_mappings(pmd_t *pmd, unsigned long start, | 213 | static void create_hyp_pte_mappings(pmd_t *pmd, unsigned long start, |
145 | unsigned long end, | 214 | unsigned long end, unsigned long pfn, |
146 | unsigned long *pfn_base) | 215 | pgprot_t prot) |
147 | { | 216 | { |
148 | pte_t *pte; | 217 | pte_t *pte; |
149 | unsigned long addr; | 218 | unsigned long addr; |
150 | 219 | ||
151 | for (addr = start & PAGE_MASK; addr < end; addr += PAGE_SIZE) { | 220 | addr = start; |
152 | unsigned long hyp_addr = KERN_TO_HYP(addr); | 221 | do { |
153 | 222 | pte = pte_offset_kernel(pmd, addr); | |
154 | pte = pte_offset_kernel(pmd, hyp_addr); | 223 | kvm_set_pte(pte, pfn_pte(pfn, prot)); |
155 | BUG_ON(pfn_valid(*pfn_base)); | 224 | get_page(virt_to_page(pte)); |
156 | kvm_set_pte(pte, pfn_pte(*pfn_base, PAGE_HYP_DEVICE)); | 225 | kvm_flush_dcache_to_poc(pte, sizeof(*pte)); |
157 | (*pfn_base)++; | 226 | pfn++; |
158 | } | 227 | } while (addr += PAGE_SIZE, addr != end); |
159 | } | 228 | } |
160 | 229 | ||
161 | static int create_hyp_pmd_mappings(pud_t *pud, unsigned long start, | 230 | static int create_hyp_pmd_mappings(pud_t *pud, unsigned long start, |
162 | unsigned long end, unsigned long *pfn_base) | 231 | unsigned long end, unsigned long pfn, |
232 | pgprot_t prot) | ||
163 | { | 233 | { |
164 | pmd_t *pmd; | 234 | pmd_t *pmd; |
165 | pte_t *pte; | 235 | pte_t *pte; |
166 | unsigned long addr, next; | 236 | unsigned long addr, next; |
167 | 237 | ||
168 | for (addr = start; addr < end; addr = next) { | 238 | addr = start; |
169 | unsigned long hyp_addr = KERN_TO_HYP(addr); | 239 | do { |
170 | pmd = pmd_offset(pud, hyp_addr); | 240 | pmd = pmd_offset(pud, addr); |
171 | 241 | ||
172 | BUG_ON(pmd_sect(*pmd)); | 242 | BUG_ON(pmd_sect(*pmd)); |
173 | 243 | ||
174 | if (pmd_none(*pmd)) { | 244 | if (pmd_none(*pmd)) { |
175 | pte = pte_alloc_one_kernel(NULL, hyp_addr); | 245 | pte = pte_alloc_one_kernel(NULL, addr); |
176 | if (!pte) { | 246 | if (!pte) { |
177 | kvm_err("Cannot allocate Hyp pte\n"); | 247 | kvm_err("Cannot allocate Hyp pte\n"); |
178 | return -ENOMEM; | 248 | return -ENOMEM; |
179 | } | 249 | } |
180 | pmd_populate_kernel(NULL, pmd, pte); | 250 | pmd_populate_kernel(NULL, pmd, pte); |
251 | get_page(virt_to_page(pmd)); | ||
252 | kvm_flush_dcache_to_poc(pmd, sizeof(*pmd)); | ||
181 | } | 253 | } |
182 | 254 | ||
183 | next = pmd_addr_end(addr, end); | 255 | next = pmd_addr_end(addr, end); |
184 | 256 | ||
185 | /* | 257 | create_hyp_pte_mappings(pmd, addr, next, pfn, prot); |
186 | * If pfn_base is NULL, we map kernel pages into HYP with the | 258 | pfn += (next - addr) >> PAGE_SHIFT; |
187 | * virtual address. Otherwise, this is considered an I/O | 259 | } while (addr = next, addr != end); |
188 | * mapping and we map the physical region starting at | ||
189 | * *pfn_base to [start, end[. | ||
190 | */ | ||
191 | if (!pfn_base) | ||
192 | create_hyp_pte_mappings(pmd, addr, next); | ||
193 | else | ||
194 | create_hyp_io_pte_mappings(pmd, addr, next, pfn_base); | ||
195 | } | ||
196 | 260 | ||
197 | return 0; | 261 | return 0; |
198 | } | 262 | } |
199 | 263 | ||
200 | static int __create_hyp_mappings(void *from, void *to, unsigned long *pfn_base) | 264 | static int __create_hyp_mappings(pgd_t *pgdp, |
265 | unsigned long start, unsigned long end, | ||
266 | unsigned long pfn, pgprot_t prot) | ||
201 | { | 267 | { |
202 | unsigned long start = (unsigned long)from; | ||
203 | unsigned long end = (unsigned long)to; | ||
204 | pgd_t *pgd; | 268 | pgd_t *pgd; |
205 | pud_t *pud; | 269 | pud_t *pud; |
206 | pmd_t *pmd; | 270 | pmd_t *pmd; |
207 | unsigned long addr, next; | 271 | unsigned long addr, next; |
208 | int err = 0; | 272 | int err = 0; |
209 | 273 | ||
210 | if (start >= end) | ||
211 | return -EINVAL; | ||
212 | /* Check for a valid kernel memory mapping */ | ||
213 | if (!pfn_base && (!virt_addr_valid(from) || !virt_addr_valid(to - 1))) | ||
214 | return -EINVAL; | ||
215 | /* Check for a valid kernel IO mapping */ | ||
216 | if (pfn_base && (!is_vmalloc_addr(from) || !is_vmalloc_addr(to - 1))) | ||
217 | return -EINVAL; | ||
218 | |||
219 | mutex_lock(&kvm_hyp_pgd_mutex); | 274 | mutex_lock(&kvm_hyp_pgd_mutex); |
220 | for (addr = start; addr < end; addr = next) { | 275 | addr = start & PAGE_MASK; |
221 | unsigned long hyp_addr = KERN_TO_HYP(addr); | 276 | end = PAGE_ALIGN(end); |
222 | pgd = hyp_pgd + pgd_index(hyp_addr); | 277 | do { |
223 | pud = pud_offset(pgd, hyp_addr); | 278 | pgd = pgdp + pgd_index(addr); |
279 | pud = pud_offset(pgd, addr); | ||
224 | 280 | ||
225 | if (pud_none_or_clear_bad(pud)) { | 281 | if (pud_none_or_clear_bad(pud)) { |
226 | pmd = pmd_alloc_one(NULL, hyp_addr); | 282 | pmd = pmd_alloc_one(NULL, addr); |
227 | if (!pmd) { | 283 | if (!pmd) { |
228 | kvm_err("Cannot allocate Hyp pmd\n"); | 284 | kvm_err("Cannot allocate Hyp pmd\n"); |
229 | err = -ENOMEM; | 285 | err = -ENOMEM; |
230 | goto out; | 286 | goto out; |
231 | } | 287 | } |
232 | pud_populate(NULL, pud, pmd); | 288 | pud_populate(NULL, pud, pmd); |
289 | get_page(virt_to_page(pud)); | ||
290 | kvm_flush_dcache_to_poc(pud, sizeof(*pud)); | ||
233 | } | 291 | } |
234 | 292 | ||
235 | next = pgd_addr_end(addr, end); | 293 | next = pgd_addr_end(addr, end); |
236 | err = create_hyp_pmd_mappings(pud, addr, next, pfn_base); | 294 | err = create_hyp_pmd_mappings(pud, addr, next, pfn, prot); |
237 | if (err) | 295 | if (err) |
238 | goto out; | 296 | goto out; |
239 | } | 297 | pfn += (next - addr) >> PAGE_SHIFT; |
298 | } while (addr = next, addr != end); | ||
240 | out: | 299 | out: |
241 | mutex_unlock(&kvm_hyp_pgd_mutex); | 300 | mutex_unlock(&kvm_hyp_pgd_mutex); |
242 | return err; | 301 | return err; |
@@ -250,27 +309,41 @@ out: | |||
250 | * The same virtual address as the kernel virtual address is also used | 309 | * The same virtual address as the kernel virtual address is also used |
251 | * in Hyp-mode mapping (modulo HYP_PAGE_OFFSET) to the same underlying | 310 | * in Hyp-mode mapping (modulo HYP_PAGE_OFFSET) to the same underlying |
252 | * physical pages. | 311 | * physical pages. |
253 | * | ||
254 | * Note: Wrapping around zero in the "to" address is not supported. | ||
255 | */ | 312 | */ |
256 | int create_hyp_mappings(void *from, void *to) | 313 | int create_hyp_mappings(void *from, void *to) |
257 | { | 314 | { |
258 | return __create_hyp_mappings(from, to, NULL); | 315 | unsigned long phys_addr = virt_to_phys(from); |
316 | unsigned long start = KERN_TO_HYP((unsigned long)from); | ||
317 | unsigned long end = KERN_TO_HYP((unsigned long)to); | ||
318 | |||
319 | /* Check for a valid kernel memory mapping */ | ||
320 | if (!virt_addr_valid(from) || !virt_addr_valid(to - 1)) | ||
321 | return -EINVAL; | ||
322 | |||
323 | return __create_hyp_mappings(hyp_pgd, start, end, | ||
324 | __phys_to_pfn(phys_addr), PAGE_HYP); | ||
259 | } | 325 | } |
260 | 326 | ||
261 | /** | 327 | /** |
262 | * create_hyp_io_mappings - duplicate a kernel IO mapping into Hyp mode | 328 | * create_hyp_io_mappings - duplicate a kernel IO mapping into Hyp mode |
263 | * @from: The kernel start VA of the range | 329 | * @from: The kernel start VA of the range |
264 | * @to: The kernel end VA of the range (exclusive) | 330 | * @to: The kernel end VA of the range (exclusive) |
265 | * @addr: The physical start address which gets mapped | 331 | * @phys_addr: The physical start address which gets mapped |
266 | * | 332 | * |
267 | * The resulting HYP VA is the same as the kernel VA, modulo | 333 | * The resulting HYP VA is the same as the kernel VA, modulo |
268 | * HYP_PAGE_OFFSET. | 334 | * HYP_PAGE_OFFSET. |
269 | */ | 335 | */ |
270 | int create_hyp_io_mappings(void *from, void *to, phys_addr_t addr) | 336 | int create_hyp_io_mappings(void *from, void *to, phys_addr_t phys_addr) |
271 | { | 337 | { |
272 | unsigned long pfn = __phys_to_pfn(addr); | 338 | unsigned long start = KERN_TO_HYP((unsigned long)from); |
273 | return __create_hyp_mappings(from, to, &pfn); | 339 | unsigned long end = KERN_TO_HYP((unsigned long)to); |
340 | |||
341 | /* Check for a valid kernel IO mapping */ | ||
342 | if (!is_vmalloc_addr(from) || !is_vmalloc_addr(to - 1)) | ||
343 | return -EINVAL; | ||
344 | |||
345 | return __create_hyp_mappings(hyp_pgd, start, end, | ||
346 | __phys_to_pfn(phys_addr), PAGE_HYP_DEVICE); | ||
274 | } | 347 | } |
275 | 348 | ||
276 | /** | 349 | /** |
@@ -307,42 +380,6 @@ int kvm_alloc_stage2_pgd(struct kvm *kvm) | |||
307 | return 0; | 380 | return 0; |
308 | } | 381 | } |
309 | 382 | ||
310 | static void clear_pud_entry(pud_t *pud) | ||
311 | { | ||
312 | pmd_t *pmd_table = pmd_offset(pud, 0); | ||
313 | pud_clear(pud); | ||
314 | pmd_free(NULL, pmd_table); | ||
315 | put_page(virt_to_page(pud)); | ||
316 | } | ||
317 | |||
318 | static void clear_pmd_entry(pmd_t *pmd) | ||
319 | { | ||
320 | pte_t *pte_table = pte_offset_kernel(pmd, 0); | ||
321 | pmd_clear(pmd); | ||
322 | pte_free_kernel(NULL, pte_table); | ||
323 | put_page(virt_to_page(pmd)); | ||
324 | } | ||
325 | |||
326 | static bool pmd_empty(pmd_t *pmd) | ||
327 | { | ||
328 | struct page *pmd_page = virt_to_page(pmd); | ||
329 | return page_count(pmd_page) == 1; | ||
330 | } | ||
331 | |||
332 | static void clear_pte_entry(pte_t *pte) | ||
333 | { | ||
334 | if (pte_present(*pte)) { | ||
335 | kvm_set_pte(pte, __pte(0)); | ||
336 | put_page(virt_to_page(pte)); | ||
337 | } | ||
338 | } | ||
339 | |||
340 | static bool pte_empty(pte_t *pte) | ||
341 | { | ||
342 | struct page *pte_page = virt_to_page(pte); | ||
343 | return page_count(pte_page) == 1; | ||
344 | } | ||
345 | |||
346 | /** | 383 | /** |
347 | * unmap_stage2_range -- Clear stage2 page table entries to unmap a range | 384 | * unmap_stage2_range -- Clear stage2 page table entries to unmap a range |
348 | * @kvm: The VM pointer | 385 | * @kvm: The VM pointer |
@@ -356,43 +393,7 @@ static bool pte_empty(pte_t *pte) | |||
356 | */ | 393 | */ |
357 | static void unmap_stage2_range(struct kvm *kvm, phys_addr_t start, u64 size) | 394 | static void unmap_stage2_range(struct kvm *kvm, phys_addr_t start, u64 size) |
358 | { | 395 | { |
359 | pgd_t *pgd; | 396 | unmap_range(kvm->arch.pgd, start, size); |
360 | pud_t *pud; | ||
361 | pmd_t *pmd; | ||
362 | pte_t *pte; | ||
363 | phys_addr_t addr = start, end = start + size; | ||
364 | u64 range; | ||
365 | |||
366 | while (addr < end) { | ||
367 | pgd = kvm->arch.pgd + pgd_index(addr); | ||
368 | pud = pud_offset(pgd, addr); | ||
369 | if (pud_none(*pud)) { | ||
370 | addr += PUD_SIZE; | ||
371 | continue; | ||
372 | } | ||
373 | |||
374 | pmd = pmd_offset(pud, addr); | ||
375 | if (pmd_none(*pmd)) { | ||
376 | addr += PMD_SIZE; | ||
377 | continue; | ||
378 | } | ||
379 | |||
380 | pte = pte_offset_kernel(pmd, addr); | ||
381 | clear_pte_entry(pte); | ||
382 | range = PAGE_SIZE; | ||
383 | |||
384 | /* If we emptied the pte, walk back up the ladder */ | ||
385 | if (pte_empty(pte)) { | ||
386 | clear_pmd_entry(pmd); | ||
387 | range = PMD_SIZE; | ||
388 | if (pmd_empty(pmd)) { | ||
389 | clear_pud_entry(pud); | ||
390 | range = PUD_SIZE; | ||
391 | } | ||
392 | } | ||
393 | |||
394 | addr += range; | ||
395 | } | ||
396 | } | 397 | } |
397 | 398 | ||
398 | /** | 399 | /** |
@@ -728,47 +729,105 @@ void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu) | |||
728 | 729 | ||
729 | phys_addr_t kvm_mmu_get_httbr(void) | 730 | phys_addr_t kvm_mmu_get_httbr(void) |
730 | { | 731 | { |
731 | VM_BUG_ON(!virt_addr_valid(hyp_pgd)); | ||
732 | return virt_to_phys(hyp_pgd); | 732 | return virt_to_phys(hyp_pgd); |
733 | } | 733 | } |
734 | 734 | ||
735 | phys_addr_t kvm_mmu_get_boot_httbr(void) | ||
736 | { | ||
737 | return virt_to_phys(boot_hyp_pgd); | ||
738 | } | ||
739 | |||
740 | phys_addr_t kvm_get_idmap_vector(void) | ||
741 | { | ||
742 | return hyp_idmap_vector; | ||
743 | } | ||
744 | |||
735 | int kvm_mmu_init(void) | 745 | int kvm_mmu_init(void) |
736 | { | 746 | { |
737 | if (!hyp_pgd) { | 747 | int err; |
748 | |||
749 | hyp_idmap_start = virt_to_phys(__hyp_idmap_text_start); | ||
750 | hyp_idmap_end = virt_to_phys(__hyp_idmap_text_end); | ||
751 | hyp_idmap_vector = virt_to_phys(__kvm_hyp_init); | ||
752 | |||
753 | if ((hyp_idmap_start ^ hyp_idmap_end) & PAGE_MASK) { | ||
754 | /* | ||
755 | * Our init code is crossing a page boundary. Allocate | ||
756 | * a bounce page, copy the code over and use that. | ||
757 | */ | ||
758 | size_t len = __hyp_idmap_text_end - __hyp_idmap_text_start; | ||
759 | phys_addr_t phys_base; | ||
760 | |||
761 | init_bounce_page = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
762 | if (!init_bounce_page) { | ||
763 | kvm_err("Couldn't allocate HYP init bounce page\n"); | ||
764 | err = -ENOMEM; | ||
765 | goto out; | ||
766 | } | ||
767 | |||
768 | memcpy(init_bounce_page, __hyp_idmap_text_start, len); | ||
769 | /* | ||
770 | * Warning: the code we just copied to the bounce page | ||
771 | * must be flushed to the point of coherency. | ||
772 | * Otherwise, the data may be sitting in L2, and HYP | ||
773 | * mode won't be able to observe it as it runs with | ||
774 | * caches off at that point. | ||
775 | */ | ||
776 | kvm_flush_dcache_to_poc(init_bounce_page, len); | ||
777 | |||
778 | phys_base = virt_to_phys(init_bounce_page); | ||
779 | hyp_idmap_vector += phys_base - hyp_idmap_start; | ||
780 | hyp_idmap_start = phys_base; | ||
781 | hyp_idmap_end = phys_base + len; | ||
782 | |||
783 | kvm_info("Using HYP init bounce page @%lx\n", | ||
784 | (unsigned long)phys_base); | ||
785 | } | ||
786 | |||
787 | hyp_pgd = kzalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL); | ||
788 | boot_hyp_pgd = kzalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL); | ||
789 | if (!hyp_pgd || !boot_hyp_pgd) { | ||
738 | kvm_err("Hyp mode PGD not allocated\n"); | 790 | kvm_err("Hyp mode PGD not allocated\n"); |
739 | return -ENOMEM; | 791 | err = -ENOMEM; |
792 | goto out; | ||
740 | } | 793 | } |
741 | 794 | ||
742 | return 0; | 795 | /* Create the idmap in the boot page tables */ |
743 | } | 796 | err = __create_hyp_mappings(boot_hyp_pgd, |
797 | hyp_idmap_start, hyp_idmap_end, | ||
798 | __phys_to_pfn(hyp_idmap_start), | ||
799 | PAGE_HYP); | ||
744 | 800 | ||
745 | /** | 801 | if (err) { |
746 | * kvm_clear_idmap - remove all idmaps from the hyp pgd | 802 | kvm_err("Failed to idmap %lx-%lx\n", |
747 | * | 803 | hyp_idmap_start, hyp_idmap_end); |
748 | * Free the underlying pmds for all pgds in range and clear the pgds (but | 804 | goto out; |
749 | * don't free them) afterwards. | 805 | } |
750 | */ | ||
751 | void kvm_clear_hyp_idmap(void) | ||
752 | { | ||
753 | unsigned long addr, end; | ||
754 | unsigned long next; | ||
755 | pgd_t *pgd = hyp_pgd; | ||
756 | pud_t *pud; | ||
757 | pmd_t *pmd; | ||
758 | 806 | ||
759 | addr = virt_to_phys(__hyp_idmap_text_start); | 807 | /* Map the very same page at the trampoline VA */ |
760 | end = virt_to_phys(__hyp_idmap_text_end); | 808 | err = __create_hyp_mappings(boot_hyp_pgd, |
809 | TRAMPOLINE_VA, TRAMPOLINE_VA + PAGE_SIZE, | ||
810 | __phys_to_pfn(hyp_idmap_start), | ||
811 | PAGE_HYP); | ||
812 | if (err) { | ||
813 | kvm_err("Failed to map trampoline @%lx into boot HYP pgd\n", | ||
814 | TRAMPOLINE_VA); | ||
815 | goto out; | ||
816 | } | ||
761 | 817 | ||
762 | pgd += pgd_index(addr); | 818 | /* Map the same page again into the runtime page tables */ |
763 | do { | 819 | err = __create_hyp_mappings(hyp_pgd, |
764 | next = pgd_addr_end(addr, end); | 820 | TRAMPOLINE_VA, TRAMPOLINE_VA + PAGE_SIZE, |
765 | if (pgd_none_or_clear_bad(pgd)) | 821 | __phys_to_pfn(hyp_idmap_start), |
766 | continue; | 822 | PAGE_HYP); |
767 | pud = pud_offset(pgd, addr); | 823 | if (err) { |
768 | pmd = pmd_offset(pud, addr); | 824 | kvm_err("Failed to map trampoline @%lx into runtime HYP pgd\n", |
825 | TRAMPOLINE_VA); | ||
826 | goto out; | ||
827 | } | ||
769 | 828 | ||
770 | pud_clear(pud); | 829 | return 0; |
771 | kvm_clean_pmd_entry(pmd); | 830 | out: |
772 | pmd_free(NULL, (pmd_t *)((unsigned long)pmd & PAGE_MASK)); | 831 | free_hyp_pgds(); |
773 | } while (pgd++, addr = next, addr < end); | 832 | return err; |
774 | } | 833 | } |
diff --git a/arch/arm/kvm/perf.c b/arch/arm/kvm/perf.c new file mode 100644 index 000000000000..1a3849da0b4b --- /dev/null +++ b/arch/arm/kvm/perf.c | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * Based on the x86 implementation. | ||
3 | * | ||
4 | * Copyright (C) 2012 ARM Ltd. | ||
5 | * Author: Marc Zyngier <marc.zyngier@arm.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include <linux/perf_event.h> | ||
21 | #include <linux/kvm_host.h> | ||
22 | |||
23 | #include <asm/kvm_emulate.h> | ||
24 | |||
25 | static int kvm_is_in_guest(void) | ||
26 | { | ||
27 | return kvm_arm_get_running_vcpu() != NULL; | ||
28 | } | ||
29 | |||
30 | static int kvm_is_user_mode(void) | ||
31 | { | ||
32 | struct kvm_vcpu *vcpu; | ||
33 | |||
34 | vcpu = kvm_arm_get_running_vcpu(); | ||
35 | |||
36 | if (vcpu) | ||
37 | return !vcpu_mode_priv(vcpu); | ||
38 | |||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | static unsigned long kvm_get_guest_ip(void) | ||
43 | { | ||
44 | struct kvm_vcpu *vcpu; | ||
45 | |||
46 | vcpu = kvm_arm_get_running_vcpu(); | ||
47 | |||
48 | if (vcpu) | ||
49 | return *vcpu_pc(vcpu); | ||
50 | |||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | static struct perf_guest_info_callbacks kvm_guest_cbs = { | ||
55 | .is_in_guest = kvm_is_in_guest, | ||
56 | .is_user_mode = kvm_is_user_mode, | ||
57 | .get_guest_ip = kvm_get_guest_ip, | ||
58 | }; | ||
59 | |||
60 | int kvm_perf_init(void) | ||
61 | { | ||
62 | return perf_register_guest_info_callbacks(&kvm_guest_cbs); | ||
63 | } | ||
64 | |||
65 | int kvm_perf_teardown(void) | ||
66 | { | ||
67 | return perf_unregister_guest_info_callbacks(&kvm_guest_cbs); | ||
68 | } | ||
diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c index 5ee505c937d1..83cb3ac27095 100644 --- a/arch/arm/mm/idmap.c +++ b/arch/arm/mm/idmap.c | |||
@@ -8,7 +8,6 @@ | |||
8 | #include <asm/pgtable.h> | 8 | #include <asm/pgtable.h> |
9 | #include <asm/sections.h> | 9 | #include <asm/sections.h> |
10 | #include <asm/system_info.h> | 10 | #include <asm/system_info.h> |
11 | #include <asm/virt.h> | ||
12 | 11 | ||
13 | pgd_t *idmap_pgd; | 12 | pgd_t *idmap_pgd; |
14 | 13 | ||
@@ -83,37 +82,10 @@ static void identity_mapping_add(pgd_t *pgd, const char *text_start, | |||
83 | } while (pgd++, addr = next, addr != end); | 82 | } while (pgd++, addr = next, addr != end); |
84 | } | 83 | } |
85 | 84 | ||
86 | #if defined(CONFIG_ARM_VIRT_EXT) && defined(CONFIG_ARM_LPAE) | ||
87 | pgd_t *hyp_pgd; | ||
88 | |||
89 | extern char __hyp_idmap_text_start[], __hyp_idmap_text_end[]; | ||
90 | |||
91 | static int __init init_static_idmap_hyp(void) | ||
92 | { | ||
93 | hyp_pgd = kzalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL); | ||
94 | if (!hyp_pgd) | ||
95 | return -ENOMEM; | ||
96 | |||
97 | pr_info("Setting up static HYP identity map for 0x%p - 0x%p\n", | ||
98 | __hyp_idmap_text_start, __hyp_idmap_text_end); | ||
99 | identity_mapping_add(hyp_pgd, __hyp_idmap_text_start, | ||
100 | __hyp_idmap_text_end, PMD_SECT_AP1); | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | #else | ||
105 | static int __init init_static_idmap_hyp(void) | ||
106 | { | ||
107 | return 0; | ||
108 | } | ||
109 | #endif | ||
110 | |||
111 | extern char __idmap_text_start[], __idmap_text_end[]; | 85 | extern char __idmap_text_start[], __idmap_text_end[]; |
112 | 86 | ||
113 | static int __init init_static_idmap(void) | 87 | static int __init init_static_idmap(void) |
114 | { | 88 | { |
115 | int ret; | ||
116 | |||
117 | idmap_pgd = pgd_alloc(&init_mm); | 89 | idmap_pgd = pgd_alloc(&init_mm); |
118 | if (!idmap_pgd) | 90 | if (!idmap_pgd) |
119 | return -ENOMEM; | 91 | return -ENOMEM; |
@@ -123,12 +95,10 @@ static int __init init_static_idmap(void) | |||
123 | identity_mapping_add(idmap_pgd, __idmap_text_start, | 95 | identity_mapping_add(idmap_pgd, __idmap_text_start, |
124 | __idmap_text_end, 0); | 96 | __idmap_text_end, 0); |
125 | 97 | ||
126 | ret = init_static_idmap_hyp(); | ||
127 | |||
128 | /* Flush L1 for the hardware to see this page table content */ | 98 | /* Flush L1 for the hardware to see this page table content */ |
129 | flush_cache_louis(); | 99 | flush_cache_louis(); |
130 | 100 | ||
131 | return ret; | 101 | return 0; |
132 | } | 102 | } |
133 | early_initcall(init_static_idmap); | 103 | early_initcall(init_static_idmap); |
134 | 104 | ||