1823f0493SLoGin #include "elf.h"
22604d783SLoGin #include "dragonstub/linux-efi.h"
3823f0493SLoGin #include "dragonstub/linux/align.h"
42604d783SLoGin #include "dragonstub/printk.h"
57fc3806dSLoGin #include "dragonstub/riscv64.h"
62604d783SLoGin #include "dragonstub/types.h"
72604d783SLoGin #include "efidef.h"
8823f0493SLoGin #include <efi.h>
9823f0493SLoGin #include <efiapi.h>
102604d783SLoGin #include <efidevp.h>
11823f0493SLoGin #include <efilib.h>
12823f0493SLoGin #include <dragonstub/dragonstub.h>
13823f0493SLoGin #include <dragonstub/elfloader.h>
14823f0493SLoGin
15823f0493SLoGin /// @brief 校验ELF文件头
16823f0493SLoGin /// @param buf 缓冲区
17823f0493SLoGin /// @param bufsize 缓冲区大小
18823f0493SLoGin /// @return
verify_ident(const void * buf,u64 bufsize)19823f0493SLoGin static bool verify_ident(const void *buf, u64 bufsize)
20823f0493SLoGin {
21823f0493SLoGin if (bufsize < EI_NIDENT) {
22823f0493SLoGin // 太短,不是ELF
23823f0493SLoGin return false;
24823f0493SLoGin }
25823f0493SLoGin // 检查magic number
26823f0493SLoGin for (int i = 0; i < EI_CLASS; i++) {
27823f0493SLoGin u8 c = *(u8 *)(buf + i);
28823f0493SLoGin if (c != ELFMAG[i]) {
29823f0493SLoGin // 不是ELF magic number,跳过
30823f0493SLoGin efi_err("ELF magic number not match\n");
31823f0493SLoGin return false;
32823f0493SLoGin }
33823f0493SLoGin }
34823f0493SLoGin
35823f0493SLoGin // verify ELF Version
36823f0493SLoGin u8 version = *(u8 *)(buf + EI_VERSION);
37823f0493SLoGin if (version != EV_CURRENT) {
38823f0493SLoGin efi_err("ELF version not match, expected EV_CURRENT(%d), got %d\n",
39823f0493SLoGin EV_CURRENT, version);
40823f0493SLoGin // 不是当前版本,跳过
41823f0493SLoGin return false;
42823f0493SLoGin }
43823f0493SLoGin
44823f0493SLoGin // verify ELF Class
45823f0493SLoGin u8 class = *(u8 *)(buf + EI_CLASS);
46823f0493SLoGin if (class != ELFCLASS64) {
47823f0493SLoGin efi_err("ELF class not match, expected ELFCLASS64(%d), got %d\n",
48823f0493SLoGin ELFCLASS64, class);
49823f0493SLoGin // 不是64位,跳过
50823f0493SLoGin return false;
51823f0493SLoGin }
52823f0493SLoGin
53823f0493SLoGin return true;
54823f0493SLoGin }
55823f0493SLoGin
elf_check(const void * payload_start,u64 payload_size)56823f0493SLoGin bool elf_check(const void *payload_start, u64 payload_size)
57823f0493SLoGin {
58823f0493SLoGin // 校验ELF文件头
59823f0493SLoGin if (!verify_ident(payload_start, payload_size)) {
60823f0493SLoGin return false;
61823f0493SLoGin }
62823f0493SLoGin // 检查架构
63823f0493SLoGin Elf64_Ehdr *ehdr = (Elf64_Ehdr *)payload_start;
64823f0493SLoGin #ifdef CONFIG_riscv64
65823f0493SLoGin if (ehdr->e_machine != EM_RISCV) {
66823f0493SLoGin efi_err("ELF machine not match, expected EM_RISCV(%d), got %d\n",
67823f0493SLoGin EM_RISCV, ehdr->e_machine);
68823f0493SLoGin return false;
69823f0493SLoGin }
70823f0493SLoGin #else
71823f0493SLoGin // 还没有对当前架构进行检查,抛出编译错误
72823f0493SLoGin #error "Unimplement ELF arch test for current cross compile arch"
73823f0493SLoGin #endif
74823f0493SLoGin return true;
75823f0493SLoGin }
76823f0493SLoGin
77823f0493SLoGin /// @brief 获取ELF文件头
78823f0493SLoGin /// @param payload_start 文件起始地址
79823f0493SLoGin /// @param payload_size 文件大小
80823f0493SLoGin /// @param ehdr 返回的ELF文件头
81823f0493SLoGin /// @return
elf_get_header(const void * payload_start,u64 payload_size,Elf64_Ehdr ** ehdr)82823f0493SLoGin efi_status_t elf_get_header(const void *payload_start, u64 payload_size,
83823f0493SLoGin Elf64_Ehdr **ehdr)
84823f0493SLoGin {
85823f0493SLoGin if (!verify_ident(payload_start, payload_size)) {
86823f0493SLoGin return EFI_INVALID_PARAMETER;
87823f0493SLoGin }
88823f0493SLoGin *ehdr = (Elf64_Ehdr *)payload_start;
89823f0493SLoGin return EFI_SUCCESS;
90823f0493SLoGin }
91823f0493SLoGin
print_elf_info(Elf64_Ehdr * ehdr)92823f0493SLoGin static void print_elf_info(Elf64_Ehdr *ehdr)
93823f0493SLoGin {
94823f0493SLoGin efi_info("ELF header:\n");
95823f0493SLoGin efi_printk(" e_type: %d\n", ehdr->e_type);
96823f0493SLoGin efi_printk(" e_machine: %d\n", ehdr->e_machine);
97823f0493SLoGin efi_printk(" e_version: %d\n", ehdr->e_version);
98823f0493SLoGin efi_printk(" e_entry: %p\n", ehdr->e_entry);
99823f0493SLoGin efi_printk(" e_phoff: %p\n", ehdr->e_phoff);
100823f0493SLoGin efi_printk(" e_shoff: %p\n", ehdr->e_shoff);
101823f0493SLoGin efi_printk(" e_flags: %d\n", ehdr->e_flags);
102823f0493SLoGin efi_printk(" e_ehsize: %d\n", ehdr->e_ehsize);
103823f0493SLoGin efi_printk(" e_phentsize: %d\n", ehdr->e_phentsize);
104823f0493SLoGin efi_printk(" e_phnum: %d\n", ehdr->e_phnum);
105823f0493SLoGin efi_printk(" e_shentsize: %d\n", ehdr->e_shentsize);
106823f0493SLoGin efi_printk(" e_shnum: %d\n", ehdr->e_shnum);
107823f0493SLoGin efi_printk(" e_shstrndx: %d\n", ehdr->e_shstrndx);
108823f0493SLoGin }
109823f0493SLoGin
parse_phdrs(const void * payload_start,u64 payload_size,const Elf64_Ehdr * ehdr,u32 * ret_segments_nr,Elf64_Phdr ** ret_phdr)110823f0493SLoGin static efi_status_t parse_phdrs(const void *payload_start, u64 payload_size,
111823f0493SLoGin const Elf64_Ehdr *ehdr, u32 *ret_segments_nr,
112823f0493SLoGin Elf64_Phdr **ret_phdr)
113823f0493SLoGin {
114823f0493SLoGin if (ehdr->e_phnum == 0) {
115823f0493SLoGin efi_err("No program header\n");
116823f0493SLoGin return EFI_INVALID_PARAMETER;
117823f0493SLoGin }
118823f0493SLoGin if (ehdr->e_phentsize != sizeof(Elf64_Phdr)) {
119823f0493SLoGin efi_err("Invalid program header size: %d, expected %d\n",
120823f0493SLoGin ehdr->e_phentsize, sizeof(Elf64_Phdr));
121823f0493SLoGin return EFI_INVALID_PARAMETER;
122823f0493SLoGin }
123823f0493SLoGin
124823f0493SLoGin u16 phnum = ehdr->e_phnum;
125823f0493SLoGin if (phnum == PN_XNUM) {
126823f0493SLoGin u64 shoff = ehdr->e_shoff;
127823f0493SLoGin if (shoff == 0) {
128823f0493SLoGin efi_err("No section header\n");
129823f0493SLoGin return EFI_INVALID_PARAMETER;
130823f0493SLoGin }
131823f0493SLoGin
132823f0493SLoGin if (shoff + sizeof(Elf64_Shdr) > payload_size) {
133823f0493SLoGin efi_err("Section header out of range\n");
134823f0493SLoGin return EFI_INVALID_PARAMETER;
135823f0493SLoGin }
136823f0493SLoGin
137823f0493SLoGin Elf64_Shdr *shdr = (Elf64_Shdr *)(payload_start + shoff);
138823f0493SLoGin
139823f0493SLoGin phnum = shdr[0].sh_info;
140823f0493SLoGin if (phnum == 0) {
141823f0493SLoGin efi_err("shdr[0].sh_info indicates no program header\n");
142823f0493SLoGin return EFI_INVALID_PARAMETER;
143823f0493SLoGin }
144823f0493SLoGin }
145823f0493SLoGin
146823f0493SLoGin size_t phoff = ehdr->e_phoff;
147823f0493SLoGin size_t phsize = ehdr->e_phentsize;
148823f0493SLoGin size_t total_size = phnum * phsize;
149823f0493SLoGin if (phoff + total_size > payload_size) {
150823f0493SLoGin efi_err("Program header out of range\n");
151823f0493SLoGin return EFI_INVALID_PARAMETER;
152823f0493SLoGin }
153823f0493SLoGin
154823f0493SLoGin Elf64_Phdr *phdr = (Elf64_Phdr *)(payload_start + phoff);
155823f0493SLoGin
156823f0493SLoGin *ret_segments_nr = phnum;
157823f0493SLoGin *ret_phdr = phdr;
158823f0493SLoGin
159823f0493SLoGin return EFI_SUCCESS;
160823f0493SLoGin }
161823f0493SLoGin
162823f0493SLoGin /*
163823f0493SLoGin * Distro versions of GRUB may ignore the BSS allocation entirely (i.e., fail
164823f0493SLoGin * to provide space, and fail to zero it). Check for this condition by double
165823f0493SLoGin * checking that the first and the last byte of the image are covered by the
166823f0493SLoGin * same EFI memory map entry.
167823f0493SLoGin */
check_image_region(u64 base,u64 size)168823f0493SLoGin static bool check_image_region(u64 base, u64 size)
169823f0493SLoGin {
170823f0493SLoGin struct efi_boot_memmap *map;
171823f0493SLoGin efi_status_t status;
172823f0493SLoGin bool ret = false;
173823f0493SLoGin u64 map_offset;
174823f0493SLoGin
175823f0493SLoGin status = efi_get_memory_map(&map, false);
176823f0493SLoGin if (status != EFI_SUCCESS)
177823f0493SLoGin return false;
178823f0493SLoGin
179823f0493SLoGin for (map_offset = 0; map_offset < map->map_size;
180823f0493SLoGin map_offset += map->desc_size) {
181823f0493SLoGin efi_memory_desc_t *md = (void *)map->map + map_offset;
182823f0493SLoGin u64 end = md->PhysicalStart + md->NumberOfPages * EFI_PAGE_SIZE;
183823f0493SLoGin
184823f0493SLoGin /*
185823f0493SLoGin * Find the region that covers base, and return whether
186823f0493SLoGin * it covers base+size bytes.
187823f0493SLoGin */
188823f0493SLoGin if (base >= md->PhysicalStart && base < end) {
189823f0493SLoGin ret = (base + size) <= end;
190823f0493SLoGin break;
191823f0493SLoGin }
192823f0493SLoGin }
193823f0493SLoGin
194823f0493SLoGin efi_bs_call(FreePool, map);
195823f0493SLoGin
196823f0493SLoGin return ret;
197823f0493SLoGin }
1982604d783SLoGin
1992604d783SLoGin /**
2002604d783SLoGin * efi_remap_image_all_rwx - Remap a loaded image with the appropriate permissions
2012604d783SLoGin * for code and data
2022604d783SLoGin *
2032604d783SLoGin * @image_base: the base of the image in memory
2042604d783SLoGin * @alloc_size: the size of the area in memory occupied by the image
2052604d783SLoGin *
2062604d783SLoGin * efi_remap_image() uses the EFI memory attribute protocol to remap the code
2072604d783SLoGin * region of the loaded image read-only/executable, and the remainder
2082604d783SLoGin * read-write/non-executable. The code region is assumed to start at the base
2092604d783SLoGin * of the image, and will therefore cover the PE/COFF header as well.
2102604d783SLoGin */
efi_remap_image_all_rwx(unsigned long image_base,unsigned alloc_size)2112604d783SLoGin void efi_remap_image_all_rwx(unsigned long image_base, unsigned alloc_size)
2122604d783SLoGin {
2132604d783SLoGin efi_guid_t guid = EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID;
2142604d783SLoGin efi_memory_attribute_protocol_t *memattr;
2152604d783SLoGin efi_status_t status;
2162604d783SLoGin u64 attr;
2172604d783SLoGin
2182604d783SLoGin /*
2192604d783SLoGin * If the firmware implements the EFI_MEMORY_ATTRIBUTE_PROTOCOL, let's
2202604d783SLoGin * invoke it to remap the text/rodata region of the decompressed image
2212604d783SLoGin * as read-only and the data/bss region as non-executable.
2222604d783SLoGin */
2232604d783SLoGin status = efi_bs_call(LocateProtocol, &guid, NULL, (void **)&memattr);
2242604d783SLoGin if (status != EFI_SUCCESS)
2252604d783SLoGin return;
2262604d783SLoGin
2272604d783SLoGin // Get the current attributes for the entire region
2282604d783SLoGin status = memattr->get_memory_attributes(memattr, image_base, alloc_size,
2292604d783SLoGin &attr);
2302604d783SLoGin if (status != EFI_SUCCESS) {
2312604d783SLoGin efi_warn(
2322604d783SLoGin "Failed to retrieve memory attributes for image region: 0x%lx\n",
2332604d783SLoGin status);
2342604d783SLoGin return;
2352604d783SLoGin }
2362604d783SLoGin
2372604d783SLoGin efi_debug("Current attributes for image region: 0x%lx\n", attr);
2382604d783SLoGin
2392604d783SLoGin // If the entire region was already mapped as non-exec, clear the
2402604d783SLoGin // attribute from the code region. Otherwise, set it on the data
2412604d783SLoGin // region.
2422604d783SLoGin if (attr & EFI_MEMORY_XP) {
2432604d783SLoGin status = memattr->clear_memory_attributes(
2442604d783SLoGin memattr, image_base, alloc_size, EFI_MEMORY_XP);
2452604d783SLoGin if (status != EFI_SUCCESS)
2462604d783SLoGin efi_warn("Failed to remap region executable\n");
2472604d783SLoGin }
2482604d783SLoGin
2492604d783SLoGin if (attr & EFI_MEMORY_WP) {
2502604d783SLoGin status = memattr->clear_memory_attributes(
2512604d783SLoGin memattr, image_base, alloc_size, EFI_MEMORY_WP);
2522604d783SLoGin if (status != EFI_SUCCESS)
2532604d783SLoGin efi_warn("Failed to remap region writable\n");
2542604d783SLoGin }
2552604d783SLoGin
2562604d783SLoGin if (attr & EFI_MEMORY_RP) {
2572604d783SLoGin status = memattr->clear_memory_attributes(
2582604d783SLoGin memattr, image_base, alloc_size, EFI_MEMORY_RP);
2592604d783SLoGin if (status != EFI_SUCCESS)
2602604d783SLoGin efi_warn("Failed to remap region readable\n");
2612604d783SLoGin }
2622604d783SLoGin }
2632604d783SLoGin
efi_allocate_kernel_memory(const Elf64_Phdr * phdr_start,u32 phdrs_nr,u64 * ret_paddr,u64 * ret_size,u64 * ret_min_paddr,u64 * ret_max_paddr,u64 * ret_min_vaddr)264823f0493SLoGin efi_status_t efi_allocate_kernel_memory(const Elf64_Phdr *phdr_start,
265823f0493SLoGin u32 phdrs_nr, u64 *ret_paddr,
266823f0493SLoGin u64 *ret_size, u64 *ret_min_paddr,
2675d9a3c15SLoGin u64 *ret_max_paddr, u64 *ret_min_vaddr)
268823f0493SLoGin {
269823f0493SLoGin efi_status_t status = EFI_SUCCESS;
2705d9a3c15SLoGin const u64 KERNEL_MEM_ALIGN = 1 << 21; // 2MB
271823f0493SLoGin
272823f0493SLoGin const Elf64_Phdr *phdr = phdr_start;
273823f0493SLoGin
274823f0493SLoGin u64 min_paddr = UINT64_MAX;
275823f0493SLoGin u64 max_paddr = 0;
2765d9a3c15SLoGin u64 min_vaddr = UINT64_MAX;
2775d9a3c15SLoGin
278823f0493SLoGin for (u32 i = 0; i < phdrs_nr; ++i, ++phdr) {
279823f0493SLoGin if (phdr->p_type != PT_LOAD) {
280823f0493SLoGin continue;
281823f0493SLoGin }
282823f0493SLoGin
283823f0493SLoGin if (phdr->p_align & !EFI_PAGE_SIZE) {
284823f0493SLoGin efi_err("ELF segment alignment should be multiple of EFI_PAGE_SIZE(%d), but got %d\n",
285823f0493SLoGin EFI_PAGE_SIZE, phdr->p_align);
286823f0493SLoGin return EFI_INVALID_PARAMETER;
287823f0493SLoGin }
288823f0493SLoGin min_paddr = min(min_paddr, (u64)phdr->p_paddr);
2895d9a3c15SLoGin min_vaddr = min(min_vaddr, (u64)phdr->p_vaddr);
290823f0493SLoGin max_paddr =
291823f0493SLoGin max(max_paddr, (u64)(phdr->p_paddr + phdr->p_memsz));
292823f0493SLoGin }
293823f0493SLoGin
2945d9a3c15SLoGin if (min_paddr & (KERNEL_MEM_ALIGN - 1)) {
2955d9a3c15SLoGin efi_err("min_paddr should be aligned to KERNEL_MEM_ALIGN(%d), but got %p\n",
2965d9a3c15SLoGin KERNEL_MEM_ALIGN, min_paddr);
2975d9a3c15SLoGin return EFI_INVALID_PARAMETER;
2985d9a3c15SLoGin }
2995d9a3c15SLoGin u64 mem_size = ALIGN_UP(max_paddr - min_paddr, KERNEL_MEM_ALIGN);
300823f0493SLoGin
301823f0493SLoGin status = efi_allocate_pages_aligned(mem_size, ret_paddr, UINT64_MAX,
3025d9a3c15SLoGin KERNEL_MEM_ALIGN, EfiLoaderData);
303823f0493SLoGin // status = efi_allocate_pages_exact(mem_size, paddr);
304823f0493SLoGin if (status != EFI_SUCCESS) {
305823f0493SLoGin efi_err("Failed to allocate pages for ELF segment: status: %d, page_size=%d, min_paddr=%p, max_paddr=%p, mem_size=%d. Maybe an OOM error or section overlaps.\n",
3065d9a3c15SLoGin status, KERNEL_MEM_ALIGN, ret_paddr, max_paddr,
3075d9a3c15SLoGin mem_size);
308823f0493SLoGin return status;
309823f0493SLoGin }
310823f0493SLoGin
311823f0493SLoGin *ret_size = mem_size;
312823f0493SLoGin *ret_min_paddr = min_paddr;
313823f0493SLoGin *ret_max_paddr = max_paddr;
3145d9a3c15SLoGin *ret_min_vaddr = min_vaddr;
315823f0493SLoGin efi_info("Allocated kernel memory: paddr=%p, mem_size= %d bytes\n",
316823f0493SLoGin *ret_paddr, mem_size);
317823f0493SLoGin // zeroed the memory
318823f0493SLoGin memset((void *)(*ret_paddr), 0, mem_size);
319823f0493SLoGin
3202604d783SLoGin efi_remap_image_all_rwx(*ret_paddr, mem_size);
3212604d783SLoGin
322823f0493SLoGin return EFI_SUCCESS;
323823f0493SLoGin }
324823f0493SLoGin
load_program(const void * payload_start,u64 payload_size,const Elf64_Phdr * phdr_start,u32 phdrs_nr,u64 * ret_program_mem_paddr,u64 * ret_program_mem_size,u64 * ret_min_paddr,u64 * ret_min_vaddr)325823f0493SLoGin static efi_status_t load_program(const void *payload_start, u64 payload_size,
326823f0493SLoGin const Elf64_Phdr *phdr_start, u32 phdrs_nr,
327823f0493SLoGin u64 *ret_program_mem_paddr,
3285d9a3c15SLoGin u64 *ret_program_mem_size, u64 *ret_min_paddr,
3295d9a3c15SLoGin u64 *ret_min_vaddr)
330823f0493SLoGin {
331823f0493SLoGin efi_status_t status = EFI_SUCCESS;
332823f0493SLoGin
333823f0493SLoGin u64 allocated_paddr = 0;
334823f0493SLoGin u64 allocated_size = 0;
335823f0493SLoGin u64 min_paddr = 0;
336823f0493SLoGin u64 max_paddr = 0;
3375d9a3c15SLoGin u64 min_vaddr = 0;
338823f0493SLoGin status = efi_allocate_kernel_memory(phdr_start, phdrs_nr,
339823f0493SLoGin &allocated_paddr, &allocated_size,
3405d9a3c15SLoGin &min_paddr, &max_paddr, &min_vaddr);
341773f7fd3SLoGin
342823f0493SLoGin if (status != EFI_SUCCESS) {
343823f0493SLoGin efi_err("Failed to allocate kernel memory\n");
344823f0493SLoGin return status;
345823f0493SLoGin }
346773f7fd3SLoGin
347773f7fd3SLoGin // 清空内存
348773f7fd3SLoGin memset((void *)allocated_paddr, 0, allocated_size);
349773f7fd3SLoGin
350823f0493SLoGin const Elf64_Phdr *phdr = phdr_start;
351823f0493SLoGin
352823f0493SLoGin for (u32 i = 0; i < phdrs_nr; ++i, ++phdr) {
353823f0493SLoGin if (phdr->p_type != PT_LOAD) {
354823f0493SLoGin continue;
355823f0493SLoGin }
356823f0493SLoGin
357823f0493SLoGin if (phdr->p_align & !EFI_PAGE_SIZE) {
358823f0493SLoGin efi_err("ELF segment alignment should be multiple of EFI_PAGE_SIZE(%d), but got %d\n",
359823f0493SLoGin EFI_PAGE_SIZE, phdr->p_align);
360823f0493SLoGin status = EFI_INVALID_PARAMETER;
361823f0493SLoGin goto failed;
362823f0493SLoGin }
363823f0493SLoGin
364823f0493SLoGin u64 paddr = phdr->p_paddr;
365823f0493SLoGin
366823f0493SLoGin u64 mem_size = phdr->p_memsz;
367823f0493SLoGin u64 file_size = phdr->p_filesz;
368823f0493SLoGin u64 file_offset = phdr->p_offset;
369823f0493SLoGin // efi_debug(
370823f0493SLoGin // "loading segment: paddr=%p, mem_size=%d, file_size=%d\n",
371823f0493SLoGin // paddr, mem_size, file_size);
372823f0493SLoGin
373823f0493SLoGin if (file_offset + file_size > payload_size) {
374823f0493SLoGin status = EFI_INVALID_PARAMETER;
375823f0493SLoGin goto failed;
376823f0493SLoGin }
377823f0493SLoGin
378823f0493SLoGin if (mem_size < file_size) {
379823f0493SLoGin status = EFI_INVALID_PARAMETER;
380823f0493SLoGin goto failed;
381823f0493SLoGin }
382823f0493SLoGin
383823f0493SLoGin if (mem_size == 0) {
384823f0493SLoGin continue;
385823f0493SLoGin }
386823f0493SLoGin
387823f0493SLoGin memcpy((void *)(allocated_paddr + (paddr - min_paddr)),
388823f0493SLoGin payload_start + file_offset, file_size);
389823f0493SLoGin
390823f0493SLoGin // efi_debug(
391773f7fd3SLoGin // "segment loaded: file_offset: %p paddr=%p, mem_size=%p, file_size=%p\n",
392773f7fd3SLoGin // file_offset, paddr, mem_size, file_size);
393823f0493SLoGin }
394823f0493SLoGin
395823f0493SLoGin *ret_program_mem_paddr = allocated_paddr;
396823f0493SLoGin *ret_program_mem_size = allocated_size;
397823f0493SLoGin *ret_min_paddr = min_paddr;
3985d9a3c15SLoGin *ret_min_vaddr = min_vaddr;
399823f0493SLoGin
400823f0493SLoGin return EFI_SUCCESS;
401823f0493SLoGin failed:
402823f0493SLoGin efi_free(allocated_size, allocated_paddr);
403823f0493SLoGin return status;
404823f0493SLoGin }
405823f0493SLoGin
load_elf(struct payload_info * payload_info)406823f0493SLoGin efi_status_t load_elf(struct payload_info *payload_info)
407823f0493SLoGin {
408823f0493SLoGin const void *payload_start = (void *)payload_info->payload_addr;
409823f0493SLoGin u64 payload_size = payload_info->payload_size;
410823f0493SLoGin Elf64_Ehdr *ehdr = NULL;
411823f0493SLoGin efi_status_t status =
412823f0493SLoGin elf_get_header(payload_start, payload_size, &ehdr);
413823f0493SLoGin if (status != EFI_SUCCESS) {
414823f0493SLoGin efi_err("Failed to get ELF header\n");
415823f0493SLoGin return status;
416823f0493SLoGin }
417823f0493SLoGin ASSERT(ehdr != NULL);
418823f0493SLoGin
419823f0493SLoGin print_elf_info(ehdr);
420823f0493SLoGin
421823f0493SLoGin u32 phdrs_nr = 0;
422823f0493SLoGin Elf64_Phdr *phdr_start = NULL;
423823f0493SLoGin
424823f0493SLoGin status = parse_phdrs(payload_start, payload_size, ehdr, &phdrs_nr,
425823f0493SLoGin &phdr_start);
426823f0493SLoGin if (status != EFI_SUCCESS) {
427823f0493SLoGin efi_err("Failed to parse ELF segments\n");
428823f0493SLoGin return status;
429823f0493SLoGin }
430823f0493SLoGin
431823f0493SLoGin efi_debug("program headers: %d\n", phdrs_nr);
432823f0493SLoGin
433823f0493SLoGin u64 program_paddr = 0;
434823f0493SLoGin u64 program_size = 0;
435823f0493SLoGin u64 image_link_base_paddr = 0;
4365d9a3c15SLoGin u64 image_link_base_vaddr = 0;
437823f0493SLoGin load_program(payload_start, payload_size, phdr_start, phdrs_nr,
4385d9a3c15SLoGin &program_paddr, &program_size, &image_link_base_paddr,
4395d9a3c15SLoGin &image_link_base_vaddr);
440823f0493SLoGin payload_info->loaded_paddr = program_paddr;
441823f0493SLoGin payload_info->loaded_size = program_size;
442823f0493SLoGin payload_info->kernel_entry =
4435d9a3c15SLoGin ehdr->e_entry - image_link_base_vaddr + program_paddr;
4442604d783SLoGin
4455d9a3c15SLoGin efi_info("loaded_paddr: %p\n", payload_info->loaded_paddr);
4465d9a3c15SLoGin efi_info("loaded_size: %p\n", payload_info->loaded_size);
4475d9a3c15SLoGin efi_info("ehdr->e_entry: %lx\n", ehdr->e_entry);
4485d9a3c15SLoGin efi_info("image_link_base_paddr: %lx\n", image_link_base_paddr);
4495d9a3c15SLoGin efi_info("kernel_entry: %lx\n", payload_info->kernel_entry);
4502604d783SLoGin // 处理权限问题
4512604d783SLoGin
4522604d783SLoGin efi_remap_image_all_rwx(program_paddr, program_size);
4532604d783SLoGin extern void _start(void);
4542604d783SLoGin extern void _image_end(void);
4552604d783SLoGin u64 image_size = (u64)&_image_end - (u64)&_start;
4562604d783SLoGin efi_debug("image_size: %d\n", image_size);
4572604d783SLoGin efi_remap_image_all_rwx((u64)&_start, (image_size + 4095) & ~4095);
4582604d783SLoGin
4597fc3806dSLoGin // 添加地址到efi configuration table
4607fc3806dSLoGin
4617fc3806dSLoGin struct dragonstub_payload_efi *tbl = NULL;
4627fc3806dSLoGin status = efi_bs_call(AllocatePool, EfiLoaderData,
4637fc3806dSLoGin sizeof(struct dragonstub_payload_efi),
4647fc3806dSLoGin (void **)&tbl);
4657fc3806dSLoGin
4667fc3806dSLoGin if (status != EFI_SUCCESS) {
4677fc3806dSLoGin efi_err("Failed to allocate memory for dragonstub_payload_efi\n");
4687fc3806dSLoGin return status;
4697fc3806dSLoGin }
4707fc3806dSLoGin
471*552e14d5SLoGin tbl->loaded_addr = payload_info->loaded_paddr;
472*552e14d5SLoGin tbl->size = payload_info->loaded_size;
4737fc3806dSLoGin
4747fc3806dSLoGin efi_guid_t dragonstub_payload_efi_guid =
4757fc3806dSLoGin DRAGONSTUB_EFI_PAYLOAD_EFI_GUID;
4767fc3806dSLoGin
4777fc3806dSLoGin status = efi_bs_call(InstallConfigurationTable,
4787fc3806dSLoGin &dragonstub_payload_efi_guid, tbl);
4797fc3806dSLoGin
4807fc3806dSLoGin if (status != EFI_SUCCESS) {
4817fc3806dSLoGin efi_err("Failed to install dragonstub_payload_efi\n");
4827fc3806dSLoGin return status;
4837fc3806dSLoGin }
4847fc3806dSLoGin
485823f0493SLoGin return EFI_SUCCESS;
486823f0493SLoGin }