elf.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. #include "elf.h"
  2. #include "dragonstub/linux/align.h"
  3. #include <efi.h>
  4. #include <efiapi.h>
  5. #include <efilib.h>
  6. #include <dragonstub/dragonstub.h>
  7. #include <dragonstub/elfloader.h>
  8. /// @brief 校验ELF文件头
  9. /// @param buf 缓冲区
  10. /// @param bufsize 缓冲区大小
  11. /// @return
  12. static bool verify_ident(const void *buf, u64 bufsize)
  13. {
  14. if (bufsize < EI_NIDENT) {
  15. // 太短,不是ELF
  16. return false;
  17. }
  18. // 检查magic number
  19. for (int i = 0; i < EI_CLASS; i++) {
  20. u8 c = *(u8 *)(buf + i);
  21. if (c != ELFMAG[i]) {
  22. // 不是ELF magic number,跳过
  23. efi_err("ELF magic number not match\n");
  24. return false;
  25. }
  26. }
  27. // verify ELF Version
  28. u8 version = *(u8 *)(buf + EI_VERSION);
  29. if (version != EV_CURRENT) {
  30. efi_err("ELF version not match, expected EV_CURRENT(%d), got %d\n",
  31. EV_CURRENT, version);
  32. // 不是当前版本,跳过
  33. return false;
  34. }
  35. // verify ELF Class
  36. u8 class = *(u8 *)(buf + EI_CLASS);
  37. if (class != ELFCLASS64) {
  38. efi_err("ELF class not match, expected ELFCLASS64(%d), got %d\n",
  39. ELFCLASS64, class);
  40. // 不是64位,跳过
  41. return false;
  42. }
  43. return true;
  44. }
  45. bool elf_check(const void *payload_start, u64 payload_size)
  46. {
  47. // 校验ELF文件头
  48. if (!verify_ident(payload_start, payload_size)) {
  49. return false;
  50. }
  51. // 检查架构
  52. Elf64_Ehdr *ehdr = (Elf64_Ehdr *)payload_start;
  53. #ifdef CONFIG_riscv64
  54. if (ehdr->e_machine != EM_RISCV) {
  55. efi_err("ELF machine not match, expected EM_RISCV(%d), got %d\n",
  56. EM_RISCV, ehdr->e_machine);
  57. return false;
  58. }
  59. #else
  60. // 还没有对当前架构进行检查,抛出编译错误
  61. #error "Unimplement ELF arch test for current cross compile arch"
  62. #endif
  63. return true;
  64. }
  65. /// @brief 获取ELF文件头
  66. /// @param payload_start 文件起始地址
  67. /// @param payload_size 文件大小
  68. /// @param ehdr 返回的ELF文件头
  69. /// @return
  70. efi_status_t elf_get_header(const void *payload_start, u64 payload_size,
  71. Elf64_Ehdr **ehdr)
  72. {
  73. if (!verify_ident(payload_start, payload_size)) {
  74. return EFI_INVALID_PARAMETER;
  75. }
  76. *ehdr = (Elf64_Ehdr *)payload_start;
  77. return EFI_SUCCESS;
  78. }
  79. static void print_elf_info(Elf64_Ehdr *ehdr)
  80. {
  81. efi_info("ELF header:\n");
  82. efi_printk(" e_type: %d\n", ehdr->e_type);
  83. efi_printk(" e_machine: %d\n", ehdr->e_machine);
  84. efi_printk(" e_version: %d\n", ehdr->e_version);
  85. efi_printk(" e_entry: %p\n", ehdr->e_entry);
  86. efi_printk(" e_phoff: %p\n", ehdr->e_phoff);
  87. efi_printk(" e_shoff: %p\n", ehdr->e_shoff);
  88. efi_printk(" e_flags: %d\n", ehdr->e_flags);
  89. efi_printk(" e_ehsize: %d\n", ehdr->e_ehsize);
  90. efi_printk(" e_phentsize: %d\n", ehdr->e_phentsize);
  91. efi_printk(" e_phnum: %d\n", ehdr->e_phnum);
  92. efi_printk(" e_shentsize: %d\n", ehdr->e_shentsize);
  93. efi_printk(" e_shnum: %d\n", ehdr->e_shnum);
  94. efi_printk(" e_shstrndx: %d\n", ehdr->e_shstrndx);
  95. }
  96. static efi_status_t parse_phdrs(const void *payload_start, u64 payload_size,
  97. const Elf64_Ehdr *ehdr, u32 *ret_segments_nr,
  98. Elf64_Phdr **ret_phdr)
  99. {
  100. if (ehdr->e_phnum == 0) {
  101. efi_err("No program header\n");
  102. return EFI_INVALID_PARAMETER;
  103. }
  104. if (ehdr->e_phentsize != sizeof(Elf64_Phdr)) {
  105. efi_err("Invalid program header size: %d, expected %d\n",
  106. ehdr->e_phentsize, sizeof(Elf64_Phdr));
  107. return EFI_INVALID_PARAMETER;
  108. }
  109. u16 phnum = ehdr->e_phnum;
  110. if (phnum == PN_XNUM) {
  111. u64 shoff = ehdr->e_shoff;
  112. if (shoff == 0) {
  113. efi_err("No section header\n");
  114. return EFI_INVALID_PARAMETER;
  115. }
  116. if (shoff + sizeof(Elf64_Shdr) > payload_size) {
  117. efi_err("Section header out of range\n");
  118. return EFI_INVALID_PARAMETER;
  119. }
  120. Elf64_Shdr *shdr = (Elf64_Shdr *)(payload_start + shoff);
  121. phnum = shdr[0].sh_info;
  122. if (phnum == 0) {
  123. efi_err("shdr[0].sh_info indicates no program header\n");
  124. return EFI_INVALID_PARAMETER;
  125. }
  126. }
  127. size_t phoff = ehdr->e_phoff;
  128. size_t phsize = ehdr->e_phentsize;
  129. size_t total_size = phnum * phsize;
  130. if (phoff + total_size > payload_size) {
  131. efi_err("Program header out of range\n");
  132. return EFI_INVALID_PARAMETER;
  133. }
  134. Elf64_Phdr *phdr = (Elf64_Phdr *)(payload_start + phoff);
  135. *ret_segments_nr = phnum;
  136. *ret_phdr = phdr;
  137. return EFI_SUCCESS;
  138. }
  139. /*
  140. * Distro versions of GRUB may ignore the BSS allocation entirely (i.e., fail
  141. * to provide space, and fail to zero it). Check for this condition by double
  142. * checking that the first and the last byte of the image are covered by the
  143. * same EFI memory map entry.
  144. */
  145. static bool check_image_region(u64 base, u64 size)
  146. {
  147. struct efi_boot_memmap *map;
  148. efi_status_t status;
  149. bool ret = false;
  150. u64 map_offset;
  151. status = efi_get_memory_map(&map, false);
  152. if (status != EFI_SUCCESS)
  153. return false;
  154. for (map_offset = 0; map_offset < map->map_size;
  155. map_offset += map->desc_size) {
  156. efi_memory_desc_t *md = (void *)map->map + map_offset;
  157. u64 end = md->PhysicalStart + md->NumberOfPages * EFI_PAGE_SIZE;
  158. /*
  159. * Find the region that covers base, and return whether
  160. * it covers base+size bytes.
  161. */
  162. if (base >= md->PhysicalStart && base < end) {
  163. ret = (base + size) <= end;
  164. break;
  165. }
  166. }
  167. efi_bs_call(FreePool, map);
  168. return ret;
  169. }
  170. efi_status_t efi_allocate_kernel_memory(const Elf64_Phdr *phdr_start,
  171. u32 phdrs_nr, u64 *ret_paddr,
  172. u64 *ret_size, u64 *ret_min_paddr,
  173. u64 *ret_max_paddr)
  174. {
  175. efi_status_t status = EFI_SUCCESS;
  176. const Elf64_Phdr *phdr = phdr_start;
  177. u64 min_paddr = UINT64_MAX;
  178. u64 max_paddr = 0;
  179. for (u32 i = 0; i < phdrs_nr; ++i, ++phdr) {
  180. if (phdr->p_type != PT_LOAD) {
  181. continue;
  182. }
  183. if (phdr->p_align & !EFI_PAGE_SIZE) {
  184. efi_err("ELF segment alignment should be multiple of EFI_PAGE_SIZE(%d), but got %d\n",
  185. EFI_PAGE_SIZE, phdr->p_align);
  186. return EFI_INVALID_PARAMETER;
  187. }
  188. min_paddr = min(min_paddr, (u64)phdr->p_paddr);
  189. max_paddr =
  190. max(max_paddr, (u64)(phdr->p_paddr + phdr->p_memsz));
  191. }
  192. u64 mem_size = ALIGN_UP(max_paddr - min_paddr, EFI_PAGE_SIZE);
  193. status = efi_allocate_pages_aligned(mem_size, ret_paddr, UINT64_MAX,
  194. EFI_PAGE_SIZE, EfiLoaderData);
  195. // status = efi_allocate_pages_exact(mem_size, paddr);
  196. if (status != EFI_SUCCESS) {
  197. 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",
  198. status, EFI_PAGE_SIZE, ret_paddr, max_paddr, mem_size);
  199. return status;
  200. }
  201. *ret_size = mem_size;
  202. *ret_min_paddr = min_paddr;
  203. *ret_max_paddr = max_paddr;
  204. efi_info("Allocated kernel memory: paddr=%p, mem_size= %d bytes\n",
  205. *ret_paddr, mem_size);
  206. // zeroed the memory
  207. memset((void *)(*ret_paddr), 0, mem_size);
  208. return EFI_SUCCESS;
  209. }
  210. static efi_status_t load_program(const void *payload_start, u64 payload_size,
  211. const Elf64_Phdr *phdr_start, u32 phdrs_nr,
  212. u64 *ret_program_mem_paddr,
  213. u64 *ret_program_mem_size, u64 *ret_min_paddr)
  214. {
  215. efi_status_t status = EFI_SUCCESS;
  216. u64 allocated_paddr = 0;
  217. u64 allocated_size = 0;
  218. u64 min_paddr = 0;
  219. u64 max_paddr = 0;
  220. status = efi_allocate_kernel_memory(phdr_start, phdrs_nr,
  221. &allocated_paddr, &allocated_size,
  222. &min_paddr, &max_paddr);
  223. if (status != EFI_SUCCESS) {
  224. efi_err("Failed to allocate kernel memory\n");
  225. return status;
  226. }
  227. const Elf64_Phdr *phdr = phdr_start;
  228. for (u32 i = 0; i < phdrs_nr; ++i, ++phdr) {
  229. if (phdr->p_type != PT_LOAD) {
  230. continue;
  231. }
  232. if (phdr->p_align & !EFI_PAGE_SIZE) {
  233. efi_err("ELF segment alignment should be multiple of EFI_PAGE_SIZE(%d), but got %d\n",
  234. EFI_PAGE_SIZE, phdr->p_align);
  235. status = EFI_INVALID_PARAMETER;
  236. goto failed;
  237. }
  238. u64 paddr = phdr->p_paddr;
  239. u64 mem_size = phdr->p_memsz;
  240. u64 file_size = phdr->p_filesz;
  241. u64 file_offset = phdr->p_offset;
  242. // efi_debug(
  243. // "loading segment: paddr=%p, mem_size=%d, file_size=%d\n",
  244. // paddr, mem_size, file_size);
  245. if (file_offset + file_size > payload_size) {
  246. status = EFI_INVALID_PARAMETER;
  247. goto failed;
  248. }
  249. if (mem_size < file_size) {
  250. status = EFI_INVALID_PARAMETER;
  251. goto failed;
  252. }
  253. if (mem_size == 0) {
  254. continue;
  255. }
  256. memcpy((void *)(allocated_paddr + (paddr - min_paddr)),
  257. payload_start + file_offset, file_size);
  258. // efi_debug(
  259. // "segment loaded: paddr=%p, mem_size=%d, file_size=%d\n",
  260. // paddr, mem_size, file_size);
  261. }
  262. *ret_program_mem_paddr = allocated_paddr;
  263. *ret_program_mem_size = allocated_size;
  264. *ret_min_paddr = min_paddr;
  265. return EFI_SUCCESS;
  266. failed:
  267. efi_free(allocated_size, allocated_paddr);
  268. return status;
  269. }
  270. efi_status_t load_elf(struct payload_info *payload_info)
  271. {
  272. const void *payload_start = (void *)payload_info->payload_addr;
  273. u64 payload_size = payload_info->payload_size;
  274. Elf64_Ehdr *ehdr = NULL;
  275. efi_status_t status =
  276. elf_get_header(payload_start, payload_size, &ehdr);
  277. if (status != EFI_SUCCESS) {
  278. efi_err("Failed to get ELF header\n");
  279. return status;
  280. }
  281. ASSERT(ehdr != NULL);
  282. print_elf_info(ehdr);
  283. u32 phdrs_nr = 0;
  284. Elf64_Phdr *phdr_start = NULL;
  285. status = parse_phdrs(payload_start, payload_size, ehdr, &phdrs_nr,
  286. &phdr_start);
  287. if (status != EFI_SUCCESS) {
  288. efi_err("Failed to parse ELF segments\n");
  289. return status;
  290. }
  291. efi_debug("program headers: %d\n", phdrs_nr);
  292. u64 program_paddr = 0;
  293. u64 program_size = 0;
  294. u64 image_link_base_paddr = 0;
  295. load_program(payload_start, payload_size, phdr_start, phdrs_nr,
  296. &program_paddr, &program_size, &image_link_base_paddr);
  297. payload_info->loaded_paddr = program_paddr;
  298. payload_info->loaded_size = program_size;
  299. payload_info->kernel_entry =
  300. ehdr->e_entry - image_link_base_paddr + program_paddr;
  301. return EFI_SUCCESS;
  302. }