1 /* $NetBSD: cd9660_eltorito.c,v 1.19 2012/04/19 17:28:25 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan 5 * Perez-Rathke and Ram Vedam. All rights reserved. 6 * 7 * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys, 8 * Alan Perez-Rathke and Ram Vedam. 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer in the documentation and/or other materials provided 18 * with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN 21 * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN 25 * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 28 * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 29 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 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 32 * OF SUCH DAMAGE. 33 */ 34 35 36 #include "cd9660.h" 37 #include "cd9660_eltorito.h" 38 #include <sys/bootblock.h> 39 40 #include <sys/cdefs.h> 41 #if defined(__RCSID) && !defined(__lint) 42 __RCSID("$NetBSD: cd9660_eltorito.c,v 1.19 2012/04/19 17:28:25 christos Exp $"); 43 #endif /* !__lint */ 44 45 #ifdef DEBUG 46 #define ELTORITO_DPRINTF(__x) printf __x 47 #else 48 #define ELTORITO_DPRINTF(__x) 49 #endif 50 51 static struct boot_catalog_entry *cd9660_init_boot_catalog_entry(void); 52 static struct boot_catalog_entry *cd9660_boot_setup_validation_entry(char); 53 static struct boot_catalog_entry *cd9660_boot_setup_default_entry( 54 struct cd9660_boot_image *); 55 static struct boot_catalog_entry *cd9660_boot_setup_section_head(char); 56 static struct boot_catalog_entry *cd9660_boot_setup_validation_entry(char); 57 #if 0 58 static u_char cd9660_boot_get_system_type(struct cd9660_boot_image *); 59 #endif 60 61 int 62 cd9660_add_boot_disk(const char *boot_info) 63 { 64 struct stat stbuf; 65 const char *mode_msg; 66 char *temp; 67 char *sysname; 68 char *filename; 69 struct cd9660_boot_image *new_image, *tmp_image; 70 71 assert(boot_info != NULL); 72 73 if (*boot_info == '\0') { 74 warnx("Error: Boot disk information must be in the " 75 "format 'system;filename'"); 76 return 0; 77 } 78 79 /* First decode the boot information */ 80 if ((temp = strdup(boot_info)) == NULL) { 81 warn("%s: strdup", __func__); 82 return 0; 83 } 84 85 sysname = temp; 86 filename = strchr(sysname, ';'); 87 if (filename == NULL) { 88 warnx("supply boot disk information in the format " 89 "'system;filename'"); 90 free(temp); 91 return 0; 92 } 93 94 *filename++ = '\0'; 95 96 if (diskStructure.verbose_level > 0) { 97 printf("Found bootdisk with system %s, and filename %s\n", 98 sysname, filename); 99 } 100 if ((new_image = malloc(sizeof(*new_image))) == NULL) { 101 warn("%s: malloc", __func__); 102 free(temp); 103 return 0; 104 } 105 (void)memset(new_image, 0, sizeof(*new_image)); 106 new_image->loadSegment = 0; /* default for now */ 107 108 /* Decode System */ 109 if (strcmp(sysname, "i386") == 0) 110 new_image->system = ET_SYS_X86; 111 else if (strcmp(sysname, "powerpc") == 0) 112 new_image->system = ET_SYS_PPC; 113 else if (strcmp(sysname, "macppc") == 0 || 114 strcmp(sysname, "mac68k") == 0) 115 new_image->system = ET_SYS_MAC; 116 else { 117 warnx("boot disk system must be " 118 "i386, powerpc, macppc, or mac68k"); 119 free(temp); 120 free(new_image); 121 return 0; 122 } 123 124 125 if ((new_image->filename = strdup(filename)) == NULL) { 126 warn("%s: strdup", __func__); 127 free(temp); 128 free(new_image); 129 return 0; 130 } 131 132 free(temp); 133 134 /* Get information about the file */ 135 if (lstat(new_image->filename, &stbuf) == -1) 136 err(EXIT_FAILURE, "%s: lstat(\"%s\")", __func__, 137 new_image->filename); 138 139 switch (stbuf.st_size) { 140 case 1440 * 1024: 141 new_image->targetMode = ET_MEDIA_144FDD; 142 mode_msg = "Assigned boot image to 1.44 emulation mode"; 143 break; 144 case 1200 * 1024: 145 new_image->targetMode = ET_MEDIA_12FDD; 146 mode_msg = "Assigned boot image to 1.2 emulation mode"; 147 break; 148 case 2880 * 1024: 149 new_image->targetMode = ET_MEDIA_288FDD; 150 mode_msg = "Assigned boot image to 2.88 emulation mode"; 151 break; 152 default: 153 new_image->targetMode = ET_MEDIA_NOEM; 154 mode_msg = "Assigned boot image to no emulation mode"; 155 break; 156 } 157 158 if (diskStructure.verbose_level > 0) 159 printf("%s\n", mode_msg); 160 161 new_image->size = stbuf.st_size; 162 new_image->num_sectors = 163 howmany(new_image->size, diskStructure.sectorSize) * 164 howmany(diskStructure.sectorSize, 512); 165 if (diskStructure.verbose_level > 0) { 166 printf("New image has size %d, uses %d 512-byte sectors\n", 167 new_image->size, new_image->num_sectors); 168 } 169 new_image->sector = -1; 170 /* Bootable by default */ 171 new_image->bootable = ET_BOOTABLE; 172 /* Add boot disk */ 173 174 /* Group images for the same platform together. */ 175 TAILQ_FOREACH(tmp_image, &diskStructure.boot_images, image_list) { 176 if (tmp_image->system != new_image->system) 177 break; 178 } 179 180 if (tmp_image == NULL) { 181 TAILQ_INSERT_HEAD(&diskStructure.boot_images, new_image, 182 image_list); 183 } else 184 TAILQ_INSERT_BEFORE(tmp_image, new_image, image_list); 185 186 new_image->serialno = diskStructure.image_serialno++; 187 188 /* TODO : Need to do anything about the boot image in the tree? */ 189 diskStructure.is_bootable = 1; 190 191 return 1; 192 } 193 194 int 195 cd9660_eltorito_add_boot_option(const char *option_string, const char *value) 196 { 197 char *eptr; 198 struct cd9660_boot_image *image; 199 200 assert(option_string != NULL); 201 202 /* Find the last image added */ 203 TAILQ_FOREACH(image, &diskStructure.boot_images, image_list) { 204 if (image->serialno + 1 == diskStructure.image_serialno) 205 break; 206 } 207 if (image == NULL) 208 errx(EXIT_FAILURE, "Attempted to add boot option, " 209 "but no boot images have been specified"); 210 211 if (strcmp(option_string, "no-emul-boot") == 0) { 212 image->targetMode = ET_MEDIA_NOEM; 213 } else if (strcmp(option_string, "no-boot") == 0) { 214 image->bootable = ET_NOT_BOOTABLE; 215 } else if (strcmp(option_string, "hard-disk-boot") == 0) { 216 image->targetMode = ET_MEDIA_HDD; 217 } else if (strcmp(option_string, "boot-load-segment") == 0) { 218 image->loadSegment = strtoul(value, &eptr, 16); 219 if (eptr == value || *eptr != '\0' || errno != ERANGE) { 220 warn("%s: strtoul", __func__); 221 return 0; 222 } 223 } else { 224 return 0; 225 } 226 return 1; 227 } 228 229 static struct boot_catalog_entry * 230 cd9660_init_boot_catalog_entry(void) 231 { 232 struct boot_catalog_entry *temp; 233 234 if ((temp = malloc(sizeof(*temp))) == NULL) 235 return NULL; 236 237 return memset(temp, 0, sizeof(*temp)); 238 } 239 240 static struct boot_catalog_entry * 241 cd9660_boot_setup_validation_entry(char sys) 242 { 243 struct boot_catalog_entry *entry; 244 boot_catalog_validation_entry *ve; 245 int16_t checksum; 246 unsigned char *csptr; 247 size_t i; 248 entry = cd9660_init_boot_catalog_entry(); 249 250 if (entry == NULL) { 251 warnx("Error: memory allocation failed in " 252 "cd9660_boot_setup_validation_entry"); 253 return 0; 254 } 255 ve = &entry->entry_data.VE; 256 257 ve->header_id[0] = 1; 258 ve->platform_id[0] = sys; 259 ve->key[0] = 0x55; 260 ve->key[1] = 0xAA; 261 262 /* Calculate checksum */ 263 checksum = 0; 264 cd9660_721(0, ve->checksum); 265 csptr = (unsigned char*)ve; 266 for (i = 0; i < sizeof(*ve); i += 2) { 267 checksum += (int16_t)csptr[i]; 268 checksum += 256 * (int16_t)csptr[i + 1]; 269 } 270 checksum = -checksum; 271 cd9660_721(checksum, ve->checksum); 272 273 ELTORITO_DPRINTF(("%s: header_id %d, platform_id %d, key[0] %d, key[1] %d, " 274 "checksum %04x\n", __func__, ve->header_id[0], ve->platform_id[0], 275 ve->key[0], ve->key[1], checksum)); 276 return entry; 277 } 278 279 static struct boot_catalog_entry * 280 cd9660_boot_setup_default_entry(struct cd9660_boot_image *disk) 281 { 282 struct boot_catalog_entry *default_entry; 283 boot_catalog_initial_entry *ie; 284 285 default_entry = cd9660_init_boot_catalog_entry(); 286 if (default_entry == NULL) 287 return NULL; 288 289 ie = &default_entry->entry_data.IE; 290 291 ie->boot_indicator[0] = disk->bootable; 292 ie->media_type[0] = disk->targetMode; 293 cd9660_721(disk->loadSegment, ie->load_segment); 294 ie->system_type[0] = disk->system; 295 cd9660_721(disk->num_sectors, ie->sector_count); 296 cd9660_731(disk->sector, ie->load_rba); 297 298 ELTORITO_DPRINTF(("%s: boot indicator %d, media type %d, " 299 "load segment %04x, system type %d, sector count %d, " 300 "load rba %d\n", __func__, ie->boot_indicator[0], 301 ie->media_type[0], disk->loadSegment, ie->system_type[0], 302 disk->num_sectors, disk->sector)); 303 return default_entry; 304 } 305 306 static struct boot_catalog_entry * 307 cd9660_boot_setup_section_head(char platform) 308 { 309 struct boot_catalog_entry *entry; 310 boot_catalog_section_header *sh; 311 312 entry = cd9660_init_boot_catalog_entry(); 313 if (entry == NULL) 314 return NULL; 315 316 sh = &entry->entry_data.SH; 317 /* More by default. The last one will manually be set to 0x91 */ 318 sh->header_indicator[0] = ET_SECTION_HEADER_MORE; 319 sh->platform_id[0] = platform; 320 sh->num_section_entries[0] = 0; 321 return entry; 322 } 323 324 static struct boot_catalog_entry * 325 cd9660_boot_setup_section_entry(struct cd9660_boot_image *disk) 326 { 327 struct boot_catalog_entry *entry; 328 boot_catalog_section_entry *se; 329 if ((entry = cd9660_init_boot_catalog_entry()) == NULL) 330 return NULL; 331 332 se = &entry->entry_data.SE; 333 334 se->boot_indicator[0] = ET_BOOTABLE; 335 se->media_type[0] = disk->targetMode; 336 cd9660_721(disk->loadSegment, se->load_segment); 337 cd9660_721(disk->num_sectors, se->sector_count); 338 cd9660_731(disk->sector, se->load_rba); 339 return entry; 340 } 341 342 #if 0 343 static u_char 344 cd9660_boot_get_system_type(struct cd9660_boot_image *disk) 345 { 346 /* 347 For hard drive booting, we need to examine the MBR to figure 348 out what the partition type is 349 */ 350 return 0; 351 } 352 #endif 353 354 /* 355 * Set up the BVD, Boot catalog, and the boot entries, but do no writing 356 */ 357 int 358 cd9660_setup_boot(int first_sector) 359 { 360 int sector; 361 int used_sectors; 362 int num_entries = 0; 363 int catalog_sectors; 364 struct boot_catalog_entry *x86_head, *mac_head, *ppc_head, 365 *valid_entry, *default_entry, *temp, *head, **headp, *next; 366 struct cd9660_boot_image *tmp_disk; 367 368 headp = NULL; 369 x86_head = mac_head = ppc_head = NULL; 370 371 /* If there are no boot disks, don't bother building boot information */ 372 if (TAILQ_EMPTY(&diskStructure.boot_images)) 373 return 0; 374 375 /* Point to catalog: For now assume it consumes one sector */ 376 ELTORITO_DPRINTF(("Boot catalog will go in sector %d\n", first_sector)); 377 diskStructure.boot_catalog_sector = first_sector; 378 cd9660_bothendian_dword(first_sector, 379 diskStructure.boot_descriptor->boot_catalog_pointer); 380 381 /* Step 1: Generate boot catalog */ 382 /* Step 1a: Validation entry */ 383 valid_entry = cd9660_boot_setup_validation_entry(ET_SYS_X86); 384 if (valid_entry == NULL) 385 return -1; 386 387 /* 388 * Count how many boot images there are, 389 * and how many sectors they consume. 390 */ 391 num_entries = 1; 392 used_sectors = 0; 393 394 TAILQ_FOREACH(tmp_disk, &diskStructure.boot_images, image_list) { 395 used_sectors += tmp_disk->num_sectors; 396 397 /* One default entry per image */ 398 num_entries++; 399 } 400 catalog_sectors = howmany(num_entries * 0x20, diskStructure.sectorSize); 401 used_sectors += catalog_sectors; 402 403 if (diskStructure.verbose_level > 0) { 404 printf("%s: there will be %i entries consuming %i sectors. " 405 "Catalog is %i sectors\n", __func__, num_entries, 406 used_sectors, catalog_sectors); 407 } 408 409 /* Populate sector numbers */ 410 sector = first_sector + catalog_sectors; 411 TAILQ_FOREACH(tmp_disk, &diskStructure.boot_images, image_list) { 412 tmp_disk->sector = sector; 413 sector += tmp_disk->num_sectors; 414 } 415 416 LIST_INSERT_HEAD(&diskStructure.boot_entries, valid_entry, ll_struct); 417 418 /* Step 1b: Initial/default entry */ 419 /* TODO : PARAM */ 420 tmp_disk = TAILQ_FIRST(&diskStructure.boot_images); 421 default_entry = cd9660_boot_setup_default_entry(tmp_disk); 422 if (default_entry == NULL) { 423 warnx("Error: memory allocation failed in cd9660_setup_boot"); 424 return -1; 425 } 426 427 LIST_INSERT_AFTER(valid_entry, default_entry, ll_struct); 428 429 /* Todo: multiple default entries? */ 430 431 tmp_disk = TAILQ_NEXT(tmp_disk, image_list); 432 433 temp = default_entry; 434 435 /* If multiple boot images are given : */ 436 while (tmp_disk != NULL) { 437 /* Step 2: Section header */ 438 switch (tmp_disk->system) { 439 case ET_SYS_X86: 440 headp = &x86_head; 441 break; 442 case ET_SYS_PPC: 443 headp = &ppc_head; 444 break; 445 case ET_SYS_MAC: 446 headp = &mac_head; 447 break; 448 default: 449 warnx("%s: internal error: unknown system type", 450 __func__); 451 return -1; 452 } 453 454 if (*headp == NULL) { 455 head = 456 cd9660_boot_setup_section_head(tmp_disk->system); 457 if (head == NULL) { 458 warnx("Error: memory allocation failed in " 459 "cd9660_setup_boot"); 460 return -1; 461 } 462 LIST_INSERT_AFTER(default_entry, head, ll_struct); 463 *headp = head; 464 } else 465 head = *headp; 466 467 head->entry_data.SH.num_section_entries[0]++; 468 469 /* Step 2a: Section entry and extensions */ 470 temp = cd9660_boot_setup_section_entry(tmp_disk); 471 if (temp == NULL) { 472 warn("%s: cd9660_boot_setup_section_entry", __func__); 473 return -1; 474 } 475 476 while ((next = LIST_NEXT(head, ll_struct)) != NULL && 477 next->entry_type == ET_ENTRY_SE) 478 head = next; 479 480 LIST_INSERT_AFTER(head, temp, ll_struct); 481 tmp_disk = TAILQ_NEXT(tmp_disk, image_list); 482 } 483 484 /* TODO: Remaining boot disks when implemented */ 485 486 return first_sector + used_sectors; 487 } 488 489 int 490 cd9660_setup_boot_volume_descriptor(volume_descriptor *bvd) 491 { 492 boot_volume_descriptor *bvdData = 493 (boot_volume_descriptor*)bvd->volumeDescriptorData; 494 495 bvdData->boot_record_indicator[0] = ISO_VOLUME_DESCRIPTOR_BOOT; 496 memcpy(bvdData->identifier, ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5); 497 bvdData->version[0] = 1; 498 memcpy(bvdData->boot_system_identifier, ET_ID, 23); 499 memcpy(bvdData->identifier, ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5); 500 diskStructure.boot_descriptor = 501 (boot_volume_descriptor*) bvd->volumeDescriptorData; 502 return 1; 503 } 504 505 static int 506 cd9660_write_mbr_partition_entry(FILE *fd, int idx, off_t sector_start, 507 off_t nsectors, int type) 508 { 509 uint8_t val; 510 uint32_t lba; 511 512 if (fseeko(fd, (off_t)(idx) * 16 + 0x1be, SEEK_SET) == -1) 513 err(1, "fseeko"); 514 515 val = 0x80; /* Bootable */ 516 fwrite(&val, sizeof(val), 1, fd); 517 518 val = 0xff; /* CHS begin */ 519 fwrite(&val, sizeof(val), 1, fd); 520 fwrite(&val, sizeof(val), 1, fd); 521 fwrite(&val, sizeof(val), 1, fd); 522 523 val = type; /* Part type */ 524 fwrite(&val, sizeof(val), 1, fd); 525 526 val = 0xff; /* CHS end */ 527 fwrite(&val, sizeof(val), 1, fd); 528 fwrite(&val, sizeof(val), 1, fd); 529 fwrite(&val, sizeof(val), 1, fd); 530 531 /* LBA extent */ 532 lba = htole32(sector_start); 533 fwrite(&lba, sizeof(lba), 1, fd); 534 lba = htole32(nsectors); 535 fwrite(&lba, sizeof(lba), 1, fd); 536 537 return 0; 538 } 539 540 static int 541 cd9660_write_apm_partition_entry(FILE *fd, int idx, int total_partitions, 542 off_t sector_start, off_t nsectors, off_t sector_size, 543 const char *part_name, const char *part_type) 544 { 545 uint32_t apm32, part_status; 546 uint16_t apm16; 547 548 /* See Apple Tech Note 1189 for the details about the pmPartStatus 549 * flags. 550 * Below the flags which are default: 551 * - IsValid 0x01 552 * - IsAllocated 0x02 553 * - IsReadable 0x10 554 * - IsWritable 0x20 555 */ 556 part_status = APPLE_PS_VALID | APPLE_PS_ALLOCATED | APPLE_PS_READABLE | 557 APPLE_PS_WRITABLE; 558 559 if (fseeko(fd, (off_t)(idx + 1) * sector_size, SEEK_SET) == -1) 560 err(1, "fseeko"); 561 562 /* Signature */ 563 apm16 = htobe16(0x504d); 564 fwrite(&apm16, sizeof(apm16), 1, fd); 565 apm16 = 0; 566 fwrite(&apm16, sizeof(apm16), 1, fd); 567 568 /* Total number of partitions */ 569 apm32 = htobe32(total_partitions); 570 fwrite(&apm32, sizeof(apm32), 1, fd); 571 /* Bounds */ 572 apm32 = htobe32(sector_start); 573 fwrite(&apm32, sizeof(apm32), 1, fd); 574 apm32 = htobe32(nsectors); 575 fwrite(&apm32, sizeof(apm32), 1, fd); 576 577 fwrite(part_name, strlen(part_name) + 1, 1, fd); 578 fseek(fd, 32 - strlen(part_name) - 1, SEEK_CUR); 579 fwrite(part_type, strlen(part_type) + 1, 1, fd); 580 fseek(fd, 32 - strlen(part_type) - 1, SEEK_CUR); 581 582 apm32 = 0; 583 /* pmLgDataStart */ 584 fwrite(&apm32, sizeof(apm32), 1, fd); 585 /* pmDataCnt */ 586 apm32 = htobe32(nsectors); 587 fwrite(&apm32, sizeof(apm32), 1, fd); 588 /* pmPartStatus */ 589 apm32 = htobe32(part_status); 590 fwrite(&apm32, sizeof(apm32), 1, fd); 591 592 return 0; 593 } 594 595 int 596 cd9660_write_boot(FILE *fd) 597 { 598 struct boot_catalog_entry *e; 599 struct cd9660_boot_image *t; 600 int apm_partitions = 0; 601 int mbr_partitions = 0; 602 603 /* write boot catalog */ 604 if (fseeko(fd, (off_t)diskStructure.boot_catalog_sector * 605 diskStructure.sectorSize, SEEK_SET) == -1) 606 err(1, "fseeko"); 607 608 if (diskStructure.verbose_level > 0) { 609 printf("Writing boot catalog to sector %" PRId64 "\n", 610 diskStructure.boot_catalog_sector); 611 } 612 LIST_FOREACH(e, &diskStructure.boot_entries, ll_struct) { 613 if (diskStructure.verbose_level > 0) { 614 printf("Writing catalog entry of type %d\n", 615 e->entry_type); 616 } 617 /* 618 * It doesnt matter which one gets written 619 * since they are the same size 620 */ 621 fwrite(&(e->entry_data.VE), 1, 32, fd); 622 } 623 if (diskStructure.verbose_level > 0) 624 printf("Finished writing boot catalog\n"); 625 626 /* copy boot images */ 627 TAILQ_FOREACH(t, &diskStructure.boot_images, image_list) { 628 if (diskStructure.verbose_level > 0) { 629 printf("Writing boot image from %s to sectors %d\n", 630 t->filename, t->sector); 631 } 632 cd9660_copy_file(fd, t->sector, t->filename); 633 634 if (t->system == ET_SYS_MAC) 635 apm_partitions++; 636 if (t->system == ET_SYS_PPC) 637 mbr_partitions++; 638 } 639 640 /* some systems need partition tables as well */ 641 if (mbr_partitions > 0 || diskStructure.chrp_boot) { 642 uint16_t sig; 643 644 fseek(fd, 0x1fe, SEEK_SET); 645 sig = htole16(0xaa55); 646 fwrite(&sig, sizeof(sig), 1, fd); 647 648 mbr_partitions = 0; 649 650 /* Write ISO9660 descriptor, enclosing the whole disk */ 651 if (diskStructure.chrp_boot) 652 cd9660_write_mbr_partition_entry(fd, mbr_partitions++, 653 0, diskStructure.totalSectors * 654 (diskStructure.sectorSize / 512), 0x96); 655 656 /* Write all partition entries */ 657 TAILQ_FOREACH(t, &diskStructure.boot_images, image_list) { 658 if (t->system != ET_SYS_PPC) 659 continue; 660 cd9660_write_mbr_partition_entry(fd, mbr_partitions++, 661 t->sector * (diskStructure.sectorSize / 512), 662 t->num_sectors * (diskStructure.sectorSize / 512), 663 0x41 /* PReP Boot */); 664 } 665 } 666 667 if (apm_partitions > 0) { 668 /* Write DDR and global APM info */ 669 uint32_t apm32; 670 uint16_t apm16; 671 int total_parts; 672 673 fseek(fd, 0, SEEK_SET); 674 apm16 = htobe16(0x4552); 675 fwrite(&apm16, sizeof(apm16), 1, fd); 676 /* Device block size */ 677 apm16 = htobe16(512); 678 fwrite(&apm16, sizeof(apm16), 1, fd); 679 /* Device block count */ 680 apm32 = htobe32(diskStructure.totalSectors * 681 (diskStructure.sectorSize / 512)); 682 fwrite(&apm32, sizeof(apm32), 1, fd); 683 /* Device type/id */ 684 apm16 = htobe16(1); 685 fwrite(&apm16, sizeof(apm16), 1, fd); 686 fwrite(&apm16, sizeof(apm16), 1, fd); 687 688 /* Count total needed entries */ 689 total_parts = 2 + apm_partitions; /* Self + ISO9660 */ 690 691 /* Write self-descriptor */ 692 cd9660_write_apm_partition_entry(fd, 0, total_parts, 1, 693 total_parts, 512, "Apple", "Apple_partition_map"); 694 695 /* Write all partition entries */ 696 apm_partitions = 0; 697 TAILQ_FOREACH(t, &diskStructure.boot_images, image_list) { 698 if (t->system != ET_SYS_MAC) 699 continue; 700 701 cd9660_write_apm_partition_entry(fd, 702 1 + apm_partitions++, total_parts, 703 t->sector * (diskStructure.sectorSize / 512), 704 t->num_sectors * (diskStructure.sectorSize / 512), 705 512, "CD Boot", "Apple_Bootstrap"); 706 } 707 708 /* Write ISO9660 descriptor, enclosing the whole disk */ 709 cd9660_write_apm_partition_entry(fd, 2 + apm_partitions, 710 total_parts, 0, diskStructure.totalSectors * 711 (diskStructure.sectorSize / 512), 512, "ISO9660", 712 "CD_ROM_Mode_1"); 713 } 714 715 return 0; 716 } 717 718