xref: /DragonBoot/src/arch/riscv64/relocate.rs (revision 1971aeeee1b8252821527c319e1327d93b88ffc4)
1 use core::{ffi::c_void, hint::spin_loop, ptr};
2 
3 #[derive(Debug, Clone, PartialEq, Eq)]
4 struct Dyn {
5     pub d_tag: i64,
6     pub(super) d_un: u64,
7 }
8 
9 impl Dyn {
d_val(&self) -> u6410     pub fn d_val(&self) -> u64 {
11         self.d_un
12     }
13 
d_ptr(&self) -> u6414     pub fn d_ptr(&self) -> u64 {
15         self.d_un
16     }
17 }
18 
19 #[no_mangle]
efi_relocate(ldbase: u64, elf_dyn: *mut c_void) -> usize20 unsafe extern "C" fn efi_relocate(ldbase: u64, elf_dyn: *mut c_void) -> usize {
21     let elf_dyn = elf_dyn as *mut Dyn;
22     return do_relocate(ldbase, elf_dyn).0 as usize;
23 }
24 
do_relocate(ldbase: u64, elf_dyn: *mut Dyn) -> uefi::Status25 unsafe fn do_relocate(ldbase: u64, elf_dyn: *mut Dyn) -> uefi::Status {
26     let mut relsz = 0;
27     let mut relent = 0;
28     let mut rel: *mut elf::relocation::Elf64_Rela = ptr::null_mut();
29 
30     let mut item = elf_dyn;
31 
32     while (*item).d_tag != elf::abi::DT_NULL {
33         match (*item).d_tag {
34             elf::abi::DT_RELA => {
35                 rel = (*item).d_ptr() as *mut elf::relocation::Elf64_Rela;
36             }
37             elf::abi::DT_RELASZ => {
38                 relsz = (*item).d_val();
39             }
40             elf::abi::DT_RELAENT => {
41                 relent = (*item).d_val();
42             }
43             _ => {}
44         }
45         item = (item as usize + core::mem::size_of::<Dyn>()) as *mut Dyn;
46     }
47 
48     if rel.is_null() && (relent == 0) {
49         return uefi::Status::SUCCESS;
50     }
51 
52     if rel.is_null() || relent == 0 {
53         return uefi::Status::LOAD_ERROR;
54     }
55 
56     while relsz > 0 {
57         match ((*rel).r_info & 0xFF) as u32 {
58             elf::abi::R_RISCV_RELATIVE => {
59                 let addr = ldbase + (*rel).r_offset as u64;
60                 let sym_addr = ldbase + (*rel).r_addend as u64;
61                 let addr_ptr = addr as *mut u64;
62                 *addr_ptr = sym_addr;
63             }
64             _ => {
65                 /* Panic */
66                 loop {
67                     spin_loop();
68                 }
69             }
70         }
71         rel = (rel as usize + relent as usize) as *mut elf::relocation::Elf64_Rela;
72         relsz -= relent;
73     }
74 
75     return uefi::Status::SUCCESS;
76 }
77