hv: risc-v: add relocation support

This patch implements relocation support for ACRN RISC-V to enable
position-independent execution. The hypervisor can now be loaded at any
physical address and will automatically relocate itself at runtime. Key
changes:
- Add relocate() function to process R_RISCV_RELATIVE relocations in
  .rela sections during early boot
- Implement arch_get_hv_image_delta() to calculate the load address offset
  from the configured base address
- Add relocation processing in cpu_entry.S before jumping to C code
- Update linker script to include .rela sections for relocation data
- Define R_RISCV_RELATIVE relocation type and linker symbol definitions

Tracked-On: #8825
Signed-off-by: Jian Jun Chen <jian.jun.chen@intel.com>
Acked-by: Wang, Yu1 <yu1.wang@intel.com>
This commit is contained in:
Jian Jun Chen
2025-09-30 08:55:04 +08:00
committed by acrnsi-robot
parent f904dbffbb
commit 1dee977429
6 changed files with 121 additions and 2 deletions

View File

@@ -42,6 +42,7 @@ HOST_S_SRCS += arch/riscv/intr.S
HOST_S_SRCS += arch/riscv/sched.S
# HV host C sources
HOST_C_SRCS += arch/riscv/boot/reloc.c
HOST_C_SRCS += arch/riscv/init.c
HOST_C_SRCS += arch/riscv/sbi.c
HOST_C_SRCS += arch/riscv/notify.c

View File

@@ -38,6 +38,15 @@ _clear_bss:
/* Setup cpu0 boot stack (full descending) */
lla sp, _boot_stack_end
#ifdef CONFIG_RELOC
mv s1, a0
lla a0, _DYNAMIC
/* Fix up the .rela sections */
call relocate
mv a0, s1
#endif /* CONFIG_RELOC */
/* a0 = hart_id, a1 = dtb_address */
tail init_primary_pcpu

View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2025 Intel Corporation.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <types.h>
#include <reloc.h>
/* get the delta between CONFIG_HV_RAM_START and the actual load address */
uint64_t arch_get_hv_image_delta(void)
{
uint64_t delta;
asm volatile (
"lla %0, _start\n"
"li t1, %1\n"
"sub %0, %0, t1\n"
: "=r" (delta)
: "i" ((uint64_t)CONFIG_HV_RAM_START)
: "t1");
return delta;
}
#ifdef CONFIG_RELOC
void relocate(struct Elf64_Dyn *dynamic)
{
struct Elf64_Dyn *dyn;
struct Elf64_Rel *entry = NULL;
uint8_t *rela_start = NULL, *rela_end = NULL;
uint64_t rela_size = 0;
uint64_t delta, entry_size = 0;
uint64_t *addr;
/* get the delta that needs to be patched */
delta = get_hv_image_delta();
/* Look for the descriptoin of relocation sections */
for (dyn = (struct Elf64_Dyn *)dynamic;
dyn->d_tag != DT_NULL; dyn++) {
switch (dyn->d_tag) {
case DT_RELA:
rela_start = (uint8_t *)(dyn->d_ptr + delta);
break;
case DT_RELASZ:
rela_size = dyn->d_ptr;
break;
case DT_RELAENT:
entry_size = dyn->d_ptr;
break;
default:
/* if no RELA/RELASZ found, both start and end will be
* initialized to NULL, and later while loop won't be executed
*/
break;
}
}
/*
* Need to subtract the relocation delta to get the correct
* absolute addresses
*/
rela_end = rela_start + rela_size;
while (rela_start < rela_end) {
entry = (struct Elf64_Rel *)rela_start;
if ((elf64_r_type(entry->r_info)) == R_RISCV_RELATIVE) {
addr = (uint64_t *)(delta + entry->r_offset);
*addr += (entry->r_addend + delta);
}
rela_start += entry_size;
}
}
#endif /* CONFIG_RELOC */

View File

@@ -10,7 +10,7 @@ ENTRY(_start)
SECTIONS
{
. = CONFIG_HV_RAM_START;
_code_start = .;
ld_ram_start = .;
.text :
{
@@ -39,6 +39,14 @@ SECTIONS
_rodata_end = .;
}
. = ALIGN(0x1000);
.rela :
{
*(.rela)
*(.rela.*)
*(.dyn*)
}
. = ALIGN(0x1000);
.data :
{
@@ -80,5 +88,5 @@ SECTIONS
}
. = ALIGN(0x1000);
_code_end = .;
ld_ram_end = .;
}

View File

@@ -188,4 +188,7 @@ static inline uint64_t elf64_r_type(uint64_t i)
/* x86-64 relocation types */
#define R_X86_64_RELATIVE 8U
/* RISC-V relocation types */
#define R_RISCV_RELATIVE 3U
#endif /* !ELF_H */

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2025 Intel Corporation.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef LD_SYM_H
#define LD_SYM_H
extern const char _text_start;
extern const char _text_end;
extern const char _rodata_start;
extern const char _rodata_end;
extern char _data_start;
extern char _data_end;
extern char _bss_start;
extern char _bss_end;
extern char ld_ram_start;
extern char ld_ram_end;
#endif /* LD_SYM_H */