1/* 2 * SPDX-License-Identifier: BSD-3-Clause 3 * SPDX-FileCopyrightText: Copyright TF-RMM Contributors. 4 */ 5 6#include <arch.h> 7#include <asm_macros.S> 8#include <xlat_defs.h> 9 10 .globl fixup_gdt_reloc 11 12/* --------------------------------------------------------------------------- 13 * Helper to fixup Global Descriptor table (GDT) and dynamic relocations 14 * (.rela.dyn) at runtime. 15 * 16 * This function is meant to be used when the firmware is compiled with -fpie 17 * and linked with -pie options. We rely on the linker script exporting 18 * appropriate markers for start and end of the section. For Global Offset 19 * Table (GOT), we expect 'rmm_got_start' and 'rmm_got_end' symbols to be 20 * defined. Similarly for *.rela.dyn, we expect rmm_rela_start and rmm_rela_end 21 * to be defined. We also expect `rmm_base` and `rmm_end` symbols to be 22 * defined by the linker script and are 4KB aligned. The RMM should be 23 * statically linked to start at 0x0. 24 * 25 * Clobber list: x0 to x7. 26 * --------------------------------------------------------------------------- 27 */ 28 29/* Relocation codes */ 30#define R_AARCH64_NONE 0 31#define R_AARCH64_RELATIVE 1027 32 33func fixup_gdt_reloc 34 /* Lower Limit for fixup */ 35 mov x0, xzr 36 /* rmm_base and rmm_end are 4KB aligned hence adrp is enough */ 37 adrp x2, rmm_base 38 adrp x1, rmm_end 39 /* Upper Limit for fixup (rmm_end - rmm_base) */ 40 sub x1, x1, x2 41 42 /* 43 * Since RMM will be compiled to start at 0x0, the current 44 * PC relative `rmm_base` loaded in x2 will be the Diff(S) 45 * to be applied to the fixups. 46 */ 47 cbz x2, 4f /* Diff(S) = 0. No relocation needed */ 48 49 adrp x6, rmm_got_start 50 add x6, x6, :lo12:rmm_got_start 51 adrp x7, rmm_got_end 52 add x7, x7, :lo12:rmm_got_end 53 54 /* 55 * GOT is an array of 64_bit addresses which must be fixed up as 56 * new_addr = old_addr + Diff(S). 57 * The new_addr is the address currently the binary is executing from 58 * and old_addr is the address at compile time. 59 */ 601: ldr x3, [x6] 61 /* Skip adding offset if address is < lower limit */ 62 cmp x3, x0 63 b.lo 2f 64 65 /* Skip adding offset if address is > upper limit */ 66 cmp x3, x1 67 b.hi 2f 68 add x3, x3, x2 69 str x3, [x6] 70 712: add x6, x6, #8 72 cmp x6, x7 73 b.lo 1b 74 75 /* Starting dynamic relocations */ 763: adrp x6, rmm_rela_start 77 add x6, x6, :lo12:rmm_rela_start 78 adrp x7, rmm_rela_end 79 add x7, x7, :lo12:rmm_rela_end 80 81 /* 82 * According to ELF-64 specification, the RELA data structure is as 83 * follows: 84 * typedef struct { 85 * Elf64_Addr r_offset; 86 * Elf64_Xword r_info; 87 * Elf64_Sxword r_addend; 88 * } Elf64_Rela; 89 * 90 * r_offset is address of reference 91 * r_info is symbol index and type of relocation (in this case 92 * code 1027 which corresponds to R_AARCH64_RELATIVE). 93 * r_addend is constant part of expression. 94 * 95 * Size of Elf64_Rela structure is 24 bytes. 96 */ 97 981: ldr x3, [x6, #8] /* r_info */ 99 /* Skip R_AARCH64_NONE entry with code 0 */ 100 cbz x3, 2f 101 102#ifndef NDEBUG 103 /* Assert that the relocation type is R_AARCH64_RELATIVE */ 104 cmp x3, #R_AARCH64_RELATIVE 105 ASM_ASSERT eq 106#endif 107 ldr x4, [x6, #16] /* r_addend */ 108 109 /* Skip adding offset if r_addend is < lower limit */ 110 cmp x4, x0 111 b.lo 2f 112 113 /* Skip adding offset if r_addend entry is > upper limit */ 114 cmp x4, x1 115 b.hi 2f 116 117 ldr x3, [x6] /* r_offset */ 118 add x4, x4, x2 /* Diff(S) + r_addend */ 119 str x4, [x3, x2] 120 1212: add x6, x6, #24 122 cmp x6, x7 123 b.lo 1b 124 1254: 126 ret 127endfunc fixup_gdt_reloc 128