diff options
-rw-r--r-- | arch/arm64/include/asm/virt.h | 51 | ||||
-rw-r--r-- | arch/arm64/kernel/head.S | 25 |
2 files changed, 73 insertions, 3 deletions
diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h new file mode 100644 index 000000000000..f28547d9edfa --- /dev/null +++ b/arch/arm64/include/asm/virt.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 ARM Ltd. | ||
3 | * Author: Marc Zyngier <marc.zyngier@arm.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, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #ifndef __ASM__VIRT_H | ||
19 | #define __ASM__VIRT_H | ||
20 | |||
21 | #define BOOT_CPU_MODE_EL2 (0x0e12b007) | ||
22 | |||
23 | #ifndef __ASSEMBLY__ | ||
24 | |||
25 | /* | ||
26 | * __boot_cpu_mode records what mode CPUs were booted in. | ||
27 | * A correctly-implemented bootloader must start all CPUs in the same mode: | ||
28 | * In this case, both 32bit halves of __boot_cpu_mode will contain the | ||
29 | * same value (either 0 if booted in EL1, BOOT_CPU_MODE_EL2 if booted in EL2). | ||
30 | * | ||
31 | * Should the bootloader fail to do this, the two values will be different. | ||
32 | * This allows the kernel to flag an error when the secondaries have come up. | ||
33 | */ | ||
34 | extern u32 __boot_cpu_mode[2]; | ||
35 | |||
36 | /* Reports the availability of HYP mode */ | ||
37 | static inline bool is_hyp_mode_available(void) | ||
38 | { | ||
39 | return (__boot_cpu_mode[0] == BOOT_CPU_MODE_EL2 && | ||
40 | __boot_cpu_mode[1] == BOOT_CPU_MODE_EL2); | ||
41 | } | ||
42 | |||
43 | /* Check if the bootloader has booted CPUs in different modes */ | ||
44 | static inline bool is_hyp_mode_mismatched(void) | ||
45 | { | ||
46 | return __boot_cpu_mode[0] != __boot_cpu_mode[1]; | ||
47 | } | ||
48 | |||
49 | #endif /* __ASSEMBLY__ */ | ||
50 | |||
51 | #endif /* ! __ASM__VIRT_H */ | ||
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index 90dec55b17a2..bc6d991f8c59 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <asm/pgtable-hwdef.h> | 31 | #include <asm/pgtable-hwdef.h> |
32 | #include <asm/pgtable.h> | 32 | #include <asm/pgtable.h> |
33 | #include <asm/page.h> | 33 | #include <asm/page.h> |
34 | #include <asm/virt.h> | ||
34 | 35 | ||
35 | /* | 36 | /* |
36 | * swapper_pg_dir is the virtual address of the initial page table. We place | 37 | * swapper_pg_dir is the virtual address of the initial page table. We place |
@@ -115,13 +116,13 @@ | |||
115 | 116 | ||
116 | ENTRY(stext) | 117 | ENTRY(stext) |
117 | mov x21, x0 // x21=FDT | 118 | mov x21, x0 // x21=FDT |
119 | bl __calc_phys_offset // x24=PHYS_OFFSET, x28=PHYS_OFFSET-PAGE_OFFSET | ||
118 | bl el2_setup // Drop to EL1 | 120 | bl el2_setup // Drop to EL1 |
119 | mrs x22, midr_el1 // x22=cpuid | 121 | mrs x22, midr_el1 // x22=cpuid |
120 | mov x0, x22 | 122 | mov x0, x22 |
121 | bl lookup_processor_type | 123 | bl lookup_processor_type |
122 | mov x23, x0 // x23=current cpu_table | 124 | mov x23, x0 // x23=current cpu_table |
123 | cbz x23, __error_p // invalid processor (x23=0)? | 125 | cbz x23, __error_p // invalid processor (x23=0)? |
124 | bl __calc_phys_offset // x24=PHYS_OFFSET, x28=PHYS_OFFSET-PAGE_OFFSET | ||
125 | bl __vet_fdt | 126 | bl __vet_fdt |
126 | bl __create_page_tables // x25=TTBR0, x26=TTBR1 | 127 | bl __create_page_tables // x25=TTBR0, x26=TTBR1 |
127 | /* | 128 | /* |
@@ -147,11 +148,16 @@ ENTRY(el2_setup) | |||
147 | mrs x0, CurrentEL | 148 | mrs x0, CurrentEL |
148 | cmp x0, #PSR_MODE_EL2t | 149 | cmp x0, #PSR_MODE_EL2t |
149 | ccmp x0, #PSR_MODE_EL2h, #0x4, ne | 150 | ccmp x0, #PSR_MODE_EL2h, #0x4, ne |
151 | ldr x0, =__boot_cpu_mode // Compute __boot_cpu_mode | ||
152 | add x0, x0, x28 | ||
150 | b.eq 1f | 153 | b.eq 1f |
154 | str wzr, [x0] // Remember we don't have EL2... | ||
151 | ret | 155 | ret |
152 | 156 | ||
153 | /* Hyp configuration. */ | 157 | /* Hyp configuration. */ |
154 | 1: mov x0, #(1 << 31) // 64-bit EL1 | 158 | 1: ldr w1, =BOOT_CPU_MODE_EL2 |
159 | str w1, [x0, #4] // This CPU has EL2 | ||
160 | mov x0, #(1 << 31) // 64-bit EL1 | ||
155 | msr hcr_el2, x0 | 161 | msr hcr_el2, x0 |
156 | 162 | ||
157 | /* Generic timers. */ | 163 | /* Generic timers. */ |
@@ -187,6 +193,19 @@ ENTRY(el2_setup) | |||
187 | eret | 193 | eret |
188 | ENDPROC(el2_setup) | 194 | ENDPROC(el2_setup) |
189 | 195 | ||
196 | /* | ||
197 | * We need to find out the CPU boot mode long after boot, so we need to | ||
198 | * store it in a writable variable. | ||
199 | * | ||
200 | * This is not in .bss, because we set it sufficiently early that the boot-time | ||
201 | * zeroing of .bss would clobber it. | ||
202 | */ | ||
203 | .pushsection .data | ||
204 | ENTRY(__boot_cpu_mode) | ||
205 | .long BOOT_CPU_MODE_EL2 | ||
206 | .long 0 | ||
207 | .popsection | ||
208 | |||
190 | .align 3 | 209 | .align 3 |
191 | 2: .quad . | 210 | 2: .quad . |
192 | .quad PAGE_OFFSET | 211 | .quad PAGE_OFFSET |
@@ -202,6 +221,7 @@ ENDPROC(el2_setup) | |||
202 | * cores are held until we're ready for them to initialise. | 221 | * cores are held until we're ready for them to initialise. |
203 | */ | 222 | */ |
204 | ENTRY(secondary_holding_pen) | 223 | ENTRY(secondary_holding_pen) |
224 | bl __calc_phys_offset // x24=phys offset | ||
205 | bl el2_setup // Drop to EL1 | 225 | bl el2_setup // Drop to EL1 |
206 | mrs x0, mpidr_el1 | 226 | mrs x0, mpidr_el1 |
207 | and x0, x0, #15 // CPU number | 227 | and x0, x0, #15 // CPU number |
@@ -227,7 +247,6 @@ ENTRY(secondary_startup) | |||
227 | mov x23, x0 // x23=current cpu_table | 247 | mov x23, x0 // x23=current cpu_table |
228 | cbz x23, __error_p // invalid processor (x23=0)? | 248 | cbz x23, __error_p // invalid processor (x23=0)? |
229 | 249 | ||
230 | bl __calc_phys_offset // x24=phys offset | ||
231 | pgtbl x25, x26, x24 // x25=TTBR0, x26=TTBR1 | 250 | pgtbl x25, x26, x24 // x25=TTBR0, x26=TTBR1 |
232 | ldr x12, [x23, #CPU_INFO_SETUP] | 251 | ldr x12, [x23, #CPU_INFO_SETUP] |
233 | add x12, x12, x28 // __virt_to_phys | 252 | add x12, x12, x28 // __virt_to_phys |