xref: /DragonStub/apps/elf.c (revision 2604d7835e66d1fccc0973634b0121c7925e25f6)
1823f0493SLoGin #include "elf.h"
2*2604d783SLoGin #include "dragonstub/linux-efi.h"
3823f0493SLoGin #include "dragonstub/linux/align.h"
4*2604d783SLoGin #include "dragonstub/printk.h"
5*2604d783SLoGin #include "dragonstub/types.h"
6*2604d783SLoGin #include "efidef.h"
7823f0493SLoGin #include <efi.h>
8823f0493SLoGin #include <efiapi.h>
9*2604d783SLoGin #include <efidevp.h>
10823f0493SLoGin #include <efilib.h>
11823f0493SLoGin #include <dragonstub/dragonstub.h>
12823f0493SLoGin #include <dragonstub/elfloader.h>
13823f0493SLoGin 
14823f0493SLoGin /// @brief 校验ELF文件头
15823f0493SLoGin /// @param buf 缓冲区
16823f0493SLoGin /// @param bufsize 缓冲区大小
17823f0493SLoGin /// @return
18823f0493SLoGin static bool verify_ident(const void *buf, u64 bufsize)
19823f0493SLoGin {
20823f0493SLoGin 	if (bufsize < EI_NIDENT) {
21823f0493SLoGin 		// 太短,不是ELF
22823f0493SLoGin 		return false;
23823f0493SLoGin 	}
24823f0493SLoGin 	// 检查magic number
25823f0493SLoGin 	for (int i = 0; i < EI_CLASS; i++) {
26823f0493SLoGin 		u8 c = *(u8 *)(buf + i);
27823f0493SLoGin 		if (c != ELFMAG[i]) {
28823f0493SLoGin 			// 不是ELF magic number,跳过
29823f0493SLoGin 			efi_err("ELF magic number not match\n");
30823f0493SLoGin 			return false;
31823f0493SLoGin 		}
32823f0493SLoGin 	}
33823f0493SLoGin 
34823f0493SLoGin 	// verify ELF Version
35823f0493SLoGin 	u8 version = *(u8 *)(buf + EI_VERSION);
36823f0493SLoGin 	if (version != EV_CURRENT) {
37823f0493SLoGin 		efi_err("ELF version not match, expected EV_CURRENT(%d), got %d\n",
38823f0493SLoGin 			EV_CURRENT, version);
39823f0493SLoGin 		// 不是当前版本,跳过
40823f0493SLoGin 		return false;
41823f0493SLoGin 	}
42823f0493SLoGin 
43823f0493SLoGin 	// verify ELF Class
44823f0493SLoGin 	u8 class = *(u8 *)(buf + EI_CLASS);
45823f0493SLoGin 	if (class != ELFCLASS64) {
46823f0493SLoGin 		efi_err("ELF class not match, expected ELFCLASS64(%d), got %d\n",
47823f0493SLoGin 			ELFCLASS64, class);
48823f0493SLoGin 		// 不是64位,跳过
49823f0493SLoGin 		return false;
50823f0493SLoGin 	}
51823f0493SLoGin 
52823f0493SLoGin 	return true;
53823f0493SLoGin }
54823f0493SLoGin 
55823f0493SLoGin bool elf_check(const void *payload_start, u64 payload_size)
56823f0493SLoGin {
57823f0493SLoGin 	// 校验ELF文件头
58823f0493SLoGin 	if (!verify_ident(payload_start, payload_size)) {
59823f0493SLoGin 		return false;
60823f0493SLoGin 	}
61823f0493SLoGin 	// 检查架构
62823f0493SLoGin 	Elf64_Ehdr *ehdr = (Elf64_Ehdr *)payload_start;
63823f0493SLoGin #ifdef CONFIG_riscv64
64823f0493SLoGin 	if (ehdr->e_machine != EM_RISCV) {
65823f0493SLoGin 		efi_err("ELF machine not match, expected EM_RISCV(%d), got %d\n",
66823f0493SLoGin 			EM_RISCV, ehdr->e_machine);
67823f0493SLoGin 		return false;
68823f0493SLoGin 	}
69823f0493SLoGin #else
70823f0493SLoGin // 还没有对当前架构进行检查,抛出编译错误
71823f0493SLoGin #error "Unimplement ELF arch test for current cross compile arch"
72823f0493SLoGin #endif
73823f0493SLoGin 	return true;
74823f0493SLoGin }
75823f0493SLoGin 
76823f0493SLoGin /// @brief 获取ELF文件头
77823f0493SLoGin /// @param payload_start 文件起始地址
78823f0493SLoGin /// @param payload_size 文件大小
79823f0493SLoGin /// @param ehdr 返回的ELF文件头
80823f0493SLoGin /// @return
81823f0493SLoGin efi_status_t elf_get_header(const void *payload_start, u64 payload_size,
82823f0493SLoGin 			    Elf64_Ehdr **ehdr)
83823f0493SLoGin {
84823f0493SLoGin 	if (!verify_ident(payload_start, payload_size)) {
85823f0493SLoGin 		return EFI_INVALID_PARAMETER;
86823f0493SLoGin 	}
87823f0493SLoGin 	*ehdr = (Elf64_Ehdr *)payload_start;
88823f0493SLoGin 	return EFI_SUCCESS;
89823f0493SLoGin }
90823f0493SLoGin 
91823f0493SLoGin static void print_elf_info(Elf64_Ehdr *ehdr)
92823f0493SLoGin {
93823f0493SLoGin 	efi_info("ELF header:\n");
94823f0493SLoGin 	efi_printk("  e_type: %d\n", ehdr->e_type);
95823f0493SLoGin 	efi_printk("  e_machine: %d\n", ehdr->e_machine);
96823f0493SLoGin 	efi_printk("  e_version: %d\n", ehdr->e_version);
97823f0493SLoGin 	efi_printk("  e_entry: %p\n", ehdr->e_entry);
98823f0493SLoGin 	efi_printk("  e_phoff: %p\n", ehdr->e_phoff);
99823f0493SLoGin 	efi_printk("  e_shoff: %p\n", ehdr->e_shoff);
100823f0493SLoGin 	efi_printk("  e_flags: %d\n", ehdr->e_flags);
101823f0493SLoGin 	efi_printk("  e_ehsize: %d\n", ehdr->e_ehsize);
102823f0493SLoGin 	efi_printk("  e_phentsize: %d\n", ehdr->e_phentsize);
103823f0493SLoGin 	efi_printk("  e_phnum: %d\n", ehdr->e_phnum);
104823f0493SLoGin 	efi_printk("  e_shentsize: %d\n", ehdr->e_shentsize);
105823f0493SLoGin 	efi_printk("  e_shnum: %d\n", ehdr->e_shnum);
106823f0493SLoGin 	efi_printk("  e_shstrndx: %d\n", ehdr->e_shstrndx);
107823f0493SLoGin }
108823f0493SLoGin 
109823f0493SLoGin static efi_status_t parse_phdrs(const void *payload_start, u64 payload_size,
110823f0493SLoGin 				const Elf64_Ehdr *ehdr, u32 *ret_segments_nr,
111823f0493SLoGin 				Elf64_Phdr **ret_phdr)
112823f0493SLoGin {
113823f0493SLoGin 	if (ehdr->e_phnum == 0) {
114823f0493SLoGin 		efi_err("No program header\n");
115823f0493SLoGin 		return EFI_INVALID_PARAMETER;
116823f0493SLoGin 	}
117823f0493SLoGin 	if (ehdr->e_phentsize != sizeof(Elf64_Phdr)) {
118823f0493SLoGin 		efi_err("Invalid program header size: %d, expected %d\n",
119823f0493SLoGin 			ehdr->e_phentsize, sizeof(Elf64_Phdr));
120823f0493SLoGin 		return EFI_INVALID_PARAMETER;
121823f0493SLoGin 	}
122823f0493SLoGin 
123823f0493SLoGin 	u16 phnum = ehdr->e_phnum;
124823f0493SLoGin 	if (phnum == PN_XNUM) {
125823f0493SLoGin 		u64 shoff = ehdr->e_shoff;
126823f0493SLoGin 		if (shoff == 0) {
127823f0493SLoGin 			efi_err("No section header\n");
128823f0493SLoGin 			return EFI_INVALID_PARAMETER;
129823f0493SLoGin 		}
130823f0493SLoGin 
131823f0493SLoGin 		if (shoff + sizeof(Elf64_Shdr) > payload_size) {
132823f0493SLoGin 			efi_err("Section header out of range\n");
133823f0493SLoGin 			return EFI_INVALID_PARAMETER;
134823f0493SLoGin 		}
135823f0493SLoGin 
136823f0493SLoGin 		Elf64_Shdr *shdr = (Elf64_Shdr *)(payload_start + shoff);
137823f0493SLoGin 
138823f0493SLoGin 		phnum = shdr[0].sh_info;
139823f0493SLoGin 		if (phnum == 0) {
140823f0493SLoGin 			efi_err("shdr[0].sh_info indicates no program header\n");
141823f0493SLoGin 			return EFI_INVALID_PARAMETER;
142823f0493SLoGin 		}
143823f0493SLoGin 	}
144823f0493SLoGin 
145823f0493SLoGin 	size_t phoff = ehdr->e_phoff;
146823f0493SLoGin 	size_t phsize = ehdr->e_phentsize;
147823f0493SLoGin 	size_t total_size = phnum * phsize;
148823f0493SLoGin 	if (phoff + total_size > payload_size) {
149823f0493SLoGin 		efi_err("Program header out of range\n");
150823f0493SLoGin 		return EFI_INVALID_PARAMETER;
151823f0493SLoGin 	}
152823f0493SLoGin 
153823f0493SLoGin 	Elf64_Phdr *phdr = (Elf64_Phdr *)(payload_start + phoff);
154823f0493SLoGin 
155823f0493SLoGin 	*ret_segments_nr = phnum;
156823f0493SLoGin 	*ret_phdr = phdr;
157823f0493SLoGin 
158823f0493SLoGin 	return EFI_SUCCESS;
159823f0493SLoGin }
160823f0493SLoGin 
161823f0493SLoGin /*
162823f0493SLoGin  * Distro versions of GRUB may ignore the BSS allocation entirely (i.e., fail
163823f0493SLoGin  * to provide space, and fail to zero it). Check for this condition by double
164823f0493SLoGin  * checking that the first and the last byte of the image are covered by the
165823f0493SLoGin  * same EFI memory map entry.
166823f0493SLoGin  */
167823f0493SLoGin static bool check_image_region(u64 base, u64 size)
168823f0493SLoGin {
169823f0493SLoGin 	struct efi_boot_memmap *map;
170823f0493SLoGin 	efi_status_t status;
171823f0493SLoGin 	bool ret = false;
172823f0493SLoGin 	u64 map_offset;
173823f0493SLoGin 
174823f0493SLoGin 	status = efi_get_memory_map(&map, false);
175823f0493SLoGin 	if (status != EFI_SUCCESS)
176823f0493SLoGin 		return false;
177823f0493SLoGin 
178823f0493SLoGin 	for (map_offset = 0; map_offset < map->map_size;
179823f0493SLoGin 	     map_offset += map->desc_size) {
180823f0493SLoGin 		efi_memory_desc_t *md = (void *)map->map + map_offset;
181823f0493SLoGin 		u64 end = md->PhysicalStart + md->NumberOfPages * EFI_PAGE_SIZE;
182823f0493SLoGin 
183823f0493SLoGin 		/*
184823f0493SLoGin 		 * Find the region that covers base, and return whether
185823f0493SLoGin 		 * it covers base+size bytes.
186823f0493SLoGin 		 */
187823f0493SLoGin 		if (base >= md->PhysicalStart && base < end) {
188823f0493SLoGin 			ret = (base + size) <= end;
189823f0493SLoGin 			break;
190823f0493SLoGin 		}
191823f0493SLoGin 	}
192823f0493SLoGin 
193823f0493SLoGin 	efi_bs_call(FreePool, map);
194823f0493SLoGin 
195823f0493SLoGin 	return ret;
196823f0493SLoGin }
197*2604d783SLoGin 
198*2604d783SLoGin /**
199*2604d783SLoGin  * efi_remap_image_all_rwx - Remap a loaded image with the appropriate permissions
200*2604d783SLoGin  *                   for code and data
201*2604d783SLoGin  *
202*2604d783SLoGin  * @image_base:	the base of the image in memory
203*2604d783SLoGin  * @alloc_size:	the size of the area in memory occupied by the image
204*2604d783SLoGin  *
205*2604d783SLoGin  * efi_remap_image() uses the EFI memory attribute protocol to remap the code
206*2604d783SLoGin  * region of the loaded image read-only/executable, and the remainder
207*2604d783SLoGin  * read-write/non-executable. The code region is assumed to start at the base
208*2604d783SLoGin  * of the image, and will therefore cover the PE/COFF header as well.
209*2604d783SLoGin  */
210*2604d783SLoGin void efi_remap_image_all_rwx(unsigned long image_base, unsigned alloc_size)
211*2604d783SLoGin {
212*2604d783SLoGin 	efi_guid_t guid = EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID;
213*2604d783SLoGin 	efi_memory_attribute_protocol_t *memattr;
214*2604d783SLoGin 	efi_status_t status;
215*2604d783SLoGin 	u64 attr;
216*2604d783SLoGin 
217*2604d783SLoGin 	/*
218*2604d783SLoGin 	 * If the firmware implements the EFI_MEMORY_ATTRIBUTE_PROTOCOL, let's
219*2604d783SLoGin 	 * invoke it to remap the text/rodata region of the decompressed image
220*2604d783SLoGin 	 * as read-only and the data/bss region as non-executable.
221*2604d783SLoGin 	 */
222*2604d783SLoGin 	status = efi_bs_call(LocateProtocol, &guid, NULL, (void **)&memattr);
223*2604d783SLoGin 	if (status != EFI_SUCCESS)
224*2604d783SLoGin 		return;
225*2604d783SLoGin 
226*2604d783SLoGin 	// Get the current attributes for the entire region
227*2604d783SLoGin 	status = memattr->get_memory_attributes(memattr, image_base, alloc_size,
228*2604d783SLoGin 						&attr);
229*2604d783SLoGin 	if (status != EFI_SUCCESS) {
230*2604d783SLoGin 		efi_warn(
231*2604d783SLoGin 			"Failed to retrieve memory attributes for image region: 0x%lx\n",
232*2604d783SLoGin 			status);
233*2604d783SLoGin 		return;
234*2604d783SLoGin 	}
235*2604d783SLoGin 
236*2604d783SLoGin 	efi_debug("Current attributes for image region: 0x%lx\n", attr);
237*2604d783SLoGin 
238*2604d783SLoGin 	// If the entire region was already mapped as non-exec, clear the
239*2604d783SLoGin 	// attribute from the code region. Otherwise, set it on the data
240*2604d783SLoGin 	// region.
241*2604d783SLoGin 	if (attr & EFI_MEMORY_XP) {
242*2604d783SLoGin 		status = memattr->clear_memory_attributes(
243*2604d783SLoGin 			memattr, image_base, alloc_size, EFI_MEMORY_XP);
244*2604d783SLoGin 		if (status != EFI_SUCCESS)
245*2604d783SLoGin 			efi_warn("Failed to remap region executable\n");
246*2604d783SLoGin 	}
247*2604d783SLoGin 
248*2604d783SLoGin 	if (attr & EFI_MEMORY_WP) {
249*2604d783SLoGin 		status = memattr->clear_memory_attributes(
250*2604d783SLoGin 			memattr, image_base, alloc_size, EFI_MEMORY_WP);
251*2604d783SLoGin 		if (status != EFI_SUCCESS)
252*2604d783SLoGin 			efi_warn("Failed to remap region writable\n");
253*2604d783SLoGin 	}
254*2604d783SLoGin 
255*2604d783SLoGin 	if (attr & EFI_MEMORY_RP) {
256*2604d783SLoGin 		status = memattr->clear_memory_attributes(
257*2604d783SLoGin 			memattr, image_base, alloc_size, EFI_MEMORY_RP);
258*2604d783SLoGin 		if (status != EFI_SUCCESS)
259*2604d783SLoGin 			efi_warn("Failed to remap region readable\n");
260*2604d783SLoGin 	}
261*2604d783SLoGin }
262*2604d783SLoGin 
263823f0493SLoGin efi_status_t efi_allocate_kernel_memory(const Elf64_Phdr *phdr_start,
264823f0493SLoGin 					u32 phdrs_nr, u64 *ret_paddr,
265823f0493SLoGin 					u64 *ret_size, u64 *ret_min_paddr,
266823f0493SLoGin 					u64 *ret_max_paddr)
267823f0493SLoGin {
268823f0493SLoGin 	efi_status_t status = EFI_SUCCESS;
269823f0493SLoGin 
270823f0493SLoGin 	const Elf64_Phdr *phdr = phdr_start;
271823f0493SLoGin 
272823f0493SLoGin 	u64 min_paddr = UINT64_MAX;
273823f0493SLoGin 	u64 max_paddr = 0;
274823f0493SLoGin 	for (u32 i = 0; i < phdrs_nr; ++i, ++phdr) {
275823f0493SLoGin 		if (phdr->p_type != PT_LOAD) {
276823f0493SLoGin 			continue;
277823f0493SLoGin 		}
278823f0493SLoGin 
279823f0493SLoGin 		if (phdr->p_align & !EFI_PAGE_SIZE) {
280823f0493SLoGin 			efi_err("ELF segment alignment should be multiple of EFI_PAGE_SIZE(%d), but got %d\n",
281823f0493SLoGin 				EFI_PAGE_SIZE, phdr->p_align);
282823f0493SLoGin 			return EFI_INVALID_PARAMETER;
283823f0493SLoGin 		}
284823f0493SLoGin 		min_paddr = min(min_paddr, (u64)phdr->p_paddr);
285823f0493SLoGin 		max_paddr =
286823f0493SLoGin 			max(max_paddr, (u64)(phdr->p_paddr + phdr->p_memsz));
287823f0493SLoGin 	}
288823f0493SLoGin 
289823f0493SLoGin 	u64 mem_size = ALIGN_UP(max_paddr - min_paddr, EFI_PAGE_SIZE);
290823f0493SLoGin 
291823f0493SLoGin 	status = efi_allocate_pages_aligned(mem_size, ret_paddr, UINT64_MAX,
292823f0493SLoGin 					    EFI_PAGE_SIZE, EfiLoaderData);
293823f0493SLoGin 	// status = efi_allocate_pages_exact(mem_size, paddr);
294823f0493SLoGin 	if (status != EFI_SUCCESS) {
295823f0493SLoGin 		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",
296823f0493SLoGin 			status, EFI_PAGE_SIZE, ret_paddr, max_paddr, mem_size);
297823f0493SLoGin 		return status;
298823f0493SLoGin 	}
299823f0493SLoGin 
300823f0493SLoGin 	*ret_size = mem_size;
301823f0493SLoGin 	*ret_min_paddr = min_paddr;
302823f0493SLoGin 	*ret_max_paddr = max_paddr;
303823f0493SLoGin 	efi_info("Allocated kernel memory: paddr=%p, mem_size= %d bytes\n",
304823f0493SLoGin 		 *ret_paddr, mem_size);
305823f0493SLoGin 	// zeroed the memory
306823f0493SLoGin 	memset((void *)(*ret_paddr), 0, mem_size);
307823f0493SLoGin 
308*2604d783SLoGin 	efi_remap_image_all_rwx(*ret_paddr, mem_size);
309*2604d783SLoGin 
310823f0493SLoGin 	return EFI_SUCCESS;
311823f0493SLoGin }
312823f0493SLoGin 
313823f0493SLoGin static efi_status_t load_program(const void *payload_start, u64 payload_size,
314823f0493SLoGin 				 const Elf64_Phdr *phdr_start, u32 phdrs_nr,
315823f0493SLoGin 				 u64 *ret_program_mem_paddr,
316823f0493SLoGin 				 u64 *ret_program_mem_size, u64 *ret_min_paddr)
317823f0493SLoGin {
318823f0493SLoGin 	efi_status_t status = EFI_SUCCESS;
319823f0493SLoGin 
320823f0493SLoGin 	u64 allocated_paddr = 0;
321823f0493SLoGin 	u64 allocated_size = 0;
322823f0493SLoGin 	u64 min_paddr = 0;
323823f0493SLoGin 	u64 max_paddr = 0;
324823f0493SLoGin 	status = efi_allocate_kernel_memory(phdr_start, phdrs_nr,
325823f0493SLoGin 					    &allocated_paddr, &allocated_size,
326823f0493SLoGin 					    &min_paddr, &max_paddr);
327823f0493SLoGin 	if (status != EFI_SUCCESS) {
328823f0493SLoGin 		efi_err("Failed to allocate kernel memory\n");
329823f0493SLoGin 		return status;
330823f0493SLoGin 	}
331823f0493SLoGin 	const Elf64_Phdr *phdr = phdr_start;
332823f0493SLoGin 
333823f0493SLoGin 	for (u32 i = 0; i < phdrs_nr; ++i, ++phdr) {
334823f0493SLoGin 		if (phdr->p_type != PT_LOAD) {
335823f0493SLoGin 			continue;
336823f0493SLoGin 		}
337823f0493SLoGin 
338823f0493SLoGin 		if (phdr->p_align & !EFI_PAGE_SIZE) {
339823f0493SLoGin 			efi_err("ELF segment alignment should be multiple of EFI_PAGE_SIZE(%d), but got %d\n",
340823f0493SLoGin 				EFI_PAGE_SIZE, phdr->p_align);
341823f0493SLoGin 			status = EFI_INVALID_PARAMETER;
342823f0493SLoGin 			goto failed;
343823f0493SLoGin 		}
344823f0493SLoGin 
345823f0493SLoGin 		u64 paddr = phdr->p_paddr;
346823f0493SLoGin 
347823f0493SLoGin 		u64 mem_size = phdr->p_memsz;
348823f0493SLoGin 		u64 file_size = phdr->p_filesz;
349823f0493SLoGin 		u64 file_offset = phdr->p_offset;
350823f0493SLoGin 		// efi_debug(
351823f0493SLoGin 		// 	"loading segment: paddr=%p, mem_size=%d, file_size=%d\n",
352823f0493SLoGin 		// 	paddr, mem_size, file_size);
353823f0493SLoGin 
354823f0493SLoGin 		if (file_offset + file_size > payload_size) {
355823f0493SLoGin 			status = EFI_INVALID_PARAMETER;
356823f0493SLoGin 			goto failed;
357823f0493SLoGin 		}
358823f0493SLoGin 
359823f0493SLoGin 		if (mem_size < file_size) {
360823f0493SLoGin 			status = EFI_INVALID_PARAMETER;
361823f0493SLoGin 			goto failed;
362823f0493SLoGin 		}
363823f0493SLoGin 
364823f0493SLoGin 		if (mem_size == 0) {
365823f0493SLoGin 			continue;
366823f0493SLoGin 		}
367823f0493SLoGin 
368823f0493SLoGin 		memcpy((void *)(allocated_paddr + (paddr - min_paddr)),
369823f0493SLoGin 		       payload_start + file_offset, file_size);
370823f0493SLoGin 
371823f0493SLoGin 		// efi_debug(
372823f0493SLoGin 		// 	"segment loaded: paddr=%p, mem_size=%d, file_size=%d\n",
373823f0493SLoGin 		// 	paddr, mem_size, file_size);
374823f0493SLoGin 	}
375823f0493SLoGin 
376823f0493SLoGin 	*ret_program_mem_paddr = allocated_paddr;
377823f0493SLoGin 	*ret_program_mem_size = allocated_size;
378823f0493SLoGin 	*ret_min_paddr = min_paddr;
379823f0493SLoGin 
380823f0493SLoGin 	return EFI_SUCCESS;
381823f0493SLoGin failed:
382823f0493SLoGin 	efi_free(allocated_size, allocated_paddr);
383823f0493SLoGin 	return status;
384823f0493SLoGin }
385823f0493SLoGin 
386823f0493SLoGin efi_status_t load_elf(struct payload_info *payload_info)
387823f0493SLoGin {
388823f0493SLoGin 	const void *payload_start = (void *)payload_info->payload_addr;
389823f0493SLoGin 	u64 payload_size = payload_info->payload_size;
390823f0493SLoGin 	Elf64_Ehdr *ehdr = NULL;
391823f0493SLoGin 	efi_status_t status =
392823f0493SLoGin 		elf_get_header(payload_start, payload_size, &ehdr);
393823f0493SLoGin 	if (status != EFI_SUCCESS) {
394823f0493SLoGin 		efi_err("Failed to get ELF header\n");
395823f0493SLoGin 		return status;
396823f0493SLoGin 	}
397823f0493SLoGin 	ASSERT(ehdr != NULL);
398823f0493SLoGin 
399823f0493SLoGin 	print_elf_info(ehdr);
400823f0493SLoGin 
401823f0493SLoGin 	u32 phdrs_nr = 0;
402823f0493SLoGin 	Elf64_Phdr *phdr_start = NULL;
403823f0493SLoGin 
404823f0493SLoGin 	status = parse_phdrs(payload_start, payload_size, ehdr, &phdrs_nr,
405823f0493SLoGin 			     &phdr_start);
406823f0493SLoGin 	if (status != EFI_SUCCESS) {
407823f0493SLoGin 		efi_err("Failed to parse ELF segments\n");
408823f0493SLoGin 		return status;
409823f0493SLoGin 	}
410823f0493SLoGin 
411823f0493SLoGin 	efi_debug("program headers: %d\n", phdrs_nr);
412823f0493SLoGin 
413823f0493SLoGin 	u64 program_paddr = 0;
414823f0493SLoGin 	u64 program_size = 0;
415823f0493SLoGin 	u64 image_link_base_paddr = 0;
416823f0493SLoGin 	load_program(payload_start, payload_size, phdr_start, phdrs_nr,
417823f0493SLoGin 		     &program_paddr, &program_size, &image_link_base_paddr);
418823f0493SLoGin 	payload_info->loaded_paddr = program_paddr;
419823f0493SLoGin 	payload_info->loaded_size = program_size;
420823f0493SLoGin 	payload_info->kernel_entry =
421823f0493SLoGin 		ehdr->e_entry - image_link_base_paddr + program_paddr;
422*2604d783SLoGin 
423*2604d783SLoGin 	// 处理权限问题
424*2604d783SLoGin 
425*2604d783SLoGin 	efi_remap_image_all_rwx(program_paddr, program_size);
426*2604d783SLoGin 	extern void _start(void);
427*2604d783SLoGin 	extern void _image_end(void);
428*2604d783SLoGin 	u64 image_size = (u64)&_image_end - (u64)&_start;
429*2604d783SLoGin 	efi_debug("image_size: %d\n", image_size);
430*2604d783SLoGin 	efi_remap_image_all_rwx((u64)&_start, (image_size + 4095) & ~4095);
431*2604d783SLoGin 
432823f0493SLoGin 	return EFI_SUCCESS;
433823f0493SLoGin }