15978408cSSascha Wildner /* $NetBSD: cd9660_eltorito.c,v 1.23 2018/03/28 06:48:55 nonaka Exp $ */
25978408cSSascha Wildner
35978408cSSascha Wildner /*-
45978408cSSascha Wildner * SPDX-License-Identifier: BSD-2-Clause-NetBSD
55978408cSSascha Wildner *
65978408cSSascha Wildner * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
75978408cSSascha Wildner * Perez-Rathke and Ram Vedam. All rights reserved.
85978408cSSascha Wildner *
95978408cSSascha Wildner * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
105978408cSSascha Wildner * Alan Perez-Rathke and Ram Vedam.
115978408cSSascha Wildner *
125978408cSSascha Wildner * Redistribution and use in source and binary forms, with or
135978408cSSascha Wildner * without modification, are permitted provided that the following
145978408cSSascha Wildner * conditions are met:
155978408cSSascha Wildner * 1. Redistributions of source code must retain the above copyright
165978408cSSascha Wildner * notice, this list of conditions and the following disclaimer.
175978408cSSascha Wildner * 2. Redistributions in binary form must reproduce the above
185978408cSSascha Wildner * copyright notice, this list of conditions and the following
195978408cSSascha Wildner * disclaimer in the documentation and/or other materials provided
205978408cSSascha Wildner * with the distribution.
215978408cSSascha Wildner *
225978408cSSascha Wildner * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
235978408cSSascha Wildner * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
245978408cSSascha Wildner * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
255978408cSSascha Wildner * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
265978408cSSascha Wildner * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
275978408cSSascha Wildner * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
285978408cSSascha Wildner * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
295978408cSSascha Wildner * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
305978408cSSascha Wildner * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
315978408cSSascha Wildner * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
325978408cSSascha Wildner * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
335978408cSSascha Wildner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
345978408cSSascha Wildner * OF SUCH DAMAGE.
35*811c2036SSascha Wildner *
36*811c2036SSascha Wildner * $FreeBSD: head/usr.sbin/makefs/cd9660/cd9660_eltorito.c 331843 2018-03-31 15:04:41Z benno $
375978408cSSascha Wildner */
385978408cSSascha Wildner
395978408cSSascha Wildner #include "cd9660.h"
405978408cSSascha Wildner #include "cd9660_eltorito.h"
415978408cSSascha Wildner #include <util.h>
425978408cSSascha Wildner
435978408cSSascha Wildner #ifdef DEBUG
445978408cSSascha Wildner #define ELTORITO_DPRINTF(__x) printf __x
455978408cSSascha Wildner #else
465978408cSSascha Wildner #define ELTORITO_DPRINTF(__x)
475978408cSSascha Wildner #endif
485978408cSSascha Wildner
495978408cSSascha Wildner #include <util.h>
505978408cSSascha Wildner
515978408cSSascha Wildner static struct boot_catalog_entry *cd9660_init_boot_catalog_entry(void);
525978408cSSascha Wildner static struct boot_catalog_entry *cd9660_boot_setup_validation_entry(char);
535978408cSSascha Wildner static struct boot_catalog_entry *cd9660_boot_setup_default_entry(
545978408cSSascha Wildner struct cd9660_boot_image *);
555978408cSSascha Wildner static struct boot_catalog_entry *cd9660_boot_setup_section_head(char);
565978408cSSascha Wildner #if 0
575978408cSSascha Wildner static u_char cd9660_boot_get_system_type(struct cd9660_boot_image *);
585978408cSSascha Wildner #endif
595978408cSSascha Wildner
605978408cSSascha Wildner static struct cd9660_boot_image *default_boot_image;
615978408cSSascha Wildner
625978408cSSascha Wildner int
cd9660_add_boot_disk(iso9660_disk * diskStructure,const char * boot_info)635978408cSSascha Wildner cd9660_add_boot_disk(iso9660_disk *diskStructure, const char *boot_info)
645978408cSSascha Wildner {
655978408cSSascha Wildner struct stat stbuf;
665978408cSSascha Wildner const char *mode_msg;
675978408cSSascha Wildner char *temp;
685978408cSSascha Wildner char *sysname;
695978408cSSascha Wildner char *filename;
705978408cSSascha Wildner struct cd9660_boot_image *new_image, *tmp_image;
715978408cSSascha Wildner
725978408cSSascha Wildner assert(boot_info != NULL);
735978408cSSascha Wildner
745978408cSSascha Wildner if (*boot_info == '\0') {
755978408cSSascha Wildner warnx("Error: Boot disk information must be in the "
765978408cSSascha Wildner "format 'system;filename'");
775978408cSSascha Wildner return 0;
785978408cSSascha Wildner }
795978408cSSascha Wildner
805978408cSSascha Wildner /* First decode the boot information */
815978408cSSascha Wildner temp = estrdup(boot_info);
825978408cSSascha Wildner
835978408cSSascha Wildner sysname = temp;
845978408cSSascha Wildner filename = strchr(sysname, ';');
855978408cSSascha Wildner if (filename == NULL) {
865978408cSSascha Wildner warnx("supply boot disk information in the format "
875978408cSSascha Wildner "'system;filename'");
885978408cSSascha Wildner free(temp);
895978408cSSascha Wildner return 0;
905978408cSSascha Wildner }
915978408cSSascha Wildner
925978408cSSascha Wildner *filename++ = '\0';
935978408cSSascha Wildner
945978408cSSascha Wildner if (diskStructure->verbose_level > 0) {
955978408cSSascha Wildner printf("Found bootdisk with system %s, and filename %s\n",
965978408cSSascha Wildner sysname, filename);
975978408cSSascha Wildner }
985978408cSSascha Wildner new_image = ecalloc(1, sizeof(*new_image));
995978408cSSascha Wildner new_image->loadSegment = 0; /* default for now */
1005978408cSSascha Wildner
1015978408cSSascha Wildner /* Decode System */
1025978408cSSascha Wildner if (strcmp(sysname, "i386") == 0)
1035978408cSSascha Wildner new_image->system = ET_SYS_X86;
1045978408cSSascha Wildner else if (strcmp(sysname, "powerpc") == 0)
1055978408cSSascha Wildner new_image->system = ET_SYS_PPC;
1065978408cSSascha Wildner else if (strcmp(sysname, "macppc") == 0 ||
1075978408cSSascha Wildner strcmp(sysname, "mac68k") == 0)
1085978408cSSascha Wildner new_image->system = ET_SYS_MAC;
1095978408cSSascha Wildner else {
1105978408cSSascha Wildner warnx("boot disk system must be "
1115978408cSSascha Wildner "i386, powerpc, macppc, or mac68k");
1125978408cSSascha Wildner free(temp);
1135978408cSSascha Wildner free(new_image);
1145978408cSSascha Wildner return 0;
1155978408cSSascha Wildner }
1165978408cSSascha Wildner
1175978408cSSascha Wildner
1185978408cSSascha Wildner new_image->filename = estrdup(filename);
1195978408cSSascha Wildner
1205978408cSSascha Wildner free(temp);
1215978408cSSascha Wildner
1225978408cSSascha Wildner /* Get information about the file */
1235978408cSSascha Wildner if (lstat(new_image->filename, &stbuf) == -1)
1245978408cSSascha Wildner err(EXIT_FAILURE, "%s: lstat(\"%s\")", __func__,
1255978408cSSascha Wildner new_image->filename);
1265978408cSSascha Wildner
1275978408cSSascha Wildner switch (stbuf.st_size) {
1285978408cSSascha Wildner case 1440 * 1024:
1295978408cSSascha Wildner new_image->targetMode = ET_MEDIA_144FDD;
1305978408cSSascha Wildner mode_msg = "Assigned boot image to 1.44 emulation mode";
1315978408cSSascha Wildner break;
1325978408cSSascha Wildner case 1200 * 1024:
1335978408cSSascha Wildner new_image->targetMode = ET_MEDIA_12FDD;
1345978408cSSascha Wildner mode_msg = "Assigned boot image to 1.2 emulation mode";
1355978408cSSascha Wildner break;
1365978408cSSascha Wildner case 2880 * 1024:
1375978408cSSascha Wildner new_image->targetMode = ET_MEDIA_288FDD;
1385978408cSSascha Wildner mode_msg = "Assigned boot image to 2.88 emulation mode";
1395978408cSSascha Wildner break;
1405978408cSSascha Wildner default:
1415978408cSSascha Wildner new_image->targetMode = ET_MEDIA_NOEM;
1425978408cSSascha Wildner mode_msg = "Assigned boot image to no emulation mode";
1435978408cSSascha Wildner break;
1445978408cSSascha Wildner }
1455978408cSSascha Wildner
1465978408cSSascha Wildner if (diskStructure->verbose_level > 0)
1475978408cSSascha Wildner printf("%s\n", mode_msg);
1485978408cSSascha Wildner
1495978408cSSascha Wildner new_image->size = stbuf.st_size;
1505978408cSSascha Wildner new_image->num_sectors =
1515978408cSSascha Wildner howmany(new_image->size, diskStructure->sectorSize) *
1525978408cSSascha Wildner howmany(diskStructure->sectorSize, 512);
1535978408cSSascha Wildner if (diskStructure->verbose_level > 0) {
1545978408cSSascha Wildner printf("New image has size %d, uses %d 512-byte sectors\n",
1555978408cSSascha Wildner new_image->size, new_image->num_sectors);
1565978408cSSascha Wildner }
1575978408cSSascha Wildner new_image->sector = -1;
1585978408cSSascha Wildner /* Bootable by default */
1595978408cSSascha Wildner new_image->bootable = ET_BOOTABLE;
1605978408cSSascha Wildner /* Add boot disk */
1615978408cSSascha Wildner
1625978408cSSascha Wildner /* Group images for the same platform together. */
1635978408cSSascha Wildner TAILQ_FOREACH(tmp_image, &diskStructure->boot_images, image_list) {
1645978408cSSascha Wildner if (tmp_image->system != new_image->system)
1655978408cSSascha Wildner break;
1665978408cSSascha Wildner }
1675978408cSSascha Wildner
1685978408cSSascha Wildner if (tmp_image == NULL) {
1695978408cSSascha Wildner TAILQ_INSERT_HEAD(&diskStructure->boot_images, new_image,
1705978408cSSascha Wildner image_list);
1715978408cSSascha Wildner } else
1725978408cSSascha Wildner TAILQ_INSERT_BEFORE(tmp_image, new_image, image_list);
1735978408cSSascha Wildner
1745978408cSSascha Wildner new_image->serialno = diskStructure->image_serialno++;
1755978408cSSascha Wildner
1765978408cSSascha Wildner new_image->platform_id = new_image->system;
1775978408cSSascha Wildner
1785978408cSSascha Wildner /* TODO : Need to do anything about the boot image in the tree? */
1795978408cSSascha Wildner diskStructure->is_bootable = 1;
1805978408cSSascha Wildner
1815978408cSSascha Wildner /* First boot image is initial/default entry. */
1825978408cSSascha Wildner if (default_boot_image == NULL)
1835978408cSSascha Wildner default_boot_image = new_image;
1845978408cSSascha Wildner
1855978408cSSascha Wildner return 1;
1865978408cSSascha Wildner }
1875978408cSSascha Wildner
1885978408cSSascha Wildner int
cd9660_eltorito_add_boot_option(iso9660_disk * diskStructure,const char * option_string,const char * value)1895978408cSSascha Wildner cd9660_eltorito_add_boot_option(iso9660_disk *diskStructure,
1905978408cSSascha Wildner const char *option_string, const char *value)
1915978408cSSascha Wildner {
1925978408cSSascha Wildner char *eptr;
1935978408cSSascha Wildner struct cd9660_boot_image *image;
1945978408cSSascha Wildner
1955978408cSSascha Wildner assert(option_string != NULL);
1965978408cSSascha Wildner
1975978408cSSascha Wildner /* Find the last image added */
1985978408cSSascha Wildner TAILQ_FOREACH(image, &diskStructure->boot_images, image_list) {
1995978408cSSascha Wildner if (image->serialno + 1 == diskStructure->image_serialno)
2005978408cSSascha Wildner break;
2015978408cSSascha Wildner }
2025978408cSSascha Wildner if (image == NULL)
2035978408cSSascha Wildner errx(EXIT_FAILURE, "Attempted to add boot option, "
2045978408cSSascha Wildner "but no boot images have been specified");
2055978408cSSascha Wildner
2065978408cSSascha Wildner if (strcmp(option_string, "no-emul-boot") == 0) {
2075978408cSSascha Wildner image->targetMode = ET_MEDIA_NOEM;
2085978408cSSascha Wildner } else if (strcmp(option_string, "no-boot") == 0) {
2095978408cSSascha Wildner image->bootable = ET_NOT_BOOTABLE;
2105978408cSSascha Wildner } else if (strcmp(option_string, "hard-disk-boot") == 0) {
2115978408cSSascha Wildner image->targetMode = ET_MEDIA_HDD;
2125978408cSSascha Wildner } else if (strcmp(option_string, "boot-load-segment") == 0) {
2135978408cSSascha Wildner image->loadSegment = strtoul(value, &eptr, 16);
2145978408cSSascha Wildner if (eptr == value || *eptr != '\0' || errno != ERANGE) {
2155978408cSSascha Wildner warn("%s: strtoul", __func__);
2165978408cSSascha Wildner return 0;
2175978408cSSascha Wildner }
2185978408cSSascha Wildner } else if (strcmp(option_string, "platformid") == 0) {
2195978408cSSascha Wildner if (strcmp(value, "efi") == 0)
2205978408cSSascha Wildner image->platform_id = ET_SYS_EFI;
2215978408cSSascha Wildner else {
2225978408cSSascha Wildner warn("%s: unknown platform: %s", __func__, value);
2235978408cSSascha Wildner return 0;
2245978408cSSascha Wildner }
2255978408cSSascha Wildner } else {
2265978408cSSascha Wildner return 0;
2275978408cSSascha Wildner }
2285978408cSSascha Wildner return 1;
2295978408cSSascha Wildner }
2305978408cSSascha Wildner
2315978408cSSascha Wildner static struct boot_catalog_entry *
cd9660_init_boot_catalog_entry(void)2325978408cSSascha Wildner cd9660_init_boot_catalog_entry(void)
2335978408cSSascha Wildner {
2345978408cSSascha Wildner return ecalloc(1, sizeof(struct boot_catalog_entry));
2355978408cSSascha Wildner }
2365978408cSSascha Wildner
2375978408cSSascha Wildner static struct boot_catalog_entry *
cd9660_boot_setup_validation_entry(char sys)2385978408cSSascha Wildner cd9660_boot_setup_validation_entry(char sys)
2395978408cSSascha Wildner {
2405978408cSSascha Wildner struct boot_catalog_entry *entry;
2415978408cSSascha Wildner boot_catalog_validation_entry *ve;
2425978408cSSascha Wildner int16_t checksum;
2435978408cSSascha Wildner unsigned char *csptr;
2445978408cSSascha Wildner size_t i;
2455978408cSSascha Wildner entry = cd9660_init_boot_catalog_entry();
2465978408cSSascha Wildner
2475978408cSSascha Wildner entry->entry_type = ET_ENTRY_VE;
2485978408cSSascha Wildner ve = &entry->entry_data.VE;
2495978408cSSascha Wildner
2505978408cSSascha Wildner ve->header_id[0] = 1;
2515978408cSSascha Wildner ve->platform_id[0] = sys;
2525978408cSSascha Wildner ve->key[0] = 0x55;
2535978408cSSascha Wildner ve->key[1] = 0xAA;
2545978408cSSascha Wildner
2555978408cSSascha Wildner /* Calculate checksum */
2565978408cSSascha Wildner checksum = 0;
2575978408cSSascha Wildner cd9660_721(0, ve->checksum);
2585978408cSSascha Wildner csptr = (unsigned char*)ve;
2595978408cSSascha Wildner for (i = 0; i < sizeof(*ve); i += 2) {
2605978408cSSascha Wildner checksum += (int16_t)csptr[i];
2615978408cSSascha Wildner checksum += 256 * (int16_t)csptr[i + 1];
2625978408cSSascha Wildner }
2635978408cSSascha Wildner checksum = -checksum;
2645978408cSSascha Wildner cd9660_721(checksum, ve->checksum);
2655978408cSSascha Wildner
2665978408cSSascha Wildner ELTORITO_DPRINTF(("%s: header_id %d, platform_id %d, key[0] %d, key[1] %d, "
2675978408cSSascha Wildner "checksum %04x\n", __func__, ve->header_id[0], ve->platform_id[0],
2685978408cSSascha Wildner ve->key[0], ve->key[1], checksum));
2695978408cSSascha Wildner return entry;
2705978408cSSascha Wildner }
2715978408cSSascha Wildner
2725978408cSSascha Wildner static struct boot_catalog_entry *
cd9660_boot_setup_default_entry(struct cd9660_boot_image * disk)2735978408cSSascha Wildner cd9660_boot_setup_default_entry(struct cd9660_boot_image *disk)
2745978408cSSascha Wildner {
2755978408cSSascha Wildner struct boot_catalog_entry *default_entry;
2765978408cSSascha Wildner boot_catalog_initial_entry *ie;
2775978408cSSascha Wildner
2785978408cSSascha Wildner default_entry = cd9660_init_boot_catalog_entry();
2795978408cSSascha Wildner if (default_entry == NULL)
2805978408cSSascha Wildner return NULL;
2815978408cSSascha Wildner
2825978408cSSascha Wildner default_entry->entry_type = ET_ENTRY_IE;
2835978408cSSascha Wildner ie = &default_entry->entry_data.IE;
2845978408cSSascha Wildner
2855978408cSSascha Wildner ie->boot_indicator[0] = disk->bootable;
2865978408cSSascha Wildner ie->media_type[0] = disk->targetMode;
2875978408cSSascha Wildner cd9660_721(disk->loadSegment, ie->load_segment);
2885978408cSSascha Wildner ie->system_type[0] = disk->system;
2895978408cSSascha Wildner cd9660_721(disk->num_sectors, ie->sector_count);
2905978408cSSascha Wildner cd9660_731(disk->sector, ie->load_rba);
2915978408cSSascha Wildner
2925978408cSSascha Wildner ELTORITO_DPRINTF(("%s: boot indicator %d, media type %d, "
2935978408cSSascha Wildner "load segment %04x, system type %d, sector count %d, "
2945978408cSSascha Wildner "load rba %d\n", __func__, ie->boot_indicator[0],
2955978408cSSascha Wildner ie->media_type[0], disk->loadSegment, ie->system_type[0],
2965978408cSSascha Wildner disk->num_sectors, disk->sector));
2975978408cSSascha Wildner return default_entry;
2985978408cSSascha Wildner }
2995978408cSSascha Wildner
3005978408cSSascha Wildner static struct boot_catalog_entry *
cd9660_boot_setup_section_head(char platform)3015978408cSSascha Wildner cd9660_boot_setup_section_head(char platform)
3025978408cSSascha Wildner {
3035978408cSSascha Wildner struct boot_catalog_entry *entry;
3045978408cSSascha Wildner boot_catalog_section_header *sh;
3055978408cSSascha Wildner
3065978408cSSascha Wildner entry = cd9660_init_boot_catalog_entry();
3075978408cSSascha Wildner if (entry == NULL)
3085978408cSSascha Wildner return NULL;
3095978408cSSascha Wildner
3105978408cSSascha Wildner entry->entry_type = ET_ENTRY_SH;
3115978408cSSascha Wildner sh = &entry->entry_data.SH;
3125978408cSSascha Wildner /*
3135978408cSSascha Wildner * More by default.
3145978408cSSascha Wildner * The last one will manually be set to ET_SECTION_HEADER_LAST
3155978408cSSascha Wildner */
3165978408cSSascha Wildner sh->header_indicator[0] = ET_SECTION_HEADER_MORE;
3175978408cSSascha Wildner sh->platform_id[0] = platform;
3185978408cSSascha Wildner sh->num_section_entries[0] = 0;
3195978408cSSascha Wildner return entry;
3205978408cSSascha Wildner }
3215978408cSSascha Wildner
3225978408cSSascha Wildner static struct boot_catalog_entry *
cd9660_boot_setup_section_entry(struct cd9660_boot_image * disk)3235978408cSSascha Wildner cd9660_boot_setup_section_entry(struct cd9660_boot_image *disk)
3245978408cSSascha Wildner {
3255978408cSSascha Wildner struct boot_catalog_entry *entry;
3265978408cSSascha Wildner boot_catalog_section_entry *se;
3275978408cSSascha Wildner if ((entry = cd9660_init_boot_catalog_entry()) == NULL)
3285978408cSSascha Wildner return NULL;
3295978408cSSascha Wildner
3305978408cSSascha Wildner entry->entry_type = ET_ENTRY_SE;
3315978408cSSascha Wildner se = &entry->entry_data.SE;
3325978408cSSascha Wildner
3335978408cSSascha Wildner se->boot_indicator[0] = ET_BOOTABLE;
3345978408cSSascha Wildner se->media_type[0] = disk->targetMode;
3355978408cSSascha Wildner cd9660_721(disk->loadSegment, se->load_segment);
3365978408cSSascha Wildner cd9660_721(disk->num_sectors, se->sector_count);
3375978408cSSascha Wildner cd9660_731(disk->sector, se->load_rba);
3385978408cSSascha Wildner return entry;
3395978408cSSascha Wildner }
3405978408cSSascha Wildner
3415978408cSSascha Wildner #if 0
3425978408cSSascha Wildner static u_char
3435978408cSSascha Wildner cd9660_boot_get_system_type(struct cd9660_boot_image *disk)
3445978408cSSascha Wildner {
3455978408cSSascha Wildner /*
3465978408cSSascha Wildner For hard drive booting, we need to examine the MBR to figure
3475978408cSSascha Wildner out what the partition type is
3485978408cSSascha Wildner */
3495978408cSSascha Wildner return 0;
3505978408cSSascha Wildner }
3515978408cSSascha Wildner #endif
3525978408cSSascha Wildner
3535978408cSSascha Wildner /*
3545978408cSSascha Wildner * Set up the BVD, Boot catalog, and the boot entries, but do no writing
3555978408cSSascha Wildner */
3565978408cSSascha Wildner int
cd9660_setup_boot(iso9660_disk * diskStructure,int first_sector)3575978408cSSascha Wildner cd9660_setup_boot(iso9660_disk *diskStructure, int first_sector)
3585978408cSSascha Wildner {
3595978408cSSascha Wildner int sector;
3605978408cSSascha Wildner int used_sectors;
3615978408cSSascha Wildner int num_entries = 0;
3625978408cSSascha Wildner int catalog_sectors;
3635978408cSSascha Wildner struct boot_catalog_entry *x86_head, *mac_head, *ppc_head, *efi_head,
3645978408cSSascha Wildner *valid_entry, *default_entry, *temp, *head, **headp, *next;
3655978408cSSascha Wildner struct cd9660_boot_image *tmp_disk;
3665978408cSSascha Wildner
3675978408cSSascha Wildner headp = NULL;
3685978408cSSascha Wildner x86_head = mac_head = ppc_head = efi_head = NULL;
3695978408cSSascha Wildner
3705978408cSSascha Wildner /* If there are no boot disks, don't bother building boot information */
3715978408cSSascha Wildner if (TAILQ_EMPTY(&diskStructure->boot_images))
3725978408cSSascha Wildner return 0;
3735978408cSSascha Wildner
3745978408cSSascha Wildner /* Point to catalog: For now assume it consumes one sector */
3755978408cSSascha Wildner ELTORITO_DPRINTF(("Boot catalog will go in sector %d\n", first_sector));
3765978408cSSascha Wildner diskStructure->boot_catalog_sector = first_sector;
3775978408cSSascha Wildner cd9660_bothendian_dword(first_sector,
3785978408cSSascha Wildner diskStructure->boot_descriptor->boot_catalog_pointer);
3795978408cSSascha Wildner
3805978408cSSascha Wildner /* Step 1: Generate boot catalog */
3815978408cSSascha Wildner /* Step 1a: Validation entry */
3825978408cSSascha Wildner valid_entry = cd9660_boot_setup_validation_entry(ET_SYS_X86);
3835978408cSSascha Wildner if (valid_entry == NULL)
3845978408cSSascha Wildner return -1;
3855978408cSSascha Wildner
3865978408cSSascha Wildner /*
3875978408cSSascha Wildner * Count how many boot images there are,
3885978408cSSascha Wildner * and how many sectors they consume.
3895978408cSSascha Wildner */
3905978408cSSascha Wildner num_entries = 1;
3915978408cSSascha Wildner used_sectors = 0;
3925978408cSSascha Wildner
3935978408cSSascha Wildner TAILQ_FOREACH(tmp_disk, &diskStructure->boot_images, image_list) {
3945978408cSSascha Wildner used_sectors += tmp_disk->num_sectors;
3955978408cSSascha Wildner
3965978408cSSascha Wildner /* One default entry per image */
3975978408cSSascha Wildner num_entries++;
3985978408cSSascha Wildner }
3995978408cSSascha Wildner catalog_sectors = howmany(num_entries * 0x20, diskStructure->sectorSize);
4005978408cSSascha Wildner used_sectors += catalog_sectors;
4015978408cSSascha Wildner
4025978408cSSascha Wildner if (diskStructure->verbose_level > 0) {
4035978408cSSascha Wildner printf("%s: there will be %i entries consuming %i sectors. "
4045978408cSSascha Wildner "Catalog is %i sectors\n", __func__, num_entries,
4055978408cSSascha Wildner used_sectors, catalog_sectors);
4065978408cSSascha Wildner }
4075978408cSSascha Wildner
4085978408cSSascha Wildner /* Populate sector numbers */
4095978408cSSascha Wildner sector = first_sector + catalog_sectors;
4105978408cSSascha Wildner TAILQ_FOREACH(tmp_disk, &diskStructure->boot_images, image_list) {
4115978408cSSascha Wildner tmp_disk->sector = sector;
4125978408cSSascha Wildner sector += tmp_disk->num_sectors /
4135978408cSSascha Wildner (diskStructure->sectorSize / 512);
4145978408cSSascha Wildner }
4155978408cSSascha Wildner
4165978408cSSascha Wildner LIST_INSERT_HEAD(&diskStructure->boot_entries, valid_entry, ll_struct);
4175978408cSSascha Wildner
4185978408cSSascha Wildner /* Step 1b: Initial/default entry */
4195978408cSSascha Wildner /* TODO : PARAM */
4205978408cSSascha Wildner if (default_boot_image != NULL) {
4215978408cSSascha Wildner struct cd9660_boot_image *tcbi;
4225978408cSSascha Wildner TAILQ_FOREACH(tcbi, &diskStructure->boot_images, image_list) {
4235978408cSSascha Wildner if (tcbi == default_boot_image) {
4245978408cSSascha Wildner tmp_disk = tcbi;
4255978408cSSascha Wildner break;
4265978408cSSascha Wildner }
4275978408cSSascha Wildner }
4285978408cSSascha Wildner }
4295978408cSSascha Wildner if (tmp_disk == NULL)
4305978408cSSascha Wildner tmp_disk = TAILQ_FIRST(&diskStructure->boot_images);
4315978408cSSascha Wildner default_entry = cd9660_boot_setup_default_entry(tmp_disk);
4325978408cSSascha Wildner if (default_entry == NULL) {
4335978408cSSascha Wildner warnx("Error: memory allocation failed in cd9660_setup_boot");
4345978408cSSascha Wildner return -1;
4355978408cSSascha Wildner }
4365978408cSSascha Wildner
4375978408cSSascha Wildner LIST_INSERT_AFTER(valid_entry, default_entry, ll_struct);
4385978408cSSascha Wildner
4395978408cSSascha Wildner /* Todo: multiple default entries? */
4405978408cSSascha Wildner
4415978408cSSascha Wildner tmp_disk = TAILQ_FIRST(&diskStructure->boot_images);
4425978408cSSascha Wildner
4435978408cSSascha Wildner head = NULL;
4445978408cSSascha Wildner temp = default_entry;
4455978408cSSascha Wildner
4465978408cSSascha Wildner /* If multiple boot images are given : */
4475978408cSSascha Wildner for (; tmp_disk != NULL; tmp_disk = TAILQ_NEXT(tmp_disk, image_list)) {
4485978408cSSascha Wildner if (tmp_disk == default_boot_image)
4495978408cSSascha Wildner continue;
4505978408cSSascha Wildner
4515978408cSSascha Wildner /* Step 2: Section header */
4525978408cSSascha Wildner switch (tmp_disk->platform_id) {
4535978408cSSascha Wildner case ET_SYS_X86:
4545978408cSSascha Wildner headp = &x86_head;
4555978408cSSascha Wildner break;
4565978408cSSascha Wildner case ET_SYS_PPC:
4575978408cSSascha Wildner headp = &ppc_head;
4585978408cSSascha Wildner break;
4595978408cSSascha Wildner case ET_SYS_MAC:
4605978408cSSascha Wildner headp = &mac_head;
4615978408cSSascha Wildner break;
4625978408cSSascha Wildner case ET_SYS_EFI:
4635978408cSSascha Wildner headp = &efi_head;
4645978408cSSascha Wildner break;
4655978408cSSascha Wildner default:
4665978408cSSascha Wildner warnx("%s: internal error: unknown system type",
4675978408cSSascha Wildner __func__);
4685978408cSSascha Wildner return -1;
4695978408cSSascha Wildner }
4705978408cSSascha Wildner
4715978408cSSascha Wildner if (*headp == NULL) {
4725978408cSSascha Wildner head =
4735978408cSSascha Wildner cd9660_boot_setup_section_head(tmp_disk->platform_id);
4745978408cSSascha Wildner if (head == NULL) {
4755978408cSSascha Wildner warnx("Error: memory allocation failed in "
4765978408cSSascha Wildner "cd9660_setup_boot");
4775978408cSSascha Wildner return -1;
4785978408cSSascha Wildner }
4795978408cSSascha Wildner LIST_INSERT_AFTER(default_entry, head, ll_struct);
4805978408cSSascha Wildner *headp = head;
4815978408cSSascha Wildner } else
4825978408cSSascha Wildner head = *headp;
4835978408cSSascha Wildner
4845978408cSSascha Wildner head->entry_data.SH.num_section_entries[0]++;
4855978408cSSascha Wildner
4865978408cSSascha Wildner /* Step 2a: Section entry and extensions */
4875978408cSSascha Wildner temp = cd9660_boot_setup_section_entry(tmp_disk);
4885978408cSSascha Wildner if (temp == NULL) {
4895978408cSSascha Wildner warn("%s: cd9660_boot_setup_section_entry", __func__);
4905978408cSSascha Wildner return -1;
4915978408cSSascha Wildner }
4925978408cSSascha Wildner
4935978408cSSascha Wildner while ((next = LIST_NEXT(head, ll_struct)) != NULL &&
4945978408cSSascha Wildner next->entry_type == ET_ENTRY_SE)
4955978408cSSascha Wildner head = next;
4965978408cSSascha Wildner
4975978408cSSascha Wildner LIST_INSERT_AFTER(head, temp, ll_struct);
4985978408cSSascha Wildner }
4995978408cSSascha Wildner
5005978408cSSascha Wildner /* Find the last Section Header entry and mark it as the last. */
5015978408cSSascha Wildner head = NULL;
5025978408cSSascha Wildner LIST_FOREACH(next, &diskStructure->boot_entries, ll_struct) {
5035978408cSSascha Wildner if (next->entry_type == ET_ENTRY_SH)
5045978408cSSascha Wildner head = next;
5055978408cSSascha Wildner }
5065978408cSSascha Wildner if (head != NULL)
5075978408cSSascha Wildner head->entry_data.SH.header_indicator[0] = ET_SECTION_HEADER_LAST;
5085978408cSSascha Wildner
5095978408cSSascha Wildner /* TODO: Remaining boot disks when implemented */
5105978408cSSascha Wildner
5115978408cSSascha Wildner return first_sector + used_sectors;
5125978408cSSascha Wildner }
5135978408cSSascha Wildner
5145978408cSSascha Wildner int
cd9660_setup_boot_volume_descriptor(iso9660_disk * diskStructure,volume_descriptor * bvd)5155978408cSSascha Wildner cd9660_setup_boot_volume_descriptor(iso9660_disk *diskStructure,
5165978408cSSascha Wildner volume_descriptor *bvd)
5175978408cSSascha Wildner {
5185978408cSSascha Wildner boot_volume_descriptor *bvdData =
5195978408cSSascha Wildner (boot_volume_descriptor*)bvd->volumeDescriptorData;
5205978408cSSascha Wildner
5215978408cSSascha Wildner bvdData->boot_record_indicator[0] = ISO_VOLUME_DESCRIPTOR_BOOT;
5225978408cSSascha Wildner memcpy(bvdData->identifier, ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5);
5235978408cSSascha Wildner bvdData->version[0] = 1;
5245978408cSSascha Wildner memcpy(bvdData->boot_system_identifier, ET_ID, 23);
5255978408cSSascha Wildner memcpy(bvdData->identifier, ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5);
5265978408cSSascha Wildner diskStructure->boot_descriptor =
5275978408cSSascha Wildner (boot_volume_descriptor*) bvd->volumeDescriptorData;
5285978408cSSascha Wildner return 1;
5295978408cSSascha Wildner }
5305978408cSSascha Wildner
5315978408cSSascha Wildner static int
cd9660_write_mbr_partition_entry(FILE * fd,int idx,off_t sector_start,off_t nsectors,int type)5325978408cSSascha Wildner cd9660_write_mbr_partition_entry(FILE *fd, int idx, off_t sector_start,
5335978408cSSascha Wildner off_t nsectors, int type)
5345978408cSSascha Wildner {
5355978408cSSascha Wildner uint8_t val;
5365978408cSSascha Wildner uint32_t lba;
5375978408cSSascha Wildner
5385978408cSSascha Wildner if (fseeko(fd, (off_t)(idx) * 16 + 0x1be, SEEK_SET) == -1)
5395978408cSSascha Wildner err(1, "fseeko");
5405978408cSSascha Wildner
5415978408cSSascha Wildner val = 0x80; /* Bootable */
5425978408cSSascha Wildner fwrite(&val, sizeof(val), 1, fd);
5435978408cSSascha Wildner
5445978408cSSascha Wildner val = 0xff; /* CHS begin */
5455978408cSSascha Wildner fwrite(&val, sizeof(val), 1, fd);
5465978408cSSascha Wildner fwrite(&val, sizeof(val), 1, fd);
5475978408cSSascha Wildner fwrite(&val, sizeof(val), 1, fd);
5485978408cSSascha Wildner
5495978408cSSascha Wildner val = type; /* Part type */
5505978408cSSascha Wildner fwrite(&val, sizeof(val), 1, fd);
5515978408cSSascha Wildner
5525978408cSSascha Wildner val = 0xff; /* CHS end */
5535978408cSSascha Wildner fwrite(&val, sizeof(val), 1, fd);
5545978408cSSascha Wildner fwrite(&val, sizeof(val), 1, fd);
5555978408cSSascha Wildner fwrite(&val, sizeof(val), 1, fd);
5565978408cSSascha Wildner
5575978408cSSascha Wildner /* LBA extent */
5585978408cSSascha Wildner lba = htole32(sector_start);
5595978408cSSascha Wildner fwrite(&lba, sizeof(lba), 1, fd);
5605978408cSSascha Wildner lba = htole32(nsectors);
5615978408cSSascha Wildner fwrite(&lba, sizeof(lba), 1, fd);
5625978408cSSascha Wildner
5635978408cSSascha Wildner return 0;
5645978408cSSascha Wildner }
5655978408cSSascha Wildner
5665978408cSSascha Wildner static int
cd9660_write_apm_partition_entry(FILE * fd,int idx,int total_partitions,off_t sector_start,off_t nsectors,off_t sector_size,const char * part_name,const char * part_type)5675978408cSSascha Wildner cd9660_write_apm_partition_entry(FILE *fd, int idx, int total_partitions,
5685978408cSSascha Wildner off_t sector_start, off_t nsectors, off_t sector_size,
5695978408cSSascha Wildner const char *part_name, const char *part_type)
5705978408cSSascha Wildner {
5715978408cSSascha Wildner uint32_t apm32, part_status;
5725978408cSSascha Wildner uint16_t apm16;
5735978408cSSascha Wildner
5745978408cSSascha Wildner /* See Apple Tech Note 1189 for the details about the pmPartStatus
5755978408cSSascha Wildner * flags.
5765978408cSSascha Wildner * Below the flags which are default:
5775978408cSSascha Wildner * - IsValid 0x01
5785978408cSSascha Wildner * - IsAllocated 0x02
5795978408cSSascha Wildner * - IsReadable 0x10
5805978408cSSascha Wildner * - IsWritable 0x20
5815978408cSSascha Wildner */
5825978408cSSascha Wildner part_status = 0x01 | 0x02 | 0x10 | 0x20;
5835978408cSSascha Wildner
5845978408cSSascha Wildner if (fseeko(fd, (off_t)(idx + 1) * sector_size, SEEK_SET) == -1)
5855978408cSSascha Wildner err(1, "fseeko");
5865978408cSSascha Wildner
5875978408cSSascha Wildner /* Signature */
5885978408cSSascha Wildner apm16 = htobe16(0x504d);
5895978408cSSascha Wildner fwrite(&apm16, sizeof(apm16), 1, fd);
5905978408cSSascha Wildner apm16 = 0;
5915978408cSSascha Wildner fwrite(&apm16, sizeof(apm16), 1, fd);
5925978408cSSascha Wildner
5935978408cSSascha Wildner /* Total number of partitions */
5945978408cSSascha Wildner apm32 = htobe32(total_partitions);
5955978408cSSascha Wildner fwrite(&apm32, sizeof(apm32), 1, fd);
5965978408cSSascha Wildner /* Bounds */
5975978408cSSascha Wildner apm32 = htobe32(sector_start);
5985978408cSSascha Wildner fwrite(&apm32, sizeof(apm32), 1, fd);
5995978408cSSascha Wildner apm32 = htobe32(nsectors);
6005978408cSSascha Wildner fwrite(&apm32, sizeof(apm32), 1, fd);
6015978408cSSascha Wildner
6025978408cSSascha Wildner fwrite(part_name, strlen(part_name) + 1, 1, fd);
6035978408cSSascha Wildner fseek(fd, 32 - strlen(part_name) - 1, SEEK_CUR);
6045978408cSSascha Wildner fwrite(part_type, strlen(part_type) + 1, 1, fd);
6055978408cSSascha Wildner fseek(fd, 32 - strlen(part_type) - 1, SEEK_CUR);
6065978408cSSascha Wildner
6075978408cSSascha Wildner apm32 = 0;
6085978408cSSascha Wildner /* pmLgDataStart */
6095978408cSSascha Wildner fwrite(&apm32, sizeof(apm32), 1, fd);
6105978408cSSascha Wildner /* pmDataCnt */
6115978408cSSascha Wildner apm32 = htobe32(nsectors);
6125978408cSSascha Wildner fwrite(&apm32, sizeof(apm32), 1, fd);
6135978408cSSascha Wildner /* pmPartStatus */
6145978408cSSascha Wildner apm32 = htobe32(part_status);
6155978408cSSascha Wildner fwrite(&apm32, sizeof(apm32), 1, fd);
6165978408cSSascha Wildner
6175978408cSSascha Wildner return 0;
6185978408cSSascha Wildner }
6195978408cSSascha Wildner
6205978408cSSascha Wildner int
cd9660_write_boot(iso9660_disk * diskStructure,FILE * fd)6215978408cSSascha Wildner cd9660_write_boot(iso9660_disk *diskStructure, FILE *fd)
6225978408cSSascha Wildner {
6235978408cSSascha Wildner struct boot_catalog_entry *e;
6245978408cSSascha Wildner struct cd9660_boot_image *t;
6255978408cSSascha Wildner int apm_partitions = 0;
6265978408cSSascha Wildner int mbr_partitions = 0;
6275978408cSSascha Wildner
6285978408cSSascha Wildner /* write boot catalog */
6295978408cSSascha Wildner if (fseeko(fd, (off_t)diskStructure->boot_catalog_sector *
6305978408cSSascha Wildner diskStructure->sectorSize, SEEK_SET) == -1)
6315978408cSSascha Wildner err(1, "fseeko");
6325978408cSSascha Wildner
6335978408cSSascha Wildner if (diskStructure->verbose_level > 0) {
6345978408cSSascha Wildner printf("Writing boot catalog to sector %" PRId64 "\n",
6355978408cSSascha Wildner diskStructure->boot_catalog_sector);
6365978408cSSascha Wildner }
6375978408cSSascha Wildner LIST_FOREACH(e, &diskStructure->boot_entries, ll_struct) {
6385978408cSSascha Wildner if (diskStructure->verbose_level > 0) {
6395978408cSSascha Wildner printf("Writing catalog entry of type %d\n",
6405978408cSSascha Wildner e->entry_type);
6415978408cSSascha Wildner }
6425978408cSSascha Wildner /*
6435978408cSSascha Wildner * It doesn't matter which one gets written
6445978408cSSascha Wildner * since they are the same size
6455978408cSSascha Wildner */
6465978408cSSascha Wildner fwrite(&(e->entry_data.VE), 1, 32, fd);
6475978408cSSascha Wildner }
6485978408cSSascha Wildner if (diskStructure->verbose_level > 0)
6495978408cSSascha Wildner printf("Finished writing boot catalog\n");
6505978408cSSascha Wildner
6515978408cSSascha Wildner /* copy boot images */
6525978408cSSascha Wildner TAILQ_FOREACH(t, &diskStructure->boot_images, image_list) {
6535978408cSSascha Wildner if (diskStructure->verbose_level > 0) {
6545978408cSSascha Wildner printf("Writing boot image from %s to sectors %d\n",
6555978408cSSascha Wildner t->filename, t->sector);
6565978408cSSascha Wildner }
6575978408cSSascha Wildner cd9660_copy_file(diskStructure, fd, t->sector, t->filename);
6585978408cSSascha Wildner
6595978408cSSascha Wildner if (t->system == ET_SYS_MAC)
6605978408cSSascha Wildner apm_partitions++;
6615978408cSSascha Wildner if (t->system == ET_SYS_PPC)
6625978408cSSascha Wildner mbr_partitions++;
6635978408cSSascha Wildner }
6645978408cSSascha Wildner
6655978408cSSascha Wildner /* some systems need partition tables as well */
6665978408cSSascha Wildner if (mbr_partitions > 0 || diskStructure->chrp_boot) {
6675978408cSSascha Wildner uint16_t sig;
6685978408cSSascha Wildner
6695978408cSSascha Wildner fseek(fd, 0x1fe, SEEK_SET);
6705978408cSSascha Wildner sig = htole16(0xaa55);
6715978408cSSascha Wildner fwrite(&sig, sizeof(sig), 1, fd);
6725978408cSSascha Wildner
6735978408cSSascha Wildner mbr_partitions = 0;
6745978408cSSascha Wildner
6755978408cSSascha Wildner /* Write ISO9660 descriptor, enclosing the whole disk */
6765978408cSSascha Wildner if (diskStructure->chrp_boot)
6775978408cSSascha Wildner cd9660_write_mbr_partition_entry(fd, mbr_partitions++,
6785978408cSSascha Wildner 0, diskStructure->totalSectors *
6795978408cSSascha Wildner (diskStructure->sectorSize / 512), 0x96);
6805978408cSSascha Wildner
6815978408cSSascha Wildner /* Write all partition entries */
6825978408cSSascha Wildner TAILQ_FOREACH(t, &diskStructure->boot_images, image_list) {
6835978408cSSascha Wildner if (t->system != ET_SYS_PPC)
6845978408cSSascha Wildner continue;
6855978408cSSascha Wildner cd9660_write_mbr_partition_entry(fd, mbr_partitions++,
6865978408cSSascha Wildner t->sector * (diskStructure->sectorSize / 512),
6875978408cSSascha Wildner t->num_sectors * (diskStructure->sectorSize / 512),
6885978408cSSascha Wildner 0x41 /* PReP Boot */);
6895978408cSSascha Wildner }
6905978408cSSascha Wildner }
6915978408cSSascha Wildner
6925978408cSSascha Wildner if (apm_partitions > 0) {
6935978408cSSascha Wildner /* Write DDR and global APM info */
6945978408cSSascha Wildner uint32_t apm32;
6955978408cSSascha Wildner uint16_t apm16;
6965978408cSSascha Wildner int total_parts;
6975978408cSSascha Wildner
6985978408cSSascha Wildner fseek(fd, 0, SEEK_SET);
6995978408cSSascha Wildner apm16 = htobe16(0x4552);
7005978408cSSascha Wildner fwrite(&apm16, sizeof(apm16), 1, fd);
7015978408cSSascha Wildner /* Device block size */
7025978408cSSascha Wildner apm16 = htobe16(512);
7035978408cSSascha Wildner fwrite(&apm16, sizeof(apm16), 1, fd);
7045978408cSSascha Wildner /* Device block count */
7055978408cSSascha Wildner apm32 = htobe32(diskStructure->totalSectors *
7065978408cSSascha Wildner (diskStructure->sectorSize / 512));
7075978408cSSascha Wildner fwrite(&apm32, sizeof(apm32), 1, fd);
7085978408cSSascha Wildner /* Device type/id */
7095978408cSSascha Wildner apm16 = htobe16(1);
7105978408cSSascha Wildner fwrite(&apm16, sizeof(apm16), 1, fd);
7115978408cSSascha Wildner fwrite(&apm16, sizeof(apm16), 1, fd);
7125978408cSSascha Wildner
7135978408cSSascha Wildner /* Count total needed entries */
7145978408cSSascha Wildner total_parts = 2 + apm_partitions; /* Self + ISO9660 */
7155978408cSSascha Wildner
7165978408cSSascha Wildner /* Write self-descriptor */
7175978408cSSascha Wildner cd9660_write_apm_partition_entry(fd, 0, total_parts, 1,
7185978408cSSascha Wildner total_parts, 512, "Apple", "Apple_partition_map");
7195978408cSSascha Wildner
7205978408cSSascha Wildner /* Write all partition entries */
7215978408cSSascha Wildner apm_partitions = 0;
7225978408cSSascha Wildner TAILQ_FOREACH(t, &diskStructure->boot_images, image_list) {
7235978408cSSascha Wildner if (t->system != ET_SYS_MAC)
7245978408cSSascha Wildner continue;
7255978408cSSascha Wildner
7265978408cSSascha Wildner cd9660_write_apm_partition_entry(fd,
7275978408cSSascha Wildner 1 + apm_partitions++, total_parts,
7285978408cSSascha Wildner t->sector * (diskStructure->sectorSize / 512),
7295978408cSSascha Wildner t->num_sectors * (diskStructure->sectorSize / 512),
7305978408cSSascha Wildner 512, "CD Boot", "Apple_Bootstrap");
7315978408cSSascha Wildner }
7325978408cSSascha Wildner
7335978408cSSascha Wildner /* Write ISO9660 descriptor, enclosing the whole disk */
7345978408cSSascha Wildner cd9660_write_apm_partition_entry(fd, 2 + apm_partitions,
7355978408cSSascha Wildner total_parts, 0, diskStructure->totalSectors *
7365978408cSSascha Wildner (diskStructure->sectorSize / 512), 512, "ISO9660",
7375978408cSSascha Wildner "CD_ROM_Mode_1");
7385978408cSSascha Wildner }
7395978408cSSascha Wildner
7405978408cSSascha Wildner return 0;
7415978408cSSascha Wildner }
742