/* * * * Open Hack'Ware BIOS Apple partition type management * * Copyright (c) 2004-2005 Jocelyn Mayer * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License V2 * as published by the Free Software Foundation * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include "bios.h" #include "libpart.h" /* Apple partitions handler */ #define HFS_BLOCSIZE (512) typedef struct Mac_head_t Mac_head_t; struct Mac_head_t { /* 0x000 */ uint8_t signature[2]; uint16_t bloc_size; uint32_t bloc_count; /* 0x008 */ uint16_t dev_type; uint16_t dev_ID; uint32_t data; /* 0x010 */ uint16_t driver_cnt; uint8_t pad[428]; /* 0x01BE */ uint8_t part_table[0x40]; /* 0x1FE */ uint8_t magic[2]; /* 0x0200 */ } __attribute__ ((packed)); typedef struct Mac_driver_entry_t Mac_driver_entry_t; struct Mac_driver_entry_t { uint32_t start; uint16_t size; uint16_t type; } __attribute__ ((packed)); typedef enum Mac_partflags_t Mac_partflags_t; enum Mac_partflags_t { MACPART_SPEC2 = 0x0100, MACPART_SPEC1 = 0x0080, MACPART_PIC = 0x0040, MACPART_WRITABLE = 0x0020, MACPART_READABLE = 0x0010, MACPART_BOOTABLE = 0x0008, MACPART_INUSE = 0x0004, MACPART_ALLOCATED = 0x0002, MACPART_VALID = 0x0001, }; #define MAC_BOOTABLE_PART (MACPART_VALID | MACPART_INUSE | MACPART_BOOTABLE) typedef struct Mac_partmap_t Mac_partmap_t; struct Mac_partmap_t { /* 0x000 */ uint8_t signature[2]; uint8_t res0[2]; uint32_t map_cnt; /* 0x008 */ uint32_t start_bloc; uint32_t bloc_cnt; /* 0x010 */ uint8_t name[32]; /* 0x030 */ uint8_t type[32]; /* 0x050 */ uint32_t data_start; uint32_t data_cnt; /* 0x058 */ uint32_t flags; uint32_t boot_start; /* 0x060 */ uint32_t boot_size; uint32_t boot_load; /* 0x068 */ uint32_t boot_load2; uint32_t boot_entry; /* 0x070 */ uint32_t boot_entry2; uint32_t boot_csum; /* 0x078 */ uint8_t CPU[16]; /* 0x088 */ uint8_t boot_args[0x80]; /* 0x108 */ uint8_t pad0[0xC8]; /* 0x1D4 */ uint16_t ntype; uint8_t ff[2]; /* 0x1D8 */ uint8_t pad1[0x24]; /* 0x1FC */ uint8_t mark[4]; /* 0x200 */ } __attribute__ ((packed)); int fs_raw_set_bootfile (part_t *part, uint32_t start_bloc, uint32_t start_offset, uint32_t size_bloc, uint32_t size_offset); part_t *Apple_probe_partitions (bloc_device_t *bd) { unsigned char tmp[33], *name; Mac_head_t *head; Mac_partmap_t *partmap; part_t *part, *boot_part; unsigned char *type; uint8_t *buffer; uint32_t pos, bloc, start, count; uint32_t bloc_size, flags; int map_count, i, n, len; part = NULL; boot_part = NULL; n = 1; buffer = malloc(HFS_BLOCSIZE); /* Read first sector */ bd_seek(bd, 0, 0); if (bd_read(bd, buffer, HFS_BLOCSIZE) < 0) { ERROR("Unable to read boot sector from boot device. Aborting...\n"); goto error; } head = (Mac_head_t *)buffer; if (head->signature[0] != 'E' || head->signature[1] != 'R') { // MSG("\rNo Apple boot bloc signature...\n"); goto error; } MSG("\rFound Apple partition map...\n"); bloc = 0; bloc_size = bd_seclen(bd); map_count = 1; #if 0 if (head->magic[0] == 0x55 && head->magic[1] == 0xAA) { /* PREP boot image ! Must parse it as MS-DOS boot bloc */ ERROR("%s PREP head magic\n", __func__); goto error; } #endif /* Partition table starts in sector 1 */ for (i = 1; i < (map_count + 1); i++) { bloc = (i * HFS_BLOCSIZE) / bloc_size; pos = (i * HFS_BLOCSIZE) % bloc_size; DPRINTF("Check part %d of %d (%d %d %d)\n", i, map_count, bloc, pos, bloc_size); bd_seek(bd, bloc, pos); if (bd_read(bd, buffer, HFS_BLOCSIZE) < 0) { ERROR("%s sector_read failed (%d)\n", __func__, i); goto error; } partmap = (Mac_partmap_t *)buffer; if (partmap->signature[0] != 'P' || partmap->signature[1] != 'M' ) { ERROR("%s bad partition signature (%c %c)\n", __func__, partmap->signature[0], partmap->signature[1]); goto error; } /* We found at least one Apple partition map, * so we won't have to try to parse with other partition mappings. */ for (type = partmap->type; (type - partmap->type) < 32; type++) { if (*type != '\0') break; } if (partmap->name[0] == '\0') { sprintf(tmp, "part%d", i); name = tmp; } else { name = partmap->name; } /* Regular Apple partition */ part = malloc(sizeof(part_t)); if (part == NULL) { ERROR("%s: can't allocate partition\n", __func__); return NULL; } memset(part, 0, sizeof(part_t)); part->start = partmap->start_bloc; part->size = partmap->bloc_cnt; part_set_blocsize(bd, part, HFS_BLOCSIZE); len = 32 - (type - partmap->type); if (len == 0) { /* Place holder. Skip it */ DPRINTF("%s placeholder part\t%d\n", __func__, i); part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY; part_register(bd, part, name, i); } else if (strncmp("Apple_Void", type, 32) == 0) { /* Void partition. Skip it */ DPRINTF("%s Void part\t%d [%s]\n", __func__, i, type); part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY; part_register(bd, part, name, i); } else if (strncmp("Apple_Free", type, 32) == 0) { /* Free space. Skip it */ DPRINTF("%s Free part (%d)\n", __func__, i); part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY; part_register(bd, part, name, i); } else if (strncmp("Apple_partition_map", type, 32) == 0 || strncmp("Apple_Partition_Map", type, 32) == 0 #if 0 // Is this really used or is it just a mistake ? || strncmp("Apple_patition_map", type, 32) == 0 #endif ) { DPRINTF("%s Partition map\t%d [%s]\n", __func__, i, type); /* We are in the partition map descriptor */ if (i == 1) { /* Get the real map blocs count */ map_count = partmap->map_cnt; DPRINTF("%s: map_count: %d\n", __func__, map_count); } else { /* Don't about about secondary partition map * Seems to be used, at least on CDROMs, to describe * the same partition map with bloc_size = 2048 */ } part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY; part_register(bd, part, name, i); } else if (strncmp("Apple_Driver", type, 32) == 0 || strncmp("Apple_Driver43", type, 32) == 0 || strncmp("Apple_Driver43_CD", type, 32) == 0 || strncmp("Apple_Driver_ATA", type, 32) == 0 || strncmp("Apple_Driver_ATAPI", type, 32) == 0 || strncmp("Apple_FWDriver", type, 32) == 0 || strncmp("Apple_Driver_IOKit", type, 32) == 0) { /* Drivers. don't care for now */ DPRINTF("%s Drivers part\t%d [%s]\n", __func__, i, type); part->flags = PART_TYPE_APPLE | PART_FLAG_DRIVER; part_register(bd, part, name, i); } else if (strncmp("Apple_Patches", type, 32) == 0) { /* Patches: don't care for now */ part->flags = PART_TYPE_APPLE | PART_FLAG_PATCH; part_register(bd, part, name, i); DPRINTF("%s Patches part\t%d [%s]\n", __func__, i, type); } else if (strncmp("Apple_HFS", type, 32) == 0 || strncmp("Apple_MFS", type, 32) == 0 || strncmp("Apple_UFS", type, 32) == 0 || strncmp("Apple_PRODOS", type, 32) == 0 || strncmp("Apple_UNIX_SVR2", type, 32) == 0 || strncmp("Linux", type, 32) == 0 || strncmp("NetBSD/macppc", type, 32) == 0 || strncmp("Apple_boot", type, 32) == 0 || strncmp("Apple_bootstrap", type, 32) == 0 || strncmp("Apple_Bootstrap", type, 32) == 0) { DPRINTF("%s Fs part\t%d [%s]\n", __func__, i, type); /* Filesystems / boot partitions */ flags = partmap->flags; start = partmap->start_bloc * HFS_BLOCSIZE; count = partmap->bloc_cnt * HFS_BLOCSIZE; if (partmap->boot_size == 0 || partmap->boot_load == 0) { printf("Not a bootable partition %d %d (%p %p)\n", partmap->boot_size, partmap->boot_load, boot_part, part); part->flags = PART_TYPE_APPLE | PART_FLAG_FS; } else { part->boot_start.bloc = partmap->boot_start; part->boot_start.offset = 0; part->boot_size.bloc = partmap->boot_size / HFS_BLOCSIZE; #if 0 printf("%0x %0x %0x\n", partmap->boot_size, HFS_BLOCSIZE, part->boot_size.bloc); #endif part->boot_size.offset = (partmap->boot_size) % HFS_BLOCSIZE; part->boot_load = partmap->boot_load; part->boot_entry = partmap->boot_entry; fs_raw_set_bootfile(part, part->boot_start.bloc, part->boot_start.offset, part->boot_size.bloc, part->boot_size.offset); boot_part = part; part->flags = PART_TYPE_APPLE | PART_FLAG_FS | PART_FLAG_BOOT; } printf("Partition: %d '%s' '%s' st %0x size %0x", i, name, type, partmap->start_bloc, partmap->bloc_cnt); #ifndef DEBUG printf("\n"); #endif DPRINTF(" - %0x %0x %p %p\n", partmap->boot_start, partmap->boot_size, part, part->fs); DPRINTF(" boot %0x %0x load %0x entry %0x\n", part->boot_start.bloc, part->boot_size.bloc, part->boot_load, part->boot_entry); DPRINTF(" load %0x entry %0x %0x\n", partmap->boot_load2, partmap->boot_entry2, HFS_BLOCSIZE); part_register(bd, part, name, i); } else { memcpy(tmp, type, 32); tmp[32] = '\0'; ERROR("Unknown partition type [%s]\n", tmp); part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY; part_register(bd, part, name, i); } } error: free(buffer); return boot_part; }