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 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 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 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 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 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 */ 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 */ 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 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 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); 341*773f7fd3SLoGin 342823f0493SLoGin if (status != EFI_SUCCESS) { 343823f0493SLoGin efi_err("Failed to allocate kernel memory\n"); 344823f0493SLoGin return status; 345823f0493SLoGin } 346*773f7fd3SLoGin 347*773f7fd3SLoGin // 清空内存 348*773f7fd3SLoGin memset((void *)allocated_paddr, 0, allocated_size); 349*773f7fd3SLoGin 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( 391*773f7fd3SLoGin // "segment loaded: file_offset: %p paddr=%p, mem_size=%p, file_size=%p\n", 392*773f7fd3SLoGin // 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 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 4717fc3806dSLoGin tbl->payload_addr = payload_info->payload_addr; 4727fc3806dSLoGin tbl->payload_size = payload_info->payload_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 }