1224762Smarius/* $NetBSD: cd9660_eltorito.c,v 1.17 2011/06/23 02:35:56 enami Exp $ */ 2214921Scognet 3214921Scognet/* 4214921Scognet * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan 5214921Scognet * Perez-Rathke and Ram Vedam. All rights reserved. 6214921Scognet * 7214921Scognet * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys, 8214921Scognet * Alan Perez-Rathke and Ram Vedam. 9214921Scognet * 10214921Scognet * Redistribution and use in source and binary forms, with or 11214921Scognet * without modification, are permitted provided that the following 12214921Scognet * conditions are met: 13214921Scognet * 1. Redistributions of source code must retain the above copyright 14214921Scognet * notice, this list of conditions and the following disclaimer. 15214921Scognet * 2. Redistributions in binary form must reproduce the above 16214921Scognet * copyright notice, this list of conditions and the following 17214921Scognet * disclaimer in the documentation and/or other materials provided 18214921Scognet * with the distribution. 19214921Scognet * 20214921Scognet * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN 21214921Scognet * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR 22214921Scognet * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23214921Scognet * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24214921Scognet * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN 25214921Scognet * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT, 26214921Scognet * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27214921Scognet * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 28214921Scognet * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 29214921Scognet * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30214921Scognet * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31214921Scognet * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 32214921Scognet * OF SUCH DAMAGE. 33214921Scognet */ 34221387Snwhitehorn 35214921Scognet#include "cd9660.h" 36214921Scognet#include "cd9660_eltorito.h" 37214921Scognet 38214921Scognet#include <sys/cdefs.h> 39214921Scognet__FBSDID("$FreeBSD$"); 40214921Scognet 41214921Scognet#ifdef DEBUG 42214921Scognet#define ELTORITO_DPRINTF(__x) printf __x 43214921Scognet#else 44214921Scognet#define ELTORITO_DPRINTF(__x) 45214921Scognet#endif 46214921Scognet 47214921Scognetstatic struct boot_catalog_entry *cd9660_init_boot_catalog_entry(void); 48214921Scognetstatic struct boot_catalog_entry *cd9660_boot_setup_validation_entry(char); 49214921Scognetstatic struct boot_catalog_entry *cd9660_boot_setup_default_entry( 50214921Scognet struct cd9660_boot_image *); 51214921Scognetstatic struct boot_catalog_entry *cd9660_boot_setup_section_head(char); 52214921Scognetstatic struct boot_catalog_entry *cd9660_boot_setup_validation_entry(char); 53214921Scognet#if 0 54214921Scognetstatic u_char cd9660_boot_get_system_type(struct cd9660_boot_image *); 55214921Scognet#endif 56214921Scognet 57214921Scognetint 58214921Scognetcd9660_add_boot_disk(const char *boot_info) 59214921Scognet{ 60214921Scognet struct stat stbuf; 61214921Scognet const char *mode_msg; 62214921Scognet char *temp; 63214921Scognet char *sysname; 64214921Scognet char *filename; 65214921Scognet struct cd9660_boot_image *new_image, *tmp_image; 66214921Scognet 67214921Scognet assert(boot_info != NULL); 68214921Scognet 69214921Scognet if (*boot_info == '\0') { 70214921Scognet warnx("Error: Boot disk information must be in the " 71214921Scognet "format 'system;filename'"); 72214921Scognet return 0; 73214921Scognet } 74214921Scognet 75214921Scognet /* First decode the boot information */ 76214921Scognet if ((temp = strdup(boot_info)) == NULL) { 77214921Scognet warn("%s: strdup", __func__); 78214921Scognet return 0; 79214921Scognet } 80214921Scognet 81214921Scognet sysname = temp; 82214921Scognet filename = strchr(sysname, ';'); 83214921Scognet if (filename == NULL) { 84214921Scognet warnx("supply boot disk information in the format " 85214921Scognet "'system;filename'"); 86214921Scognet free(temp); 87214921Scognet return 0; 88214921Scognet } 89214921Scognet 90214921Scognet *filename++ = '\0'; 91214921Scognet 92214921Scognet if (diskStructure.verbose_level > 0) { 93214921Scognet printf("Found bootdisk with system %s, and filename %s\n", 94214921Scognet sysname, filename); 95214921Scognet } 96214921Scognet if ((new_image = malloc(sizeof(*new_image))) == NULL) { 97214921Scognet warn("%s: malloc", __func__); 98214921Scognet free(temp); 99214921Scognet return 0; 100214921Scognet } 101214921Scognet (void)memset(new_image, 0, sizeof(*new_image)); 102214921Scognet new_image->loadSegment = 0; /* default for now */ 103214921Scognet 104214921Scognet /* Decode System */ 105214921Scognet if (strcmp(sysname, "i386") == 0) 106214921Scognet new_image->system = ET_SYS_X86; 107214921Scognet else if (strcmp(sysname, "powerpc") == 0) 108214921Scognet new_image->system = ET_SYS_PPC; 109214921Scognet else if (strcmp(sysname, "macppc") == 0 || 110214921Scognet strcmp(sysname, "mac68k") == 0) 111214921Scognet new_image->system = ET_SYS_MAC; 112214921Scognet else { 113214921Scognet warnx("boot disk system must be " 114214921Scognet "i386, powerpc, macppc, or mac68k"); 115214921Scognet free(temp); 116214921Scognet free(new_image); 117214921Scognet return 0; 118214921Scognet } 119214921Scognet 120214921Scognet 121214921Scognet if ((new_image->filename = strdup(filename)) == NULL) { 122214921Scognet warn("%s: strdup", __func__); 123214921Scognet free(temp); 124214921Scognet free(new_image); 125214921Scognet return 0; 126214921Scognet } 127214921Scognet 128214921Scognet free(temp); 129214921Scognet 130214921Scognet /* Get information about the file */ 131214921Scognet if (lstat(new_image->filename, &stbuf) == -1) 132214921Scognet err(EXIT_FAILURE, "%s: lstat(\"%s\")", __func__, 133214921Scognet new_image->filename); 134214921Scognet 135214921Scognet switch (stbuf.st_size) { 136214921Scognet case 1440 * 1024: 137214921Scognet new_image->targetMode = ET_MEDIA_144FDD; 138214921Scognet mode_msg = "Assigned boot image to 1.44 emulation mode"; 139214921Scognet break; 140214921Scognet case 1200 * 1024: 141214921Scognet new_image->targetMode = ET_MEDIA_12FDD; 142214921Scognet mode_msg = "Assigned boot image to 1.2 emulation mode"; 143214921Scognet break; 144214921Scognet case 2880 * 1024: 145214921Scognet new_image->targetMode = ET_MEDIA_288FDD; 146214921Scognet mode_msg = "Assigned boot image to 2.88 emulation mode"; 147214921Scognet break; 148214921Scognet default: 149214921Scognet new_image->targetMode = ET_MEDIA_NOEM; 150214921Scognet mode_msg = "Assigned boot image to no emulation mode"; 151214921Scognet break; 152214921Scognet } 153214921Scognet 154214921Scognet if (diskStructure.verbose_level > 0) 155214921Scognet printf("%s\n", mode_msg); 156214921Scognet 157214921Scognet new_image->size = stbuf.st_size; 158214921Scognet new_image->num_sectors = 159214921Scognet howmany(new_image->size, diskStructure.sectorSize) * 160214921Scognet howmany(diskStructure.sectorSize, 512); 161214921Scognet if (diskStructure.verbose_level > 0) { 162214921Scognet printf("New image has size %d, uses %d 512-byte sectors\n", 163214921Scognet new_image->size, new_image->num_sectors); 164214921Scognet } 165214921Scognet new_image->sector = -1; 166214921Scognet /* Bootable by default */ 167214921Scognet new_image->bootable = ET_BOOTABLE; 168214921Scognet /* Add boot disk */ 169214921Scognet 170214921Scognet /* Group images for the same platform together. */ 171214921Scognet TAILQ_FOREACH(tmp_image, &diskStructure.boot_images, image_list) { 172214921Scognet if (tmp_image->system != new_image->system) 173214921Scognet break; 174214921Scognet } 175214921Scognet 176214921Scognet if (tmp_image == NULL) { 177214921Scognet TAILQ_INSERT_HEAD(&diskStructure.boot_images, new_image, 178214921Scognet image_list); 179214921Scognet } else 180214921Scognet TAILQ_INSERT_BEFORE(tmp_image, new_image, image_list); 181214921Scognet 182214921Scognet new_image->serialno = diskStructure.image_serialno++; 183214921Scognet 184214921Scognet /* TODO : Need to do anything about the boot image in the tree? */ 185214921Scognet diskStructure.is_bootable = 1; 186214921Scognet 187214921Scognet return 1; 188214921Scognet} 189214921Scognet 190214921Scognetint 191214921Scognetcd9660_eltorito_add_boot_option(const char *option_string, const char *value) 192214921Scognet{ 193214921Scognet char *eptr; 194214921Scognet struct cd9660_boot_image *image; 195214921Scognet 196214921Scognet assert(option_string != NULL); 197214921Scognet 198214921Scognet /* Find the last image added */ 199214921Scognet TAILQ_FOREACH(image, &diskStructure.boot_images, image_list) { 200214921Scognet if (image->serialno + 1 == diskStructure.image_serialno) 201214921Scognet break; 202214921Scognet } 203214921Scognet if (image == NULL) 204214921Scognet errx(EXIT_FAILURE, "Attempted to add boot option, " 205214921Scognet "but no boot images have been specified"); 206214921Scognet 207214921Scognet if (strcmp(option_string, "no-emul-boot") == 0) { 208214921Scognet image->targetMode = ET_MEDIA_NOEM; 209214921Scognet } else if (strcmp(option_string, "no-boot") == 0) { 210214921Scognet image->bootable = ET_NOT_BOOTABLE; 211214921Scognet } else if (strcmp(option_string, "hard-disk-boot") == 0) { 212214921Scognet image->targetMode = ET_MEDIA_HDD; 213214921Scognet } else if (strcmp(option_string, "boot-load-segment") == 0) { 214214921Scognet image->loadSegment = strtoul(value, &eptr, 16); 215214921Scognet if (eptr == value || *eptr != '\0' || errno != ERANGE) { 216214921Scognet warn("%s: strtoul", __func__); 217214921Scognet return 0; 218214921Scognet } 219214921Scognet } else { 220214921Scognet return 0; 221214921Scognet } 222214921Scognet return 1; 223214921Scognet} 224214921Scognet 225214921Scognetstatic struct boot_catalog_entry * 226214921Scognetcd9660_init_boot_catalog_entry(void) 227214921Scognet{ 228214921Scognet struct boot_catalog_entry *temp; 229214921Scognet 230214921Scognet if ((temp = malloc(sizeof(*temp))) == NULL) 231214921Scognet return NULL; 232214921Scognet 233214921Scognet return memset(temp, 0, sizeof(*temp)); 234214921Scognet} 235214921Scognet 236214921Scognetstatic struct boot_catalog_entry * 237214921Scognetcd9660_boot_setup_validation_entry(char sys) 238214921Scognet{ 239214921Scognet struct boot_catalog_entry *entry; 240214921Scognet boot_catalog_validation_entry *ve; 241214921Scognet int16_t checksum; 242214921Scognet unsigned char *csptr; 243214921Scognet int i; 244214921Scognet entry = cd9660_init_boot_catalog_entry(); 245214921Scognet 246214921Scognet if (entry == NULL) { 247214921Scognet warnx("Error: memory allocation failed in " 248214921Scognet "cd9660_boot_setup_validation_entry"); 249214921Scognet return 0; 250214921Scognet } 251214921Scognet ve = &entry->entry_data.VE; 252214921Scognet 253214921Scognet ve->header_id[0] = 1; 254214921Scognet ve->platform_id[0] = sys; 255214921Scognet ve->key[0] = 0x55; 256214921Scognet ve->key[1] = 0xAA; 257214921Scognet 258214921Scognet /* Calculate checksum */ 259214921Scognet checksum = 0; 260214921Scognet cd9660_721(0, ve->checksum); 261214921Scognet csptr = (unsigned char*)ve; 262214921Scognet for (i = 0; i < sizeof(*ve); i += 2) { 263214921Scognet checksum += (int16_t)csptr[i]; 264214921Scognet checksum += 256 * (int16_t)csptr[i + 1]; 265214921Scognet } 266214921Scognet checksum = -checksum; 267214921Scognet cd9660_721(checksum, ve->checksum); 268214921Scognet 269214921Scognet ELTORITO_DPRINTF(("%s: header_id %d, platform_id %d, key[0] %d, key[1] %d, " 270214921Scognet "checksum %04x\n", __func__, ve->header_id[0], ve->platform_id[0], 271214921Scognet ve->key[0], ve->key[1], checksum)); 272214921Scognet return entry; 273214921Scognet} 274214921Scognet 275214921Scognetstatic struct boot_catalog_entry * 276214921Scognetcd9660_boot_setup_default_entry(struct cd9660_boot_image *disk) 277214921Scognet{ 278214921Scognet struct boot_catalog_entry *default_entry; 279214921Scognet boot_catalog_initial_entry *ie; 280214921Scognet 281214921Scognet default_entry = cd9660_init_boot_catalog_entry(); 282214921Scognet if (default_entry == NULL) 283214921Scognet return NULL; 284214921Scognet 285214921Scognet ie = &default_entry->entry_data.IE; 286214921Scognet 287214921Scognet ie->boot_indicator[0] = disk->bootable; 288214921Scognet ie->media_type[0] = disk->targetMode; 289214921Scognet cd9660_721(disk->loadSegment, ie->load_segment); 290214921Scognet ie->system_type[0] = disk->system; 291214921Scognet cd9660_721(disk->num_sectors, ie->sector_count); 292214921Scognet cd9660_731(disk->sector, ie->load_rba); 293214921Scognet 294214921Scognet ELTORITO_DPRINTF(("%s: boot indicator %d, media type %d, " 295214921Scognet "load segment %04x, system type %d, sector count %d, " 296214921Scognet "load rba %d\n", __func__, ie->boot_indicator[0], 297214921Scognet ie->media_type[0], disk->loadSegment, ie->system_type[0], 298214921Scognet disk->num_sectors, disk->sector)); 299214921Scognet return default_entry; 300214921Scognet} 301214921Scognet 302214921Scognetstatic struct boot_catalog_entry * 303214921Scognetcd9660_boot_setup_section_head(char platform) 304214921Scognet{ 305214921Scognet struct boot_catalog_entry *entry; 306214921Scognet boot_catalog_section_header *sh; 307214921Scognet 308214921Scognet entry = cd9660_init_boot_catalog_entry(); 309214921Scognet if (entry == NULL) 310214921Scognet return NULL; 311214921Scognet 312214921Scognet sh = &entry->entry_data.SH; 313214921Scognet /* More by default. The last one will manually be set to 0x91 */ 314214921Scognet sh->header_indicator[0] = ET_SECTION_HEADER_MORE; 315214921Scognet sh->platform_id[0] = platform; 316214921Scognet sh->num_section_entries[0] = 0; 317214921Scognet return entry; 318214921Scognet} 319214921Scognet 320214921Scognetstatic struct boot_catalog_entry * 321214921Scognetcd9660_boot_setup_section_entry(struct cd9660_boot_image *disk) 322214921Scognet{ 323214921Scognet struct boot_catalog_entry *entry; 324214921Scognet boot_catalog_section_entry *se; 325214921Scognet if ((entry = cd9660_init_boot_catalog_entry()) == NULL) 326214921Scognet return NULL; 327214921Scognet 328214921Scognet se = &entry->entry_data.SE; 329214921Scognet 330214921Scognet se->boot_indicator[0] = ET_BOOTABLE; 331214921Scognet se->media_type[0] = disk->targetMode; 332214921Scognet cd9660_721(disk->loadSegment, se->load_segment); 333214921Scognet cd9660_721(disk->num_sectors, se->sector_count); 334214921Scognet cd9660_731(disk->sector, se->load_rba); 335214921Scognet return entry; 336214921Scognet} 337214921Scognet 338214921Scognet#if 0 339214921Scognetstatic u_char 340214921Scognetcd9660_boot_get_system_type(struct cd9660_boot_image *disk) 341214921Scognet{ 342214921Scognet /* 343214921Scognet For hard drive booting, we need to examine the MBR to figure 344214921Scognet out what the partition type is 345214921Scognet */ 346214921Scognet return 0; 347214921Scognet} 348214921Scognet#endif 349214921Scognet 350214921Scognet/* 351214921Scognet * Set up the BVD, Boot catalog, and the boot entries, but do no writing 352214921Scognet */ 353214921Scognetint 354214921Scognetcd9660_setup_boot(int first_sector) 355214921Scognet{ 356214921Scognet int sector; 357214921Scognet int used_sectors; 358214921Scognet int num_entries = 0; 359214921Scognet int catalog_sectors; 360214921Scognet struct boot_catalog_entry *x86_head, *mac_head, *ppc_head, 361214921Scognet *valid_entry, *default_entry, *temp, *head, **headp, *next; 362214921Scognet struct cd9660_boot_image *tmp_disk; 363214921Scognet 364214921Scognet headp = NULL; 365214921Scognet x86_head = mac_head = ppc_head = NULL; 366214921Scognet 367214921Scognet /* If there are no boot disks, don't bother building boot information */ 368214921Scognet if (TAILQ_EMPTY(&diskStructure.boot_images)) 369214921Scognet return 0; 370214921Scognet 371214921Scognet /* Point to catalog: For now assume it consumes one sector */ 372214921Scognet ELTORITO_DPRINTF(("Boot catalog will go in sector %d\n", first_sector)); 373214921Scognet diskStructure.boot_catalog_sector = first_sector; 374214921Scognet cd9660_bothendian_dword(first_sector, 375214921Scognet diskStructure.boot_descriptor->boot_catalog_pointer); 376214921Scognet 377214921Scognet /* Step 1: Generate boot catalog */ 378214921Scognet /* Step 1a: Validation entry */ 379214921Scognet valid_entry = cd9660_boot_setup_validation_entry(ET_SYS_X86); 380214921Scognet if (valid_entry == NULL) 381214921Scognet return -1; 382214921Scognet 383214921Scognet /* 384214921Scognet * Count how many boot images there are, 385214921Scognet * and how many sectors they consume. 386214921Scognet */ 387214921Scognet num_entries = 1; 388214921Scognet used_sectors = 0; 389214921Scognet 390214921Scognet TAILQ_FOREACH(tmp_disk, &diskStructure.boot_images, image_list) { 391214921Scognet used_sectors += tmp_disk->num_sectors; 392214921Scognet 393214921Scognet /* One default entry per image */ 394214921Scognet num_entries++; 395214921Scognet } 396214921Scognet catalog_sectors = howmany(num_entries * 0x20, diskStructure.sectorSize); 397214921Scognet used_sectors += catalog_sectors; 398214921Scognet 399214921Scognet if (diskStructure.verbose_level > 0) { 400214921Scognet printf("%s: there will be %i entries consuming %i sectors. " 401214921Scognet "Catalog is %i sectors\n", __func__, num_entries, 402214921Scognet used_sectors, catalog_sectors); 403214921Scognet } 404214921Scognet 405214921Scognet /* Populate sector numbers */ 406214921Scognet sector = first_sector + catalog_sectors; 407214921Scognet TAILQ_FOREACH(tmp_disk, &diskStructure.boot_images, image_list) { 408214921Scognet tmp_disk->sector = sector; 409214921Scognet sector += tmp_disk->num_sectors; 410214921Scognet } 411214921Scognet 412214921Scognet LIST_INSERT_HEAD(&diskStructure.boot_entries, valid_entry, ll_struct); 413214921Scognet 414214921Scognet /* Step 1b: Initial/default entry */ 415214921Scognet /* TODO : PARAM */ 416214921Scognet tmp_disk = TAILQ_FIRST(&diskStructure.boot_images); 417214921Scognet default_entry = cd9660_boot_setup_default_entry(tmp_disk); 418214921Scognet if (default_entry == NULL) { 419214921Scognet warnx("Error: memory allocation failed in cd9660_setup_boot"); 420214921Scognet return -1; 421214921Scognet } 422214921Scognet 423214921Scognet LIST_INSERT_AFTER(valid_entry, default_entry, ll_struct); 424214921Scognet 425214921Scognet /* Todo: multiple default entries? */ 426214921Scognet 427214921Scognet tmp_disk = TAILQ_NEXT(tmp_disk, image_list); 428214921Scognet 429214921Scognet temp = default_entry; 430214921Scognet 431214921Scognet /* If multiple boot images are given : */ 432214921Scognet while (tmp_disk != NULL) { 433214921Scognet /* Step 2: Section header */ 434214921Scognet switch (tmp_disk->system) { 435214921Scognet case ET_SYS_X86: 436214921Scognet headp = &x86_head; 437214921Scognet break; 438214921Scognet case ET_SYS_PPC: 439214921Scognet headp = &ppc_head; 440214921Scognet break; 441214921Scognet case ET_SYS_MAC: 442214921Scognet headp = &mac_head; 443214921Scognet break; 444214921Scognet default: 445214921Scognet warnx("%s: internal error: unknown system type", 446214921Scognet __func__); 447214921Scognet return -1; 448214921Scognet } 449214921Scognet 450214921Scognet if (*headp == NULL) { 451214921Scognet head = 452214921Scognet cd9660_boot_setup_section_head(tmp_disk->system); 453214921Scognet if (head == NULL) { 454214921Scognet warnx("Error: memory allocation failed in " 455214921Scognet "cd9660_setup_boot"); 456214921Scognet return -1; 457214921Scognet } 458214921Scognet LIST_INSERT_AFTER(default_entry, head, ll_struct); 459214921Scognet *headp = head; 460214921Scognet } else 461214921Scognet head = *headp; 462214921Scognet 463214921Scognet head->entry_data.SH.num_section_entries[0]++; 464214921Scognet 465214921Scognet /* Step 2a: Section entry and extensions */ 466214921Scognet temp = cd9660_boot_setup_section_entry(tmp_disk); 467214921Scognet if (temp == NULL) { 468214921Scognet warn("%s: cd9660_boot_setup_section_entry", __func__); 469214921Scognet return -1; 470214921Scognet } 471214921Scognet 472214921Scognet while ((next = LIST_NEXT(head, ll_struct)) != NULL && 473214921Scognet next->entry_type == ET_ENTRY_SE) 474214921Scognet head = next; 475214921Scognet 476214921Scognet LIST_INSERT_AFTER(head, temp, ll_struct); 477214921Scognet tmp_disk = TAILQ_NEXT(tmp_disk, image_list); 478214921Scognet } 479214921Scognet 480214921Scognet /* TODO: Remaining boot disks when implemented */ 481214921Scognet 482214921Scognet return first_sector + used_sectors; 483214921Scognet} 484214921Scognet 485214921Scognetint 486214921Scognetcd9660_setup_boot_volume_descriptor(volume_descriptor *bvd) 487214921Scognet{ 488214921Scognet boot_volume_descriptor *bvdData = 489214921Scognet (boot_volume_descriptor*)bvd->volumeDescriptorData; 490214921Scognet 491214921Scognet bvdData->boot_record_indicator[0] = ISO_VOLUME_DESCRIPTOR_BOOT; 492214921Scognet memcpy(bvdData->identifier, ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5); 493214921Scognet bvdData->version[0] = 1; 494214921Scognet memcpy(bvdData->boot_system_identifier, ET_ID, 23); 495214921Scognet memcpy(bvdData->identifier, ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5); 496214921Scognet diskStructure.boot_descriptor = 497214921Scognet (boot_volume_descriptor*) bvd->volumeDescriptorData; 498214921Scognet return 1; 499214921Scognet} 500214921Scognet 501221387Snwhitehornstatic int 502224762Smariuscd9660_write_mbr_partition_entry(FILE *fd, int idx, off_t sector_start, 503222191Snwhitehorn off_t nsectors, int type) 504222191Snwhitehorn{ 505222191Snwhitehorn uint8_t val; 506222191Snwhitehorn uint32_t lba; 507222191Snwhitehorn 508224762Smarius if (fseeko(fd, (off_t)(idx) * 16 + 0x1be, SEEK_SET) == -1) 509224762Smarius err(1, "fseeko"); 510222191Snwhitehorn 511222191Snwhitehorn val = 0x80; /* Bootable */ 512222191Snwhitehorn fwrite(&val, sizeof(val), 1, fd); 513222191Snwhitehorn 514222191Snwhitehorn val = 0xff; /* CHS begin */ 515222191Snwhitehorn fwrite(&val, sizeof(val), 1, fd); 516222191Snwhitehorn fwrite(&val, sizeof(val), 1, fd); 517222191Snwhitehorn fwrite(&val, sizeof(val), 1, fd); 518222191Snwhitehorn 519222191Snwhitehorn val = type; /* Part type */ 520222191Snwhitehorn fwrite(&val, sizeof(val), 1, fd); 521222191Snwhitehorn 522222191Snwhitehorn val = 0xff; /* CHS end */ 523222191Snwhitehorn fwrite(&val, sizeof(val), 1, fd); 524222191Snwhitehorn fwrite(&val, sizeof(val), 1, fd); 525222191Snwhitehorn fwrite(&val, sizeof(val), 1, fd); 526222191Snwhitehorn 527222191Snwhitehorn /* LBA extent */ 528222191Snwhitehorn lba = htole32(sector_start); 529222191Snwhitehorn fwrite(&lba, sizeof(lba), 1, fd); 530222191Snwhitehorn lba = htole32(nsectors); 531222191Snwhitehorn fwrite(&lba, sizeof(lba), 1, fd); 532222191Snwhitehorn 533224762Smarius return 0; 534222191Snwhitehorn} 535222191Snwhitehorn 536222191Snwhitehornstatic int 537224762Smariuscd9660_write_apm_partition_entry(FILE *fd, int idx, int total_partitions, 538221387Snwhitehorn off_t sector_start, off_t nsectors, off_t sector_size, 539222191Snwhitehorn const char *part_name, const char *part_type) 540222191Snwhitehorn{ 541233783Sandreast uint32_t apm32, part_status; 542221387Snwhitehorn uint16_t apm16; 543221387Snwhitehorn 544233783Sandreast /* See Apple Tech Note 1189 for the details about the pmPartStatus 545233783Sandreast * flags. 546233783Sandreast * Below the flags which are default: 547233783Sandreast * - IsValid 0x01 548233783Sandreast * - IsAllocated 0x02 549233783Sandreast * - IsReadable 0x10 550233783Sandreast * - IsWritable 0x20 551233783Sandreast */ 552233783Sandreast part_status = 0x01 | 0x02 | 0x10 | 0x20; 553233783Sandreast 554224762Smarius if (fseeko(fd, (off_t)(idx + 1) * sector_size, SEEK_SET) == -1) 555224762Smarius err(1, "fseeko"); 556221387Snwhitehorn 557221387Snwhitehorn /* Signature */ 558222191Snwhitehorn apm16 = htobe16(0x504d); 559221387Snwhitehorn fwrite(&apm16, sizeof(apm16), 1, fd); 560221387Snwhitehorn apm16 = 0; 561221387Snwhitehorn fwrite(&apm16, sizeof(apm16), 1, fd); 562221387Snwhitehorn 563221387Snwhitehorn /* Total number of partitions */ 564222191Snwhitehorn apm32 = htobe32(total_partitions); 565221387Snwhitehorn fwrite(&apm32, sizeof(apm32), 1, fd); 566221387Snwhitehorn /* Bounds */ 567222191Snwhitehorn apm32 = htobe32(sector_start); 568221387Snwhitehorn fwrite(&apm32, sizeof(apm32), 1, fd); 569222191Snwhitehorn apm32 = htobe32(nsectors); 570221387Snwhitehorn fwrite(&apm32, sizeof(apm32), 1, fd); 571221387Snwhitehorn 572221387Snwhitehorn fwrite(part_name, strlen(part_name) + 1, 1, fd); 573221387Snwhitehorn fseek(fd, 32 - strlen(part_name) - 1, SEEK_CUR); 574221387Snwhitehorn fwrite(part_type, strlen(part_type) + 1, 1, fd); 575233783Sandreast fseek(fd, 32 - strlen(part_type) - 1, SEEK_CUR); 576221387Snwhitehorn 577233783Sandreast apm32 = 0; 578233783Sandreast /* pmLgDataStart */ 579233783Sandreast fwrite(&apm32, sizeof(apm32), 1, fd); 580233783Sandreast /* pmDataCnt */ 581233783Sandreast apm32 = htobe32(nsectors); 582233783Sandreast fwrite(&apm32, sizeof(apm32), 1, fd); 583233783Sandreast /* pmPartStatus */ 584233783Sandreast apm32 = htobe32(part_status); 585233783Sandreast fwrite(&apm32, sizeof(apm32), 1, fd); 586233783Sandreast 587221387Snwhitehorn return 0; 588221387Snwhitehorn} 589221387Snwhitehorn 590214921Scognetint 591214921Scognetcd9660_write_boot(FILE *fd) 592214921Scognet{ 593214921Scognet struct boot_catalog_entry *e; 594214921Scognet struct cd9660_boot_image *t; 595221387Snwhitehorn int apm_partitions = 0; 596222191Snwhitehorn int mbr_partitions = 0; 597214921Scognet 598214921Scognet /* write boot catalog */ 599214921Scognet if (fseeko(fd, (off_t)diskStructure.boot_catalog_sector * 600214921Scognet diskStructure.sectorSize, SEEK_SET) == -1) 601214921Scognet err(1, "fseeko"); 602214921Scognet 603214921Scognet if (diskStructure.verbose_level > 0) { 604214921Scognet printf("Writing boot catalog to sector %" PRId64 "\n", 605214921Scognet diskStructure.boot_catalog_sector); 606214921Scognet } 607214921Scognet LIST_FOREACH(e, &diskStructure.boot_entries, ll_struct) { 608214921Scognet if (diskStructure.verbose_level > 0) { 609214921Scognet printf("Writing catalog entry of type %d\n", 610214921Scognet e->entry_type); 611214921Scognet } 612214921Scognet /* 613228990Suqs * It doesn't matter which one gets written 614214921Scognet * since they are the same size 615214921Scognet */ 616214921Scognet fwrite(&(e->entry_data.VE), 1, 32, fd); 617214921Scognet } 618214921Scognet if (diskStructure.verbose_level > 0) 619214921Scognet printf("Finished writing boot catalog\n"); 620214921Scognet 621214921Scognet /* copy boot images */ 622214921Scognet TAILQ_FOREACH(t, &diskStructure.boot_images, image_list) { 623214921Scognet if (diskStructure.verbose_level > 0) { 624214921Scognet printf("Writing boot image from %s to sectors %d\n", 625214921Scognet t->filename, t->sector); 626214921Scognet } 627214921Scognet cd9660_copy_file(fd, t->sector, t->filename); 628221387Snwhitehorn 629221387Snwhitehorn if (t->system == ET_SYS_MAC) 630221387Snwhitehorn apm_partitions++; 631222191Snwhitehorn if (t->system == ET_SYS_PPC) 632222191Snwhitehorn mbr_partitions++; 633214921Scognet } 634214921Scognet 635222191Snwhitehorn /* some systems need partition tables as well */ 636222191Snwhitehorn if (mbr_partitions > 0 || diskStructure.chrp_boot) { 637222191Snwhitehorn uint16_t sig; 638222191Snwhitehorn 639222191Snwhitehorn fseek(fd, 0x1fe, SEEK_SET); 640222191Snwhitehorn sig = htole16(0xaa55); 641222191Snwhitehorn fwrite(&sig, sizeof(sig), 1, fd); 642222191Snwhitehorn 643222191Snwhitehorn mbr_partitions = 0; 644222191Snwhitehorn 645222191Snwhitehorn /* Write ISO9660 descriptor, enclosing the whole disk */ 646222191Snwhitehorn if (diskStructure.chrp_boot) 647222191Snwhitehorn cd9660_write_mbr_partition_entry(fd, mbr_partitions++, 648222191Snwhitehorn 0, diskStructure.totalSectors * 649222191Snwhitehorn (diskStructure.sectorSize / 512), 0x96); 650222191Snwhitehorn 651222191Snwhitehorn /* Write all partition entries */ 652222191Snwhitehorn TAILQ_FOREACH(t, &diskStructure.boot_images, image_list) { 653222191Snwhitehorn if (t->system != ET_SYS_PPC) 654222191Snwhitehorn continue; 655222191Snwhitehorn cd9660_write_mbr_partition_entry(fd, mbr_partitions++, 656222191Snwhitehorn t->sector * (diskStructure.sectorSize / 512), 657222191Snwhitehorn t->num_sectors * (diskStructure.sectorSize / 512), 658222191Snwhitehorn 0x41 /* PReP Boot */); 659222191Snwhitehorn } 660222191Snwhitehorn } 661222191Snwhitehorn 662221387Snwhitehorn if (apm_partitions > 0) { 663221387Snwhitehorn /* Write DDR and global APM info */ 664221387Snwhitehorn uint32_t apm32; 665221387Snwhitehorn uint16_t apm16; 666221387Snwhitehorn int total_parts; 667221387Snwhitehorn 668221387Snwhitehorn fseek(fd, 0, SEEK_SET); 669222191Snwhitehorn apm16 = htobe16(0x4552); 670221387Snwhitehorn fwrite(&apm16, sizeof(apm16), 1, fd); 671221536Snwhitehorn /* Device block size */ 672222191Snwhitehorn apm16 = htobe16(512); 673221387Snwhitehorn fwrite(&apm16, sizeof(apm16), 1, fd); 674221536Snwhitehorn /* Device block count */ 675222191Snwhitehorn apm32 = htobe32(diskStructure.totalSectors * 676221536Snwhitehorn (diskStructure.sectorSize / 512)); 677221387Snwhitehorn fwrite(&apm32, sizeof(apm32), 1, fd); 678221536Snwhitehorn /* Device type/id */ 679222191Snwhitehorn apm16 = htobe16(1); 680221536Snwhitehorn fwrite(&apm16, sizeof(apm16), 1, fd); 681221536Snwhitehorn fwrite(&apm16, sizeof(apm16), 1, fd); 682221387Snwhitehorn 683221387Snwhitehorn /* Count total needed entries */ 684221387Snwhitehorn total_parts = 2 + apm_partitions; /* Self + ISO9660 */ 685221387Snwhitehorn 686221387Snwhitehorn /* Write self-descriptor */ 687221536Snwhitehorn cd9660_write_apm_partition_entry(fd, 0, total_parts, 1, 688221536Snwhitehorn total_parts, 512, "Apple", "Apple_partition_map"); 689221387Snwhitehorn 690221387Snwhitehorn /* Write all partition entries */ 691221387Snwhitehorn apm_partitions = 0; 692221387Snwhitehorn TAILQ_FOREACH(t, &diskStructure.boot_images, image_list) { 693221387Snwhitehorn if (t->system != ET_SYS_MAC) 694221387Snwhitehorn continue; 695221387Snwhitehorn 696221387Snwhitehorn cd9660_write_apm_partition_entry(fd, 697233783Sandreast 1 + apm_partitions++, total_parts, 698221536Snwhitehorn t->sector * (diskStructure.sectorSize / 512), 699221536Snwhitehorn t->num_sectors * (diskStructure.sectorSize / 512), 700221536Snwhitehorn 512, "CD Boot", "Apple_Bootstrap"); 701221387Snwhitehorn } 702233783Sandreast /* Write ISO9660 descriptor, enclosing the whole disk */ 703233783Sandreast cd9660_write_apm_partition_entry(fd, 2 + apm_partitions, 704233783Sandreast total_parts, 0, diskStructure.totalSectors * 705233783Sandreast (diskStructure.sectorSize / 512), 512, "ISO9660", 706233783Sandreast "CD_ROM_Mode_1"); 707221387Snwhitehorn } 708221387Snwhitehorn 709214921Scognet return 0; 710214921Scognet} 711221387Snwhitehorn 712