X-Git-Url: http://git.ozlabs.org/?p=yaboot.git;a=blobdiff_plain;f=second%2Fpartition.c;h=0cb8ae85f1768bb7aef755c6ef37f64b64f5f168;hp=fff169c965cde965914b0f0564df345256b645ab;hb=6084bb9a372a5fb9fa3e63a26c1770036c31883d;hpb=5613f9fab88b71f14259856b390f1cc989b602bf diff --git a/second/partition.c b/second/partition.c index fff169c..0cb8ae8 100644 --- a/second/partition.c +++ b/second/partition.c @@ -1,23 +1,31 @@ -/* File related stuff - - Copyright (C) 1999 Benjamin Herrenschmidt - - Todo: Add disklabel (or let OF do it ?). Eventually think about - fixing CDROM handling by directly using the ATAPI layer. - - 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 2 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* + * partition.c - partition table support + * + * Copyright (C) 2004 Sven Luther + * + * Copyright (C) 2001, 2002 Ethan Benson + * + * Copyright (C) 1999 Benjamin Herrenschmidt + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * Todo: Add disklabel (or let OF do it ?). Eventually think about + * fixing CDROM handling by directly using the ATAPI layer. + */ #include "ctype.h" #include "types.h" @@ -25,12 +33,14 @@ #include "stdlib.h" #include "mac-part.h" #include "fdisk-part.h" +#include "amiga-part.h" #include "partition.h" #include "prom.h" #include "string.h" #include "linux/iso_fs.h" #include "debug.h" #include "errors.h" +#include "byteorder.h" /* We currently don't check the partition type, some users * are putting crap there and still expect it to work... @@ -39,18 +49,15 @@ #ifdef CHECK_FOR_VALID_MAC_PARTITION_TYPE static const char *valid_mac_partition_types[] = { - "apple_unix_svr2", - "linux", - "apple_hfs", - "apple_boot", - "apple_bootstrap", - NULL + "apple_unix_svr2", + "linux", + "apple_hfs", + "apple_boot", + "apple_bootstrap", + NULL }; #endif - -/* Local functions */ -static unsigned long swab32(unsigned long value); #define MAX_BLOCK_SIZE 2048 static unsigned char block_buffer[MAX_BLOCK_SIZE]; @@ -58,21 +65,22 @@ static unsigned char block_buffer[MAX_BLOCK_SIZE]; static void add_new_partition(struct partition_t** list, int part_number, const char *part_type, const char *part_name, unsigned long part_start, unsigned long part_size, - unsigned short part_blocksize) + unsigned short part_blocksize, int sys_ind) { - struct partition_t* part; - part = (struct partition_t*)malloc(sizeof(struct partition_t)); - - part->part_number = part_number; - strncpy(part->part_type, part_type, MAX_PART_NAME); - strncpy(part->part_name, part_name, MAX_PART_NAME); - part->part_start = part_start; - part->part_size = part_size; - part->blocksize = part_blocksize; - - /* Tack this entry onto the list */ - part->next = *list; - *list = part; + struct partition_t* part; + part = (struct partition_t*)malloc(sizeof(struct partition_t)); + + part->part_number = part_number; + strncpy(part->part_type, part_type, MAX_PART_NAME); + strncpy(part->part_name, part_name, MAX_PART_NAME); + part->part_start = part_start; + part->part_size = part_size; + part->blocksize = part_blocksize; + part->sys_ind = sys_ind; + + /* Tack this entry onto the list */ + part->next = *list; + *list = part; } /* Note, we rely on partitions being dev-block-size aligned, @@ -83,68 +91,69 @@ static void partition_mac_lookup( const char *dev_name, prom_handle disk, unsigned int prom_blksize, struct partition_t** list ) { - int block, map_size; - - /* block_buffer contains block 0 from the partitions_lookup() stage */ - struct mac_partition* part = (struct mac_partition *)block_buffer; - unsigned short ptable_block_size = - ((struct mac_driver_desc *)block_buffer)->block_size; - - map_size = 1; - for (block=1; block < map_size + 1; block++) - { + int block, map_size; + + /* block_buffer contains block 0 from the partitions_lookup() stage */ + struct mac_partition* part = (struct mac_partition *)block_buffer; + unsigned short ptable_block_size = + ((struct mac_driver_desc *)block_buffer)->block_size; + + map_size = 1; + for (block=1; block < map_size + 1; block++) + { #ifdef CHECK_FOR_VALID_MAC_PARTITION_TYPE - int valid = 0; - const char *ptype; + int valid = 0; + const char *ptype; #endif - if (prom_readblocks(disk, block, 1, block_buffer) != 1) { - prom_printf("Can't read partition %d\n", block); - break; - } - if (part->signature != MAC_PARTITION_MAGIC) { + if (prom_readblocks(disk, block, 1, block_buffer) != 1) { + prom_printf("Can't read partition %d\n", block); + break; + } + if (part->signature != MAC_PARTITION_MAGIC) { #if 0 - prom_printf("Wrong partition %d signature\n", block); + prom_printf("Wrong partition %d signature\n", block); #endif - break; - } - if (block == 1) - map_size = part->map_count; - + break; + } + if (block == 1) + map_size = part->map_count; + #ifdef CHECK_FOR_VALID_MAC_PARTITION_TYPE - /* We don't bother looking at swap partitions of any type, - * and the rest are the ones we know about */ - for (ptype = valid_mac_partition_types; ptype; ptype++) - if (!strcmp (part->type, ptype)) - { - valid = 1; - break; - } + /* We don't bother looking at swap partitions of any type, + * and the rest are the ones we know about */ + for (ptype = valid_mac_partition_types; ptype; ptype++) + if (!strcmp (part->type, ptype)) + { + valid = 1; + break; + } #if DEBUG - if (!valid) - prom_printf( "MAC: Unsupported partition #%d; type=%s\n", - block, part->type ); + if (!valid) + prom_printf( "MAC: Unsupported partition #%d; type=%s\n", + block, part->type ); #endif #endif #ifdef CHECK_FOR_VALID_MAC_PARTITION_TYPE - if (valid) + if (valid) #endif - /* We use the partition block size from the partition table. - * The filesystem implmentations are responsible for mapping - * to their own fs blocksize */ - add_new_partition( - list, /* partition list */ - block, /* partition number */ - part->type, /* type */ - part->name, /* name */ - part->start_block + part->data_start, /* start */ - part->data_count, /* size */ - ptable_block_size ); - } + /* We use the partition block size from the partition table. + * The filesystem implmentations are responsible for mapping + * to their own fs blocksize */ + add_new_partition( + list, /* partition list */ + block, /* partition number */ + part->type, /* type */ + part->name, /* name */ + part->start_block + part->data_start, /* start */ + part->data_count, /* size */ + ptable_block_size, + 0); + } } -/* +/* * Same function as partition_mac_lookup(), except for fdisk * partitioned disks. */ @@ -152,25 +161,26 @@ static void partition_fdisk_lookup( const char *dev_name, prom_handle disk, unsigned int prom_blksize, struct partition_t** list ) { - int partition; + int partition; - /* fdisk partition tables start at offset 0x1be - * from byte 0 of the boot drive. - */ - struct fdisk_partition* part = + /* fdisk partition tables start at offset 0x1be + * from byte 0 of the boot drive. + */ + struct fdisk_partition* part = (struct fdisk_partition *) (block_buffer + 0x1be); - for (partition=1; partition <= 4 ;partition++, part++) { - if (part->sys_ind == LINUX_NATIVE) { - add_new_partition( list, - partition, - "Linux", /* type */ - '\0', /* name */ - swab32(*(unsigned int *)(part->start4)), - swab32(*(unsigned int *)(part->size4)), - 512 /*blksize*/ ); - } - } + for (partition=1; partition <= 4 ;partition++, part++) { + if (part->sys_ind == LINUX_NATIVE || part->sys_ind == LINUX_RAID) { + add_new_partition( list, + partition, + "Linux", /* type */ + '\0', /* name */ + le32_to_cpu(*(unsigned int *)part->start4), + le32_to_cpu(*(unsigned int *)part->size4), + 512 /*blksize*/, + part->sys_ind /* partition type */ ); + } + } } /* I don't know if it's possible to handle multisession and other multitrack @@ -182,87 +192,202 @@ partition_fdisk_lookup( const char *dev_name, prom_handle disk, static int identify_iso_fs(ihandle device, unsigned int *iso_root_block) { - int block; - - for (block = 16; block < 100; block++) { - struct iso_volume_descriptor * vdp; - - if (prom_readblocks(device, block, 1, block_buffer) != 1) { - prom_printf("Can't read volume desc block %d\n", block); - break; - } - - vdp = (struct iso_volume_descriptor *)block_buffer; - - /* Due to the overlapping physical location of the descriptors, - * ISO CDs can match hdp->id==HS_STANDARD_ID as well. To ensure - * proper identification in this case, we first check for ISO. - */ - if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) { - *iso_root_block = block; - return 1; - } + int block; + + for (block = 16; block < 100; block++) { + struct iso_volume_descriptor * vdp; + + if (prom_readblocks(device, block, 1, block_buffer) != 1) { + prom_printf("Can't read volume desc block %d\n", block); + break; + } + + vdp = (struct iso_volume_descriptor *)block_buffer; + + /* Due to the overlapping physical location of the descriptors, + * ISO CDs can match hdp->id==HS_STANDARD_ID as well. To ensure + * proper identification in this case, we first check for ISO. + */ + if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) { + *iso_root_block = block; + return 1; + } + } + + return 0; +} + +/* + * Detects and read amiga partition tables. + */ + +static int +_amiga_checksum (unsigned int blk_size) +{ + unsigned int sum; + int i, end; + unsigned int *amiga_block = (unsigned int *) block_buffer; + + sum = amiga_block[0]; + end = amiga_block[AMIGA_LENGTH]; + + if (end > blk_size) end = blk_size; + + for (i = 1; i < end; i++) sum += amiga_block[i]; + + return sum; +} + +static int +_amiga_find_rdb (const char *dev_name, prom_handle disk, unsigned int prom_blksize) +{ + int i; + unsigned int *amiga_block = (unsigned int *) block_buffer; + + for (i = 0; i\n", block_buffer); - goto bail; - } - prom_blksize = prom_getblksize(disk); - DEBUG_F("block size of device is %d\n", prom_blksize); - - if (prom_blksize <= 1) - prom_blksize = 512; - if (prom_blksize > MAX_BLOCK_SIZE) { - prom_printf("block_size %d not supported !\n", prom_blksize); - goto bail; + int partition, part; + unsigned int blockspercyl; + unsigned int *amiga_block = (unsigned int *) block_buffer; + unsigned int *used = NULL; + unsigned int possible; + int checksum; + int i; + + blockspercyl = amiga_block[AMIGA_SECT] * amiga_block[AMIGA_HEADS]; + possible = amiga_block[AMIGA_RDBLIMIT]/32 +1; + + used = (unsigned int *) malloc (sizeof (unsigned int) * (possible + 1)); + if (!used) { + prom_printf("Can't allocate memory\n"); + return; } - - /* Read boot blocs */ - if (prom_readblocks(disk, 0, 1, block_buffer) != 1) { - prom_printf("Can't read boot blocks\n"); - goto bail; - } - if (desc->signature == MAC_DRIVER_MAGIC) { - /* pdisk partition format */ - partition_mac_lookup(device, disk, prom_blksize, &list); - } else if ((block_buffer[510] == 0x55) && (block_buffer[511] == 0xaa)) { - /* fdisk partition format */ - partition_fdisk_lookup(device, disk, prom_blksize, &list); - } else if (prom_blksize == 2048 && identify_iso_fs(disk, &iso_root_block)) { - add_new_partition(&list, - 0, - '\0', - '\0', - iso_root_block, - 0, - prom_blksize); - prom_printf("ISO9660 disk\n"); - } else { - prom_printf("No supported partition table detected\n"); - goto bail; + + for (i=0; i < possible; i++) used[i] = 0; + + + for (part = amiga_block[AMIGA_PARTITIONS], partition = 0; + part != AMIGA_END; + part = amiga_block[AMIGA_PART_NEXT], partition++) + { + if (prom_readblocks(disk, part, 1, block_buffer) != 1) { + prom_printf("Can't read partition block %d\n", part); + break; + } + checksum = _amiga_checksum (prom_blksize); + if ((amiga_block[AMIGA_ID] == AMIGA_ID_PART) && + (checksum == 0) && + ((used[part/32] & (0x1 << (part % 32))) == 0)) + { + used[part/32] |= (0x1 << (part % 32)); + } else { + prom_printf("Amiga partition table corrupted at block %d\n", part); + if (amiga_block[AMIGA_ID] != AMIGA_ID_PART) + prom_printf ("block type is not partition but %08x\n", amiga_block[AMIGA_ID]); + if (checksum != 0) + prom_printf ("block checsum is bad : %d\n", checksum); + if ((used[part/32] & (0x1 << (part % 32))) != 0) + prom_printf ("partition table is looping, block %d already traveled\n", part); + break; + } + + /* We use the partition block size from the partition table. + * The filesystem implmentations are responsible for mapping + * to their own fs blocksize */ + add_new_partition( + list, /* partition list */ + partition, /* partition number */ + "Linux", /* type */ + '\0', /* name */ + blockspercyl * amiga_block[AMIGA_PART_LOWCYL], /* start */ + blockspercyl * (amiga_block[AMIGA_PART_HIGHCYL] - amiga_block[AMIGA_PART_LOWCYL] + 1), /* size */ + prom_blksize, + 0 ); } + if (used) + free(used); +} + +struct partition_t* +partitions_lookup(const char *device) +{ + ihandle disk; + struct mac_driver_desc *desc = (struct mac_driver_desc *)block_buffer; + struct partition_t* list = NULL; + unsigned int prom_blksize, iso_root_block; + + strncpy(block_buffer, device, 2040); + strcat(block_buffer, ":0"); + + /* Open device */ + disk = prom_open(block_buffer); + if (disk == NULL) { + prom_printf("Can't open device <%s>\n", block_buffer); + goto bail; + } + prom_blksize = prom_getblksize(disk); + DEBUG_F("block size of device is %d\n", prom_blksize); + + if (prom_blksize <= 1) + prom_blksize = 512; + if (prom_blksize > MAX_BLOCK_SIZE) { + prom_printf("block_size %d not supported !\n", prom_blksize); + goto bail; + } + + /* Read boot blocs */ + if (prom_readblocks(disk, 0, 1, block_buffer) != 1) { + prom_printf("Can't read boot blocks\n"); + goto bail; + } + if (desc->signature == MAC_DRIVER_MAGIC) { + /* pdisk partition format */ + partition_mac_lookup(device, disk, prom_blksize, &list); + } else if ((block_buffer[510] == 0x55) && (block_buffer[511] == 0xaa)) { + /* fdisk partition format */ + partition_fdisk_lookup(device, disk, prom_blksize, &list); + } else if (prom_blksize == 2048 && identify_iso_fs(disk, &iso_root_block)) { + add_new_partition(&list, + 0, + '\0', + '\0', + iso_root_block, + 0, + prom_blksize, + 0); + prom_printf("ISO9660 disk\n"); + } else if (_amiga_find_rdb(device, disk, prom_blksize) != -1) { + /* amiga partition format */ + partition_amiga_lookup(device, disk, prom_blksize, &list); + } else { + prom_printf("No supported partition table detected\n"); + goto bail; + } bail: - prom_close(disk); - - return list; + prom_close(disk); + + return list; } char * @@ -288,7 +413,7 @@ get_part_type(char *device, int partition) if ((partition >= 0) && (partition == p->part_number)) { type = strdup(p->part_type); break; - } + } } if (parts) partitions_free(parts); @@ -299,31 +424,19 @@ get_part_type(char *device, int partition) void partitions_free(struct partition_t* list) { - struct partition_t* next; - - while(list) { - next = list->next; - free(list); - list = next; - } -} -unsigned long -swab32(unsigned long value) -{ - __u32 result; - - __asm__("rlwimi %0,%1,24,16,23\n\t" - "rlwimi %0,%1,8,8,15\n\t" - "rlwimi %0,%1,24,0,7" - : "=r" (result) - : "r" (value), "0" (value >> 24)); - return result; + struct partition_t* next; + + while(list) { + next = list->next; + free(list); + list = next; + } } -/* +/* * Local variables: - * c-file-style: "K&R" + * c-file-style: "k&r" * c-basic-offset: 5 * End: */