You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

elf_loader.c 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  1. #include "elf.h"
  2. #ifndef ELF_CHECK_ARCH
  3. #error ELF_CHECK_ARCH not defined
  4. #endif
  5. #define ELF_NOTES 1
  6. #define ELF_DEBUG 0
  7. struct elf_state
  8. {
  9. union {
  10. Elf32_Ehdr elf32;
  11. Elf64_Ehdr elf64;
  12. } e;
  13. union {
  14. Elf32_Phdr phdr32[1];
  15. Elf64_Phdr phdr64[1];
  16. unsigned char dummy[1024];
  17. } p;
  18. unsigned long curaddr;
  19. int segment; /* current segment number, -1 for none */
  20. uint64_t loc; /* start offset of current block */
  21. uint64_t skip; /* padding to be skipped to current segment */
  22. unsigned long toread; /* remaining data to be read in the segment */
  23. #if ELF_NOTES
  24. int check_ip_checksum;
  25. uint16_t ip_checksum;
  26. unsigned long ip_checksum_offset;
  27. #endif
  28. };
  29. static struct elf_state estate;
  30. static unsigned long find_segment(unsigned long size, unsigned long align)
  31. {
  32. unsigned i;
  33. /* Verify I have a power of 2 alignment */
  34. if (align & (align - 1)) {
  35. return ULONG_MAX;
  36. }
  37. for(i = 0; i < meminfo.map_count; i++) {
  38. unsigned long r_start, r_end;
  39. if (meminfo.map[i].type != E820_RAM)
  40. continue;
  41. if ((meminfo.map[i].addr + meminfo.map[i].size) > ULONG_MAX) {
  42. continue;
  43. }
  44. r_start = meminfo.map[i].addr;
  45. r_end = r_start + meminfo.map[i].size;
  46. /* Don't allow the segment to overlap etherboot */
  47. if ((r_end > virt_to_phys(_text)) && (r_start < virt_to_phys(_text))) {
  48. r_end = virt_to_phys(_text);
  49. }
  50. if ((r_start > virt_to_phys(_text)) && (r_start < virt_to_phys(_end))) {
  51. r_start = virt_to_phys(_end);
  52. }
  53. /* Don't allow the segment to overlap the heap */
  54. if ((r_end > heap_ptr) && (r_start < heap_ptr)) {
  55. r_end = heap_ptr;
  56. }
  57. if ((r_start > heap_ptr) && (r_start < heap_bot)) {
  58. r_start = heap_ptr;
  59. }
  60. r_start = (r_start + align - 1) & ~(align - 1);
  61. if ((r_end >= r_start) && ((r_end - r_start) >= size)) {
  62. return r_start;
  63. }
  64. }
  65. /* I did not find anything :( */
  66. return ULONG_MAX;
  67. }
  68. static void elf_boot(unsigned long machine, unsigned long entry)
  69. {
  70. int result;
  71. struct Elf_Bhdr *hdr;
  72. multiboot_boot(entry);
  73. /* We cleanup unconditionally, and then reawaken the network
  74. * adapter after the longjmp.
  75. */
  76. hdr = prepare_boot_params(&estate.e);
  77. result = elf_start(machine, entry, virt_to_phys(hdr));
  78. if (result == 0) {
  79. result = -1;
  80. }
  81. printf("Secondary program returned %d\n", result);
  82. longjmp(restart_etherboot, result);
  83. }
  84. #if ELF_NOTES
  85. static int elf_prep_segment(
  86. unsigned long start __unused, unsigned long mid __unused, unsigned long end __unused,
  87. unsigned long istart, unsigned long iend)
  88. {
  89. if (estate.check_ip_checksum) {
  90. if ((istart <= estate.ip_checksum_offset) &&
  91. (iend > estate.ip_checksum_offset)) {
  92. /* The checksum note is also loaded in a
  93. * PT_LOAD segment, so the computed checksum
  94. * should be 0.
  95. */
  96. estate.ip_checksum = 0;
  97. }
  98. }
  99. return 1;
  100. }
  101. #else
  102. #define elf_prep_segment(start, mid, end, istart, iend) (1)
  103. #endif
  104. #if ELF_NOTES
  105. static void process_elf_notes(unsigned char *header,
  106. unsigned long offset, unsigned long length)
  107. {
  108. unsigned char *note, *end;
  109. char *program, *version;
  110. estate.check_ip_checksum = 0;
  111. note = header + offset;
  112. end = note + length;
  113. program = version = 0;
  114. while(note < end) {
  115. Elf_Nhdr *hdr;
  116. unsigned char *n_name, *n_desc, *next;
  117. hdr = (Elf_Nhdr *)note;
  118. n_name = note + sizeof(*hdr);
  119. n_desc = n_name + ((hdr->n_namesz + 3) & ~3);
  120. next = n_desc + ((hdr->n_descsz + 3) & ~3);
  121. if (next > end) {
  122. break;
  123. }
  124. if ((hdr->n_namesz == sizeof(ELF_NOTE_BOOT)) &&
  125. (memcmp(n_name, ELF_NOTE_BOOT, sizeof(ELF_NOTE_BOOT)) == 0)) {
  126. switch(hdr->n_type) {
  127. case EIN_PROGRAM_NAME:
  128. if (n_desc[hdr->n_descsz -1] == 0) {
  129. program = n_desc;
  130. }
  131. break;
  132. case EIN_PROGRAM_VERSION:
  133. if (n_desc[hdr->n_descsz -1] == 0) {
  134. version = n_desc;
  135. }
  136. break;
  137. case EIN_PROGRAM_CHECKSUM:
  138. estate.check_ip_checksum = 1;
  139. estate.ip_checksum = *((uint16_t *)n_desc);
  140. /* Remember where the segment is so
  141. * I can detect segment overlaps.
  142. */
  143. estate.ip_checksum_offset = n_desc - header;
  144. #if ELF_DEBUG
  145. printf("Checksum: %hx\n", estate.ip_checksum);
  146. #endif
  147. break;
  148. }
  149. }
  150. #if ELF_DEBUG
  151. printf("n_type: %x n_name(%d): %s n_desc(%d): %s\n",
  152. hdr->n_type,
  153. hdr->n_namesz, n_name,
  154. hdr->n_descsz, n_desc);
  155. #endif
  156. note = next;
  157. }
  158. if (program && version) {
  159. printf("\nLoading %s version: %s\n", program, version);
  160. }
  161. }
  162. #endif
  163. #ifdef ELF_IMAGE
  164. static sector_t elf32_download(unsigned char *data, unsigned int len, int eof);
  165. static inline os_download_t elf32_probe(unsigned char *data, unsigned int len)
  166. {
  167. unsigned long phdr_size;
  168. if (len < sizeof(estate.e.elf32)) {
  169. return 0;
  170. }
  171. memcpy(&estate.e.elf32, data, sizeof(estate.e.elf32));
  172. if ((estate.e.elf32.e_ident[EI_MAG0] != ELFMAG0) ||
  173. (estate.e.elf32.e_ident[EI_MAG1] != ELFMAG1) ||
  174. (estate.e.elf32.e_ident[EI_MAG2] != ELFMAG2) ||
  175. (estate.e.elf32.e_ident[EI_MAG3] != ELFMAG3) ||
  176. (estate.e.elf32.e_ident[EI_CLASS] != ELFCLASS32) ||
  177. (estate.e.elf32.e_ident[EI_DATA] != ELFDATA_CURRENT) ||
  178. (estate.e.elf32.e_ident[EI_VERSION] != EV_CURRENT) ||
  179. ( (estate.e.elf32.e_type != ET_EXEC) &&
  180. (estate.e.elf32.e_type != ET_DYN)) ||
  181. (estate.e.elf32.e_version != EV_CURRENT) ||
  182. (estate.e.elf32.e_ehsize != sizeof(Elf32_Ehdr)) ||
  183. (estate.e.elf32.e_phentsize != sizeof(Elf32_Phdr)) ||
  184. !ELF_CHECK_ARCH(estate.e.elf32)) {
  185. return 0;
  186. }
  187. printf("(ELF");
  188. elf_freebsd_probe();
  189. multiboot_probe(data, len);
  190. printf(")... ");
  191. phdr_size = estate.e.elf32.e_phnum * estate.e.elf32.e_phentsize;
  192. if (estate.e.elf32.e_phoff + phdr_size > len) {
  193. printf("ELF header outside first block\n");
  194. return dead_download;
  195. }
  196. if (phdr_size > sizeof(estate.p.dummy)) {
  197. printf("Program header to big\n");
  198. return dead_download;
  199. }
  200. memcpy(&estate.p.phdr32, data + estate.e.elf32.e_phoff, phdr_size);
  201. if (estate.e.elf32.e_type == ET_DYN) {
  202. Elf32_Addr min, max, base_addr, delta, align;
  203. min = -1;
  204. max = 0;
  205. align = 1;
  206. for(estate.segment = 0; estate.segment < estate.e.elf32.e_phnum; estate.segment++) {
  207. Elf32_Addr val;
  208. if (estate.p.phdr32[estate.segment].p_type != PT_LOAD)
  209. continue;
  210. val = estate.p.phdr32[estate.segment].p_paddr;
  211. if (val < min) {
  212. min = val;
  213. }
  214. val += estate.p.phdr32[estate.segment].p_memsz;
  215. if (val > max) {
  216. max = val;
  217. }
  218. if (estate.p.phdr32[estate.segment].p_align > align) {
  219. align = estate.p.phdr32[estate.segment].p_align;
  220. }
  221. }
  222. if (align & (align -1)) {
  223. printf("ELF base address alignment is not a power of 2\n");
  224. return dead_download;
  225. }
  226. base_addr = find_segment(max - min, align);
  227. if (base_addr == ULONG_MAX) {
  228. printf("ELF base address not available for size %ld\n", max - min);
  229. return dead_download;
  230. }
  231. /* Compute the change in base address and fix up the addresses */
  232. delta = base_addr - min;
  233. for(estate.segment = 0; estate.segment < estate.e.elf32.e_phnum; estate.segment++) {
  234. /* Change the base address of the object to load */
  235. estate.p.phdr32[estate.segment].p_paddr += delta;
  236. }
  237. estate.e.elf32.e_entry += delta;
  238. }
  239. #if ELF_NOTES
  240. /* Load ELF notes from the image */
  241. for(estate.segment = 0; estate.segment < estate.e.elf32.e_phnum; estate.segment++) {
  242. if (estate.p.phdr32[estate.segment].p_type != PT_NOTE)
  243. continue;
  244. if (estate.p.phdr32[estate.segment].p_offset + estate.p.phdr32[estate.segment].p_filesz > len) {
  245. /* Ignore ELF notes outside of the first block */
  246. continue;
  247. }
  248. process_elf_notes(data,
  249. estate.p.phdr32[estate.segment].p_offset, estate.p.phdr32[estate.segment].p_filesz);
  250. }
  251. #endif
  252. /* Check for Etherboot related limitations. Memory
  253. * between _text and _end is not allowed.
  254. * Reasons: the Etherboot code/data area.
  255. */
  256. for (estate.segment = 0; estate.segment < estate.e.elf32.e_phnum; estate.segment++) {
  257. unsigned long start, mid, end, istart, iend;
  258. if (estate.p.phdr32[estate.segment].p_type != PT_LOAD)
  259. continue;
  260. elf_freebsd_fixup_segment();
  261. start = estate.p.phdr32[estate.segment].p_paddr;
  262. mid = start + estate.p.phdr32[estate.segment].p_filesz;
  263. end = start + estate.p.phdr32[estate.segment].p_memsz;
  264. istart = estate.p.phdr32[estate.segment].p_offset;
  265. iend = istart + estate.p.phdr32[estate.segment].p_filesz;
  266. if (!prep_segment(start, mid, end, istart, iend)) {
  267. return dead_download;
  268. }
  269. if (!elf_prep_segment(start, mid, end, istart, iend)) {
  270. return dead_download;
  271. }
  272. }
  273. estate.segment = -1;
  274. estate.loc = 0;
  275. estate.skip = 0;
  276. estate.toread = 0;
  277. return elf32_download;
  278. }
  279. static sector_t elf32_download(unsigned char *data, unsigned int len, int eof)
  280. {
  281. unsigned long skip_sectors = 0;
  282. unsigned int offset; /* working offset in the current data block */
  283. int i;
  284. offset = 0;
  285. do {
  286. if (estate.segment != -1) {
  287. if (estate.skip) {
  288. if (estate.skip >= len - offset) {
  289. estate.skip -= len - offset;
  290. break;
  291. }
  292. offset += estate.skip;
  293. estate.skip = 0;
  294. }
  295. if (estate.toread) {
  296. unsigned int cplen;
  297. cplen = len - offset;
  298. if (cplen >= estate.toread) {
  299. cplen = estate.toread;
  300. }
  301. memcpy(phys_to_virt(estate.curaddr), data+offset, cplen);
  302. estate.curaddr += cplen;
  303. estate.toread -= cplen;
  304. offset += cplen;
  305. if (estate.toread)
  306. break;
  307. elf_freebsd_find_segment_end();
  308. }
  309. }
  310. /* Data left, but current segment finished - look for the next
  311. * segment (in file offset order) that needs to be loaded.
  312. * We can only seek forward, so select the program headers,
  313. * in the correct order.
  314. */
  315. estate.segment = -1;
  316. for (i = 0; i < estate.e.elf32.e_phnum; i++) {
  317. if (estate.p.phdr32[i].p_type != PT_LOAD)
  318. continue;
  319. if (estate.p.phdr32[i].p_filesz == 0)
  320. continue;
  321. if (estate.p.phdr32[i].p_offset < estate.loc + offset)
  322. continue; /* can't go backwards */
  323. if ((estate.segment != -1) &&
  324. (estate.p.phdr32[i].p_offset >= estate.p.phdr32[estate.segment].p_offset))
  325. continue; /* search minimum file offset */
  326. estate.segment = i;
  327. }
  328. if (estate.segment == -1) {
  329. if (elf_freebsd_debug_loader(offset)) {
  330. estate.segment = 0; /* -1 makes it not read anymore */
  331. continue;
  332. }
  333. /* No more segments to be loaded, so just start the
  334. * kernel. This saves a lot of network bandwidth if
  335. * debug info is in the kernel but not loaded. */
  336. goto elf_startkernel;
  337. break;
  338. }
  339. estate.curaddr = estate.p.phdr32[estate.segment].p_paddr;
  340. estate.skip = estate.p.phdr32[estate.segment].p_offset - (estate.loc + offset);
  341. estate.toread = estate.p.phdr32[estate.segment].p_filesz;
  342. #if ELF_DEBUG
  343. printf("PHDR %d, size %#lX, curaddr %#lX\n",
  344. estate.segment, estate.toread, estate.curaddr);
  345. #endif
  346. } while (offset < len);
  347. estate.loc += len + (estate.skip & ~0x1ff);
  348. skip_sectors = estate.skip >> 9;
  349. estate.skip &= 0x1ff;
  350. if (eof) {
  351. unsigned long entry;
  352. unsigned long machine;
  353. elf_startkernel:
  354. entry = estate.e.elf32.e_entry;
  355. machine = estate.e.elf32.e_machine;
  356. #if ELF_NOTES
  357. if (estate.check_ip_checksum) {
  358. unsigned long bytes = 0;
  359. uint16_t sum, new_sum;
  360. sum = ipchksum(&estate.e.elf32, sizeof(estate.e.elf32));
  361. bytes = sizeof(estate.e.elf32);
  362. #if ELF_DEBUG
  363. printf("Ehdr: %hx %hx sz: %lx bytes: %lx\n",
  364. sum, sum, bytes, bytes);
  365. #endif
  366. new_sum = ipchksum(estate.p.phdr32, sizeof(estate.p.phdr32[0]) * estate.e.elf32.e_phnum);
  367. sum = add_ipchksums(bytes, sum, new_sum);
  368. bytes += sizeof(estate.p.phdr32[0]) * estate.e.elf32.e_phnum;
  369. #if ELF_DEBUG
  370. printf("Phdr: %hx %hx sz: %lx bytes: %lx\n",
  371. new_sum, sum,
  372. sizeof(estate.p.phdr32[0]) * estate.e.elf32.e_phnum, bytes);
  373. #endif
  374. for(i = 0; i < estate.e.elf32.e_phnum; i++) {
  375. if (estate.p.phdr32[i].p_type != PT_LOAD)
  376. continue;
  377. new_sum = ipchksum(phys_to_virt(estate.p.phdr32[i].p_paddr),
  378. estate.p.phdr32[i].p_memsz);
  379. sum = add_ipchksums(bytes, sum, new_sum);
  380. bytes += estate.p.phdr32[i].p_memsz;
  381. #if ELF_DEBUG
  382. printf("seg%d: %hx %hx sz: %x bytes: %lx\n",
  383. i, new_sum, sum,
  384. estate.p.phdr32[i].p_memsz, bytes);
  385. #endif
  386. }
  387. if (estate.ip_checksum != sum) {
  388. printf("\nImage checksum: %hx != computed checksum: %hx\n",
  389. estate.ip_checksum, sum);
  390. longjmp(restart_etherboot, -2);
  391. }
  392. }
  393. #endif
  394. done(1);
  395. /* Fixup the offset to the program header so you can find the program headers from
  396. * the ELF header mknbi needs this.
  397. */
  398. estate.e.elf32.e_phoff = (char *)&estate.p - (char *)&estate.e;
  399. elf_freebsd_boot(entry);
  400. elf_boot(machine,entry);
  401. }
  402. return skip_sectors;
  403. }
  404. #endif /* ELF_IMAGE */
  405. #ifdef ELF64_IMAGE
  406. static sector_t elf64_download(unsigned char *data, unsigned int len, int eof);
  407. static inline os_download_t elf64_probe(unsigned char *data, unsigned int len)
  408. {
  409. unsigned long phdr_size;
  410. if (len < sizeof(estate.e.elf64)) {
  411. return 0;
  412. }
  413. memcpy(&estate.e.elf64, data, sizeof(estate.e.elf64));
  414. if ((estate.e.elf64.e_ident[EI_MAG0] != ELFMAG0) ||
  415. (estate.e.elf64.e_ident[EI_MAG1] != ELFMAG1) ||
  416. (estate.e.elf64.e_ident[EI_MAG2] != ELFMAG2) ||
  417. (estate.e.elf64.e_ident[EI_MAG3] != ELFMAG3) ||
  418. (estate.e.elf64.e_ident[EI_CLASS] != ELFCLASS64) ||
  419. (estate.e.elf64.e_ident[EI_DATA] != ELFDATA_CURRENT) ||
  420. (estate.e.elf64.e_ident[EI_VERSION] != EV_CURRENT) ||
  421. ( (estate.e.elf64.e_type != ET_EXEC) &&
  422. (estate.e.elf64.e_type != ET_DYN)) ||
  423. (estate.e.elf64.e_version != EV_CURRENT) ||
  424. (estate.e.elf64.e_ehsize != sizeof(Elf64_Ehdr)) ||
  425. (estate.e.elf64.e_phentsize != sizeof(Elf64_Phdr)) ||
  426. !ELF_CHECK_ARCH(estate.e.elf64)) {
  427. return 0;
  428. }
  429. printf("(ELF64)... ");
  430. phdr_size = estate.e.elf64.e_phnum * estate.e.elf64.e_phentsize;
  431. if (estate.e.elf64.e_phoff + phdr_size > len) {
  432. printf("ELF header outside first block\n");
  433. return dead_download;
  434. }
  435. if (phdr_size > sizeof(estate.p.dummy)) {
  436. printf("Program header to big\n");
  437. return dead_download;
  438. }
  439. if (estate.e.elf64.e_entry > ULONG_MAX) {
  440. printf("ELF entry point exceeds address space\n");
  441. return dead_download;
  442. }
  443. memcpy(&estate.p.phdr64, data + estate.e.elf64.e_phoff, phdr_size);
  444. if (estate.e.elf64.e_type == ET_DYN) {
  445. Elf64_Addr min, max, base_addr, delta, align;
  446. min = -1;
  447. max = 0;
  448. align = 1;
  449. for(estate.segment = 0; estate.segment < estate.e.elf64.e_phnum; estate.segment++) {
  450. Elf64_Addr val;
  451. if (estate.p.phdr64[estate.segment].p_type != PT_LOAD)
  452. continue;
  453. val = estate.p.phdr64[estate.segment].p_paddr;
  454. if (val < min) {
  455. min = val;
  456. }
  457. val += estate.p.phdr64[estate.segment].p_memsz;
  458. if (val > max) {
  459. max = val;
  460. }
  461. if (estate.p.phdr64[estate.segment].p_align > align) {
  462. align = estate.p.phdr64[estate.segment].p_align;
  463. }
  464. }
  465. if (align > ULONG_MAX) {
  466. printf("ELF base address alignment exceeds address space\n");
  467. return dead_download;
  468. }
  469. if (align & (align -1)) {
  470. printf("ELF base address alignment is not a power of 2\n");
  471. return dead_download;
  472. }
  473. if ((max - min) > ULONG_MAX) {
  474. printf("ELF size exceeds address space\n");
  475. return dead_download;
  476. }
  477. base_addr = find_segment(max - min, align);
  478. if (base_addr == ULONG_MAX) {
  479. printf("ELF base address not available for size %ld\n", max - min);
  480. return dead_download;
  481. }
  482. /* Compute the change in base address and fix up the addresses */
  483. delta = base_addr - min;
  484. for(estate.segment = 0; estate.segment < estate.e.elf64.e_phnum; estate.segment++) {
  485. /* Change the base address of the object to load */
  486. estate.p.phdr64[estate.segment].p_paddr += delta;
  487. }
  488. estate.e.elf64.e_entry += delta;
  489. }
  490. #if ELF_NOTES
  491. /* Load ELF notes from the image */
  492. for(estate.segment = 0; estate.segment < estate.e.elf64.e_phnum; estate.segment++) {
  493. if (estate.p.phdr64[estate.segment].p_type != PT_NOTE)
  494. continue;
  495. if (estate.p.phdr64[estate.segment].p_offset + estate.p.phdr64[estate.segment].p_filesz > len) {
  496. /* Ignore ELF notes outside of the first block */
  497. continue;
  498. }
  499. process_elf_notes(data,
  500. estate.p.phdr64[estate.segment].p_offset, estate.p.phdr64[estate.segment].p_filesz);
  501. }
  502. #endif
  503. /* Check for Etherboot related limitations. Memory
  504. * between _text and _end is not allowed.
  505. * Reasons: the Etherboot code/data area.
  506. */
  507. for (estate.segment = 0; estate.segment < estate.e.elf64.e_phnum; estate.segment++) {
  508. unsigned long start, mid, end, istart, iend;
  509. if (estate.p.phdr64[estate.segment].p_type != PT_LOAD)
  510. continue;
  511. if ((estate.p.phdr64[estate.segment].p_paddr > ULONG_MAX) ||
  512. ((estate.p.phdr64[estate.segment].p_paddr + estate.p.phdr64[estate.segment].p_filesz) > ULONG_MAX) ||
  513. ((estate.p.phdr64[estate.segment].p_paddr + estate.p.phdr64[estate.segment].p_memsz) > ULONG_MAX)) {
  514. printf("ELF segment exceeds address space\n");
  515. return dead_download;
  516. }
  517. start = estate.p.phdr64[estate.segment].p_paddr;
  518. mid = start + estate.p.phdr64[estate.segment].p_filesz;
  519. end = start + estate.p.phdr64[estate.segment].p_memsz;
  520. istart = iend = ULONG_MAX;
  521. if ((estate.p.phdr64[estate.segment].p_offset < ULONG_MAX) &&
  522. ((estate.p.phdr64[estate.segment].p_offset + estate.p.phdr64[estate.segment].p_filesz) < ULONG_MAX))
  523. {
  524. istart = estate.p.phdr64[estate.segment].p_offset;
  525. iend = istart + estate.p.phdr64[estate.segment].p_filesz;
  526. }
  527. if (!prep_segment(start, mid, end, istart, iend)) {
  528. return dead_download;
  529. }
  530. if (!elf_prep_segment(start, mid, end, istart, iend)) {
  531. return dead_download;
  532. }
  533. }
  534. estate.segment = -1;
  535. estate.loc = 0;
  536. estate.skip = 0;
  537. estate.toread = 0;
  538. return elf64_download;
  539. }
  540. static sector_t elf64_download(unsigned char *data, unsigned int len, int eof)
  541. {
  542. unsigned long skip_sectors = 0;
  543. unsigned int offset; /* working offset in the current data block */
  544. int i;
  545. offset = 0;
  546. do {
  547. if (estate.segment != -1) {
  548. if (estate.skip) {
  549. if (estate.skip >= len - offset) {
  550. estate.skip -= len - offset;
  551. break;
  552. }
  553. offset += estate.skip;
  554. estate.skip = 0;
  555. }
  556. if (estate.toread) {
  557. unsigned int cplen;
  558. cplen = len - offset;
  559. if (cplen >= estate.toread) {
  560. cplen = estate.toread;
  561. }
  562. memcpy(phys_to_virt(estate.curaddr), data+offset, cplen);
  563. estate.curaddr += cplen;
  564. estate.toread -= cplen;
  565. offset += cplen;
  566. if (estate.toread)
  567. break;
  568. }
  569. }
  570. /* Data left, but current segment finished - look for the next
  571. * segment (in file offset order) that needs to be loaded.
  572. * We can only seek forward, so select the program headers,
  573. * in the correct order.
  574. */
  575. estate.segment = -1;
  576. for (i = 0; i < estate.e.elf64.e_phnum; i++) {
  577. if (estate.p.phdr64[i].p_type != PT_LOAD)
  578. continue;
  579. if (estate.p.phdr64[i].p_filesz == 0)
  580. continue;
  581. if (estate.p.phdr64[i].p_offset < estate.loc + offset)
  582. continue; /* can't go backwards */
  583. if ((estate.segment != -1) &&
  584. (estate.p.phdr64[i].p_offset >= estate.p.phdr64[estate.segment].p_offset))
  585. continue; /* search minimum file offset */
  586. estate.segment = i;
  587. }
  588. if (estate.segment == -1) {
  589. /* No more segments to be loaded, so just start the
  590. * kernel. This saves a lot of network bandwidth if
  591. * debug info is in the kernel but not loaded. */
  592. goto elf_startkernel;
  593. break;
  594. }
  595. estate.curaddr = estate.p.phdr64[estate.segment].p_paddr;
  596. estate.skip = estate.p.phdr64[estate.segment].p_offset - (estate.loc + offset);
  597. estate.toread = estate.p.phdr64[estate.segment].p_filesz;
  598. #if ELF_DEBUG
  599. printf("PHDR %d, size %#lX, curaddr %#lX\n",
  600. estate.segment, estate.toread, estate.curaddr);
  601. #endif
  602. } while (offset < len);
  603. estate.loc += len + (estate.skip & ~0x1ff);
  604. skip_sectors = estate.skip >> 9;
  605. estate.skip &= 0x1ff;
  606. if (eof) {
  607. unsigned long entry;
  608. unsigned long machine;
  609. elf_startkernel:
  610. entry = estate.e.elf64.e_entry;
  611. machine = estate.e.elf64.e_machine;
  612. #if ELF_NOTES
  613. if (estate.check_ip_checksum) {
  614. unsigned long bytes = 0;
  615. uint16_t sum, new_sum;
  616. sum = ipchksum(&estate.e.elf64, sizeof(estate.e.elf64));
  617. bytes = sizeof(estate.e.elf64);
  618. #if ELF_DEBUG
  619. printf("Ehdr: %hx %hx sz: %lx bytes: %lx\n",
  620. sum, sum, bytes, bytes);
  621. #endif
  622. new_sum = ipchksum(estate.p.phdr64, sizeof(estate.p.phdr64[0]) * estate.e.elf64.e_phnum);
  623. sum = add_ipchksums(bytes, sum, new_sum);
  624. bytes += sizeof(estate.p.phdr64[0]) * estate.e.elf64.e_phnum;
  625. #if ELF_DEBUG
  626. printf("Phdr: %hx %hx sz: %lx bytes: %lx\n",
  627. new_sum, sum,
  628. sizeof(estate.p.phdr64[0]) * estate.e.elf64.e_phnum, bytes);
  629. #endif
  630. for(i = 0; i < estate.e.elf64.e_phnum; i++) {
  631. if (estate.p.phdr64[i].p_type != PT_LOAD)
  632. continue;
  633. new_sum = ipchksum(phys_to_virt(estate.p.phdr64[i].p_paddr),
  634. estate.p.phdr64[i].p_memsz);
  635. sum = add_ipchksums(bytes, sum, new_sum);
  636. bytes += estate.p.phdr64[i].p_memsz;
  637. #if ELF_DEBUG
  638. printf("seg%d: %hx %hx sz: %x bytes: %lx\n",
  639. i, new_sum, sum,
  640. estate.p.phdr64[i].p_memsz, bytes);
  641. #endif
  642. }
  643. if (estate.ip_checksum != sum) {
  644. printf("\nImage checksum: %hx != computed checksum: %hx\n",
  645. estate.ip_checksum, sum);
  646. longjmp(restart_etherboot, -2);
  647. }
  648. }
  649. #endif
  650. done(1);
  651. /* Fixup the offset to the program header so you can find the program headers from
  652. * the ELF header mknbi needs this.
  653. */
  654. estate.e.elf64.e_phoff = (char *)&estate.p - (char *)&estate.e;
  655. elf_boot(machine,entry);
  656. }
  657. return skip_sectors;
  658. }
  659. #endif /* ELF64_IMAGE */