diff options
Diffstat (limited to 'grub-core/partmap')
-rw-r--r-- | grub-core/partmap/acorn.c | 154 | ||||
-rw-r--r-- | grub-core/partmap/amiga.c | 183 | ||||
-rw-r--r-- | grub-core/partmap/apple.c | 199 | ||||
-rw-r--r-- | grub-core/partmap/bsdlabel.c | 271 | ||||
-rw-r--r-- | grub-core/partmap/dfly.c | 132 | ||||
-rw-r--r-- | grub-core/partmap/dvh.c | 127 | ||||
-rw-r--r-- | grub-core/partmap/gpt.c | 238 | ||||
-rw-r--r-- | grub-core/partmap/msdos.c | 435 | ||||
-rw-r--r-- | grub-core/partmap/plan.c | 120 | ||||
-rw-r--r-- | grub-core/partmap/sun.c | 154 | ||||
-rw-r--r-- | grub-core/partmap/sunpc.c | 151 |
11 files changed, 2164 insertions, 0 deletions
diff --git a/grub-core/partmap/acorn.c b/grub-core/partmap/acorn.c new file mode 100644 index 0000000..c022c61 --- /dev/null +++ b/grub-core/partmap/acorn.c @@ -0,0 +1,154 @@ +/* acorn.c - Read Linux/ADFS partition tables. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005,2007 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <grub/disk.h> +#include <grub/misc.h> +#include <grub/mm.h> +#include <grub/partition.h> +#include <grub/acorn_filecore.h> + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define LINUX_NATIVE_MAGIC grub_cpu_to_le32_compile_time (0xdeafa1de) +#define LINUX_SWAP_MAGIC grub_cpu_to_le32_compile_time (0xdeafab1e) +#define LINUX_MAP_ENTRIES (512 / 12) + +#define NONADFS_PARTITION_TYPE_LINUX 9 +#define NONADFS_PARTITION_TYPE_MASK 15 + +struct grub_acorn_boot_block +{ + union + { + struct + { + grub_uint8_t misc[0x1C0]; + struct grub_filecore_disc_record disc_record; + grub_uint8_t flags; + grub_uint16_t start_cylinder; + grub_uint8_t checksum; + } GRUB_PACKED; + grub_uint8_t bin[0x200]; + }; +} GRUB_PACKED; + +struct linux_part +{ + grub_uint32_t magic; + grub_uint32_t start; + grub_uint32_t size; +}; + +static struct grub_partition_map grub_acorn_partition_map; + +static grub_err_t +acorn_partition_map_find (grub_disk_t disk, struct linux_part *m, + grub_disk_addr_t *sector) +{ + struct grub_acorn_boot_block boot; + grub_err_t err; + unsigned int checksum = 0; + unsigned int heads; + unsigned int sectors_per_cylinder; + int i; + + err = grub_disk_read (disk, 0xC00 / GRUB_DISK_SECTOR_SIZE, 0, + sizeof (struct grub_acorn_boot_block), + &boot); + if (err) + return err; + + if ((boot.flags & NONADFS_PARTITION_TYPE_MASK) != NONADFS_PARTITION_TYPE_LINUX) + goto fail; + + for (i = 0; i != 0x1ff; ++i) + checksum = ((checksum & 0xff) + (checksum >> 8) + boot.bin[i]); + + if ((grub_uint8_t) checksum != boot.checksum) + goto fail; + + heads = (boot.disc_record.heads + + ((boot.disc_record.lowsector >> 6) & 1)); + sectors_per_cylinder = boot.disc_record.secspertrack * heads; + *sector = grub_le_to_cpu16 (boot.start_cylinder) * sectors_per_cylinder; + + return grub_disk_read (disk, *sector, 0, + sizeof (struct linux_part) * LINUX_MAP_ENTRIES, + m); + +fail: + return grub_error (GRUB_ERR_BAD_PART_TABLE, + "Linux/ADFS partition map not found"); + +} + + +static grub_err_t +acorn_partition_map_iterate (grub_disk_t disk, + grub_partition_iterate_hook_t hook, + void *hook_data) +{ + struct grub_partition part; + struct linux_part map[LINUX_MAP_ENTRIES]; + int i; + grub_disk_addr_t sector = 0; + grub_err_t err; + + err = acorn_partition_map_find (disk, map, §or); + if (err) + return err; + + part.partmap = &grub_acorn_partition_map; + + for (i = 0; i != LINUX_MAP_ENTRIES; ++i) + { + if (map[i].magic != LINUX_NATIVE_MAGIC + && map[i].magic != LINUX_SWAP_MAGIC) + return GRUB_ERR_NONE; + + part.start = sector + map[i].start; + part.len = map[i].size; + part.offset = 6; + part.number = part.index = i; + + if (hook (disk, &part, hook_data)) + return grub_errno; + } + + return GRUB_ERR_NONE; +} + + + +/* Partition map type. */ +static struct grub_partition_map grub_acorn_partition_map = +{ + .name = "acorn", + .iterate = acorn_partition_map_iterate, +}; + +GRUB_MOD_INIT(part_acorn) +{ + grub_partition_map_register (&grub_acorn_partition_map); +} + +GRUB_MOD_FINI(part_acorn) +{ + grub_partition_map_unregister (&grub_acorn_partition_map); +} diff --git a/grub-core/partmap/amiga.c b/grub-core/partmap/amiga.c new file mode 100644 index 0000000..13034f1 --- /dev/null +++ b/grub-core/partmap/amiga.c @@ -0,0 +1,183 @@ +/* amiga.c - Read amiga partition tables (RDB). */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2004,2005,2006,2007 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <grub/disk.h> +#include <grub/misc.h> +#include <grub/mm.h> +#include <grub/partition.h> +#include <grub/dl.h> + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define AMIGA_CHECKSUM_WORDS 128 + +struct grub_amiga_rdsk +{ + /* "RDSK". */ + grub_uint8_t magic[4]; +#define GRUB_AMIGA_RDSK_MAGIC "RDSK" + grub_uint32_t size; + grub_int32_t checksum; + grub_uint32_t scsihost; + grub_uint32_t blksz; + grub_uint32_t flags; + grub_uint32_t badblcklst; + grub_uint32_t partitionlst; + grub_uint32_t fslst; + + grub_uint32_t unused[AMIGA_CHECKSUM_WORDS - 9]; +} GRUB_PACKED; + +struct grub_amiga_partition +{ + /* "PART". */ + grub_uint8_t magic[4]; +#define GRUB_AMIGA_PART_MAGIC "PART" + grub_uint32_t size; + grub_int32_t checksum; + grub_uint32_t scsihost; + grub_uint32_t next; + grub_uint32_t flags; + grub_uint32_t unused1[2]; + grub_uint32_t devflags; + grub_uint8_t namelen; + grub_uint8_t name[31]; + grub_uint32_t unused2[15]; + + grub_uint32_t unused3[3]; + grub_uint32_t heads; + grub_uint32_t unused4; + grub_uint32_t block_per_track; + grub_uint32_t unused5[3]; + grub_uint32_t lowcyl; + grub_uint32_t highcyl; + + grub_uint32_t firstcyl; + grub_uint32_t unused[AMIGA_CHECKSUM_WORDS - 44]; +} GRUB_PACKED; + +static struct grub_partition_map grub_amiga_partition_map; + + + +static grub_uint32_t +amiga_partition_map_checksum (void *buf) +{ + grub_uint32_t *ptr = buf; + grub_uint32_t r = 0; + grub_size_t sz; + /* Fancy and quick way of checking sz >= 512 / 4 = 128. */ + if (ptr[1] & ~grub_cpu_to_be32_compile_time (AMIGA_CHECKSUM_WORDS - 1)) + sz = AMIGA_CHECKSUM_WORDS; + else + sz = grub_be_to_cpu32 (ptr[1]); + + for (; sz; sz--, ptr++) + r += grub_be_to_cpu32 (*ptr); + + return r; +} + +static grub_err_t +amiga_partition_map_iterate (grub_disk_t disk, + grub_partition_iterate_hook_t hook, + void *hook_data) +{ + struct grub_partition part; + struct grub_amiga_rdsk rdsk; + int partno = 0; + int next = -1; + unsigned pos; + + /* The RDSK block is one of the first 15 blocks. */ + for (pos = 0; pos < 15; pos++) + { + /* Read the RDSK block which is a descriptor for the entire disk. */ + if (grub_disk_read (disk, pos, 0, sizeof (rdsk), &rdsk)) + return grub_errno; + + if (grub_memcmp (rdsk.magic, GRUB_AMIGA_RDSK_MAGIC, + sizeof (rdsk.magic)) == 0 + && amiga_partition_map_checksum (&rdsk) == 0) + { + /* Found the first PART block. */ + next = grub_be_to_cpu32 (rdsk.partitionlst); + break; + } + } + + if (next == -1) + return grub_error (GRUB_ERR_BAD_PART_TABLE, + "Amiga partition map not found"); + + /* The end of the partition list is marked using "-1". */ + while (next != -1) + { + struct grub_amiga_partition apart; + + /* Read the RDSK block which is a descriptor for the entire disk. */ + if (grub_disk_read (disk, next, 0, sizeof (apart), &apart)) + return grub_errno; + + if (grub_memcmp (apart.magic, GRUB_AMIGA_PART_MAGIC, + sizeof (apart.magic)) != 0 + || amiga_partition_map_checksum (&apart) != 0) + return grub_error (GRUB_ERR_BAD_PART_TABLE, + "invalid Amiga partition map"); + /* Calculate the first block and the size of the partition. */ + part.start = (grub_be_to_cpu32 (apart.lowcyl) + * grub_be_to_cpu32 (apart.heads) + * grub_be_to_cpu32 (apart.block_per_track)); + part.len = ((grub_be_to_cpu32 (apart.highcyl) + - grub_be_to_cpu32 (apart.lowcyl) + 1) + * grub_be_to_cpu32 (apart.heads) + * grub_be_to_cpu32 (apart.block_per_track)); + + part.offset = next; + part.number = partno; + part.index = 0; + part.partmap = &grub_amiga_partition_map; + + if (hook (disk, &part, hook_data)) + return grub_errno; + + next = grub_be_to_cpu32 (apart.next); + partno++; + } + + return 0; +} + + +/* Partition map type. */ +static struct grub_partition_map grub_amiga_partition_map = + { + .name = "amiga", + .iterate = amiga_partition_map_iterate, + }; + +GRUB_MOD_INIT(part_amiga) +{ + grub_partition_map_register (&grub_amiga_partition_map); +} + +GRUB_MOD_FINI(part_amiga) +{ + grub_partition_map_unregister (&grub_amiga_partition_map); +} diff --git a/grub-core/partmap/apple.c b/grub-core/partmap/apple.c new file mode 100644 index 0000000..c3ead0f --- /dev/null +++ b/grub-core/partmap/apple.c @@ -0,0 +1,199 @@ +/* apple.c - Read macintosh partition tables. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <grub/disk.h> +#include <grub/misc.h> +#include <grub/mm.h> +#include <grub/partition.h> + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define GRUB_APPLE_HEADER_MAGIC 0x4552 +#define GRUB_APPLE_PART_MAGIC 0x504D + +struct grub_apple_header +{ + /* The magic number to identify the partition map, it should have + the value `0x4552'. */ + grub_uint16_t magic; + grub_uint16_t blocksize; +}; + +struct grub_apple_part +{ + /* The magic number to identify this as a partition, it should have + the value `0x504D'. */ + grub_uint16_t magic; + + /* Reserved. */ + grub_uint16_t reserved; + + /* The size of the partition map in blocks. */ + grub_uint32_t partmap_size; + + /* The first physical block of the partition. */ + grub_uint32_t first_phys_block; + + /* The amount of blocks. */ + grub_uint32_t blockcnt; + + /* The partition name. */ + char partname[32]; + + /* The partition type. */ + char parttype[32]; + + /* The first datablock of the partition. */ + grub_uint32_t datablocks_first; + + /* The amount datablocks. */ + grub_uint32_t datablocks_count; + + /* The status of the partition. (???) */ + grub_uint32_t status; + + /* The first block on which the bootcode can be found. */ + grub_uint32_t bootcode_pos; + + /* The size of the bootcode in bytes. */ + grub_uint32_t bootcode_size; + + /* The load address of the bootcode. */ + grub_uint32_t bootcode_loadaddr; + + /* Reserved. */ + grub_uint32_t reserved2; + + /* The entry point of the bootcode. */ + grub_uint32_t bootcode_entrypoint; + + /* Reserved. */ + grub_uint32_t reserved3; + + /* A checksum of the bootcode. */ + grub_uint32_t bootcode_checksum; + + /* The processor type. */ + char processor[16]; + + /* Padding. */ + grub_uint16_t pad[187]; +}; + +static struct grub_partition_map grub_apple_partition_map; + + +static grub_err_t +apple_partition_map_iterate (grub_disk_t disk, + grub_partition_iterate_hook_t hook, + void *hook_data) +{ + struct grub_partition part; + struct grub_apple_header aheader; + struct grub_apple_part apart; + int partno = 0, partnum = 0; + unsigned pos; + + part.partmap = &grub_apple_partition_map; + + if (grub_disk_read (disk, 0, 0, sizeof (aheader), &aheader)) + return grub_errno; + + if (grub_be_to_cpu16 (aheader.magic) != GRUB_APPLE_HEADER_MAGIC) + { + grub_dprintf ("partition", + "bad magic (found 0x%x; wanted 0x%x)\n", + grub_be_to_cpu16 (aheader.magic), + GRUB_APPLE_HEADER_MAGIC); + goto fail; + } + + pos = grub_be_to_cpu16 (aheader.blocksize); + + do + { + part.offset = pos / GRUB_DISK_SECTOR_SIZE; + part.index = pos % GRUB_DISK_SECTOR_SIZE; + + if (grub_disk_read (disk, part.offset, part.index, + sizeof (struct grub_apple_part), &apart)) + return grub_errno; + + if (grub_be_to_cpu16 (apart.magic) != GRUB_APPLE_PART_MAGIC) + { + grub_dprintf ("partition", + "partition %d: bad magic (found 0x%x; wanted 0x%x)\n", + partno, grub_be_to_cpu16 (apart.magic), + GRUB_APPLE_PART_MAGIC); + break; + } + + if (partnum == 0) + partnum = grub_be_to_cpu32 (apart.partmap_size); + + part.start = ((grub_disk_addr_t) grub_be_to_cpu32 (apart.first_phys_block) + * grub_be_to_cpu16 (aheader.blocksize)) + / GRUB_DISK_SECTOR_SIZE; + part.len = ((grub_disk_addr_t) grub_be_to_cpu32 (apart.blockcnt) + * grub_be_to_cpu16 (aheader.blocksize)) + / GRUB_DISK_SECTOR_SIZE; + part.offset = pos; + part.index = partno; + part.number = partno; + + grub_dprintf ("partition", + "partition %d: name %s, type %s, start 0x%x, len 0x%x\n", + partno, apart.partname, apart.parttype, + grub_be_to_cpu32 (apart.first_phys_block), + grub_be_to_cpu32 (apart.blockcnt)); + + if (hook (disk, &part, hook_data)) + return grub_errno; + + pos += grub_be_to_cpu16 (aheader.blocksize); + partno++; + } + while (partno < partnum); + + if (partno != 0) + return 0; + + fail: + return grub_error (GRUB_ERR_BAD_PART_TABLE, + "Apple partition map not found"); +} + + +/* Partition map type. */ +static struct grub_partition_map grub_apple_partition_map = + { + .name = "apple", + .iterate = apple_partition_map_iterate, + }; + +GRUB_MOD_INIT(part_apple) +{ + grub_partition_map_register (&grub_apple_partition_map); +} + +GRUB_MOD_FINI(part_apple) +{ + grub_partition_map_unregister (&grub_apple_partition_map); +} + diff --git a/grub-core/partmap/bsdlabel.c b/grub-core/partmap/bsdlabel.c new file mode 100644 index 0000000..1d78590 --- /dev/null +++ b/grub-core/partmap/bsdlabel.c @@ -0,0 +1,271 @@ +/* bsdlabel.c - Read BSD style partition tables. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <grub/partition.h> +#include <grub/bsdlabel.h> +#include <grub/disk.h> +#include <grub/mm.h> +#include <grub/misc.h> +#include <grub/dl.h> +#include <grub/msdos_partition.h> +#include <grub/i18n.h> + +GRUB_MOD_LICENSE ("GPLv3+"); + +#ifdef GRUB_UTIL +#include <grub/emu/misc.h> +#endif + +static struct grub_partition_map grub_bsdlabel_partition_map; +static struct grub_partition_map grub_netbsdlabel_partition_map; +static struct grub_partition_map grub_openbsdlabel_partition_map; + + + +static grub_err_t +iterate_real (grub_disk_t disk, grub_disk_addr_t sector, int freebsd, + struct grub_partition_map *pmap, + grub_partition_iterate_hook_t hook, void *hook_data) +{ + struct grub_partition_bsd_disk_label label; + struct grub_partition p; + grub_disk_addr_t delta = 0; + grub_disk_addr_t pos; + + /* Read the BSD label. */ + if (grub_disk_read (disk, sector, 0, sizeof (label), &label)) + return grub_errno; + + /* Check if it is valid. */ + if (label.magic != grub_cpu_to_le32_compile_time (GRUB_PC_PARTITION_BSD_LABEL_MAGIC)) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature"); + + /* A kludge to determine a base of be.offset. */ + if (GRUB_PC_PARTITION_BSD_LABEL_WHOLE_DISK_PARTITION + < grub_cpu_to_le16 (label.num_partitions) && freebsd) + { + struct grub_partition_bsd_entry whole_disk_be; + + pos = sizeof (label) + sector * GRUB_DISK_SECTOR_SIZE + + sizeof (struct grub_partition_bsd_entry) + * GRUB_PC_PARTITION_BSD_LABEL_WHOLE_DISK_PARTITION; + + if (grub_disk_read (disk, pos / GRUB_DISK_SECTOR_SIZE, + pos % GRUB_DISK_SECTOR_SIZE, sizeof (whole_disk_be), + &whole_disk_be)) + return grub_errno; + + delta = grub_le_to_cpu32 (whole_disk_be.offset); + } + + pos = sizeof (label) + sector * GRUB_DISK_SECTOR_SIZE; + + for (p.number = 0; + p.number < grub_cpu_to_le16 (label.num_partitions); + p.number++, pos += sizeof (struct grub_partition_bsd_entry)) + { + struct grub_partition_bsd_entry be; + + if (p.number == GRUB_PC_PARTITION_BSD_LABEL_WHOLE_DISK_PARTITION) + continue; + + p.offset = pos / GRUB_DISK_SECTOR_SIZE; + p.index = pos % GRUB_DISK_SECTOR_SIZE; + + if (grub_disk_read (disk, p.offset, p.index, sizeof (be), &be)) + return grub_errno; + + p.start = grub_le_to_cpu32 (be.offset); + p.len = grub_le_to_cpu32 (be.size); + p.partmap = pmap; + + if (p.len == 0) + continue; + + if (p.start < delta) + { +#ifdef GRUB_UTIL + char *partname; + /* disk->partition != NULL as 0 < delta */ + partname = disk->partition ? grub_partition_get_name (disk->partition) + : 0; + grub_util_warn (_("Discarding improperly nested partition (%s,%s,%s%d)"), + disk->name, partname ? : "", p.partmap->name, + p.number + 1); + grub_free (partname); +#endif + continue; + } + + p.start -= delta; + + if (hook (disk, &p, hook_data)) + return grub_errno; + } + return GRUB_ERR_NONE; +} + +static grub_err_t +bsdlabel_partition_map_iterate (grub_disk_t disk, + grub_partition_iterate_hook_t hook, + void *hook_data) +{ + + if (disk->partition && grub_strcmp (disk->partition->partmap->name, "msdos") + == 0 && disk->partition->msdostype == GRUB_PC_PARTITION_TYPE_FREEBSD) + return iterate_real (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR, 1, + &grub_bsdlabel_partition_map, hook, hook_data); + + if (disk->partition + && (grub_strcmp (disk->partition->partmap->name, "msdos") == 0 + || disk->partition->partmap == &grub_bsdlabel_partition_map + || disk->partition->partmap == &grub_netbsdlabel_partition_map + || disk->partition->partmap == &grub_openbsdlabel_partition_map)) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "no embedding supported"); + + return iterate_real (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR, 0, + &grub_bsdlabel_partition_map, hook, hook_data); +} + +/* Context for netopenbsdlabel_partition_map_iterate. */ +struct netopenbsdlabel_ctx +{ + grub_uint8_t type; + struct grub_partition_map *pmap; + grub_partition_iterate_hook_t hook; + void *hook_data; + int count; +}; + +/* Helper for netopenbsdlabel_partition_map_iterate. */ +static int +check_msdos (grub_disk_t dsk, const grub_partition_t partition, void *data) +{ + struct netopenbsdlabel_ctx *ctx = data; + grub_err_t err; + + if (partition->msdostype != ctx->type) + return 0; + + err = iterate_real (dsk, partition->start + + GRUB_PC_PARTITION_BSD_LABEL_SECTOR, 0, ctx->pmap, + ctx->hook, ctx->hook_data); + if (err == GRUB_ERR_NONE) + { + ctx->count++; + return 1; + } + if (err == GRUB_ERR_BAD_PART_TABLE) + { + grub_errno = GRUB_ERR_NONE; + return 0; + } + grub_print_error (); + return 0; +} + +/* This is a total breakage. Even when net-/openbsd label is inside partition + it actually describes the whole disk. + */ +static grub_err_t +netopenbsdlabel_partition_map_iterate (grub_disk_t disk, grub_uint8_t type, + struct grub_partition_map *pmap, + grub_partition_iterate_hook_t hook, + void *hook_data) +{ + if (disk->partition && grub_strcmp (disk->partition->partmap->name, "msdos") + == 0) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "no embedding supported"); + + { + struct netopenbsdlabel_ctx ctx = { + .type = type, + .pmap = pmap, + .hook = hook, + .hook_data = hook_data, + .count = 0 + }; + grub_err_t err; + + err = grub_partition_msdos_iterate (disk, check_msdos, &ctx); + + if (err) + return err; + if (!ctx.count) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "no bsdlabel found"); + } + return GRUB_ERR_NONE; +} + +static grub_err_t +netbsdlabel_partition_map_iterate (grub_disk_t disk, + grub_partition_iterate_hook_t hook, + void *hook_data) +{ + return netopenbsdlabel_partition_map_iterate (disk, + GRUB_PC_PARTITION_TYPE_NETBSD, + &grub_netbsdlabel_partition_map, + hook, hook_data); +} + +static grub_err_t +openbsdlabel_partition_map_iterate (grub_disk_t disk, + grub_partition_iterate_hook_t hook, + void *hook_data) +{ + return netopenbsdlabel_partition_map_iterate (disk, + GRUB_PC_PARTITION_TYPE_OPENBSD, + &grub_openbsdlabel_partition_map, + hook, hook_data); +} + + +static struct grub_partition_map grub_bsdlabel_partition_map = + { + .name = "bsd", + .iterate = bsdlabel_partition_map_iterate, + }; + +static struct grub_partition_map grub_openbsdlabel_partition_map = + { + .name = "openbsd", + .iterate = openbsdlabel_partition_map_iterate, + }; + +static struct grub_partition_map grub_netbsdlabel_partition_map = + { + .name = "netbsd", + .iterate = netbsdlabel_partition_map_iterate, + }; + + + +GRUB_MOD_INIT(part_bsd) +{ + grub_partition_map_register (&grub_bsdlabel_partition_map); + grub_partition_map_register (&grub_netbsdlabel_partition_map); + grub_partition_map_register (&grub_openbsdlabel_partition_map); +} + +GRUB_MOD_FINI(part_bsd) +{ + grub_partition_map_unregister (&grub_bsdlabel_partition_map); + grub_partition_map_unregister (&grub_netbsdlabel_partition_map); + grub_partition_map_unregister (&grub_openbsdlabel_partition_map); +} diff --git a/grub-core/partmap/dfly.c b/grub-core/partmap/dfly.c new file mode 100644 index 0000000..d30da86 --- /dev/null +++ b/grub-core/partmap/dfly.c @@ -0,0 +1,132 @@ +/* dfly.c - Read DragonFly BSD disklabel64. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2013 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <grub/disk.h> +#include <grub/misc.h> +#include <grub/mm.h> +#include <grub/partition.h> + +GRUB_MOD_LICENSE ("GPLv3+"); + +static struct grub_partition_map grub_dfly_partition_map; + +#define GRUB_PARTITION_DISKLABEL64_HEADER_SIZE 200 + +/* Full entry is 64 bytes however we really care only + about offset and size which are in first 16 bytes. + Avoid using too much stack. */ +#define GRUB_PARTITION_DISKLABEL64_ENTRY_SIZE 64 +struct grub_partition_disklabel64_entry +{ + grub_uint64_t boffset; + grub_uint64_t bsize; +}; + +/* Full entry is 200 bytes however we really care only + about magic and number of partitions which are in first 16 bytes. + Avoid using too much stack. */ +struct grub_partition_disklabel64 +{ + grub_uint32_t magic; +#define GRUB_DISKLABEL64_MAGIC ((grub_uint32_t)0xc4464c59) + grub_uint32_t crc; + grub_uint32_t unused; + grub_uint32_t npartitions; +}; + +static grub_err_t +dfly_partition_map_iterate (grub_disk_t disk, + grub_partition_iterate_hook_t hook, + void *hook_data) +{ + struct grub_partition part; + unsigned partno, pos; + struct grub_partition_disklabel64 label; + + part.partmap = &grub_dfly_partition_map; + + if (grub_disk_read (disk, 1, 0, sizeof (label), &label)) + return grub_errno; + + if (label.magic != grub_cpu_to_le32_compile_time (GRUB_DISKLABEL64_MAGIC)) + { + grub_dprintf ("partition", + "bad magic (found 0x%x; wanted 0x%x)\n", + (unsigned int) grub_le_to_cpu32 (label.magic), + (unsigned int) GRUB_DISKLABEL64_MAGIC); + return grub_error (GRUB_ERR_BAD_PART_TABLE, "disklabel64 not found"); + } + + pos = GRUB_PARTITION_DISKLABEL64_HEADER_SIZE + GRUB_DISK_SECTOR_SIZE; + + for (partno = 0; + partno < grub_le_to_cpu32 (label.npartitions); ++partno) + { + grub_disk_addr_t sector = pos >> GRUB_DISK_SECTOR_BITS; + grub_off_t offset = pos & (GRUB_DISK_SECTOR_SIZE - 1); + struct grub_partition_disklabel64_entry dpart; + + pos += GRUB_PARTITION_DISKLABEL64_ENTRY_SIZE; + if (grub_disk_read (disk, sector, offset, sizeof (dpart), &dpart)) + return grub_errno; + + grub_dprintf ("partition", + "partition %2d: offset 0x%llx, " + "size 0x%llx\n", + partno, + (unsigned long long) grub_le_to_cpu64 (dpart.boffset), + (unsigned long long) grub_le_to_cpu64 (dpart.bsize)); + + /* Is partition initialized? */ + if (dpart.bsize == 0) + continue; + + part.number = partno; + part.start = grub_le_to_cpu64 (dpart.boffset) >> GRUB_DISK_SECTOR_BITS; + part.len = grub_le_to_cpu64 (dpart.bsize) >> GRUB_DISK_SECTOR_BITS; + + /* This is counter-intuitive, but part.offset and sector have + * the same type, and offset (NOT part.offset) is guaranteed + * to fit into part.index. */ + part.offset = sector; + part.index = offset; + + if (hook (disk, &part, hook_data)) + return grub_errno; + } + + return GRUB_ERR_NONE; +} + +/* Partition map type. */ +static struct grub_partition_map grub_dfly_partition_map = +{ + .name = "dfly", + .iterate = dfly_partition_map_iterate, +}; + +GRUB_MOD_INIT(part_dfly) +{ + grub_partition_map_register (&grub_dfly_partition_map); +} + +GRUB_MOD_FINI(part_dfly) +{ + grub_partition_map_unregister (&grub_dfly_partition_map); +} diff --git a/grub-core/partmap/dvh.c b/grub-core/partmap/dvh.c new file mode 100644 index 0000000..95c9618 --- /dev/null +++ b/grub-core/partmap/dvh.c @@ -0,0 +1,127 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2005,2006,2007,2011 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <grub/partition.h> +#include <grub/disk.h> +#include <grub/mm.h> +#include <grub/misc.h> +#include <grub/dl.h> +#include <grub/symbol.h> +#include <grub/types.h> +#include <grub/err.h> + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define DVH_MAGIC 0x0be5a941 + +struct grub_dvh_partition_descriptor +{ + grub_uint32_t length; + grub_uint32_t start; + grub_uint32_t type; +} GRUB_PACKED; + +struct grub_dvh_block +{ + grub_uint32_t magic; + grub_uint8_t unused[308]; + struct grub_dvh_partition_descriptor parts[16]; + grub_uint32_t checksum; + grub_uint32_t unused2; +} GRUB_PACKED; + +static struct grub_partition_map grub_dvh_partition_map; + +/* Verify checksum (true=ok). */ +static int +grub_dvh_is_valid (grub_uint32_t *label) +{ + grub_uint32_t *pos; + grub_uint32_t sum = 0; + + for (pos = label; + pos < (label + sizeof (struct grub_dvh_block) / 4); + pos++) + sum += grub_be_to_cpu32 (*pos); + + return ! sum; +} + +static grub_err_t +dvh_partition_map_iterate (grub_disk_t disk, + grub_partition_iterate_hook_t hook, void *hook_data) +{ + struct grub_partition p; + union + { + struct grub_dvh_block dvh; + grub_uint32_t raw[0]; + } block; + unsigned partnum; + grub_err_t err; + + p.partmap = &grub_dvh_partition_map; + err = grub_disk_read (disk, 0, 0, sizeof (struct grub_dvh_block), + &block); + if (err) + return err; + + if (DVH_MAGIC != grub_be_to_cpu32 (block.dvh.magic)) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "not a dvh partition table"); + + if (! grub_dvh_is_valid (block.raw)) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid checksum"); + + /* Maybe another error value would be better, because partition + table _is_ recognized but invalid. */ + for (partnum = 0; partnum < ARRAY_SIZE (block.dvh.parts); partnum++) + { + if (block.dvh.parts[partnum].length == 0) + continue; + + if (partnum == 10) + continue; + + p.start = grub_be_to_cpu32 (block.dvh.parts[partnum].start); + p.len = grub_be_to_cpu32 (block.dvh.parts[partnum].length); + p.number = p.index = partnum; + if (hook (disk, &p, hook_data)) + break; + } + + return grub_errno; +} + + +/* Partition map type. */ +static struct grub_partition_map grub_dvh_partition_map = + { + .name = "dvh", + .iterate = dvh_partition_map_iterate, + }; + +GRUB_MOD_INIT(part_dvh) +{ + grub_partition_map_register (&grub_dvh_partition_map); +} + +GRUB_MOD_FINI(part_dvh) +{ + grub_partition_map_unregister (&grub_dvh_partition_map); +} + diff --git a/grub-core/partmap/gpt.c b/grub-core/partmap/gpt.c new file mode 100644 index 0000000..075cc96 --- /dev/null +++ b/grub-core/partmap/gpt.c @@ -0,0 +1,238 @@ +/* gpt.c - Read GUID Partition Tables (GPT). */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2005,2006,2007,2008 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <grub/disk.h> +#include <grub/misc.h> +#include <grub/mm.h> +#include <grub/partition.h> +#include <grub/dl.h> +#include <grub/msdos_partition.h> +#include <grub/gpt_partition.h> +#include <grub/i18n.h> +#ifdef GRUB_UTIL +#include <grub/emu/misc.h> +#endif + +GRUB_MOD_LICENSE ("GPLv3+"); + +static grub_uint8_t grub_gpt_magic[8] = + { + 0x45, 0x46, 0x49, 0x20, 0x50, 0x41, 0x52, 0x54 + }; + +static const grub_gpt_part_guid_t grub_gpt_partition_type_empty = GRUB_GPT_PARTITION_TYPE_EMPTY; + +#ifdef GRUB_UTIL +static const grub_gpt_part_guid_t grub_gpt_partition_type_bios_boot = GRUB_GPT_PARTITION_TYPE_BIOS_BOOT; +#endif + +/* 512 << 7 = 65536 byte sectors. */ +#define MAX_SECTOR_LOG 7 + +static struct grub_partition_map grub_gpt_partition_map; + + + +grub_err_t +grub_gpt_partition_map_iterate (grub_disk_t disk, + grub_partition_iterate_hook_t hook, + void *hook_data) +{ + struct grub_partition part; + struct grub_gpt_header gpt; + struct grub_gpt_partentry entry; + struct grub_msdos_partition_mbr mbr; + grub_uint64_t entries; + unsigned int i; + int last_offset = 0; + int sector_log = 0; + + /* Read the protective MBR. */ + if (grub_disk_read (disk, 0, 0, sizeof (mbr), &mbr)) + return grub_errno; + + /* Check if it is valid. */ + if (mbr.signature != grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE)) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature"); + + /* Make sure the MBR is a protective MBR and not a normal MBR. */ + for (i = 0; i < 4; i++) + if (mbr.entries[i].type == GRUB_PC_PARTITION_TYPE_GPT_DISK) + break; + if (i == 4) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "no GPT partition map found"); + + /* Read the GPT header. */ + for (sector_log = 0; sector_log < MAX_SECTOR_LOG; sector_log++) + { + if (grub_disk_read (disk, 1 << sector_log, 0, sizeof (gpt), &gpt)) + return grub_errno; + + if (grub_memcmp (gpt.magic, grub_gpt_magic, sizeof (grub_gpt_magic)) == 0) + break; + } + if (sector_log == MAX_SECTOR_LOG) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "no valid GPT header"); + + grub_dprintf ("gpt", "Read a valid GPT header\n"); + + entries = grub_le_to_cpu64 (gpt.partitions) << sector_log; + for (i = 0; i < grub_le_to_cpu32 (gpt.maxpart); i++) + { + if (grub_disk_read (disk, entries, last_offset, + sizeof (entry), &entry)) + return grub_errno; + + if (grub_memcmp (&grub_gpt_partition_type_empty, &entry.type, + sizeof (grub_gpt_partition_type_empty))) + { + /* Calculate the first block and the size of the partition. */ + part.start = grub_le_to_cpu64 (entry.start) << sector_log; + part.len = (grub_le_to_cpu64 (entry.end) + - grub_le_to_cpu64 (entry.start) + 1) << sector_log; + part.offset = entries; + part.number = i; + part.index = last_offset; + part.partmap = &grub_gpt_partition_map; + part.parent = disk->partition; + + grub_dprintf ("gpt", "GPT entry %d: start=%lld, length=%lld\n", i, + (unsigned long long) part.start, + (unsigned long long) part.len); + + if (hook (disk, &part, hook_data)) + return grub_errno; + } + + last_offset += grub_le_to_cpu32 (gpt.partentry_size); + if (last_offset == GRUB_DISK_SECTOR_SIZE) + { + last_offset = 0; + entries++; + } + } + + return GRUB_ERR_NONE; +} + +#ifdef GRUB_UTIL +/* Context for gpt_partition_map_embed. */ +struct gpt_partition_map_embed_ctx +{ + grub_disk_addr_t start, len; +}; + +/* Helper for gpt_partition_map_embed. */ +static int +find_usable_region (grub_disk_t disk __attribute__ ((unused)), + const grub_partition_t p, void *data) +{ + struct gpt_partition_map_embed_ctx *ctx = data; + struct grub_gpt_partentry gptdata; + grub_partition_t p2; + + p2 = disk->partition; + disk->partition = p->parent; + if (grub_disk_read (disk, p->offset, p->index, + sizeof (gptdata), &gptdata)) + { + disk->partition = p2; + return 0; + } + disk->partition = p2; + + /* If there's an embed region, it is in a dedicated partition. */ + if (! grub_memcmp (&gptdata.type, &grub_gpt_partition_type_bios_boot, 16)) + { + ctx->start = p->start; + ctx->len = p->len; + return 1; + } + + return 0; +} + +static grub_err_t +gpt_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors, + unsigned int max_nsectors, + grub_embed_type_t embed_type, + grub_disk_addr_t **sectors, + int warn_short) +{ + struct gpt_partition_map_embed_ctx ctx = { + .start = 0, + .len = 0 + }; + unsigned i; + grub_err_t err; + + if (embed_type != GRUB_EMBED_PCBIOS) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "GPT currently supports only PC-BIOS embedding"); + + err = grub_gpt_partition_map_iterate (disk, find_usable_region, &ctx); + if (err) + return err; + + if (ctx.len == 0) + return grub_error (GRUB_ERR_FILE_NOT_FOUND, + N_("this GPT partition label contains no BIOS Boot Partition;" + " embedding won't be possible")); + + if (ctx.len < GRUB_MIN_RECOMMENDED_MBR_GAP) + grub_util_warn ("Your BIOS Boot Partition is under 1 MiB, please increase its size."); + + if (ctx.len < *nsectors) + return grub_error (GRUB_ERR_OUT_OF_RANGE, + N_("your BIOS Boot Partition is too small;" + " embedding won't be possible")); + + *nsectors = ctx.len; + if (*nsectors > max_nsectors) + *nsectors = max_nsectors; + *sectors = grub_calloc (*nsectors, sizeof (**sectors)); + if (!*sectors) + return grub_errno; + for (i = 0; i < *nsectors; i++) + (*sectors)[i] = ctx.start + i; + + return GRUB_ERR_NONE; +} +#endif + + +/* Partition map type. */ +static struct grub_partition_map grub_gpt_partition_map = + { + .name = "gpt", + .iterate = grub_gpt_partition_map_iterate, +#ifdef GRUB_UTIL + .embed = gpt_partition_map_embed +#endif + }; + +GRUB_MOD_INIT(part_gpt) +{ + grub_partition_map_register (&grub_gpt_partition_map); +} + +GRUB_MOD_FINI(part_gpt) +{ + grub_partition_map_unregister (&grub_gpt_partition_map); +} diff --git a/grub-core/partmap/msdos.c b/grub-core/partmap/msdos.c new file mode 100644 index 0000000..58c3626 --- /dev/null +++ b/grub-core/partmap/msdos.c @@ -0,0 +1,435 @@ +/* pc.c - Read PC style partition tables. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <grub/partition.h> +#include <grub/msdos_partition.h> +#include <grub/disk.h> +#include <grub/mm.h> +#include <grub/misc.h> +#include <grub/dl.h> +#include <grub/i18n.h> + +GRUB_MOD_LICENSE ("GPLv3+"); + +static struct grub_partition_map grub_msdos_partition_map; + + +#ifdef GRUB_UTIL +#include <grub/emu/misc.h> + +struct embed_signature +{ + const char *name; + const char *signature; + int signature_len; + enum { TYPE_SOFTWARE, TYPE_RAID } type; +}; + +const char message_warn[][200] = { + /* TRANSLATORS: MBR gap and boot track is the same thing and is the space + between MBR and first partitition. If your language translates well only + "boot track", you can just use it everywhere. Next two messages are about + RAID controllers/software bugs which GRUB has to live with. Please spread + the message that these are bugs in other software and not merely + suboptimal behaviour. */ + [TYPE_RAID] = N_("Sector %llu is already in use by raid controller `%s';" + " avoiding it. " + "Please ask the manufacturer not to store data in MBR gap"), + [TYPE_SOFTWARE] = N_("Sector %llu is already in use by the program `%s';" + " avoiding it. " + "This software may cause boot or other problems in " + "future. Please ask its authors not to store data " + "in the boot track") +}; + + +/* Signatures of other software that may be using sectors in the embedding + area. */ +struct embed_signature embed_signatures[] = + { + { + .name = "ZISD", + .signature = "ZISD", + .signature_len = 4, + .type = TYPE_SOFTWARE + }, + { + .name = "FlexNet", + .signature = "\xd4\x41\xa0\xf5\x03\x00\x03\x00", + .signature_len = 8, + .type = TYPE_SOFTWARE + }, + { + .name = "FlexNet", + .signature = "\xd8\x41\xa0\xf5\x02\x00\x02\x00", + .signature_len = 8, + .type = TYPE_SOFTWARE + }, + { + /* from Ryan Perkins */ + .name = "HP Backup and Recovery Manager (?)", + .signature = "\x70\x8a\x5d\x46\x35\xc5\x1b\x93" + "\xae\x3d\x86\xfd\xb1\x55\x3e\xe0", + .signature_len = 16, + .type = TYPE_SOFTWARE + }, + { + .name = "HighPoint RAID controller", + .signature = "ycgl", + .signature_len = 4, + .type = TYPE_RAID + }, + { + /* https://bugs.launchpad.net/bugs/987022 */ + .name = "Acer registration utility (?)", + .signature = "GREGRegDone.Tag\x00", + .signature_len = 16, + .type = TYPE_SOFTWARE + } + }; +#endif + +grub_err_t +grub_partition_msdos_iterate (grub_disk_t disk, + grub_partition_iterate_hook_t hook, + void *hook_data) +{ + struct grub_partition p; + struct grub_msdos_partition_mbr mbr; + int labeln = 0; + grub_disk_addr_t lastaddr; + grub_disk_addr_t ext_offset; + grub_disk_addr_t delta = 0; + + if (disk->partition && disk->partition->partmap == &grub_msdos_partition_map) + { + if (disk->partition->msdostype == GRUB_PC_PARTITION_TYPE_LINUX_MINIX) + delta = disk->partition->start; + else + return grub_error (GRUB_ERR_BAD_PART_TABLE, "no embedding supported"); + } + + p.offset = 0; + ext_offset = 0; + p.number = -1; + p.partmap = &grub_msdos_partition_map; + + /* Any value different than `p.offset' will satisfy the check during + first loop. */ + lastaddr = !p.offset; + + while (1) + { + int i; + struct grub_msdos_partition_entry *e; + + /* Read the MBR. */ + if (grub_disk_read (disk, p.offset, 0, sizeof (mbr), &mbr)) + goto finish; + + /* If this is a GPT partition, this MBR is just a dummy. */ + if (p.offset == 0) + for (i = 0; i < 4; i++) + if (mbr.entries[i].type == GRUB_PC_PARTITION_TYPE_GPT_DISK) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "dummy mbr"); + + /* This is our loop-detection algorithm. It works the following way: + It saves last position which was a power of two. Then it compares the + saved value with a current one. This way it's guaranteed that the loop + will be broken by at most third walk. + */ + if (labeln && lastaddr == p.offset) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "loop detected"); + + labeln++; + if ((labeln & (labeln - 1)) == 0) + lastaddr = p.offset; + + /* Check if it is valid. */ + if (mbr.signature != grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE)) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature"); + + for (i = 0; i < 4; i++) + if (mbr.entries[i].flag & 0x7f) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "bad boot flag"); + + /* Analyze DOS partitions. */ + for (p.index = 0; p.index < 4; p.index++) + { + e = mbr.entries + p.index; + + p.start = p.offset + + ((grub_disk_addr_t)grub_le_to_cpu32 (e->start) + << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)) - delta; + p.len = (grub_uint64_t)grub_le_to_cpu32 (e->length) + << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS); + p.msdostype = e->type; + + grub_dprintf ("partition", + "partition %d: flag 0x%x, type 0x%x, start 0x%llx, len 0x%llx\n", + p.index, e->flag, e->type, + (unsigned long long) p.start, + (unsigned long long) p.len); + + /* If this partition is a normal one, call the hook. */ + if (! grub_msdos_partition_is_empty (e->type) + && ! grub_msdos_partition_is_extended (e->type)) + { + p.number++; + + if (hook (disk, &p, hook_data)) + return grub_errno; + } + else if (p.number < 3) + /* If this partition is a logical one, shouldn't increase the + partition number. */ + p.number++; + } + + /* Find an extended partition. */ + for (i = 0; i < 4; i++) + { + e = mbr.entries + i; + + if (grub_msdos_partition_is_extended (e->type)) + { + p.offset = ext_offset + + ((grub_disk_addr_t)grub_le_to_cpu32 (e->start) + << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)); + if (! ext_offset) + ext_offset = p.offset; + + break; + } + } + + /* If no extended partition, the end. */ + if (i == 4) + break; + } + + finish: + return grub_errno; +} + +#ifdef GRUB_UTIL + +#pragma GCC diagnostic ignored "-Wformat-nonliteral" + +static grub_err_t +pc_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors, + unsigned int max_nsectors, + grub_embed_type_t embed_type, + grub_disk_addr_t **sectors, + int warn_short) +{ + grub_disk_addr_t end = ~0ULL; + struct grub_msdos_partition_mbr mbr; + int labeln = 0; + /* Any value different than `p.offset' will satisfy the check during + first loop. */ + grub_disk_addr_t lastaddr = 1; + grub_disk_addr_t ext_offset = 0; + grub_disk_addr_t offset = 0; + + if (embed_type != GRUB_EMBED_PCBIOS) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "PC-style partitions currently support " + "only PC-BIOS embedding"); + + if (disk->partition) + return grub_error (GRUB_ERR_OUT_OF_RANGE, + "Embedding on MSDOS subpartition isn't supported"); + + while (1) + { + int i; + struct grub_msdos_partition_entry *e; + grub_err_t err; + + /* Read the MBR. */ + err = grub_disk_read (disk, offset, 0, sizeof (mbr), &mbr); + if (err) + return err; + + /* This is our loop-detection algorithm. It works the following way: + It saves last position which was a power of two. Then it compares the + saved value with a current one. This way it's guaranteed that the loop + will be broken by at most third walk. + */ + if (labeln && lastaddr == offset) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "loop detected"); + + labeln++; + if ((labeln & (labeln - 1)) == 0) + lastaddr = offset; + + /* Check if it is valid. */ + if (mbr.signature != grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE)) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature"); + + for (i = 0; i < 4; i++) + if (mbr.entries[i].flag & 0x7f) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "bad boot flag"); + + /* Analyze DOS partitions. */ + for (i = 0; i < 4; i++) + { + e = mbr.entries + i; + + if (!grub_msdos_partition_is_empty (e->type) + && end > offset + + ((grub_disk_addr_t)grub_le_to_cpu32 (e->start) + << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS))) + end = offset + ((grub_disk_addr_t)grub_le_to_cpu32 (e->start) + << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)); + + /* If this is a GPT partition, this MBR is just a dummy. */ + if (e->type == GRUB_PC_PARTITION_TYPE_GPT_DISK && i == 0) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "dummy mbr"); + } + + /* Find an extended partition. */ + for (i = 0; i < 4; i++) + { + e = mbr.entries + i; + + if (grub_msdos_partition_is_extended (e->type)) + { + offset = ext_offset + + ((grub_disk_addr_t)grub_le_to_cpu32 (e->start) + << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)); + if (! ext_offset) + ext_offset = offset; + + break; + } + } + + /* If no extended partition, the end. */ + if (i == 4) + break; + } + + if (end >= *nsectors + 1) + { + unsigned i, j; + char *embed_signature_check; + unsigned int orig_nsectors, avail_nsectors; + + orig_nsectors = *nsectors; + *nsectors = end - 1; + avail_nsectors = *nsectors; + if (*nsectors > max_nsectors) + *nsectors = max_nsectors; + *sectors = grub_calloc (*nsectors, sizeof (**sectors)); + if (!*sectors) + return grub_errno; + for (i = 0; i < *nsectors; i++) + (*sectors)[i] = 1 + i; + + /* Check for software that is already using parts of the embedding + * area. + */ + embed_signature_check = grub_malloc (GRUB_DISK_SECTOR_SIZE); + for (i = 0; i < *nsectors; i++) + { + if (grub_disk_read (disk, (*sectors)[i], 0, GRUB_DISK_SECTOR_SIZE, + embed_signature_check)) + continue; + + for (j = 0; j < ARRAY_SIZE (embed_signatures); j++) + if (! grub_memcmp (embed_signatures[j].signature, + embed_signature_check, + embed_signatures[j].signature_len)) + break; + if (j == ARRAY_SIZE (embed_signatures)) + continue; + grub_util_warn (_(message_warn[embed_signatures[j].type]), + (*sectors)[i], embed_signatures[j].name); + avail_nsectors--; + if (avail_nsectors < *nsectors) + *nsectors = avail_nsectors; + + /* Avoid this sector. */ + for (j = i; j < *nsectors; j++) + (*sectors)[j]++; + + /* Have we run out of space? */ + if (avail_nsectors < orig_nsectors) + break; + + /* Make sure to check the next sector. */ + i--; + } + grub_free (embed_signature_check); + + if (*nsectors < orig_nsectors) + return grub_error (GRUB_ERR_OUT_OF_RANGE, + N_("other software is using the embedding area, and " + "there is not enough room for core.img. Such " + "software is often trying to store data in a way " + "that avoids detection. We recommend you " + "investigate")); + + return GRUB_ERR_NONE; + } + + if (end < GRUB_MIN_RECOMMENDED_MBR_GAP && warn_short) + grub_util_warn ("You have a short MBR gap and use advanced config. Please increase post-MBR gap."); + + if (end <= 1) + return grub_error (GRUB_ERR_FILE_NOT_FOUND, + N_("this msdos-style partition label has no " + "post-MBR gap; embedding won't be possible")); + + if (*nsectors > 62) + return grub_error (GRUB_ERR_OUT_OF_RANGE, + N_("your core.img is unusually large. " + "It won't fit in the embedding area")); + + return grub_error (GRUB_ERR_OUT_OF_RANGE, + N_("your embedding area is unusually small. " + "core.img won't fit in it.")); +} + +#pragma GCC diagnostic error "-Wformat-nonliteral" + +#endif + + +/* Partition map type. */ +static struct grub_partition_map grub_msdos_partition_map = + { + .name = "msdos", + .iterate = grub_partition_msdos_iterate, +#ifdef GRUB_UTIL + .embed = pc_partition_map_embed +#endif + }; + +GRUB_MOD_INIT(part_msdos) +{ + grub_partition_map_register (&grub_msdos_partition_map); +} + +GRUB_MOD_FINI(part_msdos) +{ + grub_partition_map_unregister (&grub_msdos_partition_map); +} diff --git a/grub-core/partmap/plan.c b/grub-core/partmap/plan.c new file mode 100644 index 0000000..83db224 --- /dev/null +++ b/grub-core/partmap/plan.c @@ -0,0 +1,120 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <grub/partition.h> +#include <grub/disk.h> +#include <grub/mm.h> +#include <grub/misc.h> +#include <grub/dl.h> +#include <grub/symbol.h> +#include <grub/types.h> +#include <grub/err.h> + +GRUB_MOD_LICENSE ("GPLv3+"); + +static struct grub_partition_map grub_plan_partition_map; + +static grub_err_t +plan_partition_map_iterate (grub_disk_t disk, + grub_partition_iterate_hook_t hook, + void *hook_data) +{ + struct grub_partition p; + int ptr = 0; + grub_err_t err; + + p.partmap = &grub_plan_partition_map; + p.msdostype = 0; + + for (p.number = 0; ; p.number++) + { + char sig[sizeof ("part ") - 1]; + char c; + + p.offset = (ptr >> GRUB_DISK_SECTOR_BITS) + 1; + p.index = ptr & (GRUB_DISK_SECTOR_SIZE - 1); + + err = grub_disk_read (disk, 1, ptr, sizeof (sig), sig); + if (err) + return err; + if (grub_memcmp (sig, "part ", sizeof ("part ") - 1) != 0) + break; + ptr += sizeof (sig); + do + { + err = grub_disk_read (disk, 1, ptr, 1, &c); + if (err) + return err; + ptr++; + } + while (grub_isdigit (c) || grub_isalpha (c)); + if (c != ' ') + break; + p.start = 0; + while (1) + { + err = grub_disk_read (disk, 1, ptr, 1, &c); + if (err) + return err; + ptr++; + if (!grub_isdigit (c)) + break; + p.start = p.start * 10 + (c - '0'); + } + if (c != ' ') + break; + p.len = 0; + while (1) + { + err = grub_disk_read (disk, 1, ptr, 1, &c); + if (err) + return err; + ptr++; + if (!grub_isdigit (c)) + break; + p.len = p.len * 10 + (c - '0'); + } + if (c != '\n') + break; + p.len -= p.start; + if (hook (disk, &p, hook_data)) + return grub_errno; + } + if (p.number == 0) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "not a plan partition table"); + + return GRUB_ERR_NONE; +} + +/* Partition map type. */ +static struct grub_partition_map grub_plan_partition_map = + { + .name = "plan", + .iterate = plan_partition_map_iterate, + }; + +GRUB_MOD_INIT(part_plan) +{ + grub_partition_map_register (&grub_plan_partition_map); +} + +GRUB_MOD_FINI(part_plan) +{ + grub_partition_map_unregister (&grub_plan_partition_map); +} + diff --git a/grub-core/partmap/sun.c b/grub-core/partmap/sun.c new file mode 100644 index 0000000..aac30a3 --- /dev/null +++ b/grub-core/partmap/sun.c @@ -0,0 +1,154 @@ +/* sun.c - Read SUN style partition tables. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2005,2006,2007 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <grub/partition.h> +#include <grub/disk.h> +#include <grub/mm.h> +#include <grub/misc.h> +#include <grub/dl.h> +#include <grub/symbol.h> +#include <grub/types.h> +#include <grub/err.h> + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define GRUB_PARTMAP_SUN_MAGIC 0xDABE +#define GRUB_PARTMAP_SUN_MAX_PARTS 8 +#define GRUB_PARTMAP_SUN_WHOLE_DISK_ID 0x05 + +struct grub_sun_partition_info +{ + grub_uint8_t spare1; + grub_uint8_t id; + grub_uint8_t spare2; + grub_uint8_t flags; +} GRUB_PACKED; + +struct grub_sun_partition_descriptor +{ + grub_uint32_t start_cylinder; + grub_uint32_t num_sectors; +} GRUB_PACKED; + +struct grub_sun_block +{ + grub_uint8_t info[128]; /* Informative text string. */ + grub_uint8_t spare0[14]; + struct grub_sun_partition_info infos[8]; + grub_uint8_t spare1[246]; /* Boot information etc. */ + grub_uint16_t rspeed; /* Disk rotational speed. */ + grub_uint16_t pcylcount; /* Physical cylinder count. */ + grub_uint16_t sparecyl; /* extra sects per cylinder. */ + grub_uint8_t spare2[4]; /* More magic... */ + grub_uint16_t ilfact; /* Interleave factor. */ + grub_uint16_t ncyl; /* Data cylinder count. */ + grub_uint16_t nacyl; /* Alt. cylinder count. */ + grub_uint16_t ntrks; /* Tracks per cylinder. */ + grub_uint16_t nsect; /* Sectors per track. */ + grub_uint8_t spare3[4]; /* Even more magic... */ + struct grub_sun_partition_descriptor partitions[8]; + grub_uint16_t magic; /* Magic number. */ + grub_uint16_t csum; /* Label xor'd checksum. */ +} GRUB_PACKED; + +static struct grub_partition_map grub_sun_partition_map; + +/* Verify checksum (true=ok). */ +static int +grub_sun_is_valid (grub_uint16_t *label) +{ + grub_uint16_t *pos; + grub_uint16_t sum = 0; + + for (pos = label; + pos < (label + sizeof (struct grub_sun_block) / 2); + pos++) + sum ^= *pos; + + return ! sum; +} + +static grub_err_t +sun_partition_map_iterate (grub_disk_t disk, + grub_partition_iterate_hook_t hook, void *hook_data) +{ + struct grub_partition p; + union + { + struct grub_sun_block sun_block; + grub_uint16_t raw[0]; + } block; + int partnum; + grub_err_t err; + + p.partmap = &grub_sun_partition_map; + err = grub_disk_read (disk, 0, 0, sizeof (struct grub_sun_block), + &block); + if (err) + return err; + + if (GRUB_PARTMAP_SUN_MAGIC != grub_be_to_cpu16 (block.sun_block.magic)) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "not a sun partition table"); + + if (! grub_sun_is_valid (block.raw)) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid checksum"); + + /* Maybe another error value would be better, because partition + table _is_ recognized but invalid. */ + for (partnum = 0; partnum < GRUB_PARTMAP_SUN_MAX_PARTS; partnum++) + { + struct grub_sun_partition_descriptor *desc; + + if (block.sun_block.infos[partnum].id == 0 + || block.sun_block.infos[partnum].id == GRUB_PARTMAP_SUN_WHOLE_DISK_ID) + continue; + + desc = &block.sun_block.partitions[partnum]; + p.start = ((grub_uint64_t) grub_be_to_cpu32 (desc->start_cylinder) + * grub_be_to_cpu16 (block.sun_block.ntrks) + * grub_be_to_cpu16 (block.sun_block.nsect)); + p.len = grub_be_to_cpu32 (desc->num_sectors); + p.number = p.index = partnum; + if (p.len) + { + if (hook (disk, &p, hook_data)) + partnum = GRUB_PARTMAP_SUN_MAX_PARTS; + } + } + + return grub_errno; +} + +/* Partition map type. */ +static struct grub_partition_map grub_sun_partition_map = + { + .name = "sun", + .iterate = sun_partition_map_iterate, + }; + +GRUB_MOD_INIT(part_sun) +{ + grub_partition_map_register (&grub_sun_partition_map); +} + +GRUB_MOD_FINI(part_sun) +{ + grub_partition_map_unregister (&grub_sun_partition_map); +} + diff --git a/grub-core/partmap/sunpc.c b/grub-core/partmap/sunpc.c new file mode 100644 index 0000000..73a430c --- /dev/null +++ b/grub-core/partmap/sunpc.c @@ -0,0 +1,151 @@ +/* sunpc.c - Read SUN PC style partition tables. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2005,2006,2007,2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <grub/partition.h> +#include <grub/disk.h> +#include <grub/mm.h> +#include <grub/misc.h> +#include <grub/dl.h> +#include <grub/symbol.h> +#include <grub/types.h> +#include <grub/err.h> + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define GRUB_PARTMAP_SUN_PC_MAGIC 0xDABE +#define GRUB_PARTMAP_SUN_PC_MAX_PARTS 16 +#define GRUB_PARTMAP_SUN_PC_WHOLE_DISK_ID 0x05 + +struct grub_sun_pc_partition_descriptor +{ + grub_uint16_t id; + grub_uint16_t unused; + grub_uint32_t start_sector; + grub_uint32_t num_sectors; +} GRUB_PACKED; + +struct grub_sun_pc_block +{ + grub_uint8_t unused[72]; + struct grub_sun_pc_partition_descriptor partitions[GRUB_PARTMAP_SUN_PC_MAX_PARTS]; + grub_uint8_t unused2[244]; + grub_uint16_t magic; /* Magic number. */ + grub_uint16_t csum; /* Label xor'd checksum. */ +} GRUB_PACKED; + +static struct grub_partition_map grub_sun_pc_partition_map; + +/* Verify checksum (true=ok). */ +static int +grub_sun_is_valid (grub_uint16_t *label) +{ + grub_uint16_t *pos; + grub_uint16_t sum = 0; + + for (pos = label; + pos < (label + sizeof (struct grub_sun_pc_block) / 2); + pos++) + sum ^= *pos; + + return ! sum; +} + +static grub_err_t +sun_pc_partition_map_iterate (grub_disk_t disk, + grub_partition_iterate_hook_t hook, + void *hook_data) +{ + grub_partition_t p; + union + { + struct grub_sun_pc_block sun_block; + grub_uint16_t raw[0]; + } block; + int partnum; + grub_err_t err; + + p = (grub_partition_t) grub_zalloc (sizeof (struct grub_partition)); + if (! p) + return grub_errno; + + p->partmap = &grub_sun_pc_partition_map; + err = grub_disk_read (disk, 1, 0, sizeof (struct grub_sun_pc_block), &block); + if (err) + { + grub_free (p); + return err; + } + + if (GRUB_PARTMAP_SUN_PC_MAGIC != grub_le_to_cpu16 (block.sun_block.magic)) + { + grub_free (p); + return grub_error (GRUB_ERR_BAD_PART_TABLE, + "not a sun_pc partition table"); + } + + if (! grub_sun_is_valid (block.raw)) + { + grub_free (p); + return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid checksum"); + } + + /* Maybe another error value would be better, because partition + table _is_ recognized but invalid. */ + for (partnum = 0; partnum < GRUB_PARTMAP_SUN_PC_MAX_PARTS; partnum++) + { + struct grub_sun_pc_partition_descriptor *desc; + + if (block.sun_block.partitions[partnum].id == 0 + || block.sun_block.partitions[partnum].id + == GRUB_PARTMAP_SUN_PC_WHOLE_DISK_ID) + continue; + + desc = &block.sun_block.partitions[partnum]; + p->start = grub_le_to_cpu32 (desc->start_sector); + p->len = grub_le_to_cpu32 (desc->num_sectors); + p->number = partnum; + if (p->len) + { + if (hook (disk, p, hook_data)) + partnum = GRUB_PARTMAP_SUN_PC_MAX_PARTS; + } + } + + grub_free (p); + + return grub_errno; +} + +/* Partition map type. */ +static struct grub_partition_map grub_sun_pc_partition_map = + { + .name = "sunpc", + .iterate = sun_pc_partition_map_iterate, + }; + +GRUB_MOD_INIT(part_sunpc) +{ + grub_partition_map_register (&grub_sun_pc_partition_map); +} + +GRUB_MOD_FINI(part_sunpc) +{ + grub_partition_map_unregister (&grub_sun_pc_partition_map); +} + |