diff --git a/Makefile.util.def b/Makefile.util.def index 35bcd81b2..20224cf02 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -89,6 +89,9 @@ library = { common = grub-core/partmap/msdos.c; common = grub-core/partmap/sun.c; common = grub-core/partmap/sunpc.c; + common = grub-core/partmap/bsdlabel.c; + common = grub-core/partmap/netbsdlabel.c; + common = grub-core/partmap/openbsdlabel.c; common = grub-core/script/function.c; common = grub-core/script/lexer.c; common = grub-core/script/main.c; diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 353b9d123..4f28c54f4 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -1208,6 +1208,16 @@ module = { common = partmap/bsdlabel.c; }; +module = { + name = part_netbsd; + common = partmap/netbsdlabel.c; +}; + +module = { + name = part_openbsd; + common = partmap/openbsdlabel.c; +}; + module = { name = part_sunpc; common = partmap/sunpc.c; diff --git a/grub-core/partmap/bsdlabel.c b/grub-core/partmap/bsdlabel.c index a27b8eaec..3d481843a 100644 --- a/grub-core/partmap/bsdlabel.c +++ b/grub-core/partmap/bsdlabel.c @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef GRUB_UTIL #include @@ -32,9 +33,9 @@ static struct grub_partition_map grub_bsdlabel_partition_map; static grub_err_t -bsdlabel_partition_map_iterate (grub_disk_t disk, - int (*hook) (grub_disk_t disk, - const grub_partition_t partition)) +iterate_real (grub_disk_t disk, grub_disk_addr_t sector, int freebsd, + int (*hook) (grub_disk_t disk, + const grub_partition_t partition)) { struct grub_partition_bsd_disk_label label; struct grub_partition p; @@ -42,22 +43,27 @@ bsdlabel_partition_map_iterate (grub_disk_t disk, unsigned pos; /* Read the BSD label. */ - if (grub_disk_read (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR, - 0, sizeof (label), &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"); + { + grub_dprintf ("partition", + "bad signature (found 0x%08x, expected 0x%08x)\n", + 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)) + < grub_cpu_to_le16 (label.num_partitions) && freebsd) { struct grub_partition_bsd_entry whole_disk_be; - pos = sizeof (label) + GRUB_PC_PARTITION_BSD_LABEL_SECTOR - * GRUB_DISK_SECTOR_SIZE + sizeof (struct grub_partition_bsd_entry) + 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, @@ -68,8 +74,10 @@ bsdlabel_partition_map_iterate (grub_disk_t disk, delta = grub_le_to_cpu32 (whole_disk_be.offset); } - pos = sizeof (label) + GRUB_PC_PARTITION_BSD_LABEL_SECTOR - * GRUB_DISK_SECTOR_SIZE; + pos = sizeof (label) + sector * GRUB_DISK_SECTOR_SIZE; + + grub_dprintf ("partition", "bsdlabel with %d partitions detected\n", + grub_cpu_to_le16 (label.num_partitions)); for (p.number = 0; p.number < grub_cpu_to_le16 (label.num_partitions); @@ -124,24 +132,112 @@ bsdlabel_partition_map_iterate (grub_disk_t disk, if (hook (disk, &p)) return grub_errno; } - return GRUB_ERR_NONE; } +#if !defined (NETBSDLABEL) && !defined (OPENBSDLABEL) + +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) + { + grub_dprintf ("partition", "FreeBSD embedded iterating\n"); + return iterate_real (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR, 1, + hook); + } + + if (disk->partition + && (grub_strcmp (disk->partition->partmap->name, "msdos") == 0 + || grub_strcmp (disk->partition->partmap->name, "bsd") == 0 + || grub_strcmp (disk->partition->partmap->name, "netbsd") == 0 + || grub_strcmp (disk->partition->partmap->name, "openbsd") == 0)) + { + grub_dprintf ("partition", "no embedded iterating\n"); + return grub_error (GRUB_ERR_BAD_PART_TABLE, "no embedding supported"); + } + + return iterate_real (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR, 0, hook); +} + +#else + +#ifdef OPENBSDLABEL +#define GRUB_PC_PARTITION_TYPE_BSD GRUB_PC_PARTITION_TYPE_OPENBSD +#else +#define GRUB_PC_PARTITION_TYPE_BSD GRUB_PC_PARTITION_TYPE_NETBSD +#endif + +static grub_err_t +bsdlabel_partition_map_iterate (grub_disk_t disk, + int (*hook) (grub_disk_t disk, + const grub_partition_t partition)) +{ + grub_err_t err; + + if (disk->partition && grub_strcmp (disk->partition->partmap->name, "msdos") + == 0) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "no embedding supported"); + + { + struct grub_msdos_partition_mbr mbr; + unsigned i; + + err = grub_disk_read (disk, 0, 0, sizeof (mbr), &mbr); + if (err) + return err; + + for (i = 0; i < ARRAY_SIZE (mbr.entries); i++) + if (mbr.entries[i].type == GRUB_PC_PARTITION_TYPE_BSD) + { + err = iterate_real (disk, mbr.entries[i].start + + GRUB_PC_PARTITION_BSD_LABEL_SECTOR, 0, hook); + if (err != GRUB_ERR_BAD_PART_TABLE) + return err; + } + } + + return grub_error (GRUB_ERR_BAD_PART_TABLE, "no bsdlabel found"); +} + +#endif + /* Partition map type. */ static struct grub_partition_map grub_bsdlabel_partition_map = { +#if defined (OPENBSDLABEL) + .name = "openbsd", +#elif defined (NETBSDLABEL) + .name = "netbsd", +#else .name = "bsd", +#endif .iterate = bsdlabel_partition_map_iterate, }; +#if defined (OPENBSDLABEL) +GRUB_MOD_INIT(part_openbsd) +#elif defined (NETBSDLABEL) +GRUB_MOD_INIT(part_netbsd) +#else GRUB_MOD_INIT(part_bsd) +#endif { grub_partition_map_register (&grub_bsdlabel_partition_map); } +#if defined (OPENBSDLABEL) +GRUB_MOD_FINI(part_openbsd) +#elif defined (NETBSDLABEL) +GRUB_MOD_FINI(part_netbsd) +#else GRUB_MOD_FINI(part_bsd) +#endif { grub_partition_map_unregister (&grub_bsdlabel_partition_map); } diff --git a/grub-core/partmap/msdos.c b/grub-core/partmap/msdos.c index 3898d09fa..02105e622 100644 --- a/grub-core/partmap/msdos.c +++ b/grub-core/partmap/msdos.c @@ -37,6 +37,15 @@ pc_partition_map_iterate (grub_disk_t disk, 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->offset; + else + return grub_error (GRUB_ERR_BAD_PART_TABLE, "no embedding supported"); + } p.offset = 0; ext_offset = 0; @@ -81,8 +90,9 @@ pc_partition_map_iterate (grub_disk_t disk, { e = mbr.entries + p.index; - p.start = p.offset + grub_le_to_cpu32 (e->start); + 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", diff --git a/grub-core/partmap/netbsdlabel.c b/grub-core/partmap/netbsdlabel.c new file mode 100644 index 000000000..63c0166da --- /dev/null +++ b/grub-core/partmap/netbsdlabel.c @@ -0,0 +1,2 @@ +#define NETBSDLABEL 1 +#include "bsdlabel.c" diff --git a/grub-core/partmap/openbsdlabel.c b/grub-core/partmap/openbsdlabel.c new file mode 100644 index 000000000..4df075a9c --- /dev/null +++ b/grub-core/partmap/openbsdlabel.c @@ -0,0 +1,2 @@ +#define OPENBSDLABEL 1 +#include "bsdlabel.c" diff --git a/include/grub/partition.h b/include/grub/partition.h index 20705c527..d5398def7 100644 --- a/include/grub/partition.h +++ b/include/grub/partition.h @@ -65,6 +65,10 @@ struct grub_partition /* The type partition map. */ grub_partition_map_t partmap; + + /* The type of partition whne it's on MSDOS. + Used for embedding detection. */ + grub_uint8_t msdostype; }; grub_partition_t EXPORT_FUNC(grub_partition_probe) (struct grub_disk *disk,