| /* This file is part of the program psim. |
| |
| Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au> |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3 of the License, or |
| (at your option) any later version. |
| |
| 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, see <http://www.gnu.org/licenses/>. |
| |
| */ |
| |
| |
| #ifndef _PK_DISKLABEL_C_ |
| #define _PK_DISKLABEL_C_ |
| |
| #ifndef STATIC_INLINE_PK_DISKLABEL |
| #define STATIC_INLINE_PK_DISKLABEL STATIC_INLINE |
| #endif |
| |
| #include "device_table.h" |
| |
| #include "pk.h" |
| |
| #include <stdlib.h> |
| |
| /* PACKAGE |
| |
| disk-label - all knowing disk I/O package |
| |
| DESCRIPTION |
| |
| The disk-label package provides a generic interface to disk |
| devices. It uses the arguments specified when an instance is being |
| created to determine if the raw disk, a partition, or a file within |
| a partition should be opened. |
| |
| An instance create call to disk-label could result, for instance, |
| in the opening of a DOS file system contained within a dos |
| partition contained within a physical disk. |
| |
| */ |
| |
| /* taken from bfd/ppcboot.c by Michael Meissner */ |
| |
| /* PPCbug location structure */ |
| typedef struct ppcboot_location { |
| unsigned8 ind; |
| unsigned8 head; |
| unsigned8 sector; |
| unsigned8 cylinder; |
| } ppcboot_location_t; |
| |
| /* PPCbug partition table layout */ |
| typedef struct ppcboot_partition { |
| ppcboot_location_t partition_begin; /* partition begin */ |
| ppcboot_location_t partition_end; /* partition end */ |
| unsigned8 sector_begin[4]; /* 32-bit start RBA (zero-based), little endian */ |
| unsigned8 sector_length[4]; /* 32-bit RBA count (one-based), little endian */ |
| } ppcboot_partition_t; |
| |
| #if 0 |
| /* PPCbug boot layout. */ |
| typedef struct ppcboot_hdr { |
| unsigned8 pc_compatibility[446]; /* x86 instruction field */ |
| ppcboot_partition_t partition[4]; /* partition information */ |
| unsigned8 signature[2]; /* 0x55 and 0xaa */ |
| unsigned8 entry_offset[4]; /* entry point offset, little endian */ |
| unsigned8 length[4]; /* load image length, little endian */ |
| unsigned8 flags; /* flag field */ |
| unsigned8 os_id; /* OS_ID */ |
| char partition_name[32]; /* partition name */ |
| unsigned8 reserved1[470]; /* reserved */ |
| } ppcboot_hdr_t; |
| #endif |
| |
| |
| typedef struct _disklabel { |
| device_instance *parent; |
| device_instance *raw_disk; |
| unsigned_word pos; |
| unsigned_word sector_begin; |
| unsigned_word sector_length; |
| } disklabel; |
| |
| |
| static unsigned_word |
| sector2uw(unsigned8 s[4]) |
| { |
| return ((s[3] << 24) |
| + (s[2] << 16) |
| + (s[1] << 8) |
| + (s[0] << 0)); |
| } |
| |
| |
| static void |
| disklabel_delete(device_instance *instance) |
| { |
| disklabel *label = device_instance_data(instance); |
| device_instance_delete(label->raw_disk); |
| free(label); |
| } |
| |
| |
| static int |
| disklabel_read(device_instance *instance, |
| void *buf, |
| unsigned_word len) |
| { |
| disklabel *label = device_instance_data(instance); |
| int nr_read; |
| if (label->pos + len > label->sector_length) |
| len = label->sector_length - label->pos; |
| if (device_instance_seek(label->raw_disk, 0, |
| label->sector_begin + label->pos) < 0) |
| return -1; |
| nr_read = device_instance_read(label->raw_disk, buf, len); |
| if (nr_read > 0) |
| label->pos += nr_read; |
| return nr_read; |
| } |
| |
| static int |
| disklabel_write(device_instance *instance, |
| const void *buf, |
| unsigned_word len) |
| { |
| disklabel *label = device_instance_data(instance); |
| int nr_written; |
| if (label->pos + len > label->sector_length) |
| len = label->sector_length - label->pos; |
| if (device_instance_seek(label->raw_disk, 0, |
| label->sector_begin + label->pos) < 0) |
| return -1; |
| nr_written = device_instance_write(label->raw_disk, buf, len); |
| if (nr_written > 0) |
| label->pos += nr_written; |
| return nr_written; |
| } |
| |
| static int |
| disklabel_seek(device_instance *instance, |
| unsigned_word pos_hi, |
| unsigned_word pos_lo) |
| { |
| disklabel *label = device_instance_data(instance); |
| if (pos_lo >= label->sector_length || pos_hi != 0) |
| return -1; |
| label->pos = pos_lo; |
| return 0; |
| } |
| |
| |
| static const device_instance_callbacks package_disklabel_callbacks = { |
| disklabel_delete, |
| disklabel_read, |
| disklabel_write, |
| disklabel_seek, |
| }; |
| |
| /* Reconize different types of boot block */ |
| |
| static int |
| block0_is_bpb(const unsigned8 block[]) |
| { |
| const char ebdic_ibma[] = { 0xc9, 0xc2, 0xd4, 0xc1 }; |
| /* ref PowerPC Microprocessor CHRP bindings 1.2b - page 47 */ |
| /* can't start with IBMA */ |
| if (memcmp(block, ebdic_ibma, sizeof(ebdic_ibma)) == 0) |
| return 0; |
| /* must have LE 0xAA55 signature at offset 510 */ |
| if (block[511] != 0xAA && block[510] != 0x55) |
| return 0; |
| /* valid 16 bit LE bytes per sector - 256, 512, 1024 */ |
| if (block[11] != 0 |
| || (block[12] != 1 && block[12] != 2 && block[12] != 4)) |
| return 0; |
| /* nr fats is 1 or 2 */ |
| if (block[16] != 1 && block[16] != 2) |
| return 0; |
| return 1; |
| } |
| |
| |
| /* Verify that the device contains an ISO-9660 File system */ |
| |
| static int |
| is_iso9660(device_instance *raw_disk) |
| { |
| /* ref PowerPC Microprocessor CHRP bindings 1.2b - page 47 */ |
| unsigned8 block[512]; |
| if (device_instance_seek(raw_disk, 0, 512 * 64) < 0) |
| return 0; |
| if (device_instance_read(raw_disk, block, sizeof(block)) != sizeof(block)) |
| return 0; |
| if (block[0] == 0x01 |
| && block[1] == 'C' |
| && block[2] == 'D' |
| && block[3] == '0' |
| && block[4] == '0' |
| && block[5] == '1') |
| return 1; |
| return 0; |
| } |
| |
| |
| /* Verify that the disk block contains a valid DOS partition table. |
| While we're at it have a look around for active partitions etc. |
| |
| Return 0: invalid |
| Return 1..4: valid, value returned is the first active partition |
| Return -1: no active partition */ |
| |
| static int |
| block0_is_fdisk(const unsigned8 block[]) |
| { |
| const int partition_type_fields[] = { 0, 0x1c2, 0x1d2, 0x1e2, 0x1f2 }; |
| const int partition_active_fields[] = { 0, 0x1be, 0x1ce, 0x1de, 0xee }; |
| int partition; |
| int active = -1; |
| /* ref PowerPC Microprocessor CHRP bindings 1.2b - page 47 */ |
| /* must have LE 0xAA55 signature at offset 510 */ |
| if (block[511/*0x1ff*/] != 0xAA && block[510/*0x1fe*/] != 0x55) |
| return 0; |
| /* must contain valid partition types */ |
| for (partition = 1; partition <= 4 && active != 0; partition++) { |
| int partition_type = block[partition_type_fields[partition]]; |
| int is_active = block[partition_active_fields[partition]] == 0x80; |
| const char *type; |
| switch (partition_type) { |
| case 0x00: |
| type = "UNUSED"; |
| break; |
| case 0x01: |
| type = "FAT 12 File system"; |
| break; |
| case 0x04: |
| type = "FAT 16 File system"; |
| break; |
| case 0x05: |
| case 0x06: |
| type = "rejected - extended/chained partition not supported"; |
| active = 0; |
| break; |
| case 0x41: |
| type = "Single program image"; |
| break; |
| case 0x82: |
| type = "Solaris?"; |
| break; |
| case 0x96: |
| type = "ISO 9660 File system"; |
| break; |
| default: |
| type = "rejected - unknown type"; |
| active = 0; |
| break; |
| } |
| PTRACE(disklabel, ("partition %d of type 0x%02x - %s%s\n", |
| partition, |
| partition_type, |
| type, |
| is_active && active != 0 ? " (active)" : "")); |
| if (partition_type != 0 && is_active && active < 0) |
| active = partition; |
| } |
| return active; |
| } |
| |
| |
| /* Verify that block0 corresponds to a MAC disk */ |
| |
| static int |
| block0_is_mac_disk(const unsigned8 block[]) |
| { |
| /* ref PowerPC Microprocessor CHRP bindings 1.2b - page 47 */ |
| /* signature - BEx4552 at offset 0 */ |
| if (block[0] != 0x45 || block[1] != 0x52) |
| return 0; |
| return 1; |
| } |
| |
| |
| /* Open a logical disk/file */ |
| |
| device_instance * |
| pk_disklabel_create_instance(device_instance *raw_disk, |
| const char *args) |
| { |
| int partition; |
| char *filename; |
| |
| /* parse the arguments */ |
| if (args == NULL) { |
| partition = 0; |
| filename = NULL; |
| } |
| else { |
| partition = strtoul((char*)args, &filename, 0); |
| if (filename == args) |
| partition = -1; /* not specified */ |
| if (*filename == ',') |
| filename++; |
| if (*filename == '\0') |
| filename = NULL; /* easier */ |
| } |
| |
| if (partition == 0) { |
| /* select the raw disk */ |
| return raw_disk; |
| } |
| else { |
| unsigned8 boot_block[512]; |
| /* get the boot block for examination */ |
| if (device_instance_seek(raw_disk, 0, 0) < 0) |
| device_error(device_instance_device(raw_disk), |
| "Problem seeking on raw disk"); |
| if (device_instance_read(raw_disk, &boot_block, sizeof(boot_block)) |
| != sizeof(boot_block)) |
| device_error(device_instance_device(raw_disk), "Problem reading boot block"); |
| |
| if (partition < 0) { |
| /* select the active partition */ |
| if (block0_is_bpb(boot_block)) { |
| device_error(device_instance_device(raw_disk), "Unimplemented active BPB"); |
| } |
| else if (block0_is_fdisk(boot_block)) { |
| int active = block0_is_fdisk(boot_block); |
| device_error(device_instance_device(raw_disk), "Unimplemented active FDISK (%d)", |
| active); |
| } |
| else if (is_iso9660(raw_disk)) { |
| device_error(device_instance_device(raw_disk), "Unimplemented active ISO9660"); |
| } |
| else if (block0_is_mac_disk(boot_block)) { |
| device_error(device_instance_device(raw_disk), "Unimplemented active MAC DISK"); |
| } |
| else { |
| device_error(device_instance_device(raw_disk), "Unreconized bootblock"); |
| } |
| } |
| else { |
| /* select the specified disk partition */ |
| if (block0_is_bpb(boot_block)) { |
| device_error(device_instance_device(raw_disk), "Unimplemented BPB"); |
| } |
| else if (block0_is_fdisk(boot_block)) { |
| /* return an instance */ |
| ppcboot_partition_t *partition_table = (ppcboot_partition_t*) &boot_block[446]; |
| ppcboot_partition_t *partition_entry; |
| disklabel *label; |
| if (partition > 4) |
| device_error(device_instance_device(raw_disk), |
| "Only FDISK partitions 1..4 supported"); |
| partition_entry = &partition_table[partition - 1]; |
| label = ZALLOC(disklabel); |
| label->raw_disk = raw_disk; |
| label->pos = 0; |
| label->sector_begin = 512 * sector2uw(partition_entry->sector_begin); |
| label->sector_length = 512 * sector2uw(partition_entry->sector_length); |
| PTRACE(disklabel, ("partition %ld, sector-begin %ld, length %ld\n", |
| (long)partition, |
| (long)label->sector_begin, |
| (long)label->sector_length)); |
| if (filename != NULL) |
| device_error(device_instance_device(raw_disk), |
| "FDISK file names not yet supported"); |
| return device_create_instance_from(NULL, raw_disk, |
| label, |
| NULL, args, |
| &package_disklabel_callbacks); |
| } |
| else if (block0_is_mac_disk(boot_block)) { |
| device_error(device_instance_device(raw_disk), "Unimplemented MAC DISK"); |
| } |
| else { |
| device_error(device_instance_device(raw_disk), |
| "Unreconized bootblock"); |
| } |
| } |
| } |
| |
| return NULL; |
| } |
| |
| |
| #endif /* _PK_DISKLABEL_C_ */ |
| |