Simplify EFI handover to decompressor
The EFI stub in the ARM kernel runs in the context of the firmware, which means it usually runs with the caches and MMU on. Currently, we relocate the zImage so it appears in the first 128 MiB, disable the MMU and caches and invoke the decompressor via its ordinary entry point. However, since we can pass the base of DRAM directly, there is no need to relocate the zImage, which also means there is no need to disable and re-enable the caches and create new page tables etc. This also allows systems whose DRAM start address is not a round multiple of 128 MB to decompress the kernel proper to the base of memory, ensuring that all memory is usable at runtime. -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEnNKg2mrY9zMBdeK7wjcgfpV0+n0FAl7FbMMACgkQwjcgfpV0 +n15TAgAmWgczY35HCM4Hosv8c7N1xG3HAo5Dn/M6I0twTtAYki33Nb2UgX771sq tkk8eetDCOtDmfGP0ZED/n2EstXIRcpmCl2cqPdZjX/0XrSpUEyyuTZ+jGoaL6Tb l8joWq9cr9aCDd0jIKLdwFhusk+dXJWyyoXguFZnIkwMsTauBeNCwMbuUgTyOFro 6R5iF9CFnWl+yNheNQe/F2QKbsCdExW22gBaR2z3sMCeuJKSviy9nwJZGafmm/+S ySKhFnzREdAdTfk9BEzOm4J3kZFrSOn5YxEOAde/zYB1kcPg/+t0xFdIEu2C0iQp ruTaJmq0YLSr7psZm3CMmMe0P2lBiw== =2BnA -----END PGP SIGNATURE----- Merge tag 'efi-arm-no-relocate-for-rmk' of git://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux into misc Simplify EFI handover to decompressor The EFI stub in the ARM kernel runs in the context of the firmware, which means it usually runs with the caches and MMU on. Currently, we relocate the zImage so it appears in the first 128 MiB, disable the MMU and caches and invoke the decompressor via its ordinary entry point. However, since we can pass the base of DRAM directly, there is no need to relocate the zImage, which also means there is no need to disable and re-enable the caches and create new page tables etc. This also allows systems whose DRAM start address is not a round multiple of 128 MB to decompress the kernel proper to the base of memory, ensuring that all memory is usable at runtime.
This commit is contained in:
commit
fce2bc254a
@ -287,28 +287,22 @@ not_angel:
|
|||||||
*/
|
*/
|
||||||
mov r0, pc
|
mov r0, pc
|
||||||
cmp r0, r4
|
cmp r0, r4
|
||||||
ldrcc r0, LC0+28
|
ldrcc r0, .Lheadroom
|
||||||
addcc r0, r0, pc
|
addcc r0, r0, pc
|
||||||
cmpcc r4, r0
|
cmpcc r4, r0
|
||||||
orrcc r4, r4, #1 @ remember we skipped cache_on
|
orrcc r4, r4, #1 @ remember we skipped cache_on
|
||||||
blcs cache_on
|
blcs cache_on
|
||||||
|
|
||||||
restart: adr r0, LC0
|
restart: adr r0, LC1
|
||||||
ldmia r0, {r1, r2, r3, r6, r11, r12}
|
ldr sp, [r0]
|
||||||
ldr sp, [r0, #24]
|
ldr r6, [r0, #4]
|
||||||
|
add sp, sp, r0
|
||||||
/*
|
add r6, r6, r0
|
||||||
* We might be running at a different address. We need
|
|
||||||
* to fix up various pointers.
|
|
||||||
*/
|
|
||||||
sub r0, r0, r1 @ calculate the delta offset
|
|
||||||
add r6, r6, r0 @ _edata
|
|
||||||
|
|
||||||
get_inflated_image_size r9, r10, lr
|
get_inflated_image_size r9, r10, lr
|
||||||
|
|
||||||
#ifndef CONFIG_ZBOOT_ROM
|
#ifndef CONFIG_ZBOOT_ROM
|
||||||
/* malloc space is above the relocated stack (64k max) */
|
/* malloc space is above the relocated stack (64k max) */
|
||||||
add sp, sp, r0
|
|
||||||
add r10, sp, #0x10000
|
add r10, sp, #0x10000
|
||||||
#else
|
#else
|
||||||
/*
|
/*
|
||||||
@ -322,9 +316,6 @@ restart: adr r0, LC0
|
|||||||
mov r5, #0 @ init dtb size to 0
|
mov r5, #0 @ init dtb size to 0
|
||||||
#ifdef CONFIG_ARM_APPENDED_DTB
|
#ifdef CONFIG_ARM_APPENDED_DTB
|
||||||
/*
|
/*
|
||||||
* r0 = delta
|
|
||||||
* r2 = BSS start
|
|
||||||
* r3 = BSS end
|
|
||||||
* r4 = final kernel address (possibly with LSB set)
|
* r4 = final kernel address (possibly with LSB set)
|
||||||
* r5 = appended dtb size (still unknown)
|
* r5 = appended dtb size (still unknown)
|
||||||
* r6 = _edata
|
* r6 = _edata
|
||||||
@ -332,8 +323,6 @@ restart: adr r0, LC0
|
|||||||
* r8 = atags/device tree pointer
|
* r8 = atags/device tree pointer
|
||||||
* r9 = size of decompressed image
|
* r9 = size of decompressed image
|
||||||
* r10 = end of this image, including bss/stack/malloc space if non XIP
|
* r10 = end of this image, including bss/stack/malloc space if non XIP
|
||||||
* r11 = GOT start
|
|
||||||
* r12 = GOT end
|
|
||||||
* sp = stack pointer
|
* sp = stack pointer
|
||||||
*
|
*
|
||||||
* if there are device trees (dtb) appended to zImage, advance r10 so that the
|
* if there are device trees (dtb) appended to zImage, advance r10 so that the
|
||||||
@ -381,7 +370,6 @@ restart: adr r0, LC0
|
|||||||
/* temporarily relocate the stack past the DTB work space */
|
/* temporarily relocate the stack past the DTB work space */
|
||||||
add sp, sp, r5
|
add sp, sp, r5
|
||||||
|
|
||||||
stmfd sp!, {r0-r3, ip, lr}
|
|
||||||
mov r0, r8
|
mov r0, r8
|
||||||
mov r1, r6
|
mov r1, r6
|
||||||
mov r2, r5
|
mov r2, r5
|
||||||
@ -400,7 +388,6 @@ restart: adr r0, LC0
|
|||||||
mov r2, r5
|
mov r2, r5
|
||||||
bleq atags_to_fdt
|
bleq atags_to_fdt
|
||||||
|
|
||||||
ldmfd sp!, {r0-r3, ip, lr}
|
|
||||||
sub sp, sp, r5
|
sub sp, sp, r5
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -537,6 +524,10 @@ dtb_check_done:
|
|||||||
mov pc, r0
|
mov pc, r0
|
||||||
|
|
||||||
wont_overwrite:
|
wont_overwrite:
|
||||||
|
adr r0, LC0
|
||||||
|
ldmia r0, {r1, r2, r3, r11, r12}
|
||||||
|
sub r0, r0, r1 @ calculate the delta offset
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If delta is zero, we are running at the address we were linked at.
|
* If delta is zero, we are running at the address we were linked at.
|
||||||
* r0 = delta
|
* r0 = delta
|
||||||
@ -660,13 +651,18 @@ not_relocated: mov r0, #0
|
|||||||
LC0: .word LC0 @ r1
|
LC0: .word LC0 @ r1
|
||||||
.word __bss_start @ r2
|
.word __bss_start @ r2
|
||||||
.word _end @ r3
|
.word _end @ r3
|
||||||
.word _edata @ r6
|
|
||||||
.word _got_start @ r11
|
.word _got_start @ r11
|
||||||
.word _got_end @ ip
|
.word _got_end @ ip
|
||||||
.word .L_user_stack_end @ sp
|
|
||||||
.word _end - restart + 16384 + 1024*1024
|
|
||||||
.size LC0, . - LC0
|
.size LC0, . - LC0
|
||||||
|
|
||||||
|
.type LC1, #object
|
||||||
|
LC1: .word .L_user_stack_end - LC1 @ sp
|
||||||
|
.word _edata - LC1 @ r6
|
||||||
|
.size LC1, . - LC1
|
||||||
|
|
||||||
|
.Lheadroom:
|
||||||
|
.word _end - restart + 16384 + 1024*1024
|
||||||
|
|
||||||
.Linflated_image_size_offset:
|
.Linflated_image_size_offset:
|
||||||
.long (input_data_end - 4) - .
|
.long (input_data_end - 4) - .
|
||||||
|
|
||||||
@ -1434,37 +1430,26 @@ reloc_code_end:
|
|||||||
|
|
||||||
#ifdef CONFIG_EFI_STUB
|
#ifdef CONFIG_EFI_STUB
|
||||||
ENTRY(efi_enter_kernel)
|
ENTRY(efi_enter_kernel)
|
||||||
mov r7, r0 @ preserve image base
|
mov r4, r0 @ preserve image base
|
||||||
mov r4, r1 @ preserve DT pointer
|
mov r8, r1 @ preserve DT pointer
|
||||||
|
|
||||||
mov r0, r4 @ DT start
|
mrc p15, 0, r0, c1, c0, 0 @ read SCTLR
|
||||||
add r1, r4, r2 @ DT end
|
tst r0, #0x1 @ MMU enabled?
|
||||||
|
orreq r4, r4, #1 @ set LSB if not
|
||||||
|
|
||||||
|
mov r0, r8 @ DT start
|
||||||
|
add r1, r8, r2 @ DT end
|
||||||
bl cache_clean_flush
|
bl cache_clean_flush
|
||||||
|
|
||||||
mov r0, r7 @ relocated zImage
|
adr r0, 0f @ switch to our stack
|
||||||
ldr r1, =_edata @ size of zImage
|
ldr sp, [r0]
|
||||||
add r1, r1, r0 @ end of zImage
|
add sp, sp, r0
|
||||||
bl cache_clean_flush
|
|
||||||
|
|
||||||
@ The PE/COFF loader might not have cleaned the code we are
|
mov r5, #0 @ appended DTB size
|
||||||
@ running beyond the PoU, and so calling cache_off below from
|
mov r7, #0xFFFFFFFF @ machine ID
|
||||||
@ inside the PE/COFF loader allocated region is unsafe unless
|
b wont_overwrite
|
||||||
@ we explicitly clean it to the PoC.
|
|
||||||
adr r0, call_cache_fn @ region of code we will
|
|
||||||
adr r1, 0f @ run with MMU off
|
|
||||||
bl cache_clean_flush
|
|
||||||
bl cache_off
|
|
||||||
|
|
||||||
@ Set parameters for booting zImage according to boot protocol
|
|
||||||
@ put FDT address in r2, it was returned by efi_entry()
|
|
||||||
@ r1 is the machine type, and r0 needs to be 0
|
|
||||||
mov r0, #0
|
|
||||||
mov r1, #0xFFFFFFFF
|
|
||||||
mov r2, r4
|
|
||||||
add r7, r7, #(__efi_start - start)
|
|
||||||
mov pc, r7 @ no mode switch
|
|
||||||
ENDPROC(efi_enter_kernel)
|
ENDPROC(efi_enter_kernel)
|
||||||
0:
|
0: .long .L_user_stack_end - .
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
.align
|
.align
|
||||||
|
@ -63,9 +63,11 @@ SECTIONS
|
|||||||
_etext = .;
|
_etext = .;
|
||||||
|
|
||||||
.got.plt : { *(.got.plt) }
|
.got.plt : { *(.got.plt) }
|
||||||
|
#ifndef CONFIG_EFI_STUB
|
||||||
_got_start = .;
|
_got_start = .;
|
||||||
.got : { *(.got) }
|
.got : { *(.got) }
|
||||||
_got_end = .;
|
_got_end = .;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* ensure the zImage file size is always a multiple of 64 bits */
|
/* ensure the zImage file size is always a multiple of 64 bits */
|
||||||
/* (without a dummy byte, ld just ignores the empty section) */
|
/* (without a dummy byte, ld just ignores the empty section) */
|
||||||
@ -74,6 +76,9 @@ SECTIONS
|
|||||||
#ifdef CONFIG_EFI_STUB
|
#ifdef CONFIG_EFI_STUB
|
||||||
.data : ALIGN(4096) {
|
.data : ALIGN(4096) {
|
||||||
__pecoff_data_start = .;
|
__pecoff_data_start = .;
|
||||||
|
_got_start = .;
|
||||||
|
*(.got)
|
||||||
|
_got_end = .;
|
||||||
/*
|
/*
|
||||||
* The EFI stub always executes from RAM, and runs strictly before the
|
* The EFI stub always executes from RAM, and runs strictly before the
|
||||||
* decompressor, so we can make an exception for its r/w data, and keep it
|
* decompressor, so we can make an exception for its r/w data, and keep it
|
||||||
|
@ -199,14 +199,8 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
|
|||||||
unsigned long kernel_base;
|
unsigned long kernel_base;
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
|
|
||||||
/*
|
/* use a 16 MiB aligned base for the decompressed kernel */
|
||||||
* Verify that the DRAM base address is compatible with the ARM
|
kernel_base = round_up(dram_base, SZ_16M) + TEXT_OFFSET;
|
||||||
* boot protocol, which determines the base of DRAM by masking
|
|
||||||
* off the low 27 bits of the address at which the zImage is
|
|
||||||
* loaded. These assumptions are made by the decompressor,
|
|
||||||
* before any memory map is available.
|
|
||||||
*/
|
|
||||||
kernel_base = round_up(dram_base, SZ_128M);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note that some platforms (notably, the Raspberry Pi 2) put
|
* Note that some platforms (notably, the Raspberry Pi 2) put
|
||||||
@ -215,41 +209,14 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
|
|||||||
* base of the kernel image is only partially used at the moment.
|
* base of the kernel image is only partially used at the moment.
|
||||||
* (Up to 5 pages are used for the swapper page tables)
|
* (Up to 5 pages are used for the swapper page tables)
|
||||||
*/
|
*/
|
||||||
kernel_base += TEXT_OFFSET - 5 * PAGE_SIZE;
|
status = reserve_kernel_base(kernel_base - 5 * PAGE_SIZE, reserve_addr,
|
||||||
|
reserve_size);
|
||||||
status = reserve_kernel_base(kernel_base, reserve_addr, reserve_size);
|
|
||||||
if (status != EFI_SUCCESS) {
|
if (status != EFI_SUCCESS) {
|
||||||
pr_efi_err("Unable to allocate memory for uncompressed kernel.\n");
|
pr_efi_err("Unable to allocate memory for uncompressed kernel.\n");
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
*image_addr = kernel_base;
|
||||||
* Relocate the zImage, so that it appears in the lowest 128 MB
|
*image_size = 0;
|
||||||
* memory window.
|
|
||||||
*/
|
|
||||||
*image_addr = (unsigned long)image->image_base;
|
|
||||||
*image_size = image->image_size;
|
|
||||||
status = efi_relocate_kernel(image_addr, *image_size, *image_size,
|
|
||||||
kernel_base + MAX_UNCOMP_KERNEL_SIZE, 0, 0);
|
|
||||||
if (status != EFI_SUCCESS) {
|
|
||||||
pr_efi_err("Failed to relocate kernel.\n");
|
|
||||||
efi_free(*reserve_size, *reserve_addr);
|
|
||||||
*reserve_size = 0;
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check to see if we were able to allocate memory low enough
|
|
||||||
* in memory. The kernel determines the base of DRAM from the
|
|
||||||
* address at which the zImage is loaded.
|
|
||||||
*/
|
|
||||||
if (*image_addr + *image_size > dram_base + ZIMAGE_OFFSET_LIMIT) {
|
|
||||||
pr_efi_err("Failed to relocate kernel, no low memory available.\n");
|
|
||||||
efi_free(*reserve_size, *reserve_addr);
|
|
||||||
*reserve_size = 0;
|
|
||||||
efi_free(*image_size, *image_addr);
|
|
||||||
*image_size = 0;
|
|
||||||
return EFI_LOAD_ERROR;
|
|
||||||
}
|
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user