summaryrefslogtreecommitdiff
path: root/src/libpart/apple.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libpart/apple.c')
-rw-r--r--src/libpart/apple.c305
1 files changed, 305 insertions, 0 deletions
diff --git a/src/libpart/apple.c b/src/libpart/apple.c
new file mode 100644
index 0000000..b006c61
--- /dev/null
+++ b/src/libpart/apple.c
@@ -0,0 +1,305 @@
+/*
+ * <apple.c>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#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);
+ } else if (strncmp("Apple_Void", type, 32) == 0) {
+ /* Void partition. Skip it */
+ DPRINTF("%s Void part\t%d [%s]\n", __func__, i, type);
+ } 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);
+ } 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);
+ } 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);
+ } else if (strncmp("Apple_Patches", type, 32) == 0) {
+ /* Patches: don't care for now */
+ 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);
+ if (boot_part == NULL)
+ 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 st %0x size %0x",
+ i, name, 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);
+ } else {
+ memcpy(tmp, type, 32);
+ tmp[32] = '\0';
+ ERROR("Unknown partition type [%s]\n", tmp);
+ }
+ }
+ error:
+ free(buffer);
+
+ return boot_part;
+
+}