aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2013-04-12 14:12:06 -0400
committerChristoffer Dall <cdall@cs.columbia.edu>2013-04-29 01:23:10 -0400
commit5a677ce044f18a341ab942e23516e52ad89f7687 (patch)
tree3db77d34c381b19b0a73afbe95a13414a5daa8f6 /arch
parent4f728276fbf1e043010485d7e9275082a1c3d650 (diff)
ARM: KVM: switch to a dual-step HYP init code
Our HYP init code suffers from two major design issues: - it cannot support CPU hotplug, as we tear down the idmap very early - it cannot perform a TLB invalidation when switching from init to runtime mappings, as pages are manipulated from PL1 exclusively The hotplug problem mandates that we keep two sets of page tables (boot and runtime). The TLB problem mandates that we're able to transition from one PGD to another while in HYP, invalidating the TLBs in the process. To be able to do this, we need to share a page between the two page tables. A page that will have the same VA in both configurations. All we need is a VA that has the following properties: - This VA can't be used to represent a kernel mapping. - This VA will not conflict with the physical address of the kernel text The vectors page seems to satisfy this requirement: - The kernel never maps anything else there - The kernel text being copied at the beginning of the physical memory, it is unlikely to use the last 64kB (I doubt we'll ever support KVM on a system with something like 4MB of RAM, but patches are very welcome). Let's call this VA the trampoline VA. Now, we map our init page at 3 locations: - idmap in the boot pgd - trampoline VA in the boot pgd - trampoline VA in the runtime pgd The init scenario is now the following: - We jump in HYP with four parameters: boot HYP pgd, runtime HYP pgd, runtime stack, runtime vectors - Enable the MMU with the boot pgd - Jump to a target into the trampoline page (remember, this is the same physical page!) - Now switch to the runtime pgd (same VA, and still the same physical page!) - Invalidate TLBs - Set stack and vectors - Profit! (or eret, if you only care about the code). Note that we keep the boot mapping permanently (it is not strictly an idmap anymore) to allow for CPU hotplug in later patches. Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/include/asm/kvm_host.h31
-rw-r--r--arch/arm/include/asm/kvm_mmu.h24
-rw-r--r--arch/arm/kvm/arm.c11
-rw-r--r--arch/arm/kvm/init.S78
-rw-r--r--arch/arm/kvm/mmu.c132
5 files changed, 197 insertions, 79 deletions
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 78813b8fad32..6c2a35da867e 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -188,23 +188,30 @@ int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
188int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, 188int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
189 int exception_index); 189 int exception_index);
190 190
191static inline void __cpu_init_hyp_mode(unsigned long long pgd_ptr, 191static inline void __cpu_init_hyp_mode(unsigned long long boot_pgd_ptr,
192 unsigned long long pgd_ptr,
192 unsigned long hyp_stack_ptr, 193 unsigned long hyp_stack_ptr,
193 unsigned long vector_ptr) 194 unsigned long vector_ptr)
194{ 195{
195 unsigned long pgd_low, pgd_high;
196
197 pgd_low = (pgd_ptr & ((1ULL << 32) - 1));
198 pgd_high = (pgd_ptr >> 32ULL);
199
200 /* 196 /*
201 * Call initialization code, and switch to the full blown 197 * Call initialization code, and switch to the full blown HYP
202 * HYP code. The init code doesn't need to preserve these registers as 198 * code. The init code doesn't need to preserve these
203 * r1-r3 and r12 are already callee save according to the AAPCS. 199 * registers as r0-r3 are already callee saved according to
204 * Note that we slightly misuse the prototype by casing the pgd_low to 200 * the AAPCS.
205 * a void *. 201 * Note that we slightly misuse the prototype by casing the
202 * stack pointer to a void *.
203 *
204 * We don't have enough registers to perform the full init in
205 * one go. Install the boot PGD first, and then install the
206 * runtime PGD, stack pointer and vectors. The PGDs are always
207 * passed as the third argument, in order to be passed into
208 * r2-r3 to the init code (yes, this is compliant with the
209 * PCS!).
206 */ 210 */
207 kvm_call_hyp((void *)pgd_low, pgd_high, hyp_stack_ptr, vector_ptr); 211
212 kvm_call_hyp(NULL, 0, boot_pgd_ptr);
213
214 kvm_call_hyp((void*)hyp_stack_ptr, vector_ptr, pgd_ptr);
208} 215}
209 216
210int kvm_perf_init(void); 217int kvm_perf_init(void);
diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
index 92eb20d57942..24b767a8cdb9 100644
--- a/arch/arm/include/asm/kvm_mmu.h
+++ b/arch/arm/include/asm/kvm_mmu.h
@@ -19,17 +19,29 @@
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 24
25/* 25/*
26 * 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
27 * the mapping (HTTBR "covers" TTBR1). 27 * the mapping (HTTBR "covers" TTBR1).
28 */ 28 */
29#define HYP_PAGE_OFFSET_MASK (~0UL) 29#define HYP_PAGE_OFFSET_MASK UL(~0)
30#define HYP_PAGE_OFFSET PAGE_OFFSET 30#define HYP_PAGE_OFFSET PAGE_OFFSET
31#define KERN_TO_HYP(kva) (kva) 31#define KERN_TO_HYP(kva) (kva)
32 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
33int create_hyp_mappings(void *from, void *to); 45int create_hyp_mappings(void *from, void *to);
34int create_hyp_io_mappings(void *from, void *to, phys_addr_t); 46int create_hyp_io_mappings(void *from, void *to, phys_addr_t);
35void free_hyp_pgds(void); 47void free_hyp_pgds(void);
@@ -44,6 +56,8 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run);
44void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu); 56void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu);
45 57
46phys_addr_t kvm_mmu_get_httbr(void); 58phys_addr_t kvm_mmu_get_httbr(void);
59phys_addr_t kvm_mmu_get_boot_httbr(void);
60phys_addr_t kvm_get_idmap_vector(void);
47int kvm_mmu_init(void); 61int kvm_mmu_init(void);
48void kvm_clear_hyp_idmap(void); 62void kvm_clear_hyp_idmap(void);
49 63
@@ -113,4 +127,8 @@ static inline void coherent_icache_guest_page(struct kvm *kvm, gfn_t gfn)
113 } 127 }
114} 128}
115 129
130#define kvm_flush_dcache_to_poc(a,l) __cpuc_flush_dcache_area((a), (l))
131
132#endif /* !__ASSEMBLY__ */
133
116#endif /* __ARM_KVM_MMU_H__ */ 134#endif /* __ARM_KVM_MMU_H__ */
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 16f164a5db86..fc47bd721ab0 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -787,20 +787,22 @@ long kvm_arch_vm_ioctl(struct file *filp,
787 787
788static void cpu_init_hyp_mode(void *vector) 788static void cpu_init_hyp_mode(void *vector)
789{ 789{
790 unsigned long long boot_pgd_ptr;
790 unsigned long long pgd_ptr; 791 unsigned long long pgd_ptr;
791 unsigned long hyp_stack_ptr; 792 unsigned long hyp_stack_ptr;
792 unsigned long stack_page; 793 unsigned long stack_page;
793 unsigned long vector_ptr; 794 unsigned long vector_ptr;
794 795
795 /* Switch from the HYP stub to our own HYP init vector */ 796 /* Switch from the HYP stub to our own HYP init vector */
796 __hyp_set_vectors((unsigned long)vector); 797 __hyp_set_vectors(kvm_get_idmap_vector());
797 798
799 boot_pgd_ptr = (unsigned long long)kvm_mmu_get_boot_httbr();
798 pgd_ptr = (unsigned long long)kvm_mmu_get_httbr(); 800 pgd_ptr = (unsigned long long)kvm_mmu_get_httbr();
799 stack_page = __get_cpu_var(kvm_arm_hyp_stack_page); 801 stack_page = __get_cpu_var(kvm_arm_hyp_stack_page);
800 hyp_stack_ptr = stack_page + PAGE_SIZE; 802 hyp_stack_ptr = stack_page + PAGE_SIZE;
801 vector_ptr = (unsigned long)__kvm_hyp_vector; 803 vector_ptr = (unsigned long)__kvm_hyp_vector;
802 804
803 __cpu_init_hyp_mode(pgd_ptr, hyp_stack_ptr, vector_ptr); 805 __cpu_init_hyp_mode(boot_pgd_ptr, pgd_ptr, hyp_stack_ptr, vector_ptr);
804} 806}
805 807
806/** 808/**
@@ -854,11 +856,6 @@ static int init_hyp_mode(void)
854 } 856 }
855 857
856 /* 858 /*
857 * Unmap the identity mapping
858 */
859 kvm_clear_hyp_idmap();
860
861 /*
862 * Map the Hyp-code called directly from the host 859 * Map the Hyp-code called directly from the host
863 */ 860 */
864 err = create_hyp_mappings(__kvm_hyp_code_start, __kvm_hyp_code_end); 861 err = create_hyp_mappings(__kvm_hyp_code_start, __kvm_hyp_code_end);
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
126phase2:
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
139target: @ 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 7464824c17ef..4646c17f571c 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -32,9 +32,15 @@
32 32
33extern char __hyp_idmap_text_start[], __hyp_idmap_text_end[]; 33extern char __hyp_idmap_text_start[], __hyp_idmap_text_end[];
34 34
35static pgd_t *boot_hyp_pgd;
35static pgd_t *hyp_pgd; 36static pgd_t *hyp_pgd;
36static DEFINE_MUTEX(kvm_hyp_pgd_mutex); 37static DEFINE_MUTEX(kvm_hyp_pgd_mutex);
37 38
39static void *init_bounce_page;
40static unsigned long hyp_idmap_start;
41static unsigned long hyp_idmap_end;
42static phys_addr_t hyp_idmap_vector;
43
38static void kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa) 44static void kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa)
39{ 45{
40 kvm_call_hyp(__kvm_tlb_flush_vmid_ipa, kvm, ipa); 46 kvm_call_hyp(__kvm_tlb_flush_vmid_ipa, kvm, ipa);
@@ -152,9 +158,12 @@ static void unmap_range(pgd_t *pgdp, unsigned long long start, u64 size)
152/** 158/**
153 * free_hyp_pgds - free Hyp-mode page tables 159 * free_hyp_pgds - free Hyp-mode page tables
154 * 160 *
155 * Assumes hyp_pgd is a page table used strictly in Hyp-mode and therefore contains 161 * Assumes hyp_pgd is a page table used strictly in Hyp-mode and
156 * either mappings in the kernel memory area (above PAGE_OFFSET), or 162 * therefore contains either mappings in the kernel memory area (above
157 * device mappings in the vmalloc range (from VMALLOC_START to VMALLOC_END). 163 * PAGE_OFFSET), or device mappings in the vmalloc range (from
164 * VMALLOC_START to VMALLOC_END).
165 *
166 * boot_hyp_pgd should only map two pages for the init code.
158 */ 167 */
159void free_hyp_pgds(void) 168void free_hyp_pgds(void)
160{ 169{
@@ -162,6 +171,12 @@ void free_hyp_pgds(void)
162 171
163 mutex_lock(&kvm_hyp_pgd_mutex); 172 mutex_lock(&kvm_hyp_pgd_mutex);
164 173
174 if (boot_hyp_pgd) {
175 unmap_range(boot_hyp_pgd, hyp_idmap_start, PAGE_SIZE);
176 unmap_range(boot_hyp_pgd, TRAMPOLINE_VA, PAGE_SIZE);
177 kfree(boot_hyp_pgd);
178 }
179
165 if (hyp_pgd) { 180 if (hyp_pgd) {
166 for (addr = PAGE_OFFSET; virt_addr_valid(addr); addr += PGDIR_SIZE) 181 for (addr = PAGE_OFFSET; virt_addr_valid(addr); addr += PGDIR_SIZE)
167 unmap_range(hyp_pgd, KERN_TO_HYP(addr), PGDIR_SIZE); 182 unmap_range(hyp_pgd, KERN_TO_HYP(addr), PGDIR_SIZE);
@@ -170,6 +185,7 @@ void free_hyp_pgds(void)
170 kfree(hyp_pgd); 185 kfree(hyp_pgd);
171 } 186 }
172 187
188 kfree(init_bounce_page);
173 mutex_unlock(&kvm_hyp_pgd_mutex); 189 mutex_unlock(&kvm_hyp_pgd_mutex);
174} 190}
175 191
@@ -185,6 +201,7 @@ static void create_hyp_pte_mappings(pmd_t *pmd, unsigned long start,
185 pte = pte_offset_kernel(pmd, addr); 201 pte = pte_offset_kernel(pmd, addr);
186 kvm_set_pte(pte, pfn_pte(pfn, prot)); 202 kvm_set_pte(pte, pfn_pte(pfn, prot));
187 get_page(virt_to_page(pte)); 203 get_page(virt_to_page(pte));
204 kvm_flush_dcache_to_poc(pte, sizeof(*pte));
188 pfn++; 205 pfn++;
189 } while (addr += PAGE_SIZE, addr != end); 206 } while (addr += PAGE_SIZE, addr != end);
190} 207}
@@ -211,6 +228,7 @@ static int create_hyp_pmd_mappings(pud_t *pud, unsigned long start,
211 } 228 }
212 pmd_populate_kernel(NULL, pmd, pte); 229 pmd_populate_kernel(NULL, pmd, pte);
213 get_page(virt_to_page(pmd)); 230 get_page(virt_to_page(pmd));
231 kvm_flush_dcache_to_poc(pmd, sizeof(*pmd));
214 } 232 }
215 233
216 next = pmd_addr_end(addr, end); 234 next = pmd_addr_end(addr, end);
@@ -248,6 +266,7 @@ static int __create_hyp_mappings(pgd_t *pgdp,
248 } 266 }
249 pud_populate(NULL, pud, pmd); 267 pud_populate(NULL, pud, pmd);
250 get_page(virt_to_page(pud)); 268 get_page(virt_to_page(pud));
269 kvm_flush_dcache_to_poc(pud, sizeof(*pud));
251 } 270 }
252 271
253 next = pgd_addr_end(addr, end); 272 next = pgd_addr_end(addr, end);
@@ -689,18 +708,64 @@ void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu)
689 708
690phys_addr_t kvm_mmu_get_httbr(void) 709phys_addr_t kvm_mmu_get_httbr(void)
691{ 710{
692 VM_BUG_ON(!virt_addr_valid(hyp_pgd));
693 return virt_to_phys(hyp_pgd); 711 return virt_to_phys(hyp_pgd);
694} 712}
695 713
714phys_addr_t kvm_mmu_get_boot_httbr(void)
715{
716 return virt_to_phys(boot_hyp_pgd);
717}
718
719phys_addr_t kvm_get_idmap_vector(void)
720{
721 return hyp_idmap_vector;
722}
723
696int kvm_mmu_init(void) 724int kvm_mmu_init(void)
697{ 725{
698 unsigned long hyp_idmap_start = virt_to_phys(__hyp_idmap_text_start);
699 unsigned long hyp_idmap_end = virt_to_phys(__hyp_idmap_text_end);
700 int err; 726 int err;
701 727
728 hyp_idmap_start = virt_to_phys(__hyp_idmap_text_start);
729 hyp_idmap_end = virt_to_phys(__hyp_idmap_text_end);
730 hyp_idmap_vector = virt_to_phys(__kvm_hyp_init);
731
732 if ((hyp_idmap_start ^ hyp_idmap_end) & PAGE_MASK) {
733 /*
734 * Our init code is crossing a page boundary. Allocate
735 * a bounce page, copy the code over and use that.
736 */
737 size_t len = __hyp_idmap_text_end - __hyp_idmap_text_start;
738 phys_addr_t phys_base;
739
740 init_bounce_page = kmalloc(PAGE_SIZE, GFP_KERNEL);
741 if (!init_bounce_page) {
742 kvm_err("Couldn't allocate HYP init bounce page\n");
743 err = -ENOMEM;
744 goto out;
745 }
746
747 memcpy(init_bounce_page, __hyp_idmap_text_start, len);
748 /*
749 * Warning: the code we just copied to the bounce page
750 * must be flushed to the point of coherency.
751 * Otherwise, the data may be sitting in L2, and HYP
752 * mode won't be able to observe it as it runs with
753 * caches off at that point.
754 */
755 kvm_flush_dcache_to_poc(init_bounce_page, len);
756
757 phys_base = virt_to_phys(init_bounce_page);
758 hyp_idmap_vector += phys_base - hyp_idmap_start;
759 hyp_idmap_start = phys_base;
760 hyp_idmap_end = phys_base + len;
761
762 kvm_info("Using HYP init bounce page @%lx\n",
763 (unsigned long)phys_base);
764 }
765
702 hyp_pgd = kzalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL); 766 hyp_pgd = kzalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL);
703 if (!hyp_pgd) { 767 boot_hyp_pgd = kzalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL);
768 if (!hyp_pgd || !boot_hyp_pgd) {
704 kvm_err("Hyp mode PGD not allocated\n"); 769 kvm_err("Hyp mode PGD not allocated\n");
705 err = -ENOMEM; 770 err = -ENOMEM;
706 goto out; 771 goto out;
@@ -718,39 +783,30 @@ int kvm_mmu_init(void)
718 goto out; 783 goto out;
719 } 784 }
720 785
786 /* Map the very same page at the trampoline VA */
787 err = __create_hyp_mappings(boot_hyp_pgd,
788 TRAMPOLINE_VA, TRAMPOLINE_VA + PAGE_SIZE,
789 __phys_to_pfn(hyp_idmap_start),
790 PAGE_HYP);
791 if (err) {
792 kvm_err("Failed to map trampoline @%lx into boot HYP pgd\n",
793 TRAMPOLINE_VA);
794 goto out;
795 }
796
797 /* Map the same page again into the runtime page tables */
798 err = __create_hyp_mappings(hyp_pgd,
799 TRAMPOLINE_VA, TRAMPOLINE_VA + PAGE_SIZE,
800 __phys_to_pfn(hyp_idmap_start),
801 PAGE_HYP);
802 if (err) {
803 kvm_err("Failed to map trampoline @%lx into runtime HYP pgd\n",
804 TRAMPOLINE_VA);
805 goto out;
806 }
807
721 return 0; 808 return 0;
722out: 809out:
723 free_hyp_pgds(); 810 free_hyp_pgds();
724 return err; 811 return err;
725} 812}
726
727/**
728 * kvm_clear_idmap - remove all idmaps from the hyp pgd
729 *
730 * Free the underlying pmds for all pgds in range and clear the pgds (but
731 * don't free them) afterwards.
732 */
733void kvm_clear_hyp_idmap(void)
734{
735 unsigned long addr, end;
736 unsigned long next;
737 pgd_t *pgd = hyp_pgd;
738 pud_t *pud;
739 pmd_t *pmd;
740
741 addr = virt_to_phys(__hyp_idmap_text_start);
742 end = virt_to_phys(__hyp_idmap_text_end);
743
744 pgd += pgd_index(addr);
745 do {
746 next = pgd_addr_end(addr, end);
747 if (pgd_none_or_clear_bad(pgd))
748 continue;
749 pud = pud_offset(pgd, addr);
750 pmd = pmd_offset(pud, addr);
751
752 pud_clear(pud);
753 kvm_clean_pmd_entry(pmd);
754 pmd_free(NULL, (pmd_t *)((unsigned long)pmd & PAGE_MASK));
755 } while (pgd++, addr = next, addr < end);
756}