2 * partition.c - partition table support
4 * Copyright (C) 2013 Dinar Valeev
6 * Copyright (C) 2004 Sven Luther
8 * Copyright (C) 2001, 2002 Ethan Benson
10 * Copyright (C) 1999 Benjamin Herrenschmidt
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 * Todo: Add disklabel (or let OF do it ?). Eventually think about
29 * fixing CDROM handling by directly using the ATAPI layer.
37 #include "fdisk-part.h"
38 #include "amiga-part.h"
40 #include "partition.h"
43 #include "linux/iso_fs.h"
47 #include "byteorder.h"
49 /* We currently don't check the partition type, some users
50 * are putting crap there and still expect it to work...
52 #undef CHECK_FOR_VALID_MAC_PARTITION_TYPE
54 #ifdef CHECK_FOR_VALID_MAC_PARTITION_TYPE
55 static const char *valid_mac_partition_types[] = {
66 #define MAX_BLOCK_SIZE 4096
67 static unsigned char block_buffer[MAX_BLOCK_SIZE];
70 add_new_partition(struct partition_t** list, int part_number, const char *part_type,
71 const char *part_name, unsigned long long part_start, unsigned long long part_size,
72 unsigned short part_blocksize, int sys_ind)
74 struct partition_t* part;
75 part = (struct partition_t*)malloc(sizeof(struct partition_t));
77 part->part_number = part_number;
78 strncpy(part->part_type, part_type, MAX_PART_NAME);
79 strncpy(part->part_name, part_name, MAX_PART_NAME);
80 part->part_start = part_start;
81 part->part_size = part_size;
82 part->blocksize = part_blocksize;
83 part->sys_ind = sys_ind;
85 /* Tack this entry onto the list */
90 /* Note, we rely on partitions being dev-block-size aligned,
91 * I have to check if it's true. If it's not, then things will get
92 * a bit more complicated
95 partition_mac_lookup( const char *dev_name, prom_handle disk,
96 unsigned int prom_blksize, struct partition_t** list )
100 /* block_buffer contains block 0 from the partitions_lookup() stage */
101 struct mac_partition* part = (struct mac_partition *)block_buffer;
102 unsigned short ptable_block_size =
103 ((struct mac_driver_desc *)block_buffer)->block_size;
106 for (block=1; block < map_size + 1; block++)
108 #ifdef CHECK_FOR_VALID_MAC_PARTITION_TYPE
112 if (prom_readblocks(disk, block, 1, block_buffer) != 1) {
113 prom_printf("Can't read partition %d\n", block);
116 if (part->signature != MAC_PARTITION_MAGIC) {
118 prom_printf("Wrong partition %d signature\n", block);
123 map_size = part->map_count;
125 #ifdef CHECK_FOR_VALID_MAC_PARTITION_TYPE
126 /* We don't bother looking at swap partitions of any type,
127 * and the rest are the ones we know about */
128 for (ptype = valid_mac_partition_types; ptype; ptype++)
129 if (!strcmp (part->type, ptype))
136 prom_printf( "MAC: Unsupported partition #%d; type=%s\n",
142 #ifdef CHECK_FOR_VALID_MAC_PARTITION_TYPE
145 /* We use the partition block size from the partition table.
146 * The filesystem implmentations are responsible for mapping
147 * to their own fs blocksize */
149 list, /* partition list */
150 block, /* partition number */
151 part->type, /* type */
152 part->name, /* name */
153 part->start_block + part->data_start, /* start */
154 part->data_count, /* size */
161 * Same function as partition_mac_lookup(), except for fdisk
165 partition_fdisk_lookup( const char *dev_name, prom_handle disk,
166 unsigned int prom_blksize, struct partition_t** list )
170 /* fdisk partition tables start at offset 0x1be
171 * from byte 0 of the boot drive.
173 struct fdisk_partition* part =
174 (struct fdisk_partition *) (block_buffer + 0x1be);
176 for (partition=1; partition <= 4 ;partition++, part++) {
177 if (part->sys_ind == LINUX_NATIVE || part->sys_ind == LINUX_RAID) {
178 add_new_partition( list,
182 le32_to_cpu(*(unsigned int *)part->start4),
183 le32_to_cpu(*(unsigned int *)part->size4),
185 part->sys_ind /* partition type */ );
190 /* GPT partition format */
191 static int gpt_magic_present(unsigned char *block_buffer, unsigned int prom_blksize)
193 struct gpt_header *header = (struct gpt_header *)(block_buffer + prom_blksize);
194 return cpu_to_le64(header->signature) == GPT_HEADER_SIGNATURE;
198 guid_cmp (gpt_part_type_t left, gpt_part_type_t right)
200 return memcmp(&left, &right, sizeof (gpt_part_type_t));
203 static void partition_gpt_lookup(prom_handle disk, unsigned int prom_blksize,
204 struct partition_t **list)
207 struct gpt_header *header = (struct gpt_header *)(block_buffer + prom_blksize);
209 if (prom_readblocks(disk, cpu_to_le64(header->partitions), 1, block_buffer) != 1) {
210 prom_printf("Can't read GPT partition table %Lu\n", header->partitions);
213 struct gpt_partition *part = (struct gpt_partition *)(block_buffer);
215 for (partition = 1; partition <= cpu_to_le32(header->maxpart); partition++, part++) {
216 if ((!guid_cmp(part->type, GPT_BASIC_DATA))||(!guid_cmp(part->type, GPT_LINUX_NATIVE))||(!guid_cmp(part->type, GPT_LINUX_RAID))) {
217 add_new_partition(list, partition, "Linux", 0, le64_to_cpu(part->start), \
218 cpu_to_le64(part->end) - cpu_to_le64(part->start) + 1, \
225 /* I don't know if it's possible to handle multisession and other multitrack
226 * stuffs with the current OF disklabel package. This can still be implemented
227 * with direct calls to atapi stuffs.
228 * Currently, we enter this code for any device of block size 0x2048 who lacks
229 * a MacOS partition map signature.
232 identify_iso_fs(ihandle device, unsigned int *iso_root_block)
236 for (block = 16; block < 100; block++) {
237 struct iso_volume_descriptor * vdp;
239 if (prom_readblocks(device, block, 1, block_buffer) != 1) {
240 prom_printf("Can't read volume desc block %d\n", block);
244 vdp = (struct iso_volume_descriptor *)block_buffer;
246 /* Due to the overlapping physical location of the descriptors,
247 * ISO CDs can match hdp->id==HS_STANDARD_ID as well. To ensure
248 * proper identification in this case, we first check for ISO.
250 if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) {
251 *iso_root_block = block;
260 * Detects and read amiga partition tables.
264 _amiga_checksum (unsigned int blk_size)
268 unsigned int *amiga_block = (unsigned int *) block_buffer;
270 sum = amiga_block[0];
271 end = amiga_block[AMIGA_LENGTH];
273 if (end > blk_size) end = blk_size;
275 for (i = 1; i < end; i++) sum += amiga_block[i];
281 _amiga_find_rdb (const char *dev_name, prom_handle disk, unsigned int prom_blksize)
284 unsigned int *amiga_block = (unsigned int *) block_buffer;
286 for (i = 0; i<AMIGA_RDB_MAX; i++) {
288 if (prom_readblocks(disk, i, 1, block_buffer) != 1) {
289 prom_printf("Can't read boot block %d\n", i);
293 if ((amiga_block[AMIGA_ID] == AMIGA_ID_RDB) && (_amiga_checksum (prom_blksize) == 0))
296 /* Amiga partition table not found, let's reread block 0 */
297 if (prom_readblocks(disk, 0, 1, block_buffer) != 1) {
298 prom_printf("Can't read boot blocks\n");
299 return 0; /* TODO: something bad happened, should fail more verbosely */
305 partition_amiga_lookup( const char *dev_name, prom_handle disk,
306 unsigned int prom_blksize, struct partition_t** list )
309 unsigned int blockspercyl;
310 unsigned int *amiga_block = (unsigned int *) block_buffer;
311 unsigned int *used = NULL;
312 unsigned int possible;
316 blockspercyl = amiga_block[AMIGA_SECT] * amiga_block[AMIGA_HEADS];
317 possible = amiga_block[AMIGA_RDBLIMIT]/32 +1;
319 used = (unsigned int *) malloc (sizeof (unsigned int) * (possible + 1));
321 prom_printf("Can't allocate memory\n");
325 for (i=0; i < possible; i++) used[i] = 0;
328 for (part = amiga_block[AMIGA_PARTITIONS], partition = 1;
330 part = amiga_block[AMIGA_PART_NEXT], partition++)
332 if (prom_readblocks(disk, part, 1, block_buffer) != 1) {
333 prom_printf("Can't read partition block %d\n", part);
336 checksum = _amiga_checksum (prom_blksize);
337 if ((amiga_block[AMIGA_ID] == AMIGA_ID_PART) &&
339 ((used[part/32] & (0x1 << (part % 32))) == 0))
341 used[part/32] |= (0x1 << (part % 32));
343 prom_printf("Amiga partition table corrupted at block %d\n", part);
344 if (amiga_block[AMIGA_ID] != AMIGA_ID_PART)
345 prom_printf ("block type is not partition but %08x\n", amiga_block[AMIGA_ID]);
347 prom_printf ("block checsum is bad : %d\n", checksum);
348 if ((used[part/32] & (0x1 << (part % 32))) != 0)
349 prom_printf ("partition table is looping, block %d already traveled\n", part);
353 /* We use the partition block size from the partition table.
354 * The filesystem implmentations are responsible for mapping
355 * to their own fs blocksize */
357 list, /* partition list */
358 partition, /* partition number */
361 blockspercyl * amiga_block[AMIGA_PART_LOWCYL], /* start */
362 blockspercyl * (amiga_block[AMIGA_PART_HIGHCYL] - amiga_block[AMIGA_PART_LOWCYL] + 1), /* size */
371 partitions_lookup(const char *device)
374 struct mac_driver_desc *desc = (struct mac_driver_desc *)block_buffer;
375 struct partition_t* list = NULL;
376 unsigned int prom_blksize, iso_root_block;
378 strncpy((char *)block_buffer, device, 2040);
379 if (_machine != _MACH_bplan)
380 strcat((char *)block_buffer, ":0");
383 disk = prom_open((char *)block_buffer);
385 prom_printf("Can't open device <%s>\n", block_buffer);
388 prom_blksize = prom_getblksize(disk);
389 DEBUG_F("block size of device is %d\n", prom_blksize);
391 if (prom_blksize <= 1)
393 if (prom_blksize > MAX_BLOCK_SIZE) {
394 prom_printf("block_size %d not supported !\n", prom_blksize);
398 /* Read boot blocks */
399 if (prom_readblocks(disk, 0, 2, block_buffer) != 1) {
400 prom_printf("Can't read boot blocks\n");
403 if (desc->signature == MAC_DRIVER_MAGIC) {
404 /* pdisk partition format */
405 partition_mac_lookup(device, disk, prom_blksize, &list);
406 } else if (gpt_magic_present(block_buffer, prom_blksize)) {
407 /* gpt partition format */
408 partition_gpt_lookup(disk, prom_blksize, &list);
409 } else if ((block_buffer[510] == 0x55) && (block_buffer[511] == 0xaa)) {
410 /* fdisk partition format */
411 partition_fdisk_lookup(device, disk, prom_blksize, &list);
412 } else if (prom_blksize == 2048 && identify_iso_fs(disk, &iso_root_block)) {
413 add_new_partition(&list,
421 prom_printf("ISO9660 disk\n");
422 } else if (_amiga_find_rdb(device, disk, prom_blksize) != -1) {
423 /* amiga partition format */
424 partition_amiga_lookup(device, disk, prom_blksize, &list);
426 prom_printf("No supported partition table detected\n");
437 get_part_type(char *device, int partition)
439 struct partition_t* parts;
440 struct partition_t* p;
441 struct partition_t* found;
444 int device_kind = prom_get_devtype(device);
445 if (device_kind != FILE_DEVICE_BLOCK && device_kind != FILE_DEVICE_ISCSI)
448 parts = partitions_lookup(device);
454 for (p = parts; p && !found; p=p->next) {
455 DEBUG_F("number: %02d, start: 0x%08Lx, length: 0x%08Lx, type: %s, name: %s\n",
456 p->part_number, p->part_start, p->part_size, p->part_type, p->part_name);
457 if ((partition >= 0) && (partition == p->part_number)) {
458 type = strdup(p->part_type);
463 partitions_free(parts);
467 /* Freed in reverse order of allocation to help malloc'ator */
469 partitions_free(struct partition_t* list)
471 struct partition_t* next;
483 * c-file-style: "k&r"