aarch64: introduce early relocation of the bootloader

All newer exynos devices with s-boot have the "feature" of placing the
android kernel at a random location in dram, specifically around
0x80000000 and 0x83000000. This made it hard to assume where we are at,
hence why we made everything as PiE (position-independent) as possible.

This, however, resulted in a lot of issues. I usually managed to get
around them with ugly hacks, but in the last 5-6 commits, with the
fixed support for armv7, everything fell apart for arm64.

So, the solution for this is to implement code at the beginning
of the bootloader that relocates it to a safe place in memory.
This is currently enabled for dreamlte, and it must be enabled
and configured for all other boards with that issue. Otherwise they
will NOT boot anymore. Boards that don't need this can keep
CONFIG_POSITION_INDEPENDENT disabled.
This commit is contained in:
Ivaylo Ivanov
2025-07-10 15:48:37 +03:00
parent 2ebd7ac7a5
commit c6b486f0ed
9 changed files with 95 additions and 20 deletions

View File

@@ -4,6 +4,8 @@
#
mainmenu "uniLoader Configuration"
source "arch/Kconfig"
menu "Building options"
config CROSS_COMPILE
string "Cross-compiler tool prefix"

View File

@@ -373,7 +373,8 @@ all: arch/$(ARCH)/linker.lds uniLoader
# Generate linker script from template
quiet_cmd_cpp_lds = LDS $@
cmd_cpp_lds = $(CPP) $< -DTEXT_BASE=$(TEXT_BASE) \
cmd_cpp_lds = $(CPP) -include include/generated/autoconf.h $< \
-DTEXT_BASE=$(TEXT_BASE) \
-DKERNEL_PATH=$(KERNEL_PATH) \
-DDTB_PATH=$(DT_PATH) \
-DRAMDISK_PATH=$(RAMDISK_PATH) \

7
arch/Kconfig Normal file
View File

@@ -0,0 +1,7 @@
menu "Architecture"
config POSITION_INDEPENDENT
bool "Code relocation during early boot"
help
Say Y if your previous bootloader loads uniLoader at an unknown
or different address every time.
endmenu

View File

@@ -2,4 +2,5 @@
#
# Copyright (c) 2025 Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>
obj-$(CONFIG_POSITION_INDEPENDENT) += aarch64/reloc.o
obj-y += aarch64/start.o aarch64/memcpy.o

View File

@@ -2,8 +2,14 @@
/*
* Copyright (c) 2022, Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>
*/
ENTRY(
#ifdef CONFIG_POSITION_INDEPENDENT
_head
#else
_start
#endif
);
ENTRY(_start);
OUTPUT_FORMAT("elf64-littleaarch64")
OUTPUT_ARCH(aarch64)
@@ -15,12 +21,31 @@ INPUT(RAMDISK_PATH)
SECTIONS
{
. = TEXT_BASE;
.text : {
KEEP(*(.text.start))
#ifdef CONFIG_POSITION_INDEPENDENT
_reloc_start = .;
#endif
*(.text)
*(.text.*)
}
.kernel ALIGN(4096) : {
kernel = .;
KERNEL_PATH
}
.dtb ALIGN(4096) : {
dtb = .;
DTB_PATH
}
.ramdisk ALIGN(4096) : {
ramdisk = .;
RAMDISK_PATH
}
.rodata ALIGN(4) : {
*(.rodata)
*(.rodata.*)
@@ -42,23 +67,14 @@ SECTIONS
.stack ALIGN(4096) : {
. = . + 4096;
_stack_end = .;
}
.dtb ALIGN(4096) : {
dtb = .;
DTB_PATH
}
.kernel ALIGN(4096) : {
kernel = .;
KERNEL_PATH
}
.ramdisk ALIGN(4096) : {
ramdisk = .;
RAMDISK_PATH
#ifdef CONFIG_POSITION_INDEPENDENT
_reloc_end = .;
#endif
}
kernel_size = SIZEOF(.kernel);
ramdisk_size = SIZEOF(.ramdisk);
#ifdef CONFIG_POSITION_INDEPENDENT
_reloc_size = _reloc_end - _reloc_start;
#endif
}

46
arch/aarch64/reloc.S Normal file
View File

@@ -0,0 +1,46 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2025, Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>
*/
#include "asmdefs.h"
.extern _reloc_size
.extern _start
ENTRY_ALIAS(_head)
adr x1, _relocated_uni
b _reloc_entry
ENTRY_ALIAS(_rel_stack_base)
.quad _start
ENTRY_ALIAS(_rel_stack_size)
.quad _reloc_size
.quad 0
.quad 0
.quad 0
.quad 0
.ascii "ARM\x64"
.long 0
ENTRY_ALIAS( _reloc_entry)
adr x4, _start
ldr x5, _rel_stack_base
cmp x4, x5
beq _entry
ldr x6, _rel_stack_size
_copy:
ldp x2, x3, [x4], #16
stp x2, x3, [x5], #16
subs x6, x6, #16
b.ne _copy
ldr x5, _rel_stack_base
_entry:
br x5
_dead: /* we should never get here */
b _dead
ENTRY_ALIAS(_relocated_uni)

View File

@@ -27,3 +27,4 @@ END(_start)
ENTRY(load_kernel_and_jump)
br x4
END(load_kernel_and_jump)

View File

@@ -1,7 +1,9 @@
CONFIG_POSITION_INDEPENDENT=y
CONFIG_EXYNOS_8895=y
CONFIG_SAMSUNG_DREAMLTE=y
CONFIG_TEXT_BASE=0x87000000
CONFIG_PAYLOAD_ENTRY=0x90000000
CONFIG_RAMDISK_ENTRY=0x82000000
CONFIG_RAMDISK_ENTRY=0x84000000
CONFIG_FRAMEBUFFER_BASE=0xcc000000
CONFIG_FRAMEBUFFER_WIDTH=1440
CONFIG_FRAMEBUFFER_HEIGHT=2960

View File

@@ -44,7 +44,6 @@ void main(void* dt, void* kernel, void* ramdisk)
/* Copy kernel to memory and boot */
printk(-1, "booting linux...\n");
#ifdef __aarch64__
memcpy((void*)CONFIG_PAYLOAD_ENTRY, kernel, (unsigned long) &kernel_size);
__optimized_memcpy((void*)CONFIG_RAMDISK_ENTRY, ramdisk, (unsigned long) &ramdisk_size);