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.

3177 lines
104 KiB

  1. /*
  2. * Copyright (c) 2008 Vreixo Formoso
  3. * Copyright (c) 2010 - 2017 Thomas Schmitt
  4. *
  5. * This file is part of the libisofs project; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License version 2
  7. * or later as published by the Free Software Foundation.
  8. * See COPYING file for details.
  9. */
  10. #ifdef HAVE_CONFIG_H
  11. #include "../config.h"
  12. #endif
  13. #include "libisofs.h"
  14. #include "system_area.h"
  15. #include "eltorito.h"
  16. #include "filesrc.h"
  17. #include "ecma119_tree.h"
  18. #include "image.h"
  19. #include "messages.h"
  20. #include "ecma119.h"
  21. #include "writer.h"
  22. #include <string.h>
  23. #include <stdio.h>
  24. #include <sys/types.h>
  25. #include <sys/stat.h>
  26. #include <unistd.h>
  27. #include <fcntl.h>
  28. /* for gettimeofday() */
  29. #include <sys/time.h>
  30. /* >>> Need ./configure test for uuid_generate() which checks for:
  31. uuid_t, uuid_generate, the need for -luuid
  32. */
  33. /*
  34. #define Libisofs_with_uuid_generatE 1
  35. */
  36. #ifdef Libisofs_with_uuid_generatE
  37. #include <uuid/uuid.h>
  38. #endif
  39. /* O_BINARY is needed for Cygwin but undefined elsewhere */
  40. #ifndef O_BINARY
  41. #define O_BINARY 0
  42. #endif
  43. /*
  44. * Create a MBR for an isohybrid enabled ISOLINUX boot image.
  45. * See libisofs/make_isohybrid_mbr.c
  46. * Deprecated.
  47. */
  48. int make_isohybrid_mbr(int bin_lba, int *img_blocks, char *mbr, int flag);
  49. /*
  50. * The New ISOLINUX MBR Producer.
  51. * Be cautious with changing parameters. Only few combinations are tested.
  52. *
  53. */
  54. int make_isolinux_mbr(uint32_t *img_blocks, Ecma119Image *t,
  55. int part_offset, int part_number, int fs_type,
  56. uint8_t *buf, int flag);
  57. /* Find out whether GPT and APM are desired by isohybrid
  58. flag bit0 = register APM and GPT requests in Ecma119Image
  59. */
  60. int assess_isohybrid_gpt_apm(Ecma119Image *t, int *gpt_count, int gpt_idx[128],
  61. int *apm_count, int flag);
  62. static int precompute_gpt(Ecma119Image *t);
  63. /*
  64. * @param flag bit0= img_blocks is start address rather than end address:
  65. do not subtract 1
  66. bit1= img_blocks is counted in 512-byte units rather than 2 KiB
  67. */
  68. static
  69. void iso_compute_cyl_head_sec(uint64_t img_blocks, int hpc, int sph,
  70. uint32_t *end_lba, uint32_t *end_sec,
  71. uint32_t *end_head, uint32_t *end_cyl, int flag)
  72. {
  73. uint64_t secs;
  74. if(flag & 2)
  75. secs = img_blocks;
  76. else
  77. secs = img_blocks * 4;
  78. if (secs > (uint64_t) 0xfffffffc)
  79. secs = 0xfffffffc; /* truncate rather than roll over */
  80. if (flag & 1)
  81. *end_lba = secs; /* first valid 512-lba */
  82. else
  83. secs = *end_lba = secs - 1; /* last valid 512-lba */
  84. *end_cyl = secs / (sph * hpc);
  85. secs -= *end_cyl * sph * hpc;
  86. *end_head = secs / sph;
  87. *end_sec = secs - *end_head * sph + 1; /* Sector count starts by 1 */
  88. if (*end_cyl >= 1024) {
  89. *end_cyl = 1023;
  90. *end_head = hpc - 1;
  91. *end_sec = sph;
  92. }
  93. }
  94. /* @param flag bit0= The path contains instructions for the interval reader
  95. @return ISO_SUCCESS = ok, partition will be written
  96. ISO_SUCCESS + 1 = interval which shall be kept in place
  97. else : error code
  98. */
  99. static int compute_partition_size(Ecma119Image *t, char *disk_path,
  100. uint32_t *size, int flag)
  101. {
  102. int ret, keep;
  103. off_t num;
  104. struct stat stbuf;
  105. struct iso_interval_reader *ivr;
  106. off_t byte_count;
  107. if (flag & 1) {
  108. ret = iso_interval_reader_new(t->image, disk_path,
  109. &ivr, &byte_count, 0);
  110. if (ret < 0)
  111. return ret;
  112. *size = (byte_count + BLOCK_SIZE - 1) / BLOCK_SIZE;
  113. keep = iso_interval_reader_keep(t, ivr, 0);
  114. iso_interval_reader_destroy(&ivr, 0);
  115. if (keep < 0)
  116. return keep;
  117. return ISO_SUCCESS + (keep > 0);
  118. }
  119. *size = 0;
  120. ret = stat(disk_path, &stbuf);
  121. if (ret == -1)
  122. return ISO_BAD_PARTITION_FILE;
  123. if (! S_ISREG(stbuf.st_mode))
  124. return ISO_BAD_PARTITION_FILE;
  125. num = ((stbuf.st_size + 2047) / 2048);
  126. if (num > 0x3fffffff || num == 0)
  127. return ISO_BAD_PARTITION_FILE;
  128. *size = num;
  129. return ISO_SUCCESS;
  130. }
  131. /* Compute size and position of appended partitions.
  132. @param flag bit0= Partitions inside ISO : update t->curblock
  133. */
  134. int iso_compute_append_partitions(Ecma119Image *t, int flag)
  135. {
  136. int ret, i, sa_type, cyl_align, cyl_size = 0;
  137. uint32_t pos, size, add_pos = 0;
  138. off_t start_byte, byte_count;
  139. sa_type = (t->system_area_options >> 2) & 0x3f;
  140. cyl_align = (t->system_area_options >> 8) & 0x3;
  141. if (sa_type == 0 && cyl_align == 3) {
  142. cyl_size = t->partition_heads_per_cyl * t->partition_secs_per_head;
  143. if (cyl_size % 4)
  144. cyl_size = 0;
  145. else
  146. cyl_size /= 4;
  147. }
  148. pos = (t->vol_space_size + t->opts->ms_block);
  149. for (i = 0; i < ISO_MAX_PARTITIONS; i++) {
  150. if (t->opts->appended_partitions[i] == NULL)
  151. continue;
  152. if (t->opts->appended_partitions[i][0] == 0)
  153. continue;
  154. ret = compute_partition_size(t, t->opts->appended_partitions[i], &size,
  155. t->opts->appended_part_flags[i]);
  156. if (ret < 0)
  157. return ret;
  158. if (ret == ISO_SUCCESS + 1) {
  159. /* Interval from imported_iso in add-on session */
  160. t->appended_part_prepad[i] = 0;
  161. ret = iso_interval_reader_start_size(t,
  162. t->opts->appended_partitions[i],
  163. &start_byte, &byte_count, 0);
  164. if (ret < 0)
  165. return ret;
  166. t->appended_part_start[i] = start_byte / 2048;
  167. t->appended_part_size[i] = size;
  168. t->opts->iso_mbr_part_type = 0;
  169. continue;
  170. }
  171. add_pos = 0;
  172. if (sa_type == 3 && (pos % ISO_SUN_CYL_SIZE)) {
  173. add_pos = ISO_SUN_CYL_SIZE - (pos % ISO_SUN_CYL_SIZE);
  174. } else if (cyl_size > 0 && (pos % cyl_size)) {
  175. add_pos = cyl_size - (pos % cyl_size);
  176. }
  177. t->appended_part_prepad[i] = add_pos;
  178. t->appended_part_start[i] = pos + add_pos;
  179. if (cyl_size > 0 && (size % cyl_size)) {
  180. /* Obey cylinder alignment (missing data will be written as
  181. zeros by iso_write_partition_file()) */
  182. size += cyl_size - (size % cyl_size);
  183. }
  184. t->appended_part_size[i] = size;
  185. pos += add_pos + size;
  186. t->total_size += (((off_t) add_pos) + size) * 2048;
  187. if (flag & 1)
  188. t->curblock = pos;
  189. }
  190. return ISO_SUCCESS;
  191. }
  192. static int mbr_part_slot_is_unused(uint8_t *slot)
  193. {
  194. int i;
  195. for (i = 0; i < 16; i++)
  196. if (slot[i] != 0)
  197. break;
  198. if (i >= 16)
  199. return 1;
  200. return 0;
  201. }
  202. /* @param flag
  203. bit1= partition_offset and partition_size are counted in
  204. blocks of 512 rather than 2048
  205. */
  206. static int write_mbr_partition_entry(int partition_number, int partition_type,
  207. uint64_t partition_offset, uint64_t partition_size,
  208. int sph, int hpc, uint8_t *buf, int flag)
  209. {
  210. uint8_t *wpt;
  211. uint32_t end_lba, end_sec, end_head, end_cyl;
  212. uint32_t start_lba, start_sec, start_head, start_cyl;
  213. uint32_t after_end;
  214. int i;
  215. after_end = partition_offset + partition_size;
  216. iso_compute_cyl_head_sec((uint64_t) partition_offset, hpc, sph,
  217. &start_lba, &start_sec, &start_head, &start_cyl,
  218. 1 | (flag & 2));
  219. iso_compute_cyl_head_sec((uint64_t) after_end, hpc, sph,
  220. &end_lba, &end_sec, &end_head, &end_cyl,
  221. (flag & 2));
  222. wpt = buf + 446 + (partition_number - 1) * 16;
  223. /* Not bootable */
  224. *(wpt++) = 0x00;
  225. /* C/H/S of the start */
  226. *(wpt++) = start_head;
  227. *(wpt++) = start_sec | ((start_cyl & 0x300) >> 2);
  228. *(wpt++) = start_cyl & 0xff;
  229. /* (partition type) */
  230. *(wpt++) = partition_type;
  231. /* 3 bytes of C/H/S end */
  232. *(wpt++) = end_head;
  233. *(wpt++) = end_sec | ((end_cyl & 0x300) >> 2);
  234. *(wpt++) = end_cyl & 0xff;
  235. /* LBA start in little endian */
  236. for (i = 0; i < 4; i++)
  237. *(wpt++) = (start_lba >> (8 * i)) & 0xff;
  238. /* Number of sectors in partition, little endian */
  239. end_lba = end_lba - start_lba + 1;
  240. for (i = 0; i < 4; i++)
  241. *(wpt++) = (end_lba >> (8 * i)) & 0xff;
  242. /* Afaik, partition tables are recognize donly with MBR signature */
  243. buf[510] = 0x55;
  244. buf[511] = 0xAA;
  245. return ISO_SUCCESS;
  246. }
  247. /* This is the gesture of grub-mkisofs --protective-msdos-label as explained by
  248. Vladimir Serbinenko <phcoder@gmail.com>, 2 April 2010, on grub-devel@gnu.org
  249. "Currently we use first and not last entry. You need to:
  250. 1) Zero-fill 446-510
  251. 2) Put 0x55, 0xAA into 510-512
  252. 3) Put 0x80 (for bootable partition), 0, 2, 0 (C/H/S of the start), 0xcd
  253. (partition type), [3 bytes of C/H/S end], 0x01, 0x00, 0x00, 0x00 (LBA
  254. start in little endian), [LBA end in little endian] at 446-462
  255. "
  256. "C/H/S end" means the CHS address of the last block in the partition.
  257. It seems that not "[LBA end in little endian]" but "number of blocks"
  258. should go into bytes 458-461. But with a start lba of 1, this is the
  259. same number.
  260. See also http://en.wikipedia.org/wiki/Master_boot_record
  261. flag bit0= do not write 0x55, 0xAA to 510,511
  262. bit1= do not mark partition as bootable
  263. */
  264. static
  265. int make_grub_msdos_label(uint32_t img_blocks, int sph, int hpc,
  266. uint8_t part_type, uint8_t *buf, int flag)
  267. {
  268. uint8_t *wpt;
  269. uint32_t end_lba, end_sec, end_head, end_cyl;
  270. int i;
  271. iso_compute_cyl_head_sec((uint64_t) img_blocks, hpc, sph,
  272. &end_lba, &end_sec, &end_head, &end_cyl, 0);
  273. /* 1) Zero-fill 446-510 */
  274. wpt = buf + 446;
  275. memset(wpt, 0, 64);
  276. if (!(flag & 1)) {
  277. /* 2) Put 0x55, 0xAA into 510-512 (actually 510-511) */
  278. buf[510] = 0x55;
  279. buf[511] = 0xAA;
  280. }
  281. if ((!(flag & 2)) && part_type != 0xee && part_type != 0xef) {
  282. /* 3) Put 0x80 (for bootable partition), */
  283. *(wpt++) = 0x80;
  284. } else {
  285. *(wpt++) = 0;
  286. }
  287. /* 0, 2, 0 (C/H/S of the start), */
  288. *(wpt++) = 0;
  289. *(wpt++) = 2;
  290. *(wpt++) = 0;
  291. /* 0xcd (partition type) */
  292. *(wpt++) = part_type;
  293. /* [3 bytes of C/H/S end], */
  294. *(wpt++) = end_head;
  295. *(wpt++) = end_sec | ((end_cyl & 0x300) >> 2);
  296. *(wpt++) = end_cyl & 0xff;
  297. /* 0x01, 0x00, 0x00, 0x00 (LBA start in little endian), */
  298. *(wpt++) = 0x01;
  299. *(wpt++) = 0x00;
  300. *(wpt++) = 0x00;
  301. *(wpt++) = 0x00;
  302. /* [LBA end in little endian] */
  303. for (i = 0; i < 4; i++)
  304. *(wpt++) = (end_lba >> (8 * i)) & 0xff;
  305. /* at 446-462 */
  306. if (wpt - buf != 462) {
  307. fprintf(stderr,
  308. "libisofs: program error in make_grub_msdos_label: \"assert 462\"\n");
  309. return ISO_ASSERT_FAILURE;
  310. }
  311. return ISO_SUCCESS;
  312. }
  313. /* @param flag bit0= zeroize partitions entries 2, 3, 4
  314. bit1= UEFI protective MBR: start LBA = 1
  315. */
  316. static
  317. int iso_offset_partition_start(uint32_t img_blocks, int post_part_pad,
  318. uint32_t partition_offset,
  319. int sph, int hpc, uint8_t *buf, int flag)
  320. {
  321. uint8_t *wpt;
  322. uint32_t end_lba, end_sec, end_head, end_cyl;
  323. uint32_t start_lba, start_sec, start_head, start_cyl;
  324. uint64_t img_hd_blocks;
  325. int i;
  326. iso_compute_cyl_head_sec((uint64_t) partition_offset, hpc, sph,
  327. &start_lba, &start_sec, &start_head, &start_cyl, 1);
  328. img_hd_blocks = ((uint64_t) img_blocks) * 4 - post_part_pad / 512;
  329. iso_compute_cyl_head_sec(img_hd_blocks, hpc, sph,
  330. &end_lba, &end_sec, &end_head, &end_cyl, 2);
  331. if (flag & 2) {
  332. start_lba = 1;
  333. start_sec = 2;
  334. start_head = start_cyl = 0;
  335. }
  336. wpt = buf + 446;
  337. /* Let pass only legal bootability values */
  338. if (*wpt != 0 && *wpt != 0x80)
  339. (*wpt) = 0;
  340. wpt++;
  341. /* C/H/S of the start */
  342. *(wpt++) = start_head;
  343. *(wpt++) = start_sec | ((start_cyl & 0x300) >> 2);
  344. *(wpt++) = start_cyl & 0xff;
  345. /* (partition type) */
  346. wpt++;
  347. /* 3 bytes of C/H/S end */
  348. *(wpt++) = end_head;
  349. *(wpt++) = end_sec | ((end_cyl & 0x300) >> 2);
  350. *(wpt++) = end_cyl & 0xff;
  351. /* LBA start in little endian */
  352. for (i = 0; i < 4; i++)
  353. *(wpt++) = (start_lba >> (8 * i)) & 0xff;
  354. /* Number of sectors in partition, little endian */
  355. end_lba = end_lba - start_lba + 1;
  356. for (i = 0; i < 4; i++)
  357. *(wpt++) = (end_lba >> (8 * i)) & 0xff;
  358. if (wpt - buf != 462) {
  359. fprintf(stderr,
  360. "libisofs: program error in iso_offset_partition_start: \"assert 462\"\n");
  361. return ISO_ASSERT_FAILURE;
  362. }
  363. if (flag & 1) /* zeroize the other partition entries */
  364. memset(wpt, 0, 3 * 16);
  365. return ISO_SUCCESS;
  366. }
  367. static int boot_nodes_from_iso_path(Ecma119Image *t, char *path,
  368. IsoNode **iso_node, Ecma119Node **ecma_node,
  369. char *purpose, int flag)
  370. {
  371. int ret;
  372. ret = iso_tree_path_to_node(t->image, path, iso_node);
  373. if (ret <= 0) {
  374. iso_msg_submit(t->image->id, ISO_BOOT_FILE_MISSING, 0,
  375. "Cannot find in ISO image: %s '%s'", purpose, path);
  376. return ISO_BOOT_FILE_MISSING;
  377. }
  378. if ((*iso_node)->type != LIBISO_FILE) {
  379. iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
  380. "Designated boot file is not a data file: '%s'", path);
  381. return ISO_BOOT_IMAGE_NOT_VALID;
  382. }
  383. *ecma_node= ecma119_search_iso_node(t, *iso_node);
  384. if (*ecma_node == NULL) {
  385. iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
  386. "Program error: IsoFile has no Ecma119Node: '%s'", path);
  387. return ISO_ASSERT_FAILURE;
  388. } else {
  389. if ((*ecma_node)->type != ECMA119_FILE) {
  390. iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
  391. "Program error: Ecma119Node of IsoFile is no ECMA119_FILE: '%s'",
  392. path);
  393. return ISO_ASSERT_FAILURE;
  394. }
  395. }
  396. return ISO_SUCCESS;
  397. }
  398. /* This function was implemented according to doc/boot_sectors.txt section
  399. "MIPS Volume Header" which was derived by Thomas Schmitt from
  400. cdrkit-1.1.10/genisoimage/boot-mips.c by Steve McIntyre which is based
  401. on work of Florian Lohoff and Thiemo Seufer who possibly learned from
  402. documents of MIPS Computer Systems, Inc. and Silicon Graphics Computer
  403. Systems, Inc.
  404. This function itself is entirely under copyright (C) 2010 Thomas Schmitt.
  405. */
  406. static int make_mips_volume_header(Ecma119Image *t, uint8_t *buf, int flag)
  407. {
  408. char *namept, *name_field;
  409. uint32_t num_cyl, idx, blocks, num, checksum;
  410. off_t image_size;
  411. static uint32_t bps = 512, spt = 32;
  412. Ecma119Node *ecma_node;
  413. IsoNode *node;
  414. IsoStream *stream;
  415. off_t file_size;
  416. uint32_t file_lba;
  417. int ret;
  418. /* Bytes 512 to 32767 may come from image or external file */
  419. memset(buf, 0, 512);
  420. image_size = t->curblock * 2048;
  421. /* 0 - 3 | 0x0be5a941 | Magic number */
  422. iso_msb(buf, 0x0be5a941, 4);
  423. /* 28 - 29 | num_cyl_l | Number of usable cylinder, lower two bytes */
  424. num_cyl = (image_size + (bps * spt) - 1) / (bps * spt);
  425. iso_msb(buf + 28, num_cyl & 0xffff, 2);
  426. /* 32 - 33 | 1 | Number of tracks per cylinder */
  427. iso_msb(buf + 32, 1, 2);
  428. /* 35 - 35 | num_cyl_h | Number of usable cylinders, high byte */
  429. buf[35] = (num_cyl >> 16) & 0xff;
  430. /* 38 - 39 | 32 | Sectors per track */
  431. iso_msb(buf + 38, spt, 2);
  432. /* 40 - 41 | 512 | Bytes per sector */
  433. iso_msb(buf + 40, bps, 2);
  434. /* 44 - 47 | 0x00000034 | Controller characteristics */
  435. iso_msb(buf + 44, 0x00000034, 4);
  436. /* 72 - 87 | ========== | Volume Directory Entry 1 */
  437. /* 72 - 79 | boot_name | Boot file basename */
  438. /* 80 - 83 | boot_block | ISO 9660 LBA of boot file * 4 */
  439. /* 84 - 87 | boot_bytes | File length in bytes */
  440. /* 88 - 311 | 0 | Volume Directory Entries 2 to 15 */
  441. for (idx = 0; (int) idx < t->image->num_mips_boot_files; idx++) {
  442. ret = boot_nodes_from_iso_path(t, t->image->mips_boot_file_paths[idx],
  443. &node, &ecma_node, "MIPS boot file", 0);
  444. if (ret < 0)
  445. return ret;
  446. namept = (char *) iso_node_get_name(node);
  447. name_field = (char *) (buf + (72 + 16 * idx));
  448. strncpy(name_field, namept, 8);
  449. file_lba = ecma_node->info.file->sections[0].block;
  450. iso_msb(buf + (72 + 16 * idx) + 8, file_lba * 4, 4);
  451. stream = iso_file_get_stream((IsoFile *) node);
  452. file_size = iso_stream_get_size(stream);
  453. /* Shall i really round up to 2048 ? Steve says yes.*/
  454. iso_msb(buf + (72 + 16 * idx) + 12,
  455. ((file_size + 2047) / 2048 ) * 2048, 4);
  456. }
  457. /* 408 - 411 | part_blks | Number of 512 byte blocks in partition */
  458. blocks = (image_size + bps - 1) / bps;
  459. iso_msb(buf + 408, blocks, 4);
  460. /* 416 - 419 | 0 | Partition is volume header */
  461. iso_msb(buf + 416, 0, 4);
  462. /* 432 - 435 | part_blks | Number of 512 byte blocks in partition */
  463. iso_msb(buf + 432, blocks, 4);
  464. iso_msb(buf + 444, 6, 4);
  465. /* 504 - 507 | head_chk | Volume header checksum
  466. The two's complement of bytes 0 to 503 read
  467. as big endian unsigned 32 bit:
  468. sum(32-bit-words) + head_chk == 0
  469. */
  470. checksum = 0;
  471. for (idx = 0; idx < 504; idx += 4) {
  472. num = iso_read_msb(buf + idx, 4);
  473. /* Addition modulo a natural number is commutative and associative.
  474. Thus the inverse of a sum is the sum of the inverses of the addends.
  475. */
  476. checksum -= num;
  477. }
  478. iso_msb(buf + 504, checksum, 4);
  479. return ISO_SUCCESS;
  480. }
  481. /* The following two functions were implemented according to
  482. doc/boot_sectors.txt section "MIPS Little Endian" which was derived
  483. by Thomas Schmitt from
  484. cdrkit-1.1.10/genisoimage/boot-mipsel.c by Steve McIntyre which is based
  485. on work of Florian Lohoff and Thiemo Seufer,
  486. and from <elf.h> by Free Software Foundation, Inc.
  487. Both functions are entirely under copyright (C) 2010 Thomas Schmitt.
  488. */
  489. /**
  490. * Read the necessary ELF information from the first MIPS boot file.
  491. * This is done before image writing starts.
  492. */
  493. int iso_read_mipsel_elf(Ecma119Image *t, int flag)
  494. {
  495. uint32_t phdr_adr, todo, count;
  496. int ret;
  497. uint8_t *elf_buf = NULL;
  498. IsoNode *iso_node;
  499. Ecma119Node *ecma_node;
  500. IsoStream *stream;
  501. if (t->image->num_mips_boot_files <= 0)
  502. {ret = ISO_SUCCESS; goto ex;}
  503. LIBISO_ALLOC_MEM(elf_buf, uint8_t, 2048);
  504. ret = boot_nodes_from_iso_path(t, t->image->mips_boot_file_paths[0],
  505. &iso_node, &ecma_node, "MIPS boot file", 0);
  506. if (ret < 0)
  507. goto ex;
  508. stream = iso_file_get_stream((IsoFile *) iso_node);
  509. ret = iso_stream_open(stream);
  510. if (ret < 0) {
  511. iso_msg_submit(t->image->id, ret, 0,
  512. "Cannot open designated MIPS boot file '%s'",
  513. t->image->mips_boot_file_paths[0]);
  514. goto ex;
  515. }
  516. ret = iso_stream_read(stream, elf_buf, 32);
  517. if (ret != 32) {
  518. cannot_read:;
  519. iso_stream_close(stream);
  520. iso_msg_submit(t->image->id, ret, 0,
  521. "Cannot read from designated MIPS boot file '%s'",
  522. t->image->mips_boot_file_paths[0]);
  523. goto ex;
  524. }
  525. /* 24 - 27 | e_entry | Entry point virtual address */
  526. t->mipsel_e_entry = iso_read_lsb(elf_buf + 24, 4);
  527. /* 28 - 31 | e_phoff | Program header table file offset */
  528. phdr_adr = iso_read_lsb(elf_buf + 28, 4);
  529. /* Skip stream up to byte address phdr_adr */
  530. todo