aboutsummaryrefslogtreecommitdiffstats
path: root/grub-core/partmap
diff options
context:
space:
mode:
authorJames <james.mckenzie@citrix.com>2012-11-16 10:41:01 +0000
committerJames <james.mckenzie@citrix.com>2012-11-16 10:41:01 +0000
commit041d1ea37802bf7178a31a53f96c26efa6b8fb7b (patch)
treec193e84ad1237f25a79d0f6a267722e44c73f56a /grub-core/partmap
downloadgrub-1.99-041d1ea37802bf7178a31a53f96c26efa6b8fb7b.tar.gz
grub-1.99-041d1ea37802bf7178a31a53f96c26efa6b8fb7b.tar.bz2
grub-1.99-041d1ea37802bf7178a31a53f96c26efa6b8fb7b.zip
fish
Diffstat (limited to 'grub-core/partmap')
-rw-r--r--grub-core/partmap/acorn.c147
-rw-r--r--grub-core/partmap/amiga.c160
-rw-r--r--grub-core/partmap/apple.c199
-rw-r--r--grub-core/partmap/bsdlabel.c254
-rw-r--r--grub-core/partmap/gpt.c208
-rw-r--r--grub-core/partmap/msdos.c284
-rw-r--r--grub-core/partmap/sun.c151
-rw-r--r--grub-core/partmap/sunpc.c146
8 files changed, 1549 insertions, 0 deletions
diff --git a/grub-core/partmap/acorn.c b/grub-core/partmap/acorn.c
new file mode 100644
index 0000000..9a68ddd
--- /dev/null
+++ b/grub-core/partmap/acorn.c
@@ -0,0 +1,147 @@
+/* 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 (0xdeafa1de)
+#define LINUX_SWAP_MAGIC grub_cpu_to_le32 (0xdeafab1e)
+#define LINUX_MAP_ENTRIES (512 / 12)
+
+#define NONADFS_PARTITION_TYPE_LINUX 9
+#define NONADFS_PARTITION_TYPE_MASK 15
+
+struct grub_acorn_boot_block
+{
+ 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;
+} __attribute__ ((packed, aligned));
+
+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.misc[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,
+ int (*hook) (grub_disk_t disk,
+ const grub_partition_t partition))
+{
+ 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))
+ 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..36e318b
--- /dev/null
+++ b/grub-core/partmap/amiga.c
@@ -0,0 +1,160 @@
+/* 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+");
+
+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;
+
+ /* The other information is not important for us. */
+} __attribute__ ((packed));
+
+struct grub_amiga_partition
+{
+ /* "PART". */
+ grub_uint8_t magic[4];
+#define GRUB_AMIGA_PART_MAGIC "PART"
+ grub_int32_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;
+} __attribute__ ((packed));
+
+static struct grub_partition_map grub_amiga_partition_map;
+
+
+
+static grub_err_t
+amiga_partition_map_iterate (grub_disk_t disk,
+ int (*hook) (grub_disk_t disk,
+ const grub_partition_t partition))
+{
+ 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)
+ {
+ /* 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)
+ 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 = (grub_off_t) next * 512;
+ part.number = partno;
+ part.index = 0;
+ part.partmap = &grub_amiga_partition_map;
+
+ if (hook (disk, &part))
+ 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..c08cae5
--- /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,
+ int (*hook) (grub_disk_t disk,
+ const grub_partition_t partition))
+{
+ 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))
+ 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..888100a
--- /dev/null
+++ b/grub-core/partmap/bsdlabel.c
@@ -0,0 +1,254 @@
+/* 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>
+
+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,
+ int (*hook) (grub_disk_t disk,
+ const grub_partition_t partition))
+{
+ 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 (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)
+ : "";
+ 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))
+ return grub_errno;
+ }
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+bsdlabel_partition_map_iterate (grub_disk_t disk,
+ int (*hook) (grub_disk_t disk,
+ const grub_partition_t partition))
+{
+
+ 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);
+
+ 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);
+}
+
+/* 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,
+ int (*hook) (grub_disk_t disk,
+ const grub_partition_t partition))
+{
+ int count = 0;
+
+ auto int check_msdos (grub_disk_t dsk,
+ const grub_partition_t partition);
+
+ int check_msdos (grub_disk_t dsk,
+ const grub_partition_t partition)
+ {
+ grub_err_t err;
+
+ if (partition->msdostype != type)
+ return 0;
+
+ err = iterate_real (dsk, partition->start
+ + GRUB_PC_PARTITION_BSD_LABEL_SECTOR, 0, pmap, hook);
+ if (err == GRUB_ERR_NONE)
+ {
+ count++;
+ return 1;
+ }
+ if (err == GRUB_ERR_BAD_PART_TABLE)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ return 0;
+ }
+ grub_print_error ();
+ return 0;
+ }
+
+ if (disk->partition && grub_strcmp (disk->partition->partmap->name, "msdos")
+ == 0)
+ return grub_error (GRUB_ERR_BAD_PART_TABLE, "no embedding supported");
+
+ {
+ grub_err_t err;
+ err = grub_partition_msdos_iterate (disk, check_msdos);
+
+ if (err)
+ return err;
+ if (!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,
+ int (*hook) (grub_disk_t disk,
+ const grub_partition_t partition))
+{
+ return netopenbsdlabel_partition_map_iterate (disk,
+ GRUB_PC_PARTITION_TYPE_NETBSD,
+ &grub_netbsdlabel_partition_map,
+ hook);
+}
+
+static grub_err_t
+openbsdlabel_partition_map_iterate (grub_disk_t disk,
+ int (*hook) (grub_disk_t disk,
+ const grub_partition_t partition))
+{
+ return netopenbsdlabel_partition_map_iterate (disk,
+ GRUB_PC_PARTITION_TYPE_OPENBSD,
+ &grub_openbsdlabel_partition_map,
+ hook);
+}
+
+
+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/gpt.c b/grub-core/partmap/gpt.c
new file mode 100644
index 0000000..73a1c3b
--- /dev/null
+++ b/grub-core/partmap/gpt.c
@@ -0,0 +1,208 @@
+/* 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>
+
+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_type_t grub_gpt_partition_type_empty = GRUB_GPT_PARTITION_TYPE_EMPTY;
+
+#ifdef GRUB_UTIL
+static const grub_gpt_part_type_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;
+
+
+
+static grub_err_t
+gpt_partition_map_iterate (grub_disk_t disk,
+ int (*hook) (grub_disk_t disk,
+ const grub_partition_t partition))
+{
+ 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 (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. */
+ if (mbr.entries[0].type != GRUB_PC_PARTITION_TYPE_GPT_DISK)
+ 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))
+ 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
+static grub_err_t
+gpt_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors,
+ grub_embed_type_t embed_type,
+ grub_disk_addr_t **sectors)
+{
+ grub_disk_addr_t start = 0, len = 0;
+ unsigned i;
+ grub_err_t err;
+
+ auto int NESTED_FUNC_ATTR find_usable_region (grub_disk_t disk,
+ const grub_partition_t p);
+ int NESTED_FUNC_ATTR find_usable_region (grub_disk_t disk __attribute__ ((unused)),
+ const grub_partition_t p)
+ {
+ struct grub_gpt_partentry gptdata;
+
+ disk->partition = p->parent;
+ if (grub_disk_read (disk, p->offset, p->index,
+ sizeof (gptdata), &gptdata))
+ return 0;
+
+ /* If there's an embed region, it is in a dedicated partition. */
+ if (! grub_memcmp (&gptdata.type, &grub_gpt_partition_type_bios_boot, 16))
+ {
+ start = p->start;
+ len = p->len;
+ return 1;
+ }
+
+ return 0;
+ }
+
+ if (embed_type != GRUB_EMBED_PCBIOS)
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "GPT curently supports only PC-BIOS embedding");
+
+ err = gpt_partition_map_iterate (disk, find_usable_region);
+ if (err)
+ return err;
+
+ if (len == 0)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND,
+ "This GPT partition label has no BIOS Boot Partition;"
+ " embedding won't be possible!");
+
+ if (len < *nsectors)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ "Your BIOS Boot Partition is too small;"
+ " embedding won't be possible!");
+
+ *nsectors = len;
+ *sectors = grub_malloc (*nsectors * sizeof (**sectors));
+ if (!*sectors)
+ return grub_errno;
+ for (i = 0; i < *nsectors; i++)
+ (*sectors)[i] = start + i;
+
+ return GRUB_ERR_NONE;
+}
+#endif
+
+
+/* Partition map type. */
+static struct grub_partition_map grub_gpt_partition_map =
+ {
+ .name = "gpt",
+ .iterate = 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..1b71c69
--- /dev/null
+++ b/grub-core/partmap/msdos.c
@@ -0,0 +1,284 @@
+/* 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>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static struct grub_partition_map grub_msdos_partition_map;
+
+
+grub_err_t
+grub_partition_msdos_iterate (grub_disk_t disk,
+ int (*hook) (grub_disk_t disk,
+ const grub_partition_t partition))
+{
+ 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;
+
+ /* 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 (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_le_to_cpu32 (e->start) - delta;
+ p.len = grub_le_to_cpu32 (e->length);
+ 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 is a GPT partition, this MBR is just a dummy. */
+ if (e->type == GRUB_PC_PARTITION_TYPE_GPT_DISK && p.index == 0)
+ return grub_error (GRUB_ERR_BAD_PART_TABLE, "dummy mbr");
+
+ /* 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))
+ return grub_errno;
+ }
+ else if (p.number < 4)
+ /* 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_le_to_cpu32 (e->start);
+ 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
+static grub_err_t
+pc_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors,
+ grub_embed_type_t embed_type,
+ grub_disk_addr_t **sectors)
+{
+ 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 curently 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 (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_le_to_cpu32 (e->start))
+ end = offset + grub_le_to_cpu32 (e->start);
+
+ /* 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_le_to_cpu32 (e->start);
+ if (! ext_offset)
+ ext_offset = offset;
+
+ break;
+ }
+ }
+
+ /* If no extended partition, the end. */
+ if (i == 4)
+ break;
+ }
+
+ if (end >= *nsectors + 2)
+ {
+ unsigned i;
+ *nsectors = end - 2;
+ *sectors = grub_malloc (*nsectors * sizeof (**sectors));
+ if (!*sectors)
+ return grub_errno;
+ for (i = 0; i < *nsectors; i++)
+ (*sectors)[i] = 1 + i;
+ return GRUB_ERR_NONE;
+ }
+
+ if (end <= 1)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND,
+ "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,
+ "Your core.img is unusually large. "
+ "It won't fit in the embedding area.");
+
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ "Your embedding area is unusually small. "
+ "core.img won't fit in it.");
+}
+#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/sun.c b/grub-core/partmap/sun.c
new file mode 100644
index 0000000..c7ef681
--- /dev/null
+++ b/grub-core/partmap/sun.c
@@ -0,0 +1,151 @@
+/* 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;
+} __attribute__ ((packed));
+
+struct grub_sun_partition_descriptor
+{
+ grub_uint32_t start_cylinder;
+ grub_uint32_t num_sectors;
+} __attribute__ ((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. */
+} __attribute__ ((packed));
+
+static struct grub_partition_map grub_sun_partition_map;
+
+/* Verify checksum (true=ok). */
+static int
+grub_sun_is_valid (struct grub_sun_block *label)
+{
+ grub_uint16_t *pos;
+ grub_uint16_t sum = 0;
+
+ for (pos = (grub_uint16_t *) label;
+ pos < (grub_uint16_t *) (label + 1);
+ pos++)
+ sum ^= *pos;
+
+ return ! sum;
+}
+
+static grub_err_t
+sun_partition_map_iterate (grub_disk_t disk,
+ int (*hook) (grub_disk_t disk,
+ const grub_partition_t partition))
+{
+ struct grub_partition p;
+ struct grub_sun_block 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.magic))
+ return grub_error (GRUB_ERR_BAD_PART_TABLE, "not a sun partition table");
+
+ if (! grub_sun_is_valid (&block))
+ 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.infos[partnum].id == 0
+ || block.infos[partnum].id == GRUB_PARTMAP_SUN_WHOLE_DISK_ID)
+ continue;
+
+ desc = &block.partitions[partnum];
+ p.start = ((grub_uint64_t) grub_be_to_cpu32 (desc->start_cylinder)
+ * grub_be_to_cpu16 (block.ntrks)
+ * grub_be_to_cpu16 (block.nsect));
+ p.len = grub_be_to_cpu32 (desc->num_sectors);
+ p.number = p.index = partnum;
+ if (p.len)
+ {
+ if (hook (disk, &p))
+ 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..28dc4f5
--- /dev/null
+++ b/grub-core/partmap/sunpc.c
@@ -0,0 +1,146 @@
+/* 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;
+} __attribute__ ((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. */
+} __attribute__ ((packed));
+
+static struct grub_partition_map grub_sun_pc_partition_map;
+
+/* Verify checksum (true=ok). */
+static int
+grub_sun_is_valid (struct grub_sun_pc_block *label)
+{
+ grub_uint16_t *pos;
+ grub_uint16_t sum = 0;
+
+ for (pos = (grub_uint16_t *) label;
+ pos < (grub_uint16_t *) (label + 1);
+ pos++)
+ sum ^= *pos;
+
+ return ! sum;
+}
+
+static grub_err_t
+sun_pc_partition_map_iterate (grub_disk_t disk,
+ int (*hook) (grub_disk_t disk,
+ const grub_partition_t partition))
+{
+ grub_partition_t p;
+ struct grub_sun_pc_block 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.magic))
+ {
+ grub_free (p);
+ return grub_error (GRUB_ERR_BAD_PART_TABLE,
+ "not a sun_pc partition table");
+ }
+
+ if (! grub_sun_is_valid (&block))
+ {
+ 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.partitions[partnum].id == 0
+ || block.partitions[partnum].id == GRUB_PARTMAP_SUN_PC_WHOLE_DISK_ID)
+ continue;
+
+ desc = &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))
+ 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);
+}
+