Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: zImage/virt: hyp mode entry support for the zImage loader

The zImage loader needs to turn on the MMU in order to take
advantage of caching while decompressing the zImage. Running this
in hyp mode would require the LPAE pagetable format to be
supported; to avoid this complexity, this patch switches out of hyp
mode, and returns back to hyp mode just before booting the kernel.

This implementation assumes that the Hyp mode view of memory and the
PL1 view of memory are coherent, providing that the MMU and caches
are off in both, as required by the boot protocol. The zImage
decompression code must drain the write buffer on completion anyway, and
entry into Hyp mode should flush any prefetch buffer, avoiding hazards
associated with local write buffers and the pipeline.

Signed-off-by: Dave Martin <dave.martin@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

authored by

Dave Martin and committed by
Marc Zyngier
424e5994 80c59daf

+91 -8
+1
arch/arm/boot/compressed/.gitignore
··· 1 1 ashldi3.S 2 2 font.c 3 3 lib1funcs.S 4 + hyp-stub.S 4 5 piggy.gzip 5 6 piggy.lzo 6 7 piggy.lzma
+8 -1
arch/arm/boot/compressed/Makefile
··· 30 30 OBJS += string.o 31 31 CFLAGS_string.o := -Os 32 32 33 + ifeq ($(CONFIG_ARM_VIRT_EXT),y) 34 + OBJS += hyp-stub.o 35 + endif 36 + 33 37 # 34 38 # Architecture dependencies 35 39 # ··· 130 126 endif 131 127 132 128 ccflags-y := -fpic -fno-builtin -I$(obj) 133 - asflags-y := -Wa,-march=all 129 + asflags-y := -Wa,-march=all -DZIMAGE 134 130 135 131 # Supply kernel BSS size to the decompressor via a linker symbol. 136 132 KBSS_SZ = $(shell $(CROSS_COMPILE)size $(obj)/../../../../vmlinux | \ ··· 202 198 203 199 $(obj)/vmlinux.lds: $(obj)/vmlinux.lds.in arch/arm/boot/Makefile $(KCONFIG_CONFIG) 204 200 @sed "$(SEDFLAGS)" < $< > $@ 201 + 202 + $(obj)/hyp-stub.S: $(srctree)/arch/$(SRCARCH)/kernel/hyp-stub.S 203 + $(call cmd,shipped)
+64 -7
arch/arm/boot/compressed/head.S
··· 9 9 * published by the Free Software Foundation. 10 10 */ 11 11 #include <linux/linkage.h> 12 + #include <asm/assembler.h> 12 13 13 14 /* 14 15 * Debugging stuff ··· 133 132 .word start @ absolute load/run zImage address 134 133 .word _edata @ zImage end address 135 134 THUMB( .thumb ) 136 - 1: mov r7, r1 @ save architecture ID 135 + 1: 136 + mrs r9, cpsr 137 + #ifdef CONFIG_ARM_VIRT_EXT 138 + bl __hyp_stub_install @ get into SVC mode, reversibly 139 + #endif 140 + mov r7, r1 @ save architecture ID 137 141 mov r8, r2 @ save atags pointer 138 142 139 143 #ifndef __ARM_ARCH_2__ ··· 154 148 ARM( swi 0x123456 ) @ angel_SWI_ARM 155 149 THUMB( svc 0xab ) @ angel_SWI_THUMB 156 150 not_angel: 157 - mrs r2, cpsr @ turn off interrupts to 158 - orr r2, r2, #0xc0 @ prevent angel from running 159 - msr cpsr_c, r2 151 + safe_svcmode_maskall r0 152 + msr spsr_cxsf, r9 @ Save the CPU boot mode in 153 + @ SPSR 160 154 #else 161 155 teqp pc, #0x0c000003 @ turn off interrupts 162 156 #endif ··· 356 350 adr r5, restart 357 351 bic r5, r5, #31 358 352 353 + /* Relocate the hyp vector base if necessary */ 354 + #ifdef CONFIG_ARM_VIRT_EXT 355 + mrs r0, spsr 356 + and r0, r0, #MODE_MASK 357 + cmp r0, #HYP_MODE 358 + bne 1f 359 + 360 + bl __hyp_get_vectors 361 + sub r0, r0, r5 362 + add r0, r0, r10 363 + bl __hyp_set_vectors 364 + 1: 365 + #endif 366 + 359 367 sub r9, r6, r5 @ size to copy 360 368 add r9, r9, #31 @ rounded up to a multiple 361 369 bic r9, r9, #31 @ ... of 32 bytes ··· 478 458 bl decompress_kernel 479 459 bl cache_clean_flush 480 460 bl cache_off 481 - mov r0, #0 @ must be zero 482 461 mov r1, r7 @ restore architecture number 483 462 mov r2, r8 @ restore atags pointer 484 - ARM( mov pc, r4 ) @ call kernel 485 - THUMB( bx r4 ) @ entry point is always ARM 463 + 464 + #ifdef CONFIG_ARM_VIRT_EXT 465 + mrs r0, spsr @ Get saved CPU boot mode 466 + and r0, r0, #MODE_MASK 467 + cmp r0, #HYP_MODE @ if not booted in HYP mode... 468 + bne __enter_kernel @ boot kernel directly 469 + 470 + adr r12, .L__hyp_reentry_vectors_offset 471 + ldr r0, [r12] 472 + add r0, r0, r12 473 + 474 + bl __hyp_set_vectors 475 + __HVC(0) @ otherwise bounce to hyp mode 476 + 477 + b . @ should never be reached 478 + 479 + .align 2 480 + .L__hyp_reentry_vectors_offset: .long __hyp_reentry_vectors - . 481 + #else 482 + b __enter_kernel 483 + #endif 486 484 487 485 .align 2 488 486 .type LC0, #object ··· 1229 1191 #endif 1230 1192 1231 1193 .ltorg 1194 + 1195 + #ifdef CONFIG_ARM_VIRT_EXT 1196 + .align 5 1197 + __hyp_reentry_vectors: 1198 + W(b) . @ reset 1199 + W(b) . @ undef 1200 + W(b) . @ svc 1201 + W(b) . @ pabort 1202 + W(b) . @ dabort 1203 + W(b) __enter_kernel @ hyp 1204 + W(b) . @ irq 1205 + W(b) . @ fiq 1206 + #endif /* CONFIG_ARM_VIRT_EXT */ 1207 + 1208 + __enter_kernel: 1209 + mov r0, #0 @ must be 0 1210 + ARM( mov pc, r4 ) @ call kernel 1211 + THUMB( bx r4 ) @ entry point is always ARM 1212 + 1232 1213 reloc_code_end: 1233 1214 1234 1215 .align
+18
arch/arm/kernel/hyp-stub.S
··· 21 21 #include <asm/assembler.h> 22 22 #include <asm/virt.h> 23 23 24 + #ifndef ZIMAGE 24 25 /* 25 26 * For the kernel proper, we need to find out the CPU boot mode long after 26 27 * boot, so we need to store it in a writable variable. ··· 59 58 orrne r7, r7, #BOOT_CPU_MODE_MISMATCH 60 59 strne r7, [r5, r6] @ record what happened and give up 61 60 .endm 61 + 62 + #else /* ZIMAGE */ 63 + 64 + .macro store_primary_cpu_mode reg1:req, reg2:req, reg3:req 65 + .endm 66 + 67 + /* 68 + * The zImage loader only runs on one CPU, so we don't bother with mult-CPU 69 + * consistency checking: 70 + */ 71 + .macro compare_cpu_mode_with_primary mode, reg1, reg2, reg3 72 + cmp \mode, \mode 73 + .endm 74 + 75 + #endif /* ZIMAGE */ 62 76 63 77 /* 64 78 * Hypervisor stub installation functions. ··· 190 174 bx lr 191 175 ENDPROC(__hyp_set_vectors) 192 176 177 + #ifndef ZIMAGE 193 178 .align 2 194 179 .L__boot_cpu_mode_offset: 195 180 .long __boot_cpu_mode - . 181 + #endif 196 182 197 183 .align 5 198 184 __hyp_stub_vectors: