X-Git-Url: http://git.ozlabs.org/?p=yaboot.git;a=blobdiff_plain;f=second%2Fpartition.c;h=1ade1b671f4e422b28546407ecfc5aace2a2ebe9;hp=ea84ee23f8817f26cc713596b94f64cdbb208eee;hb=refs%2Fheads%2Fdevel;hpb=0ef1539b6f680ba09c88be5bb94a821fd2599931 diff --git a/second/partition.c b/second/partition.c index ea84ee2..1ade1b6 100644 --- a/second/partition.c +++ b/second/partition.c @@ -1,23 +1,33 @@ -/* 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) 2013 Dinar Valeev + * + * 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 +35,16 @@ #include "stdlib.h" #include "mac-part.h" #include "fdisk-part.h" +#include "amiga-part.h" +#include "gpt-part.h" #include "partition.h" #include "prom.h" #include "string.h" #include "linux/iso_fs.h" #include "debug.h" #include "errors.h" +#include "bootinfo.h" +#include "byteorder.h" /* We currently don't check the partition type, some users * are putting crap there and still expect it to work... @@ -47,28 +61,26 @@ static const char *valid_mac_partition_types[] = { NULL }; #endif - -/* Local functions */ -static unsigned long swab32(unsigned long value); -#define MAX_BLOCK_SIZE 2048 -static unsigned char block_buffer[MAX_BLOCK_SIZE]; +#define MAX_BLOCK_SIZE 4096 +static unsigned char block_buffer[MAX_BLOCK_SIZE * 2]; 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) + const char *part_name, unsigned long long part_start, unsigned long long part_size, + 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; + part->sys_ind = sys_ind; /* Tack this entry onto the list */ part->next = *list; @@ -89,7 +101,7 @@ partition_mac_lookup( const char *dev_name, prom_handle disk, 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++) { @@ -109,9 +121,9 @@ partition_mac_lookup( const char *dev_name, prom_handle disk, } 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, + /* 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)) @@ -140,11 +152,12 @@ partition_mac_lookup( const char *dev_name, prom_handle disk, part->name, /* name */ part->start_block + part->data_start, /* start */ part->data_count, /* size */ - ptable_block_size ); + ptable_block_size, + 0); } } -/* +/* * Same function as partition_mac_lookup(), except for fdisk * partitioned disks. */ @@ -157,22 +170,58 @@ partition_fdisk_lookup( const char *dev_name, prom_handle disk, /* fdisk partition tables start at offset 0x1be * from byte 0 of the boot drive. */ - struct fdisk_partition* part = + struct fdisk_partition* part = (struct fdisk_partition *) (block_buffer + 0x1be); for (partition=1; partition <= 4 ;partition++, part++) { - if (part->sys_ind == LINUX_NATIVE) { + if (part->sys_ind == LINUX_NATIVE || part->sys_ind == LINUX_RAID) { add_new_partition( list, partition, "Linux", /* type */ '\0', /* name */ - swab32(*(unsigned int *)(part->start4)), - swab32(*(unsigned int *)(part->size4)), - 512 /*blksize*/ ); + le32_to_cpu(*(unsigned int *)part->start4), + le32_to_cpu(*(unsigned int *)part->size4), + 512 /*blksize*/, + part->sys_ind /* partition type */ ); } } } +/* GPT partition format */ +static int gpt_magic_present(unsigned char *block_buffer, unsigned int prom_blksize) +{ + struct gpt_header *header = (struct gpt_header *)(block_buffer + prom_blksize); + return cpu_to_le64(header->signature) == GPT_HEADER_SIGNATURE; +} + +static inline int +guid_cmp (gpt_part_type_t left, gpt_part_type_t right) +{ + return memcmp(&left, &right, sizeof (gpt_part_type_t)); +} + +static void partition_gpt_lookup(prom_handle disk, unsigned int prom_blksize, + struct partition_t **list) +{ + int partition; + struct gpt_header *header = (struct gpt_header *)(block_buffer + prom_blksize); + + if (prom_readblocks(disk, cpu_to_le64(header->partitions), 1, block_buffer) != 1) { + prom_printf("Can't read GPT partition table %Lu\n", header->partitions); + return; + } + struct gpt_partition *part = (struct gpt_partition *)(block_buffer); + + for (partition = 1; partition <= cpu_to_le32(header->maxpart); partition++, part++) { + if ((!guid_cmp(part->type, GPT_BASIC_DATA))||(!guid_cmp(part->type, GPT_LINUX_NATIVE))||(!guid_cmp(part->type, GPT_LINUX_RAID))) { + add_new_partition(list, partition, "Linux", 0, le64_to_cpu(part->start), \ + cpu_to_le64(part->end) - cpu_to_le64(part->start) + 1, \ + prom_blksize, 1); + } + } +} + + /* I don't know if it's possible to handle multisession and other multitrack * stuffs with the current OF disklabel package. This can still be implemented * with direct calls to atapi stuffs. @@ -191,11 +240,11 @@ identify_iso_fs(ihandle device, unsigned int *iso_root_block) 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 + + /* 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) { @@ -203,10 +252,121 @@ identify_iso_fs(ihandle device, unsigned int *iso_root_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; @@ -233,15 +394,18 @@ partitions_lookup(const char *device) prom_printf("block_size %d not supported !\n", prom_blksize); goto bail; } - - /* Read boot blocs */ - if (prom_readblocks(disk, 0, 1, block_buffer) != 1) { + + /* Read boot blocks */ + if (prom_readblocks(disk, 0, 2, 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 (gpt_magic_present(block_buffer, prom_blksize)) { + /* gpt partition format */ + partition_gpt_lookup(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); @@ -252,8 +416,12 @@ partitions_lookup(const char *device) '\0', iso_root_block, 0, - prom_blksize); + 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; @@ -261,7 +429,7 @@ partitions_lookup(const char *device) bail: prom_close(disk); - + return list; } @@ -273,7 +441,8 @@ get_part_type(char *device, int partition) struct partition_t* found; char *type = NULL; - if (prom_get_devtype(device) != FILE_DEVICE_BLOCK) + int device_kind = prom_get_devtype(device); + if (device_kind != FILE_DEVICE_BLOCK && device_kind != FILE_DEVICE_ISCSI) return NULL; parts = partitions_lookup(device); @@ -283,12 +452,12 @@ get_part_type(char *device, int partition) return '\0'; for (p = parts; p && !found; p=p->next) { - DEBUG_F("number: %02d, start: 0x%08lx, length: 0x%08lx, type: %s, name: %s\n", + DEBUG_F("number: %02d, start: 0x%08Lx, length: 0x%08Lx, type: %s, name: %s\n", p->part_number, p->part_start, p->part_size, p->part_type, p->part_name); if ((partition >= 0) && (partition == p->part_number)) { type = strdup(p->part_type); break; - } + } } if (parts) partitions_free(parts); @@ -300,30 +469,18 @@ 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; -} -/* +/* * Local variables: - * c-file-style: "K&R" + * c-file-style: "k&r" * c-basic-offset: 5 * End: */