| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: cd9660_eltorito.c,v 1.20 2013/01/28 21:03:28 christos Exp $ */ | | 1 | /* $NetBSD: cd9660_eltorito.c,v 1.21 2017/01/24 11:22:43 nonaka Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan | | 4 | * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan |
5 | * Perez-Rathke and Ram Vedam. All rights reserved. | | 5 | * Perez-Rathke and Ram Vedam. All rights reserved. |
6 | * | | 6 | * |
7 | * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys, | | 7 | * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys, |
8 | * Alan Perez-Rathke and Ram Vedam. | | 8 | * Alan Perez-Rathke and Ram Vedam. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or | | 10 | * Redistribution and use in source and binary forms, with or |
11 | * without modification, are permitted provided that the following | | 11 | * without modification, are permitted provided that the following |
12 | * conditions are met: | | 12 | * conditions are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -30,47 +30,48 @@ | | | @@ -30,47 +30,48 @@ |
30 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 30 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY | | 31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY |
32 | * OF SUCH DAMAGE. | | 32 | * OF SUCH DAMAGE. |
33 | */ | | 33 | */ |
34 | | | 34 | |
35 | | | 35 | |
36 | #include "cd9660.h" | | 36 | #include "cd9660.h" |
37 | #include "cd9660_eltorito.h" | | 37 | #include "cd9660_eltorito.h" |
38 | #include <sys/bootblock.h> | | 38 | #include <sys/bootblock.h> |
39 | #include <util.h> | | 39 | #include <util.h> |
40 | | | 40 | |
41 | #include <sys/cdefs.h> | | 41 | #include <sys/cdefs.h> |
42 | #if defined(__RCSID) && !defined(__lint) | | 42 | #if defined(__RCSID) && !defined(__lint) |
43 | __RCSID("$NetBSD: cd9660_eltorito.c,v 1.20 2013/01/28 21:03:28 christos Exp $"); | | 43 | __RCSID("$NetBSD: cd9660_eltorito.c,v 1.21 2017/01/24 11:22:43 nonaka Exp $"); |
44 | #endif /* !__lint */ | | 44 | #endif /* !__lint */ |
45 | | | 45 | |
46 | #ifdef DEBUG | | 46 | #ifdef DEBUG |
47 | #define ELTORITO_DPRINTF(__x) printf __x | | 47 | #define ELTORITO_DPRINTF(__x) printf __x |
48 | #else | | 48 | #else |
49 | #define ELTORITO_DPRINTF(__x) | | 49 | #define ELTORITO_DPRINTF(__x) |
50 | #endif | | 50 | #endif |
51 | | | 51 | |
52 | #include <util.h> | | 52 | #include <util.h> |
53 | | | 53 | |
54 | static struct boot_catalog_entry *cd9660_init_boot_catalog_entry(void); | | 54 | static struct boot_catalog_entry *cd9660_init_boot_catalog_entry(void); |
55 | static struct boot_catalog_entry *cd9660_boot_setup_validation_entry(char); | | 55 | static struct boot_catalog_entry *cd9660_boot_setup_validation_entry(char); |
56 | static struct boot_catalog_entry *cd9660_boot_setup_default_entry( | | 56 | static struct boot_catalog_entry *cd9660_boot_setup_default_entry( |
57 | struct cd9660_boot_image *); | | 57 | struct cd9660_boot_image *); |
58 | static struct boot_catalog_entry *cd9660_boot_setup_section_head(char); | | 58 | static struct boot_catalog_entry *cd9660_boot_setup_section_head(char); |
59 | static struct boot_catalog_entry *cd9660_boot_setup_validation_entry(char); | | | |
60 | #if 0 | | 59 | #if 0 |
61 | static u_char cd9660_boot_get_system_type(struct cd9660_boot_image *); | | 60 | static u_char cd9660_boot_get_system_type(struct cd9660_boot_image *); |
62 | #endif | | 61 | #endif |
63 | | | 62 | |
| | | 63 | static struct cd9660_boot_image *default_boot_image; |
| | | 64 | |
64 | int | | 65 | int |
65 | cd9660_add_boot_disk(iso9660_disk *diskStructure, const char *boot_info) | | 66 | cd9660_add_boot_disk(iso9660_disk *diskStructure, const char *boot_info) |
66 | { | | 67 | { |
67 | struct stat stbuf; | | 68 | struct stat stbuf; |
68 | const char *mode_msg; | | 69 | const char *mode_msg; |
69 | char *temp; | | 70 | char *temp; |
70 | char *sysname; | | 71 | char *sysname; |
71 | char *filename; | | 72 | char *filename; |
72 | struct cd9660_boot_image *new_image, *tmp_image; | | 73 | struct cd9660_boot_image *new_image, *tmp_image; |
73 | | | 74 | |
74 | assert(boot_info != NULL); | | 75 | assert(boot_info != NULL); |
75 | | | 76 | |
76 | if (*boot_info == '\0') { | | 77 | if (*boot_info == '\0') { |
| @@ -165,29 +166,35 @@ cd9660_add_boot_disk(iso9660_disk *diskS | | | @@ -165,29 +166,35 @@ cd9660_add_boot_disk(iso9660_disk *diskS |
165 | TAILQ_FOREACH(tmp_image, &diskStructure->boot_images, image_list) { | | 166 | TAILQ_FOREACH(tmp_image, &diskStructure->boot_images, image_list) { |
166 | if (tmp_image->system != new_image->system) | | 167 | if (tmp_image->system != new_image->system) |
167 | break; | | 168 | break; |
168 | } | | 169 | } |
169 | | | 170 | |
170 | if (tmp_image == NULL) { | | 171 | if (tmp_image == NULL) { |
171 | TAILQ_INSERT_HEAD(&diskStructure->boot_images, new_image, | | 172 | TAILQ_INSERT_HEAD(&diskStructure->boot_images, new_image, |
172 | image_list); | | 173 | image_list); |
173 | } else | | 174 | } else |
174 | TAILQ_INSERT_BEFORE(tmp_image, new_image, image_list); | | 175 | TAILQ_INSERT_BEFORE(tmp_image, new_image, image_list); |
175 | | | 176 | |
176 | new_image->serialno = diskStructure->image_serialno++; | | 177 | new_image->serialno = diskStructure->image_serialno++; |
177 | | | 178 | |
| | | 179 | new_image->platform_id = new_image->system; |
| | | 180 | |
178 | /* TODO : Need to do anything about the boot image in the tree? */ | | 181 | /* TODO : Need to do anything about the boot image in the tree? */ |
179 | diskStructure->is_bootable = 1; | | 182 | diskStructure->is_bootable = 1; |
180 | | | 183 | |
| | | 184 | /* First boot image is initial/default entry. */ |
| | | 185 | if (default_boot_image == NULL) |
| | | 186 | default_boot_image = new_image; |
| | | 187 | |
181 | return 1; | | 188 | return 1; |
182 | } | | 189 | } |
183 | | | 190 | |
184 | int | | 191 | int |
185 | cd9660_eltorito_add_boot_option(iso9660_disk *diskStructure, | | 192 | cd9660_eltorito_add_boot_option(iso9660_disk *diskStructure, |
186 | const char *option_string, const char *value) | | 193 | const char *option_string, const char *value) |
187 | { | | 194 | { |
188 | char *eptr; | | 195 | char *eptr; |
189 | struct cd9660_boot_image *image; | | 196 | struct cd9660_boot_image *image; |
190 | | | 197 | |
191 | assert(option_string != NULL); | | 198 | assert(option_string != NULL); |
192 | | | 199 | |
193 | /* Find the last image added */ | | 200 | /* Find the last image added */ |
| @@ -201,26 +208,33 @@ cd9660_eltorito_add_boot_option(iso9660_ | | | @@ -201,26 +208,33 @@ cd9660_eltorito_add_boot_option(iso9660_ |
201 | | | 208 | |
202 | if (strcmp(option_string, "no-emul-boot") == 0) { | | 209 | if (strcmp(option_string, "no-emul-boot") == 0) { |
203 | image->targetMode = ET_MEDIA_NOEM; | | 210 | image->targetMode = ET_MEDIA_NOEM; |
204 | } else if (strcmp(option_string, "no-boot") == 0) { | | 211 | } else if (strcmp(option_string, "no-boot") == 0) { |
205 | image->bootable = ET_NOT_BOOTABLE; | | 212 | image->bootable = ET_NOT_BOOTABLE; |
206 | } else if (strcmp(option_string, "hard-disk-boot") == 0) { | | 213 | } else if (strcmp(option_string, "hard-disk-boot") == 0) { |
207 | image->targetMode = ET_MEDIA_HDD; | | 214 | image->targetMode = ET_MEDIA_HDD; |
208 | } else if (strcmp(option_string, "boot-load-segment") == 0) { | | 215 | } else if (strcmp(option_string, "boot-load-segment") == 0) { |
209 | image->loadSegment = strtoul(value, &eptr, 16); | | 216 | image->loadSegment = strtoul(value, &eptr, 16); |
210 | if (eptr == value || *eptr != '\0' || errno != ERANGE) { | | 217 | if (eptr == value || *eptr != '\0' || errno != ERANGE) { |
211 | warn("%s: strtoul", __func__); | | 218 | warn("%s: strtoul", __func__); |
212 | return 0; | | 219 | return 0; |
213 | } | | 220 | } |
| | | 221 | } else if (strcmp(option_string, "platformid") == 0) { |
| | | 222 | if (strcmp(value, "efi") == 0) |
| | | 223 | image->platform_id = ET_SYS_EFI; |
| | | 224 | else { |
| | | 225 | warn("%s: unknown platform: %s", __func__, value); |
| | | 226 | return 0; |
| | | 227 | } |
214 | } else { | | 228 | } else { |
215 | return 0; | | 229 | return 0; |
216 | } | | 230 | } |
217 | return 1; | | 231 | return 1; |
218 | } | | 232 | } |
219 | | | 233 | |
220 | static struct boot_catalog_entry * | | 234 | static struct boot_catalog_entry * |
221 | cd9660_init_boot_catalog_entry(void) | | 235 | cd9660_init_boot_catalog_entry(void) |
222 | { | | 236 | { |
223 | return ecalloc(1, sizeof(struct boot_catalog_entry)); | | 237 | return ecalloc(1, sizeof(struct boot_catalog_entry)); |
224 | } | | 238 | } |
225 | | | 239 | |
226 | static struct boot_catalog_entry * | | 240 | static struct boot_catalog_entry * |
| @@ -332,32 +346,32 @@ cd9660_boot_get_system_type(struct cd966 | | | @@ -332,32 +346,32 @@ cd9660_boot_get_system_type(struct cd966 |
332 | } | | 346 | } |
333 | #endif | | 347 | #endif |
334 | | | 348 | |
335 | /* | | 349 | /* |
336 | * Set up the BVD, Boot catalog, and the boot entries, but do no writing | | 350 | * Set up the BVD, Boot catalog, and the boot entries, but do no writing |
337 | */ | | 351 | */ |
338 | int | | 352 | int |
339 | cd9660_setup_boot(iso9660_disk *diskStructure, int first_sector) | | 353 | cd9660_setup_boot(iso9660_disk *diskStructure, int first_sector) |
340 | { | | 354 | { |
341 | int sector; | | 355 | int sector; |
342 | int used_sectors; | | 356 | int used_sectors; |
343 | int num_entries = 0; | | 357 | int num_entries = 0; |
344 | int catalog_sectors; | | 358 | int catalog_sectors; |
345 | struct boot_catalog_entry *x86_head, *mac_head, *ppc_head, | | 359 | struct boot_catalog_entry *x86_head, *mac_head, *ppc_head, *efi_head, |
346 | *valid_entry, *default_entry, *temp, *head, **headp, *next; | | 360 | *valid_entry, *default_entry, *temp, *head, **headp, *next; |
347 | struct cd9660_boot_image *tmp_disk; | | 361 | struct cd9660_boot_image *tmp_disk; |
348 | | | 362 | |
349 | headp = NULL; | | 363 | headp = NULL; |
350 | x86_head = mac_head = ppc_head = NULL; | | 364 | x86_head = mac_head = ppc_head = efi_head = NULL; |
351 | | | 365 | |
352 | /* If there are no boot disks, don't bother building boot information */ | | 366 | /* If there are no boot disks, don't bother building boot information */ |
353 | if (TAILQ_EMPTY(&diskStructure->boot_images)) | | 367 | if (TAILQ_EMPTY(&diskStructure->boot_images)) |
354 | return 0; | | 368 | return 0; |
355 | | | 369 | |
356 | /* Point to catalog: For now assume it consumes one sector */ | | 370 | /* Point to catalog: For now assume it consumes one sector */ |
357 | ELTORITO_DPRINTF(("Boot catalog will go in sector %d\n", first_sector)); | | 371 | ELTORITO_DPRINTF(("Boot catalog will go in sector %d\n", first_sector)); |
358 | diskStructure->boot_catalog_sector = first_sector; | | 372 | diskStructure->boot_catalog_sector = first_sector; |
359 | cd9660_bothendian_dword(first_sector, | | 373 | cd9660_bothendian_dword(first_sector, |
360 | diskStructure->boot_descriptor->boot_catalog_pointer); | | 374 | diskStructure->boot_descriptor->boot_catalog_pointer); |
361 | | | 375 | |
362 | /* Step 1: Generate boot catalog */ | | 376 | /* Step 1: Generate boot catalog */ |
363 | /* Step 1a: Validation entry */ | | 377 | /* Step 1a: Validation entry */ |
| @@ -381,97 +395,117 @@ cd9660_setup_boot(iso9660_disk *diskStru | | | @@ -381,97 +395,117 @@ cd9660_setup_boot(iso9660_disk *diskStru |
381 | catalog_sectors = howmany(num_entries * 0x20, diskStructure->sectorSize); | | 395 | catalog_sectors = howmany(num_entries * 0x20, diskStructure->sectorSize); |
382 | used_sectors += catalog_sectors; | | 396 | used_sectors += catalog_sectors; |
383 | | | 397 | |
384 | if (diskStructure->verbose_level > 0) { | | 398 | if (diskStructure->verbose_level > 0) { |
385 | printf("%s: there will be %i entries consuming %i sectors. " | | 399 | printf("%s: there will be %i entries consuming %i sectors. " |
386 | "Catalog is %i sectors\n", __func__, num_entries, | | 400 | "Catalog is %i sectors\n", __func__, num_entries, |
387 | used_sectors, catalog_sectors); | | 401 | used_sectors, catalog_sectors); |
388 | } | | 402 | } |
389 | | | 403 | |
390 | /* Populate sector numbers */ | | 404 | /* Populate sector numbers */ |
391 | sector = first_sector + catalog_sectors; | | 405 | sector = first_sector + catalog_sectors; |
392 | TAILQ_FOREACH(tmp_disk, &diskStructure->boot_images, image_list) { | | 406 | TAILQ_FOREACH(tmp_disk, &diskStructure->boot_images, image_list) { |
393 | tmp_disk->sector = sector; | | 407 | tmp_disk->sector = sector; |
394 | sector += tmp_disk->num_sectors; | | 408 | sector += tmp_disk->num_sectors / |
| | | 409 | (diskStructure->sectorSize / 512); |
395 | } | | 410 | } |
396 | | | 411 | |
397 | LIST_INSERT_HEAD(&diskStructure->boot_entries, valid_entry, ll_struct); | | 412 | LIST_INSERT_HEAD(&diskStructure->boot_entries, valid_entry, ll_struct); |
398 | | | 413 | |
399 | /* Step 1b: Initial/default entry */ | | 414 | /* Step 1b: Initial/default entry */ |
400 | /* TODO : PARAM */ | | 415 | /* TODO : PARAM */ |
401 | tmp_disk = TAILQ_FIRST(&diskStructure->boot_images); | | 416 | if (default_boot_image != NULL) { |
| | | 417 | struct cd9660_boot_image *tcbi; |
| | | 418 | TAILQ_FOREACH(tcbi, &diskStructure->boot_images, image_list) { |
| | | 419 | if (tcbi == default_boot_image) { |
| | | 420 | tmp_disk = tcbi; |
| | | 421 | break; |
| | | 422 | } |
| | | 423 | } |
| | | 424 | } |
| | | 425 | if (tmp_disk == NULL) |
| | | 426 | tmp_disk = TAILQ_FIRST(&diskStructure->boot_images); |
402 | default_entry = cd9660_boot_setup_default_entry(tmp_disk); | | 427 | default_entry = cd9660_boot_setup_default_entry(tmp_disk); |
403 | if (default_entry == NULL) { | | 428 | if (default_entry == NULL) { |
404 | warnx("Error: memory allocation failed in cd9660_setup_boot"); | | 429 | warnx("Error: memory allocation failed in cd9660_setup_boot"); |
405 | return -1; | | 430 | return -1; |
406 | } | | 431 | } |
407 | | | 432 | |
408 | LIST_INSERT_AFTER(valid_entry, default_entry, ll_struct); | | 433 | LIST_INSERT_AFTER(valid_entry, default_entry, ll_struct); |
409 | | | 434 | |
410 | /* Todo: multiple default entries? */ | | 435 | /* Todo: multiple default entries? */ |
411 | | | 436 | |
412 | tmp_disk = TAILQ_NEXT(tmp_disk, image_list); | | 437 | tmp_disk = TAILQ_FIRST(&diskStructure->boot_images); |
413 | | | 438 | |
| | | 439 | head = NULL; |
414 | temp = default_entry; | | 440 | temp = default_entry; |
415 | | | 441 | |
416 | /* If multiple boot images are given : */ | | 442 | /* If multiple boot images are given : */ |
417 | while (tmp_disk != NULL) { | | 443 | for (; tmp_disk != NULL; tmp_disk = TAILQ_NEXT(tmp_disk, image_list)) { |
| | | 444 | if (tmp_disk == default_boot_image) |
| | | 445 | continue; |
| | | 446 | |
418 | /* Step 2: Section header */ | | 447 | /* Step 2: Section header */ |
419 | switch (tmp_disk->system) { | | 448 | switch (tmp_disk->platform_id) { |
420 | case ET_SYS_X86: | | 449 | case ET_SYS_X86: |
421 | headp = &x86_head; | | 450 | headp = &x86_head; |
422 | break; | | 451 | break; |
423 | case ET_SYS_PPC: | | 452 | case ET_SYS_PPC: |
424 | headp = &ppc_head; | | 453 | headp = &ppc_head; |
425 | break; | | 454 | break; |
426 | case ET_SYS_MAC: | | 455 | case ET_SYS_MAC: |
427 | headp = &mac_head; | | 456 | headp = &mac_head; |
428 | break; | | 457 | break; |
| | | 458 | case ET_SYS_EFI: |
| | | 459 | headp = &efi_head; |
| | | 460 | break; |
429 | default: | | 461 | default: |
430 | warnx("%s: internal error: unknown system type", | | 462 | warnx("%s: internal error: unknown system type", |
431 | __func__); | | 463 | __func__); |
432 | return -1; | | 464 | return -1; |
433 | } | | 465 | } |
434 | | | 466 | |
435 | if (*headp == NULL) { | | 467 | if (*headp == NULL) { |
436 | head = | | 468 | head = |
437 | cd9660_boot_setup_section_head(tmp_disk->system); | | 469 | cd9660_boot_setup_section_head(tmp_disk->platform_id); |
438 | if (head == NULL) { | | 470 | if (head == NULL) { |
439 | warnx("Error: memory allocation failed in " | | 471 | warnx("Error: memory allocation failed in " |
440 | "cd9660_setup_boot"); | | 472 | "cd9660_setup_boot"); |
441 | return -1; | | 473 | return -1; |
442 | } | | 474 | } |
443 | LIST_INSERT_AFTER(default_entry, head, ll_struct); | | 475 | LIST_INSERT_AFTER(default_entry, head, ll_struct); |
444 | *headp = head; | | 476 | *headp = head; |
445 | } else | | 477 | } else |
446 | head = *headp; | | 478 | head = *headp; |
447 | | | 479 | |
448 | head->entry_data.SH.num_section_entries[0]++; | | 480 | head->entry_data.SH.num_section_entries[0]++; |
449 | | | 481 | |
450 | /* Step 2a: Section entry and extensions */ | | 482 | /* Step 2a: Section entry and extensions */ |
451 | temp = cd9660_boot_setup_section_entry(tmp_disk); | | 483 | temp = cd9660_boot_setup_section_entry(tmp_disk); |
452 | if (temp == NULL) { | | 484 | if (temp == NULL) { |
453 | warn("%s: cd9660_boot_setup_section_entry", __func__); | | 485 | warn("%s: cd9660_boot_setup_section_entry", __func__); |
454 | return -1; | | 486 | return -1; |
455 | } | | 487 | } |
456 | | | 488 | |
457 | while ((next = LIST_NEXT(head, ll_struct)) != NULL && | | 489 | while ((next = LIST_NEXT(head, ll_struct)) != NULL && |
458 | next->entry_type == ET_ENTRY_SE) | | 490 | next->entry_type == ET_ENTRY_SE) |
459 | head = next; | | 491 | head = next; |
460 | | | 492 | |
461 | LIST_INSERT_AFTER(head, temp, ll_struct); | | 493 | LIST_INSERT_AFTER(head, temp, ll_struct); |
462 | tmp_disk = TAILQ_NEXT(tmp_disk, image_list); | | | |
463 | } | | 494 | } |
464 | | | 495 | |
| | | 496 | if (head != NULL) |
| | | 497 | head->entry_data.SH.header_indicator[0] = ET_SECTION_HEADER_LAST; |
| | | 498 | |
465 | /* TODO: Remaining boot disks when implemented */ | | 499 | /* TODO: Remaining boot disks when implemented */ |
466 | | | 500 | |
467 | return first_sector + used_sectors; | | 501 | return first_sector + used_sectors; |
468 | } | | 502 | } |
469 | | | 503 | |
470 | int | | 504 | int |
471 | cd9660_setup_boot_volume_descriptor(iso9660_disk *diskStructure, | | 505 | cd9660_setup_boot_volume_descriptor(iso9660_disk *diskStructure, |
472 | volume_descriptor *bvd) | | 506 | volume_descriptor *bvd) |
473 | { | | 507 | { |
474 | boot_volume_descriptor *bvdData = | | 508 | boot_volume_descriptor *bvdData = |
475 | (boot_volume_descriptor*)bvd->volumeDescriptorData; | | 509 | (boot_volume_descriptor*)bvd->volumeDescriptorData; |
476 | | | 510 | |
477 | bvdData->boot_record_indicator[0] = ISO_VOLUME_DESCRIPTOR_BOOT; | | 511 | bvdData->boot_record_indicator[0] = ISO_VOLUME_DESCRIPTOR_BOOT; |