[PATCH 1/3] firmware: Support position independent execution
Vincent Chen
vincent.chen at sifive.com
Tue Mar 2 15:25:50 GMT 2021
Enable OpenSBI to support position independent execution. Because the
position independent code will cause an additional GOT reference when
accessing the global variables, it will reduce performance a bit. Therefore,
the position independent execution is disabled by default. Users can
through specifying "FW_PIC=y" on the make command to enable this feature.
In theory, after enabling position-independent execution, the OpenSBI
can run at arbitrary address with appropriate alignment. Therefore, the
original relocation mechanism will be skipped. In other words, OpenSBI will
directly run at the load address without any code movement.
Signed-off-by: Vincent Chen <vincent.chen at sifive.com>
---
Makefile | 10 +++++++
firmware/fw_base.S | 70 +++++++++++++++++++++++++++++++++++++++++++++----
firmware/fw_base.ldS | 13 +++++++++
firmware/fw_jump.S | 10 +++++++
firmware/fw_payload.S | 6 +++++
include/sbi/riscv_elf.h | 9 +++++++
6 files changed, 113 insertions(+), 5 deletions(-)
create mode 100644 include/sbi/riscv_elf.h
diff --git a/Makefile b/Makefile
index d6f097d..0bebdf3 100644
--- a/Makefile
+++ b/Makefile
@@ -202,6 +202,9 @@ endif
GENFLAGS += $(libsbiutils-genflags-y)
GENFLAGS += $(platform-genflags-y)
GENFLAGS += $(firmware-genflags-y)
+ifeq ($(FW_PIC),y)
+GENFLAGS += -DFW_PIC
+endif
CFLAGS = -g -Wall -Werror -ffreestanding -nostdlib -fno-strict-aliasing -O2
CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
@@ -211,7 +214,11 @@ CFLAGS += -mcmodel=$(PLATFORM_RISCV_CODE_MODEL)
CFLAGS += $(GENFLAGS)
CFLAGS += $(platform-cflags-y)
CFLAGS += $(firmware-cflags-y)
+ifeq ($(FW_PIC),y)
+CFLAGS += -fPIE -pie
+else
CFLAGS += -fno-pie -no-pie
+endif
CPPFLAGS += $(GENFLAGS)
CPPFLAGS += $(platform-cppflags-y)
@@ -231,6 +238,9 @@ ARFLAGS = rcs
ELFFLAGS += -Wl,--build-id=none -N -static-libgcc -lgcc
ELFFLAGS += $(platform-ldflags-y)
ELFFLAGS += $(firmware-ldflags-y)
+ifeq ($(FW_PIC),y)
+ELFFLAGS += -Wl,--no-dynamic-linker
+endif
MERGEFLAGS += -r
MERGEFLAGS += -b elf$(PLATFORM_RISCV_XLEN)-littleriscv
diff --git a/firmware/fw_base.S b/firmware/fw_base.S
index ab33e11..8f8e5dc 100644
--- a/firmware/fw_base.S
+++ b/firmware/fw_base.S
@@ -9,6 +9,7 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
+#include <sbi/riscv_elf.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_trap.h>
@@ -41,6 +42,9 @@
999:
.endm
+#ifdef FW_PIC
+ .option pic
+#endif
.section .entry, "ax", %progbits
.align 3
.globl _start
@@ -48,7 +52,7 @@
_start:
/* Find preferred boot HART id */
MOV_3R s0, a0, s1, a1, s2, a2
- call fw_boot_hart
+ lla t0, _start_hang
add a6, a0, zero
MOV_3R a0, s0, a1, s1, a2, s2
li a7, -1
@@ -57,16 +61,67 @@ _start:
bne a0, a6, _wait_relocate_copy_done
_try_lottery:
/* Jump to relocation wait loop if we don't get relocation lottery */
- la a6, _relocate_lottery
+ lla a6, _relocate_lottery
li a7, 1
amoadd.w a6, a7, (a6)
bnez a6, _wait_relocate_copy_done
/* Save load address */
- la t0, _load_start
- la t1, _start
+ lla t0, _load_start
+ lla t1, _start
REG_S t1, 0(t0)
+#ifdef FW_PIC
+ /* relocate the global table content */
+ lla t0, _link_start
+ REG_L t0, 0(t0)
+ sub t2, t1, t0
+ lla t3, _runtime_offset
+ REG_S t2, (t3)
+ lla t0, __rel_dyn_start
+ lla t1, __rel_dyn_end
+ beq t0, t1, _relocate_done
+ j 5f
+2:
+ REG_L t5, -(REGBYTES*2)(t0) /* t5 <-- relocation info:type */
+ li t3, R_RISCV_RELATIVE /* reloc type R_RISCV_RELATIVE */
+ bne t5, t3, 3f
+ REG_L t3, -(REGBYTES*3)(t0)
+ REG_L t5, -(REGBYTES)(t0) /* t5 <-- addend */
+ add t5, t5, t2
+ add t3, t3, t2
+ REG_S t5, 0(t3) /* store runtime address to the GOT entry */
+ j 5f
+
+3:
+ lla t4, __dyn_sym_start
+
+4:
+ REG_L t5, -(REGBYTES*2)(t0) /* t5 <-- relocation info:type */
+ srli t6, t5, SYM_INDEX /* t6 <--- sym table index */
+ andi t5, t5, 0xFF /* t5 <--- relocation type */
+ li t3, RELOC_TYPE
+ bne t5, t3, 5f
+
+ /* address R_RISCV_64 or R_RISCV_32 cases*/
+ REG_L t3, -(REGBYTES*3)(t0)
+ li t5, SYM_SIZE
+ mul t6, t6, t5
+ add s5, t4, t6
+ REG_L t6, -(REGBYTES)(t0) /* t0 <-- addend */
+ REG_L t5, REGBYTES(s5)
+ add t5, t5, t6
+ add t5, t5, t2 /* t5 <-- location to fix up in RAM */
+ add t3, t3, t2 /* t3 <-- location to fix up in RAM */
+ REG_S t5, 0(t3) /* store runtime address to the variable */
+
+5:
+ addi t0, t0, (REGBYTES*3)
+ ble t0, t1, 2b
+ j _relocate_done
+_wait_relocate_copy_done:
+ j _wait_for_boot_hart
+#else
/* Relocate if load address != link address */
_relocate:
la t0, _link_start
@@ -137,6 +192,7 @@ _wait_relocate_copy_done:
nop
bgt t4, t5, 1b
jr t3
+#endif
_relocate_done:
/*
@@ -144,12 +200,14 @@ _relocate_done:
* Use _boot_status copy relative to the load address
*/
la t0, _boot_status
+#ifndef FW_PIC
la t1, _link_start
REG_L t1, 0(t1)
la t2, _load_start
REG_L t2, 0(t2)
sub t0, t0, t1
add t0, t0, t2
+#endif
li t1, BOOT_STATUS_RELOCATE_DONE
REG_S t1, 0(t0)
fence rw, rw
@@ -446,6 +504,8 @@ _skip_trap_exit_rv32_hyp:
j _start_hang
.align 3
+_runtime_offset:
+ RISCV_PTR 0
_relocate_lottery:
RISCV_PTR 0
_boot_status:
@@ -453,7 +513,7 @@ _boot_status:
_load_start:
RISCV_PTR _fw_start
_link_start:
- RISCV_PTR _fw_start
+ RISCV_PTR FW_TEXT_START
_link_end:
RISCV_PTR _fw_reloc_end
diff --git a/firmware/fw_base.ldS b/firmware/fw_base.ldS
index 0ac75f2..3904959 100644
--- a/firmware/fw_base.ldS
+++ b/firmware/fw_base.ldS
@@ -61,6 +61,19 @@
PROVIDE(_data_end = .);
}
+ .dynsym : {
+ PROVIDE(__dyn_sym_start = .);
+ *(.dynsym)
+ PROVIDE(__dyn_sym_end = .);
+ }
+
+ .rela.dyn : {
+ PROVIDE(__rel_dyn_start = .);
+ *(.rela*)
+ . = ALIGN(8);
+ PROVIDE(__rel_dyn_end = .);
+ }
+
. = ALIGN(0x1000); /* Ensure next section is page aligned */
.bss :
diff --git a/firmware/fw_jump.S b/firmware/fw_jump.S
index 8553f8c..3cce3f7 100644
--- a/firmware/fw_jump.S
+++ b/firmware/fw_jump.S
@@ -46,6 +46,11 @@ fw_save_info:
fw_next_arg1:
#ifdef FW_JUMP_FDT_ADDR
li a0, FW_JUMP_FDT_ADDR
+#ifdef FW_PIC
+ la a1, _runtime_offset
+ REG_L a1, (a1)
+ add a0, a0, a1
+#endif
#else
add a0, a1, zero
#endif
@@ -61,6 +66,11 @@ fw_next_arg1:
fw_next_addr:
la a0, _jump_addr
REG_L a0, (a0)
+#ifdef FW_PIC
+ la a1, _runtime_offset
+ REG_L a1, (a1)
+ add a0, a0, a1
+#endif
ret
.section .entry, "ax", %progbits
diff --git a/firmware/fw_payload.S b/firmware/fw_payload.S
index 1ef121e..18b51d0 100644
--- a/firmware/fw_payload.S
+++ b/firmware/fw_payload.S
@@ -46,6 +46,12 @@ fw_save_info:
fw_next_arg1:
#ifdef FW_PAYLOAD_FDT_ADDR
li a0, FW_PAYLOAD_FDT_ADDR
+#ifdef FW_PIC
+ la a1, _runtime_offset
+ REG_L a1, (a1)
+ add a0, a0, a1
+#endif
+
#else
add a0, a1, zero
#endif
diff --git a/include/sbi/riscv_elf.h b/include/sbi/riscv_elf.h
new file mode 100644
index 0000000..cf211ac
--- /dev/null
+++ b/include/sbi/riscv_elf.h
@@ -0,0 +1,9 @@
+#include <sbi/riscv_asm.h>
+
+#define R_RISCV_32 1
+#define R_RISCV_64 2
+#define R_RISCV_RELATIVE 3
+
+#define RELOC_TYPE __REG_SEL(R_RISCV_64, R_RISCV_32)
+#define SYM_INDEX __REG_SEL(0x20, 0x8)
+#define SYM_SIZE __REG_SEL(0x18,0x10)
--
2.7.4
More information about the opensbi
mailing list