From 7981c1d1c79e88293d3651c57abc5260875c7432 Mon Sep 17 00:00:00 2001 From: Sam Roberts Date: Tue, 17 Mar 2026 15:37:26 -0400 Subject: [PATCH] arm64: Add runtime_loader support + TLS Change-Id: Ic462c6b08e6949039457e6141c83468e6a6a6964 Reviewed-on: https://review.haiku-os.org/c/haiku/+/10604 Tested-by: Commit checker robot Reviewed-by: waddlesplash --- headers/private/kernel/arch/arm64/arch_cpu.h | 1 + headers/private/system/arch/arm64/arch_elf.h | 4 +- src/system/kernel/arch/arm64/arch_asm.S | 12 ++- src/system/kernel/arch/arm64/arch_thread.cpp | 11 +-- src/system/kernel/arch/arm64/asm_offsets.cpp | 1 + src/system/libroot/os/arch/arm64/tls.c | 2 +- .../arch/arm64/arch_relocate.cpp | 82 ++++++++++++++++++- 7 files changed, 95 insertions(+), 18 deletions(-) diff --git a/headers/private/kernel/arch/arm64/arch_cpu.h b/headers/private/kernel/arch/arm64/arch_cpu.h index cfbc3b5416..475f3ecf18 100644 --- a/headers/private/kernel/arch/arm64/arch_cpu.h +++ b/headers/private/kernel/arch/arm64/arch_cpu.h @@ -136,6 +136,7 @@ struct iframe { uint64 fp; uint64 lr; uint64 sp; + uint64 tpidr; // exception info uint64 esr; diff --git a/headers/private/system/arch/arm64/arch_elf.h b/headers/private/system/arch/arm64/arch_elf.h index 6dca3dbb6e..490270879b 100644 --- a/headers/private/system/arch/arm64/arch_elf.h +++ b/headers/private/system/arch/arm64/arch_elf.h @@ -20,8 +20,8 @@ #define R_AARCH64_GLOB_DAT 1025 /* Set GOT entry to data address */ #define R_AARCH64_JUMP_SLOT 1026 /* Set GOT entry to code address */ #define R_AARCH64_RELATIVE 1027 /* Add load address of shared object */ -#define R_AARCH64_TLS_DTPREL64 1028 /* Module-relative offset, 64 bit. */ -#define R_AARCH64_TLS_DTPMOD64 1029 /* Module number, 64 bit. */ +#define R_AARCH64_TLS_DTPMOD64 1028 /* Module number, 64 bit. */ +#define R_AARCH64_TLS_DTPREL64 1029 /* Module-relative offset, 64 bit. */ #define R_AARCH64_TLS_TPREL64 1030 /* TP-relative offset, 64 bit. */ #define R_AARCH64_TLSDESC 1031 /* Identify the TLS descriptor */ #define R_AARCH64_IRELATIVE 1032 /* STT_GNU_IFUNC relocation. */ diff --git a/src/system/kernel/arch/arm64/arch_asm.S b/src/system/kernel/arch/arm64/arch_asm.S index 74ff183951..8a5e20aaa1 100644 --- a/src/system/kernel/arch/arm64/arch_asm.S +++ b/src/system/kernel/arch/arm64/arch_asm.S @@ -58,12 +58,14 @@ sub sp, sp, \xt mrs x2, SPSR_EL1 mrs x3, ESR_EL1 mrs x4, FAR_EL1 + mrs x5, TPIDR_EL0 str x0, [x19, #(IFRAME_sp)] str x1, [x19, #(IFRAME_elr)] str x2, [x19, #(IFRAME_spsr)] str x3, [x19, #(IFRAME_esr)] str x4, [x19, #(IFRAME_far)] + str x5, [x19, #(IFRAME_tpidr)] .endm .macro EXCEPTION_RETURN el @@ -108,6 +110,9 @@ sub sp, sp, \xt mov sp, x18 .endif + ldr x0, [x19, #(IFRAME_tpidr)] + msr TPIDR_EL0, x0 + // finally restore remaining registers ldp x0, x1, [x19, #(IFRAME_x + 0 * 8)] ldp x18, x19, [x19, #(IFRAME_x + 18 * 8)] @@ -192,6 +197,7 @@ FUNCTION(_eret_with_iframe): EXCEPTION_RETURN 0 FUNCTION_END(_eret_with_iframe) + FUNCTION(_fp_save): stp q0, q1, [x0], #32 stp q2, q3, [x0], #32 @@ -264,8 +270,7 @@ FUNCTION(_arch_context_swap): stp x29, x30, [x0], #16 mov x2, sp - mrs x3, TPIDR_EL0 - stp x2, x3, [x0], #16 + str x2, [x0], #8 stp d8, d9, [x0], #16 stp d10, d11, [x0], #16 @@ -280,9 +285,8 @@ FUNCTION(_arch_context_swap): ldp x27, x28, [x1], #16 ldp x29, x30, [x1], #16 - ldp x2, x3, [x1], #16 + ldr x2, [x1], #8 mov sp, x2 - msr TPIDR_EL0, x3 ldp d8, d9, [x1], #16 ldp d10, d11, [x1], #16 diff --git a/src/system/kernel/arch/arm64/arch_thread.cpp b/src/system/kernel/arch/arm64/arch_thread.cpp index a7f152e7ae..66b7b54e99 100644 --- a/src/system/kernel/arch/arm64/arch_thread.cpp +++ b/src/system/kernel/arch/arm64/arch_thread.cpp @@ -84,13 +84,6 @@ arch_thread_init_tls(Thread *thread) return B_OK; } - -static void -arm64_set_tls_context(Thread *thread) -{ - WRITE_SPECIALREG(tpidrro_el0, thread->user_local_storage); -} - extern "C" void _arch_context_swap(arch_thread *from, arch_thread *to); @@ -98,7 +91,6 @@ void arch_thread_context_switch(Thread *from, Thread *to) { arch_vm_aspace_swap(from->team->address_space, to->team->address_space); - arm64_set_tls_context(to); _arch_context_swap(&from->arch_info, &to->arch_info); } @@ -116,8 +108,6 @@ status_t arch_thread_enter_userspace(Thread *thread, addr_t entry, void *arg1, void *arg2) { - arm64_set_tls_context(thread); - addr_t threadExitAddr; { addr_t commpageAdr = (addr_t)thread->team->commpage_address; @@ -137,6 +127,7 @@ arch_thread_enter_userspace(Thread *thread, addr_t entry, frame.x[1] = (uint64_t)arg2; frame.lr = threadExitAddr; frame.sp = thread->user_stack_base + thread->user_stack_size; + frame.tpidr = thread->user_local_storage; _eret_with_iframe(&frame); return B_ERROR; diff --git a/src/system/kernel/arch/arm64/asm_offsets.cpp b/src/system/kernel/arch/arm64/asm_offsets.cpp index 00247fb953..c820c8676c 100644 --- a/src/system/kernel/arch/arm64/asm_offsets.cpp +++ b/src/system/kernel/arch/arm64/asm_offsets.cpp @@ -40,6 +40,7 @@ dummy() DEFINE_OFFSET_MACRO(IFRAME, iframe, fp); DEFINE_OFFSET_MACRO(IFRAME, iframe, esr); DEFINE_OFFSET_MACRO(IFRAME, iframe, far); + DEFINE_OFFSET_MACRO(IFRAME, iframe, tpidr); DEFINE_OFFSET_MACRO(CPU_ENT, cpu_ent, fault_handler); DEFINE_OFFSET_MACRO(CPU_ENT, cpu_ent, fault_handler_stack_pointer); diff --git a/src/system/libroot/os/arch/arm64/tls.c b/src/system/libroot/os/arch/arm64/tls.c index 48869294ca..bee367c8c4 100644 --- a/src/system/libroot/os/arch/arm64/tls.c +++ b/src/system/libroot/os/arch/arm64/tls.c @@ -24,7 +24,7 @@ static inline void** get_tls() { void **tls; - asm volatile("MRS %0, tpidrro_el0" : "=r" (tls)); + asm volatile("MRS %0, tpidr_el0" : "=r" (tls)); return tls; } diff --git a/src/system/runtime_loader/arch/arm64/arch_relocate.cpp b/src/system/runtime_loader/arch/arm64/arch_relocate.cpp index 13968f0db2..24fd7bbd84 100644 --- a/src/system/runtime_loader/arch/arm64/arch_relocate.cpp +++ b/src/system/runtime_loader/arch/arm64/arch_relocate.cpp @@ -7,6 +7,7 @@ #include #include +#include "arch_elf.h" #include "runtime_loader_private.h" #include @@ -20,10 +21,89 @@ #endif +static status_t +relocate_rela(image_t* rootImage, image_t* image, Elf64_Rela* rel, + size_t relLength, SymbolLookupCache* cache) +{ + for (size_t i = 0; i < relLength / sizeof(Elf64_Rela); i++) { + int type = ELF64_R_TYPE(rel[i].r_info); + int symIndex = ELF64_R_SYM(rel[i].r_info); + Elf64_Addr symAddr = 0; + image_t* symbolImage = NULL; + + // Resolve the symbol, if any. + if (symIndex != 0) { + Elf64_Sym* sym = SYMBOL(image, symIndex); + + status_t status = resolve_symbol(rootImage, image, sym, cache, + &symAddr, &symbolImage); + if (status != B_OK) { + TRACE(("resolve symbol \"%s\" returned: %" B_PRId32 "\n", + SYMNAME(image, sym), status)); + printf("resolve symbol \"%s\" returned: %" B_PRId32 "\n", + SYMNAME(image, sym), status); + return status; + } + } + + // Address of the relocation. + Elf64_Addr relocAddr = image->regions[0].delta + rel[i].r_offset; + + // Calculate the relocation value. + Elf64_Addr relocValue; + switch (type) { + case R_AARCH64_NONE: + continue; + case R_AARCH64_ABS64: + case R_AARCH64_GLOB_DAT: + case R_AARCH64_JUMP_SLOT: + relocValue = symAddr + rel[i].r_addend; + break; + case R_AARCH64_RELATIVE: + relocValue = image->regions[0].delta + rel[i].r_addend; + break; + case R_AARCH64_TLS_DTPMOD64: + relocValue = symbolImage == NULL + ? image->dso_tls_id : symbolImage->dso_tls_id; + break; + case R_AARCH64_TLS_DTPREL64: + relocValue = symAddr; + break; + default: + TRACE(("unhandled relocation type %d\n", type)); + return B_BAD_DATA; + } + + *(Elf64_Addr *)relocAddr = relocValue; + } + + return B_OK; +} + + status_t arch_relocate_image(image_t *rootImage, image_t *image, SymbolLookupCache* cache) { - debugger("arch_relocate_image: Not Yet Implemented!"); + status_t status; + + // No REL on arm64. + + // Perform RELA relocations. + if (image->rela) { + status = relocate_rela(rootImage, image, image->rela, image->rela_len, + cache); + if (status != B_OK) + return status; + } + + // PLT relocations (they are RELA on arm64). + if (image->pltrel) { + status = relocate_rela(rootImage, image, (Elf64_Rela*)image->pltrel, + image->pltrel_len, cache); + if (status != B_OK) + return status; + } + return B_OK; }