summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--firmware/fw_base.S62
-rw-r--r--firmware/fw_base.ldS13
-rw-r--r--firmware/objects.mk7
-rw-r--r--include/sbi/riscv_elf.h14
5 files changed, 96 insertions, 2 deletions
diff --git a/Makefile b/Makefile
index d6f097d..038cc99 100644
--- a/Makefile
+++ b/Makefile
@@ -210,8 +210,8 @@ CFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)
CFLAGS += -mcmodel=$(PLATFORM_RISCV_CODE_MODEL)
CFLAGS += $(GENFLAGS)
CFLAGS += $(platform-cflags-y)
-CFLAGS += $(firmware-cflags-y)
CFLAGS += -fno-pie -no-pie
+CFLAGS += $(firmware-cflags-y)
CPPFLAGS += $(GENFLAGS)
CPPFLAGS += $(platform-cppflags-y)
diff --git a/firmware/fw_base.S b/firmware/fw_base.S
index 6cc5f88..2ce3851 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>
@@ -67,6 +68,58 @@ _try_lottery:
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)
+ /* t1 shall has the address of _start */
+ 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:
lla t0, _link_start
@@ -137,6 +190,7 @@ _wait_relocate_copy_done:
nop
bgt t4, t5, 1b
jr t3
+#endif
_relocate_done:
/*
@@ -144,12 +198,14 @@ _relocate_done:
* Use _boot_status copy relative to the load address
*/
lla t0, _boot_status
+#ifndef FW_PIC
lla t1, _link_start
REG_L t1, 0(t1)
lla 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 +502,10 @@ _skip_trap_exit_rv32_hyp:
j _start_hang
.align 3
+#ifdef FW_PIC
+_runtime_offset:
+ RISCV_PTR 0
+#endif
_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..0d222da 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/objects.mk b/firmware/objects.mk
index b2ace75..c1f632e 100644
--- a/firmware/objects.mk
+++ b/firmware/objects.mk
@@ -13,6 +13,13 @@ firmware-cflags-y +=
firmware-asflags-y +=
firmware-ldflags-y +=
+ifeq ($(FW_PIC),y)
+firmware-genflags-y += -DFW_PIC
+firmware-asflags-y += -fpic
+firmware-cflags-y += -fPIE -pie
+firmware-ldflags-y += -Wl,--no-dynamic-linker
+endif
+
ifdef FW_TEXT_START
firmware-genflags-y += -DFW_TEXT_START=$(FW_TEXT_START)
endif
diff --git a/include/sbi/riscv_elf.h b/include/sbi/riscv_elf.h
new file mode 100644
index 0000000..3b62c38
--- /dev/null
+++ b/include/sbi/riscv_elf.h
@@ -0,0 +1,14 @@
+#ifndef __RISCV_ELF_H__
+#define __RISCV_ELF_H__
+
+#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)
+
+#endif