summaryrefslogtreecommitdiffstats
path: root/grub-core/partmap
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:29:51 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:29:51 +0000
commit6e7a315eb67cb6c113cf37e1d66c4f11a51a2b3e (patch)
tree32451fa3cdd9321fb2591fada9891b2cb70a9cd1 /grub-core/partmap
parentInitial commit. (diff)
downloadgrub2-3e86199209a10ed6555e30b8b71884cb7cc45ed2.tar.xz
grub2-3e86199209a10ed6555e30b8b71884cb7cc45ed2.zip
Adding upstream version 2.06.upstream/2.06upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'grub-core/partmap')
-rw-r--r--grub-core/partmap/acorn.c154
-rw-r--r--grub-core/partmap/amiga.c183
-rw-r--r--grub-core/partmap/apple.c199
-rw-r--r--grub-core/partmap/bsdlabel.c271
-rw-r--r--grub-core/partmap/dfly.c132
-rw-r--r--grub-core/partmap/dvh.c127
-rw-r--r--grub-core/partmap/gpt.c238
-rw-r--r--grub-core/partmap/msdos.c435
-rw-r--r--grub-core/partmap/plan.c120
-rw-r--r--grub-core/partmap/sun.c154
-rw-r--r--grub-core/partmap/sunpc.c151
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, &sector);
+ 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);
+}
+