aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorChristoffer Dall <c.dall@virtualopensystems.com>2013-01-20 18:28:06 -0500
committerChristoffer Dall <c.dall@virtualopensystems.com>2013-01-23 13:29:10 -0500
commit342cd0ab0e6ca3fe7c88a78890352748b8e894a9 (patch)
tree90381be821d65fdb2fd2255752a124e9ad771a2d /arch
parent749cf76c5a363e1383108a914ea09530bfa0bd43 (diff)
KVM: ARM: Hypervisor initialization
Sets up KVM code to handle all exceptions taken to Hyp mode. When the kernel is booted in Hyp mode, calling an hvc instruction with r0 pointing to the new vectors, the HVBAR is changed to the the vector pointers. This allows subsystems (like KVM here) to execute code in Hyp-mode with the MMU disabled. We initialize other Hyp-mode registers and enables the MMU for Hyp-mode from the id-mapped hyp initialization code. Afterwards, the HVBAR is changed to point to KVM Hyp vectors used to catch guest faults and to switch to Hyp mode to perform a world-switch into a KVM guest. Also provides memory mapping code to map required code pages, data structures, and I/O regions accessed in Hyp mode at the same virtual address as the host kernel virtual addresses, but which conforms to the architectural requirements for translations in Hyp mode. This interface is added in arch/arm/kvm/arm_mmu.c and comprises: - create_hyp_mappings(from, to); - create_hyp_io_mappings(from, to, phys_addr); - free_hyp_pmds(); Reviewed-by: Will Deacon <will.deacon@arm.com> Reviewed-by: Marcelo Tosatti <mtosatti@redhat.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Christoffer Dall <c.dall@virtualopensystems.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/include/asm/kvm_arm.h124
-rw-r--r--arch/arm/include/asm/kvm_asm.h20
-rw-r--r--arch/arm/include/asm/kvm_host.h1
-rw-r--r--arch/arm/include/asm/kvm_mmu.h29
-rw-r--r--arch/arm/include/asm/pgtable-3level-hwdef.h4
-rw-r--r--arch/arm/kvm/arm.c172
-rw-r--r--arch/arm/kvm/init.S95
-rw-r--r--arch/arm/kvm/interrupts.S62
-rw-r--r--arch/arm/kvm/mmu.c248
9 files changed, 755 insertions, 0 deletions
diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h
index dc678e193417..8875b3f605a7 100644
--- a/arch/arm/include/asm/kvm_arm.h
+++ b/arch/arm/include/asm/kvm_arm.h
@@ -21,4 +21,128 @@
21 21
22#include <linux/types.h> 22#include <linux/types.h>
23 23
24/* Hyp Configuration Register (HCR) bits */
25#define HCR_TGE (1 << 27)
26#define HCR_TVM (1 << 26)
27#define HCR_TTLB (1 << 25)
28#define HCR_TPU (1 << 24)
29#define HCR_TPC (1 << 23)
30#define HCR_TSW (1 << 22)
31#define HCR_TAC (1 << 21)
32#define HCR_TIDCP (1 << 20)
33#define HCR_TSC (1 << 19)
34#define HCR_TID3 (1 << 18)
35#define HCR_TID2 (1 << 17)
36#define HCR_TID1 (1 << 16)
37#define HCR_TID0 (1 << 15)
38#define HCR_TWE (1 << 14)
39#define HCR_TWI (1 << 13)
40#define HCR_DC (1 << 12)
41#define HCR_BSU (3 << 10)
42#define HCR_BSU_IS (1 << 10)
43#define HCR_FB (1 << 9)
44#define HCR_VA (1 << 8)
45#define HCR_VI (1 << 7)
46#define HCR_VF (1 << 6)
47#define HCR_AMO (1 << 5)
48#define HCR_IMO (1 << 4)
49#define HCR_FMO (1 << 3)
50#define HCR_PTW (1 << 2)
51#define HCR_SWIO (1 << 1)
52#define HCR_VM 1
53
54/*
55 * The bits we set in HCR:
56 * TAC: Trap ACTLR
57 * TSC: Trap SMC
58 * TSW: Trap cache operations by set/way
59 * TWI: Trap WFI
60 * TIDCP: Trap L2CTLR/L2ECTLR
61 * BSU_IS: Upgrade barriers to the inner shareable domain
62 * FB: Force broadcast of all maintainance operations
63 * AMO: Override CPSR.A and enable signaling with VA
64 * IMO: Override CPSR.I and enable signaling with VI
65 * FMO: Override CPSR.F and enable signaling with VF
66 * SWIO: Turn set/way invalidates into set/way clean+invalidate
67 */
68#define HCR_GUEST_MASK (HCR_TSC | HCR_TSW | HCR_TWI | HCR_VM | HCR_BSU_IS | \
69 HCR_FB | HCR_TAC | HCR_AMO | HCR_IMO | HCR_FMO | \
70 HCR_SWIO | HCR_TIDCP)
71
72/* Hyp System Control Register (HSCTLR) bits */
73#define HSCTLR_TE (1 << 30)
74#define HSCTLR_EE (1 << 25)
75#define HSCTLR_FI (1 << 21)
76#define HSCTLR_WXN (1 << 19)
77#define HSCTLR_I (1 << 12)
78#define HSCTLR_C (1 << 2)
79#define HSCTLR_A (1 << 1)
80#define HSCTLR_M 1
81#define HSCTLR_MASK (HSCTLR_M | HSCTLR_A | HSCTLR_C | HSCTLR_I | \
82 HSCTLR_WXN | HSCTLR_FI | HSCTLR_EE | HSCTLR_TE)
83
84/* TTBCR and HTCR Registers bits */
85#define TTBCR_EAE (1 << 31)
86#define TTBCR_IMP (1 << 30)
87#define TTBCR_SH1 (3 << 28)
88#define TTBCR_ORGN1 (3 << 26)
89#define TTBCR_IRGN1 (3 << 24)
90#define TTBCR_EPD1 (1 << 23)
91#define TTBCR_A1 (1 << 22)
92#define TTBCR_T1SZ (3 << 16)
93#define TTBCR_SH0 (3 << 12)
94#define TTBCR_ORGN0 (3 << 10)
95#define TTBCR_IRGN0 (3 << 8)
96#define TTBCR_EPD0 (1 << 7)
97#define TTBCR_T0SZ 3
98#define HTCR_MASK (TTBCR_T0SZ | TTBCR_IRGN0 | TTBCR_ORGN0 | TTBCR_SH0)
99
100/* Hyp Debug Configuration Register bits */
101#define HDCR_TDRA (1 << 11)
102#define HDCR_TDOSA (1 << 10)
103#define HDCR_TDA (1 << 9)
104#define HDCR_TDE (1 << 8)
105#define HDCR_HPME (1 << 7)
106#define HDCR_TPM (1 << 6)
107#define HDCR_TPMCR (1 << 5)
108#define HDCR_HPMN_MASK (0x1F)
109
110/*
111 * The architecture supports 40-bit IPA as input to the 2nd stage translations
112 * and PTRS_PER_S2_PGD becomes 1024, because each entry covers 1GB of address
113 * space.
114 */
115#define KVM_PHYS_SHIFT (40)
116#define KVM_PHYS_SIZE (1ULL << KVM_PHYS_SHIFT)
117#define KVM_PHYS_MASK (KVM_PHYS_SIZE - 1ULL)
118#define PTRS_PER_S2_PGD (1ULL << (KVM_PHYS_SHIFT - 30))
119#define S2_PGD_ORDER get_order(PTRS_PER_S2_PGD * sizeof(pgd_t))
120#define S2_PGD_SIZE (1 << S2_PGD_ORDER)
121
122/* Virtualization Translation Control Register (VTCR) bits */
123#define VTCR_SH0 (3 << 12)
124#define VTCR_ORGN0 (3 << 10)
125#define VTCR_IRGN0 (3 << 8)
126#define VTCR_SL0 (3 << 6)
127#define VTCR_S (1 << 4)
128#define VTCR_T0SZ (0xf)
129#define VTCR_MASK (VTCR_SH0 | VTCR_ORGN0 | VTCR_IRGN0 | VTCR_SL0 | \
130 VTCR_S | VTCR_T0SZ)
131#define VTCR_HTCR_SH (VTCR_SH0 | VTCR_ORGN0 | VTCR_IRGN0)
132#define VTCR_SL_L2 (0 << 6) /* Starting-level: 2 */
133#define VTCR_SL_L1 (1 << 6) /* Starting-level: 1 */
134#define KVM_VTCR_SL0 VTCR_SL_L1
135/* stage-2 input address range defined as 2^(32-T0SZ) */
136#define KVM_T0SZ (32 - KVM_PHYS_SHIFT)
137#define KVM_VTCR_T0SZ (KVM_T0SZ & VTCR_T0SZ)
138#define KVM_VTCR_S ((KVM_VTCR_T0SZ << 1) & VTCR_S)
139
140/* Virtualization Translation Table Base Register (VTTBR) bits */
141#if KVM_VTCR_SL0 == VTCR_SL_L2 /* see ARM DDI 0406C: B4-1720 */
142#define VTTBR_X (14 - KVM_T0SZ)
143#else
144#define VTTBR_X (5 - KVM_T0SZ)
145#endif
146
147
24#endif /* __ARM_KVM_ARM_H__ */ 148#endif /* __ARM_KVM_ARM_H__ */
diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h
index f9993e5fb695..81324e2eb3f9 100644
--- a/arch/arm/include/asm/kvm_asm.h
+++ b/arch/arm/include/asm/kvm_asm.h
@@ -54,5 +54,25 @@
54#define ARM_EXCEPTION_DATA_ABORT 4 54#define ARM_EXCEPTION_DATA_ABORT 4
55#define ARM_EXCEPTION_IRQ 5 55#define ARM_EXCEPTION_IRQ 5
56#define ARM_EXCEPTION_FIQ 6 56#define ARM_EXCEPTION_FIQ 6
57#define ARM_EXCEPTION_HVC 7
58
59#ifndef __ASSEMBLY__
60struct kvm_vcpu;
61
62extern char __kvm_hyp_init[];
63extern char __kvm_hyp_init_end[];
64
65extern char __kvm_hyp_exit[];
66extern char __kvm_hyp_exit_end[];
67
68extern char __kvm_hyp_vector[];
69
70extern char __kvm_hyp_code_start[];
71extern char __kvm_hyp_code_end[];
72
73extern void __kvm_flush_vm_context(void);
74
75extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
76#endif
57 77
58#endif /* __ARM_KVM_ASM_H__ */ 78#endif /* __ARM_KVM_ASM_H__ */
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 0d9938a20751..067ef2898c26 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -111,4 +111,5 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
111struct kvm_one_reg; 111struct kvm_one_reg;
112int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); 112int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
113int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); 113int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
114u64 kvm_call_hyp(void *hypfn, ...);
114#endif /* __ARM_KVM_HOST_H__ */ 115#endif /* __ARM_KVM_HOST_H__ */
diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
new file mode 100644
index 000000000000..e8679b317b0f
--- /dev/null
+++ b/arch/arm/include/asm/kvm_mmu.h
@@ -0,0 +1,29 @@
1/*
2 * Copyright (C) 2012 - Virtual Open Systems and Columbia University
3 * Author: Christoffer Dall <c.dall@virtualopensystems.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License, version 2, as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19#ifndef __ARM_KVM_MMU_H__
20#define __ARM_KVM_MMU_H__
21
22int create_hyp_mappings(void *from, void *to);
23int create_hyp_io_mappings(void *from, void *to, phys_addr_t);
24void free_hyp_pmds(void);
25
26phys_addr_t kvm_mmu_get_httbr(void);
27int kvm_mmu_init(void);
28void kvm_clear_hyp_idmap(void);
29#endif /* __ARM_KVM_MMU_H__ */
diff --git a/arch/arm/include/asm/pgtable-3level-hwdef.h b/arch/arm/include/asm/pgtable-3level-hwdef.h
index a2d404ed1ade..18f5cef82ad5 100644
--- a/arch/arm/include/asm/pgtable-3level-hwdef.h
+++ b/arch/arm/include/asm/pgtable-3level-hwdef.h
@@ -32,6 +32,9 @@
32#define PMD_TYPE_SECT (_AT(pmdval_t, 1) << 0) 32#define PMD_TYPE_SECT (_AT(pmdval_t, 1) << 0)
33#define PMD_BIT4 (_AT(pmdval_t, 0)) 33#define PMD_BIT4 (_AT(pmdval_t, 0))
34#define PMD_DOMAIN(x) (_AT(pmdval_t, 0)) 34#define PMD_DOMAIN(x) (_AT(pmdval_t, 0))
35#define PMD_APTABLE_SHIFT (61)
36#define PMD_APTABLE (_AT(pgdval_t, 3) << PGD_APTABLE_SHIFT)
37#define PMD_PXNTABLE (_AT(pgdval_t, 1) << 59)
35 38
36/* 39/*
37 * - section 40 * - section
@@ -41,6 +44,7 @@
41#define PMD_SECT_S (_AT(pmdval_t, 3) << 8) 44#define PMD_SECT_S (_AT(pmdval_t, 3) << 8)
42#define PMD_SECT_AF (_AT(pmdval_t, 1) << 10) 45#define PMD_SECT_AF (_AT(pmdval_t, 1) << 10)
43#define PMD_SECT_nG (_AT(pmdval_t, 1) << 11) 46#define PMD_SECT_nG (_AT(pmdval_t, 1) << 11)
47#define PMD_SECT_PXN (_AT(pmdval_t, 1) << 53)
44#define PMD_SECT_XN (_AT(pmdval_t, 1) << 54) 48#define PMD_SECT_XN (_AT(pmdval_t, 1) << 54)
45#define PMD_SECT_AP_WRITE (_AT(pmdval_t, 0)) 49#define PMD_SECT_AP_WRITE (_AT(pmdval_t, 0))
46#define PMD_SECT_AP_READ (_AT(pmdval_t, 0)) 50#define PMD_SECT_AP_READ (_AT(pmdval_t, 0))
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index d3506b4001aa..2c6b780e78a7 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -34,11 +34,21 @@
34#include <asm/ptrace.h> 34#include <asm/ptrace.h>
35#include <asm/mman.h> 35#include <asm/mman.h>
36#include <asm/cputype.h> 36#include <asm/cputype.h>
37#include <asm/tlbflush.h>
38#include <asm/virt.h>
39#include <asm/kvm_arm.h>
40#include <asm/kvm_asm.h>
41#include <asm/kvm_mmu.h>
37 42
38#ifdef REQUIRES_VIRT 43#ifdef REQUIRES_VIRT
39__asm__(".arch_extension virt"); 44__asm__(".arch_extension virt");
40#endif 45#endif
41 46
47static DEFINE_PER_CPU(unsigned long, kvm_arm_hyp_stack_page);
48static struct vfp_hard_struct __percpu *kvm_host_vfp_state;
49static unsigned long hyp_default_vectors;
50
51
42int kvm_arch_hardware_enable(void *garbage) 52int kvm_arch_hardware_enable(void *garbage)
43{ 53{
44 return 0; 54 return 0;
@@ -331,9 +341,171 @@ long kvm_arch_vm_ioctl(struct file *filp,
331 return -EINVAL; 341 return -EINVAL;
332} 342}
333 343
344static void cpu_init_hyp_mode(void *vector)
345{
346 unsigned long long pgd_ptr;
347 unsigned long pgd_low, pgd_high;
348 unsigned long hyp_stack_ptr;
349 unsigned long stack_page;
350 unsigned long vector_ptr;
351
352 /* Switch from the HYP stub to our own HYP init vector */
353 __hyp_set_vectors((unsigned long)vector);
354
355 pgd_ptr = (unsigned long long)kvm_mmu_get_httbr();
356 pgd_low = (pgd_ptr & ((1ULL << 32) - 1));
357 pgd_high = (pgd_ptr >> 32ULL);
358 stack_page = __get_cpu_var(kvm_arm_hyp_stack_page);
359 hyp_stack_ptr = stack_page + PAGE_SIZE;
360 vector_ptr = (unsigned long)__kvm_hyp_vector;
361
362 /*
363 * Call initialization code, and switch to the full blown
364 * HYP code. The init code doesn't need to preserve these registers as
365 * r1-r3 and r12 are already callee save according to the AAPCS.
366 * Note that we slightly misuse the prototype by casing the pgd_low to
367 * a void *.
368 */
369 kvm_call_hyp((void *)pgd_low, pgd_high, hyp_stack_ptr, vector_ptr);
370}
371
372/**
373 * Inits Hyp-mode on all online CPUs
374 */
375static int init_hyp_mode(void)
376{
377 phys_addr_t init_phys_addr;
378 int cpu;
379 int err = 0;
380
381 /*
382 * Allocate Hyp PGD and setup Hyp identity mapping
383 */
384 err = kvm_mmu_init();
385 if (err)
386 goto out_err;
387
388 /*
389 * It is probably enough to obtain the default on one
390 * CPU. It's unlikely to be different on the others.
391 */
392 hyp_default_vectors = __hyp_get_vectors();
393
394 /*
395 * Allocate stack pages for Hypervisor-mode
396 */
397 for_each_possible_cpu(cpu) {
398 unsigned long stack_page;
399
400 stack_page = __get_free_page(GFP_KERNEL);
401 if (!stack_page) {
402 err = -ENOMEM;
403 goto out_free_stack_pages;
404 }
405
406 per_cpu(kvm_arm_hyp_stack_page, cpu) = stack_page;
407 }
408
409 /*
410 * Execute the init code on each CPU.
411 *
412 * Note: The stack is not mapped yet, so don't do anything else than
413 * initializing the hypervisor mode on each CPU using a local stack
414 * space for temporary storage.
415 */
416 init_phys_addr = virt_to_phys(__kvm_hyp_init);
417 for_each_online_cpu(cpu) {
418 smp_call_function_single(cpu, cpu_init_hyp_mode,
419 (void *)(long)init_phys_addr, 1);
420 }
421
422 /*
423 * Unmap the identity mapping
424 */
425 kvm_clear_hyp_idmap();
426
427 /*
428 * Map the Hyp-code called directly from the host
429 */
430 err = create_hyp_mappings(__kvm_hyp_code_start, __kvm_hyp_code_end);
431 if (err) {
432 kvm_err("Cannot map world-switch code\n");
433 goto out_free_mappings;
434 }
435
436 /*
437 * Map the Hyp stack pages
438 */
439 for_each_possible_cpu(cpu) {
440 char *stack_page = (char *)per_cpu(kvm_arm_hyp_stack_page, cpu);
441 err = create_hyp_mappings(stack_page, stack_page + PAGE_SIZE);
442
443 if (err) {
444 kvm_err("Cannot map hyp stack\n");
445 goto out_free_mappings;
446 }
447 }
448
449 /*
450 * Map the host VFP structures
451 */
452 kvm_host_vfp_state = alloc_percpu(struct vfp_hard_struct);
453 if (!kvm_host_vfp_state) {
454 err = -ENOMEM;
455 kvm_err("Cannot allocate host VFP state\n");
456 goto out_free_mappings;
457 }
458
459 for_each_possible_cpu(cpu) {
460 struct vfp_hard_struct *vfp;
461
462 vfp = per_cpu_ptr(kvm_host_vfp_state, cpu);
463 err = create_hyp_mappings(vfp, vfp + 1);
464
465 if (err) {
466 kvm_err("Cannot map host VFP state: %d\n", err);
467 goto out_free_vfp;
468 }
469 }
470
471 kvm_info("Hyp mode initialized successfully\n");
472 return 0;
473out_free_vfp:
474 free_percpu(kvm_host_vfp_state);
475out_free_mappings:
476 free_hyp_pmds();
477out_free_stack_pages:
478 for_each_possible_cpu(cpu)
479 free_page(per_cpu(kvm_arm_hyp_stack_page, cpu));
480out_err:
481 kvm_err("error initializing Hyp mode: %d\n", err);
482 return err;
483}
484
485/**
486 * Initialize Hyp-mode and memory mappings on all CPUs.
487 */
334int kvm_arch_init(void *opaque) 488int kvm_arch_init(void *opaque)
335{ 489{
490 int err;
491
492 if (!is_hyp_mode_available()) {
493 kvm_err("HYP mode not available\n");
494 return -ENODEV;
495 }
496
497 if (kvm_target_cpu() < 0) {
498 kvm_err("Target CPU not supported!\n");
499 return -ENODEV;
500 }
501
502 err = init_hyp_mode();
503 if (err)
504 goto out_err;
505
336 return 0; 506 return 0;
507out_err:
508 return err;
337} 509}
338 510
339/* NOP: Compiling as a module not supported */ 511/* NOP: Compiling as a module not supported */
diff --git a/arch/arm/kvm/init.S b/arch/arm/kvm/init.S
index 1dc8926e26d2..9f37a79b880b 100644
--- a/arch/arm/kvm/init.S
+++ b/arch/arm/kvm/init.S
@@ -15,5 +15,100 @@
15 * along with this program; if not, write to the Free Software 15 * along with this program; if not, write to the Free Software
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
19#include <linux/linkage.h>
20#include <asm/unified.h>
18#include <asm/asm-offsets.h> 21#include <asm/asm-offsets.h>
19#include <asm/kvm_asm.h> 22#include <asm/kvm_asm.h>
23#include <asm/kvm_arm.h>
24
25/********************************************************************
26 * Hypervisor initialization
27 * - should be called with:
28 * r0,r1 = Hypervisor pgd pointer
29 * r2 = top of Hyp stack (kernel VA)
30 * r3 = pointer to hyp vectors
31 */
32
33 .text
34 .pushsection .hyp.idmap.text,"ax"
35 .align 5
36__kvm_hyp_init:
37 .globl __kvm_hyp_init
38
39 @ Hyp-mode exception vector
40 W(b) .
41 W(b) .
42 W(b) .
43 W(b) .
44 W(b) .
45 W(b) __do_hyp_init
46 W(b) .
47 W(b) .
48
49__do_hyp_init:
50 @ Set the HTTBR to point to the hypervisor PGD pointer passed
51 mcrr p15, 4, r0, r1, c2
52
53 @ Set the HTCR and VTCR to the same shareability and cacheability
54 @ settings as the non-secure TTBCR and with T0SZ == 0.
55 mrc p15, 4, r0, c2, c0, 2 @ HTCR
56 ldr r12, =HTCR_MASK
57 bic r0, r0, r12
58 mrc p15, 0, r1, c2, c0, 2 @ TTBCR
59 and r1, r1, #(HTCR_MASK & ~TTBCR_T0SZ)
60 orr r0, r0, r1
61 mcr p15, 4, r0, c2, c0, 2 @ HTCR
62
63 mrc p15, 4, r1, c2, c1, 2 @ VTCR
64 ldr r12, =VTCR_MASK
65 bic r1, r1, r12
66 bic r0, r0, #(~VTCR_HTCR_SH) @ clear non-reusable HTCR bits
67 orr r1, r0, r1
68 orr r1, r1, #(KVM_VTCR_SL0 | KVM_VTCR_T0SZ | KVM_VTCR_S)
69 mcr p15, 4, r1, c2, c1, 2 @ VTCR
70
71 @ Use the same memory attributes for hyp. accesses as the kernel
72 @ (copy MAIRx ro HMAIRx).
73 mrc p15, 0, r0, c10, c2, 0
74 mcr p15, 4, r0, c10, c2, 0
75 mrc p15, 0, r0, c10, c2, 1
76 mcr p15, 4, r0, c10, c2, 1
77
78 @ Set the HSCTLR to:
79 @ - ARM/THUMB exceptions: Kernel config (Thumb-2 kernel)
80 @ - Endianness: Kernel config
81 @ - Fast Interrupt Features: Kernel config
82 @ - Write permission implies XN: disabled
83 @ - Instruction cache: enabled
84 @ - Data/Unified cache: enabled
85 @ - Memory alignment checks: enabled
86 @ - MMU: enabled (this code must be run from an identity mapping)
87 mrc p15, 4, r0, c1, c0, 0 @ HSCR
88 ldr r12, =HSCTLR_MASK
89 bic r0, r0, r12
90 mrc p15, 0, r1, c1, c0, 0 @ SCTLR
91 ldr r12, =(HSCTLR_EE | HSCTLR_FI | HSCTLR_I | HSCTLR_C)
92 and r1, r1, r12
93 ARM( ldr r12, =(HSCTLR_M | HSCTLR_A) )
94 THUMB( ldr r12, =(HSCTLR_M | HSCTLR_A | HSCTLR_TE) )
95 orr r1, r1, r12
96 orr r0, r0, r1
97 isb
98 mcr p15, 4, r0, c1, c0, 0 @ HSCR
99 isb
100
101 @ Set stack pointer and return to the kernel
102 mov sp, r2
103
104 @ Set HVBAR to point to the HYP vectors
105 mcr p15, 4, r3, c12, c0, 0 @ HVBAR
106
107 eret
108
109 .ltorg
110
111 .globl __kvm_hyp_init_end
112__kvm_hyp_init_end:
113
114 .popsection
diff --git a/arch/arm/kvm/interrupts.S b/arch/arm/kvm/interrupts.S
index 1dc8926e26d2..d10a8075409a 100644
--- a/arch/arm/kvm/interrupts.S
+++ b/arch/arm/kvm/interrupts.S
@@ -15,5 +15,67 @@
15 * along with this program; if not, write to the Free Software 15 * along with this program; if not, write to the Free Software
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
19#include <linux/linkage.h>
20#include <linux/const.h>
21#include <asm/unified.h>
22#include <asm/page.h>
18#include <asm/asm-offsets.h> 23#include <asm/asm-offsets.h>
19#include <asm/kvm_asm.h> 24#include <asm/kvm_asm.h>
25#include <asm/kvm_arm.h>
26
27 .text
28
29__kvm_hyp_code_start:
30 .globl __kvm_hyp_code_start
31
32/********************************************************************
33 * Flush per-VMID TLBs
34 */
35ENTRY(__kvm_flush_vm_context)
36 bx lr
37ENDPROC(__kvm_flush_vm_context)
38
39/********************************************************************
40 * Hypervisor world-switch code
41 */
42ENTRY(__kvm_vcpu_run)
43 bx lr
44
45/********************************************************************
46 * Call function in Hyp mode
47 *
48 *
49 * u64 kvm_call_hyp(void *hypfn, ...);
50 *
51 * This is not really a variadic function in the classic C-way and care must
52 * be taken when calling this to ensure parameters are passed in registers
53 * only, since the stack will change between the caller and the callee.
54 *
55 * Call the function with the first argument containing a pointer to the
56 * function you wish to call in Hyp mode, and subsequent arguments will be
57 * passed as r0, r1, and r2 (a maximum of 3 arguments in addition to the
58 * function pointer can be passed). The function being called must be mapped
59 * in Hyp mode (see init_hyp_mode in arch/arm/kvm/arm.c). Return values are
60 * passed in r0 and r1.
61 *
62 * The calling convention follows the standard AAPCS:
63 * r0 - r3: caller save
64 * r12: caller save
65 * rest: callee save
66 */
67ENTRY(kvm_call_hyp)
68 hvc #0
69 bx lr
70
71/********************************************************************
72 * Hypervisor exception vector and handlers
73 */
74
75 .align 5
76__kvm_hyp_vector:
77 .globl __kvm_hyp_vector
78 nop
79
80__kvm_hyp_code_end:
81 .globl __kvm_hyp_code_end
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index 10ed4643269f..4decdb618019 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -15,3 +15,251 @@
15 * along with this program; if not, write to the Free Software 15 * along with this program; if not, write to the Free Software
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
19#include <linux/mman.h>
20#include <linux/kvm_host.h>
21#include <linux/io.h>
22#include <asm/idmap.h>
23#include <asm/pgalloc.h>
24#include <asm/kvm_arm.h>
25#include <asm/kvm_mmu.h>
26#include <asm/mach/map.h>
27
28extern char __hyp_idmap_text_start[], __hyp_idmap_text_end[];
29
30static DEFINE_MUTEX(kvm_hyp_pgd_mutex);
31
32static void kvm_set_pte(pte_t *pte, pte_t new_pte)
33{
34 pte_val(*pte) = new_pte;
35 /*
36 * flush_pmd_entry just takes a void pointer and cleans the necessary
37 * cache entries, so we can reuse the function for ptes.
38 */
39 flush_pmd_entry(pte);
40}
41
42static void free_ptes(pmd_t *pmd, unsigned long addr)
43{
44 pte_t *pte;
45 unsigned int i;
46
47 for (i = 0; i < PTRS_PER_PMD; i++, addr += PMD_SIZE) {
48 if (!pmd_none(*pmd) && pmd_table(*pmd)) {
49 pte = pte_offset_kernel(pmd, addr);
50 pte_free_kernel(NULL, pte);
51 }
52 pmd++;
53 }
54}
55
56/**
57 * free_hyp_pmds - free a Hyp-mode level-2 tables and child level-3 tables
58 *
59 * Assumes this is a page table used strictly in Hyp-mode and therefore contains
60 * only mappings in the kernel memory area, which is above PAGE_OFFSET.
61 */
62void free_hyp_pmds(void)
63{
64 pgd_t *pgd;
65 pud_t *pud;
66 pmd_t *pmd;
67 unsigned long addr;
68
69 mutex_lock(&kvm_hyp_pgd_mutex);
70 for (addr = PAGE_OFFSET; addr != 0; addr += PGDIR_SIZE) {
71 pgd = hyp_pgd + pgd_index(addr);
72 pud = pud_offset(pgd, addr);
73
74 if (pud_none(*pud))
75 continue;
76 BUG_ON(pud_bad(*pud));
77
78 pmd = pmd_offset(pud, addr);
79 free_ptes(pmd, addr);
80 pmd_free(NULL, pmd);
81 pud_clear(pud);
82 }
83 mutex_unlock(&kvm_hyp_pgd_mutex);
84}
85
86static void create_hyp_pte_mappings(pmd_t *pmd, unsigned long start,
87 unsigned long end)
88{
89 pte_t *pte;
90 unsigned long addr;
91 struct page *page;
92
93 for (addr = start & PAGE_MASK; addr < end; addr += PAGE_SIZE) {
94 pte = pte_offset_kernel(pmd, addr);
95 BUG_ON(!virt_addr_valid(addr));
96 page = virt_to_page(addr);
97 kvm_set_pte(pte, mk_pte(page, PAGE_HYP));
98 }
99}
100
101static void create_hyp_io_pte_mappings(pmd_t *pmd, unsigned long start,
102 unsigned long end,
103 unsigned long *pfn_base)
104{
105 pte_t *pte;
106 unsigned long addr;
107
108 for (addr = start & PAGE_MASK; addr < end; addr += PAGE_SIZE) {
109 pte = pte_offset_kernel(pmd, addr);
110 BUG_ON(pfn_valid(*pfn_base));
111 kvm_set_pte(pte, pfn_pte(*pfn_base, PAGE_HYP_DEVICE));
112 (*pfn_base)++;
113 }
114}
115
116static int create_hyp_pmd_mappings(pud_t *pud, unsigned long start,
117 unsigned long end, unsigned long *pfn_base)
118{
119 pmd_t *pmd;
120 pte_t *pte;
121 unsigned long addr, next;
122
123 for (addr = start; addr < end; addr = next) {
124 pmd = pmd_offset(pud, addr);
125
126 BUG_ON(pmd_sect(*pmd));
127
128 if (pmd_none(*pmd)) {
129 pte = pte_alloc_one_kernel(NULL, addr);
130 if (!pte) {
131 kvm_err("Cannot allocate Hyp pte\n");
132 return -ENOMEM;
133 }
134 pmd_populate_kernel(NULL, pmd, pte);
135 }
136
137 next = pmd_addr_end(addr, end);
138
139 /*
140 * If pfn_base is NULL, we map kernel pages into HYP with the
141 * virtual address. Otherwise, this is considered an I/O
142 * mapping and we map the physical region starting at
143 * *pfn_base to [start, end[.
144 */
145 if (!pfn_base)
146 create_hyp_pte_mappings(pmd, addr, next);
147 else
148 create_hyp_io_pte_mappings(pmd, addr, next, pfn_base);
149 }
150
151 return 0;
152}
153
154static int __create_hyp_mappings(void *from, void *to, unsigned long *pfn_base)
155{
156 unsigned long start = (unsigned long)from;
157 unsigned long end = (unsigned long)to;
158 pgd_t *pgd;
159 pud_t *pud;
160 pmd_t *pmd;
161 unsigned long addr, next;
162 int err = 0;
163
164 BUG_ON(start > end);
165 if (start < PAGE_OFFSET)
166 return -EINVAL;
167
168 mutex_lock(&kvm_hyp_pgd_mutex);
169 for (addr = start; addr < end; addr = next) {
170 pgd = hyp_pgd + pgd_index(addr);
171 pud = pud_offset(pgd, addr);
172
173 if (pud_none_or_clear_bad(pud)) {
174 pmd = pmd_alloc_one(NULL, addr);
175 if (!pmd) {
176 kvm_err("Cannot allocate Hyp pmd\n");
177 err = -ENOMEM;
178 goto out;
179 }
180 pud_populate(NULL, pud, pmd);
181 }
182
183 next = pgd_addr_end(addr, end);
184 err = create_hyp_pmd_mappings(pud, addr, next, pfn_base);
185 if (err)
186 goto out;
187 }
188out:
189 mutex_unlock(&kvm_hyp_pgd_mutex);
190 return err;
191}
192
193/**
194 * create_hyp_mappings - map a kernel virtual address range in Hyp mode
195 * @from: The virtual kernel start address of the range
196 * @to: The virtual kernel end address of the range (exclusive)
197 *
198 * The same virtual address as the kernel virtual address is also used in
199 * Hyp-mode mapping to the same underlying physical pages.
200 *
201 * Note: Wrapping around zero in the "to" address is not supported.
202 */
203int create_hyp_mappings(void *from, void *to)
204{
205 return __create_hyp_mappings(from, to, NULL);
206}
207
208/**
209 * create_hyp_io_mappings - map a physical IO range in Hyp mode
210 * @from: The virtual HYP start address of the range
211 * @to: The virtual HYP end address of the range (exclusive)
212 * @addr: The physical start address which gets mapped
213 */
214int create_hyp_io_mappings(void *from, void *to, phys_addr_t addr)
215{
216 unsigned long pfn = __phys_to_pfn(addr);
217 return __create_hyp_mappings(from, to, &pfn);
218}
219
220int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run)
221{
222 return -EINVAL;
223}
224
225phys_addr_t kvm_mmu_get_httbr(void)
226{
227 VM_BUG_ON(!virt_addr_valid(hyp_pgd));
228 return virt_to_phys(hyp_pgd);
229}
230
231int kvm_mmu_init(void)
232{
233 return hyp_pgd ? 0 : -ENOMEM;
234}
235
236/**
237 * kvm_clear_idmap - remove all idmaps from the hyp pgd
238 *
239 * Free the underlying pmds for all pgds in range and clear the pgds (but
240 * don't free them) afterwards.
241 */
242void kvm_clear_hyp_idmap(void)
243{
244 unsigned long addr, end;
245 unsigned long next;
246 pgd_t *pgd = hyp_pgd;
247 pud_t *pud;
248 pmd_t *pmd;
249
250 addr = virt_to_phys(__hyp_idmap_text_start);
251 end = virt_to_phys(__hyp_idmap_text_end);
252
253 pgd += pgd_index(addr);
254 do {
255 next = pgd_addr_end(addr, end);
256 if (pgd_none_or_clear_bad(pgd))
257 continue;
258 pud = pud_offset(pgd, addr);
259 pmd = pmd_offset(pud, addr);
260
261 pud_clear(pud);
262 clean_pmd_entry(pmd);
263 pmd_free(NULL, (pmd_t *)((unsigned long)pmd & PAGE_MASK));
264 } while (pgd++, addr = next, addr < end);
265}