aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm64/include/asm/virt.h51
-rw-r--r--arch/arm64/kernel/head.S25
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 */
34extern u32 __boot_cpu_mode[2];
35
36/* Reports the availability of HYP mode */
37static 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 */
44static 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
116ENTRY(stext) 117ENTRY(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. */
1541: mov x0, #(1 << 31) // 64-bit EL1 1581: 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
188ENDPROC(el2_setup) 194ENDPROC(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
204ENTRY(__boot_cpu_mode)
205 .long BOOT_CPU_MODE_EL2
206 .long 0
207 .popsection
208
190 .align 3 209 .align 3
1912: .quad . 2102: .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 */
204ENTRY(secondary_holding_pen) 223ENTRY(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