summaryrefslogtreecommitdiff
path: root/src/libpart/isofs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libpart/isofs.c')
-rw-r--r--src/libpart/isofs.c257
1 files changed, 257 insertions, 0 deletions
diff --git a/src/libpart/isofs.c b/src/libpart/isofs.c
new file mode 100644
index 0000000..466a2e7
--- /dev/null
+++ b/src/libpart/isofs.c
@@ -0,0 +1,257 @@
+/*
+ * <isofs.c>
+ *
+ * Open Hack'Ware BIOS ISOFS 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"
+
+/* ISO FS partitions handlers */
+#define ISOFS_BLOCSIZE (2048)
+
+/* Generic ISO fs descriptor */
+typedef struct isofs_desc_t isofs_desc_t;
+struct isofs_desc_t {
+ uint8_t type;
+ uint8_t ID[5];
+ uint8_t version;
+ uint8_t data[2041];
+} __attribute__ ((packed));
+
+typedef struct iso_primary_desc_t iso_primary_desc_t;
+struct iso_primary_desc_t {
+ uint8_t type;
+ uint8_t ID[5];
+ uint8_t version;
+ uint8_t pad0;
+ uint8_t system_id[32];
+ uint8_t volume_id[32];
+ uint8_t pad1[8];
+ uint32_t volume_size;
+} __attribute__ ((packed));
+
+/* The only descriptor we're interrested in here
+ * is El-torito boot descriptor
+ */
+typedef struct isofs_bootdesc_t isofs_bootdesc_t;
+struct isofs_bootdesc_t {
+ uint8_t type;
+ uint8_t ID[5];
+ uint8_t version;
+ uint8_t sys_ID[32];
+ uint8_t pad[32];
+ uint32_t catalog;
+ uint8_t data[1973];
+} __attribute__ ((packed));
+
+#define ISO_BOOTABLE 0x88
+enum {
+ ISOBOOT_IX86 = 0,
+ ISOBOOT_PPC = 1,
+ ISOBOOT_MAC = 2,
+};
+
+enum {
+ ISOMEDIA_NOEMUL = 0,
+ ISOMEDIA_FL12 = 1,
+ ISOMEDIA_FL144 = 2,
+ ISOMEDIA_FL288 = 3,
+ ISOMEDIA_HD = 4,
+};
+
+typedef struct isofs_validdesc_t isofs_validdesc_t;
+struct isofs_validdesc_t {
+ uint8_t ID;
+ uint8_t arch;
+ uint8_t pad[2];
+ uint8_t name[24];
+ uint8_t csum[2];
+ uint16_t key;
+} __attribute__ ((packed));
+
+typedef struct isofs_bootcat_t isofs_bootcat_t;
+struct isofs_bootcat_t {
+ uint8_t bootable;
+ uint8_t media;
+ uint8_t segment[2];
+ uint8_t sys_type;
+ uint8_t pad;
+ uint16_t nsect;
+ uint32_t offset;
+ uint8_t data[20];
+} __attribute__ ((packed));
+
+part_t *isofs_probe_partitions (bloc_device_t *bd)
+{
+ unsigned char name[32];
+ void *buffer;
+ union {
+ isofs_desc_t desc;
+ isofs_bootdesc_t bootdesc;
+ iso_primary_desc_t primdesc;
+ } *desc;
+ isofs_validdesc_t *valid;
+ isofs_bootcat_t *bootcat;
+ part_t *part;
+ uint32_t boot_desc;
+ uint32_t nsect, bloc, offset, length;
+ int i, end_reached;
+
+ part = NULL;
+ buffer = malloc(ISOFS_BLOCSIZE);
+ end_reached = 0;
+ desc = buffer;
+ boot_desc = -1;
+ /* The descriptors start at offset 0x8000 */
+ for (bloc = 0x8000 / ISOFS_BLOCSIZE; end_reached == 0; bloc++) {
+ bd_seek(bd, bloc, 0);
+ if (bd_read(bd, buffer, ISOFS_BLOCSIZE) < 0) {
+ ERROR("%s bloc_read %d failed\n", __func__, bloc);
+ goto error;
+ }
+ if (strncmp("CD001", desc->desc.ID, 5) != 0) {
+ // MSG("\rNo ISO9660 signature\n");
+ goto error;
+ }
+ /* We found at least one valid descriptor */
+ switch (desc->desc.type) {
+ case 0x00:
+ /* El-torito descriptor, great ! */
+ DPRINTF("El-torito descriptor: %08x %d\n", desc->bootdesc.catalog,
+ (char *)&desc->bootdesc.catalog - (char *)desc);
+ boot_desc = get_le32(&desc->bootdesc.catalog);
+ break;
+ case 0x01:
+ /* ISOFS primary descriptor */
+ DPRINTF("ISOFS primary descriptor (%d %d)\n",
+ get_le32(&desc->primdesc.volume_size) * 2048,
+ get_le32(&desc->primdesc.volume_size));
+ break;
+ case 0x02:
+ /* ISOFS suplementary descriptor */
+ DPRINTF("ISOFS suplementary descriptor\n");
+ break;
+ case 0xFF:
+ /* End of descriptor list */
+ DPRINTF("End of descriptor list\n");
+ end_reached = 1;
+ break;
+ }
+ }
+ if (boot_desc != (uint32_t)(-1)) {
+ /* Find the validation descriptor */
+ bd_seek(bd, boot_desc, 0);
+ for (i = 0; i < (ISOFS_BLOCSIZE / 64); i++) {
+ DPRINTF("ISO catalog...\n");
+ bd_read(bd, buffer, 64);
+ valid = buffer;
+#if 1
+ if (valid->ID != 0x01 || get_le16(&valid->key) != 0xAA55) {
+ ERROR("ISO catalog with invalid ID/key: %x %x\n",
+ valid->ID, valid->key);
+ continue;
+ }
+#endif
+#if 0
+#if defined (__i386__)
+ if (valid->arch != ISOBOOT_IX86) {
+ ERROR("ISO catalog not for x86: %d\n", valid->arch);
+ continue;
+ }
+#elif defined (__powerpc__)
+ if (valid->arch != ISOBOOT_PPC && valid->arch != ISOBOOT_MAC) {
+ ERROR("ISO catalog not for PPC: %d\n", valid->arch);
+ continue;
+ }
+#else
+ ERROR("Unknown host architecture !\n");
+ continue;
+#endif
+#endif
+ bootcat = (void *)(valid + 1);
+ if (bootcat->bootable != ISO_BOOTABLE) {
+ ERROR("Non bootable ISO catalog\n");
+ continue;
+ }
+ nsect = get_le16(&bootcat->nsect);
+ switch (bootcat->media) {
+ case ISOMEDIA_NOEMUL:
+ length = nsect * ISOFS_BLOCSIZE;
+ dprintf("No emulation\n");
+ break;
+ case ISOMEDIA_FL12:
+ length = 1200 * 1024;
+ dprintf("1.2 MB floppy\n");
+ break;
+ case ISOMEDIA_FL144:
+ length = 1440 * 1024;
+ dprintf("1.44 MB floppy\n");
+ break;
+ case ISOMEDIA_FL288:
+ length = 2880 * 1024;
+ dprintf("2.88 MB floppy\n");
+ break;
+ case ISOMEDIA_HD:
+ length = nsect * ISOFS_BLOCSIZE;
+ dprintf("HD image\n");
+ break;
+ default:
+ ERROR("Unknown media type: %d\n", bootcat->media);
+ continue;
+ }
+ offset = get_le32(&bootcat->offset);
+ /* Register boot disc */
+ part = malloc(sizeof(part_t));
+ part->bd = bd;
+ part_set_blocsize(bd, part, ISOFS_BLOCSIZE);
+ part->start = offset;
+ part->size = (length + ISOFS_BLOCSIZE - 1) / ISOFS_BLOCSIZE;
+ part->boot_start.bloc = 0;
+ part->boot_start.offset = 0;
+ part->boot_size.bloc = length / ISOFS_BLOCSIZE;
+ part->boot_size.offset = length % ISOFS_BLOCSIZE;
+ part->boot_load = 0;
+ part->boot_entry = 0;
+ if (valid->name[0] == '\0') {
+ strcpy(name, "ISOFS");
+ } else {
+ memcpy(name, valid->name, sizeof(valid->name));
+ name[sizeof(valid->name)] = '\0';
+ }
+ printf("Partition '%s': %p st %0x size %0x %d\n",
+ name, part, offset, length, bootcat->media);
+ printf(" boot %0x %0x load %0x entry %0x\n",
+ part->boot_start.bloc, part->boot_size.bloc,
+ part->boot_load, part->boot_entry);
+ part->flags = PART_TYPE_ISO9660 | PART_FLAG_BOOT;
+ part_register(bd, part, name);
+ fs_raw_set_bootfile(part, part->boot_start.bloc,
+ part->boot_start.offset,
+ part->boot_size.bloc,
+ part->boot_size.offset);
+ break;
+ }
+ }
+error:
+ free(buffer);
+
+ return part;
+}