-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 with aim for inclusion in mainline Grub2.
Grub2 1.99 is base. Patches to gpt.c and msdos.c in /grub-core/partmap/. Diffs attached with original code and patched code. Goal: To make the disk bootable on: PCs using BIOS, PCs using UEFI, Intel Macintoshes using BIOS, and Intel Macintoshes using EFI, as well as having the (HybridData) partition readable by both Windows and MacOSX. ExaExample partition layout:mple partition layout: Physical: MBR GPT (HybridData) (EFI) (BIOS) MBR: 1: 0C (FAT32) : FAT32 (HybridData) 2: EF (EFI) : FAT32 (EFI) 3: EE (GPT) : (Protective) GPT: 1: 0700 (Data) : FAT32 (HybridData) 2: ef00 (EFI) : FAT32 (EFI) 3: 0f02 (BIOS) : Unformatted (BIOS) Current behaviour: Grub2 detects an MBR and checks if the first MBR primary partition is GPT protective partition. The first MBR primary partition is not a GPT protective partition, so it treats the disk as a pure MBR disk and so refuses to install the boot loader kernel in the post-MBR gap because there is no post-MBR gap because it is taken by GPT protective partition. Proposed behaviour: Grub2 detects an MBR and checks if any of the MBR primary partitions are GPT protective partitions. It finds a GPT protective partition (MBR primary partition 3 in the example), and concludes that the disk is a GPT disk and looks for a BIOS boot partition (Hah!IdontNeedEFI) (GPT partition 3 in the example) in which to install the boot loader kernel. Questions, Comments, and Feedback welcome. See also: http://perditauranus.dyndns.org/tdiary/?date=20110803 See also: http://www.rodsbooks.com/gdisk/hybrid.html#bootloaders - -- David Joshua Geary UNE Linux User Group: li...@une.edu.au <http://lugune.dyndns.org> I don't care what software you use so long as we only exchange files in open data formats Open-Document <http://en.wikipedia.org/wiki/Open_Document> Ogg <http://en.wikipedia.org/wiki/Ogg> PDF <http://en.wikipedia.org/wiki/Pdf> - -----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1.4.10 (GNU/Linux) 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 =kv+y - -----END PGP PUBLIC KEY BLOCK----- -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iQIcBAEBAgAGBQJOULD7AAoJEMR6DgDuR4If/vkP/3K3gczRr5LpChbtDKuDdu3/ SGCtRahsnwsR9hmyxwCRKjuiYFDFw+K7aybX/bI9doJxQfR3rL5rclgkuvxvl4nK fhEF+FmIANVvAHVQU4rJNHu1xpxgwplJ2AhBpuNbMWyyVrA8yBwezEgd1YYDedMs tf2G1e4HW+RYvF1oqDZARhJpfgXZJW1oqeVrNA8ZBdyj05nVDm8yB7Os3JawsFE9 E9fvypowlydLDzM1U//3a4CjJ8Q09QTa0GzGiE07pCOWENEehdW2pDJXnQB/BXUY 91FxIcLsMXuY5qg2PVaEOpYt8yQsAVzqNEYX/0nPHf5/++jOtLUiYgXRtd/vq+90 l7kYxo1rm+sRusmy2y0S5BKD8LsqB/I8Y/PP0vKwkKujzFKTcbYRKxyqTvgFLyia HopvTZxEwLzvjsn9k2h2kDYVYOXnMiylpyyMlWBlT1J5xwS70RsVlGwfxYqebpLg S6FZBN9SU20SX7LaRcGwedfjhrHAJk5MLvy3m8cuECZp7HZr3fzBe/a4hJfiD2dG nqHNiDhAFSJLh6lRCELO0noMVLfuJ5nsdubIi0esWIBLrf0aGmkwUwWu+w+txfdU T3YpKfPzCrnnVDV1jc81uuXrnKrKMyQTpd33fnd3Rc5DpnvgBhlkN8WyeljA/lqo 2XLjGbJyhTZjlIh3SJG0 =/0rL -----END PGP SIGNATURE-----
/* 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 or hybrid 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)) 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); }
70,71c70,75 < /* Make sure the MBR is a protective MBR and not a normal MBR. */ < if (mbr.entries[0].type != GRUB_PC_PARTITION_TYPE_GPT_DISK) --- > /* Make sure the MBR is a protective or hybrid 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)
/* 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); }
/* 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"); /* First pass to find GPT partitions. */ for (p.index = 0; p.index < 4; p.index++) { e = mbr.entries + p.index; /* If this is a GPT partition, this MBR is just a dummy. */ if (e->type == GRUB_PC_PARTITION_TYPE_GPT_DISK) return grub_error (GRUB_ERR_BAD_PART_TABLE, "dummy mbr"); } /* Second pass to 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 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) 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); }
90c90,100 < /* Analyze DOS partitions. */ --- > /* First pass to find GPT partitions. */ > for (p.index = 0; p.index < 4; p.index++) > { > e = mbr.entries + p.index; > > /* If this is a GPT partition, this MBR is just a dummy. */ > if (e->type == GRUB_PC_PARTITION_TYPE_GPT_DISK) > return grub_error (GRUB_ERR_BAD_PART_TABLE, "dummy mbr"); > } > > /* Second pass to analyze DOS partitions. */ 105,108d114 < /* 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"); < 213c219 < if (e->type == GRUB_PC_PARTITION_TYPE_GPT_DISK && i == 0) --- > if (e->type == GRUB_PC_PARTITION_TYPE_GPT_DISK)
/* 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); }
gpt.c.sig
Description: PGP signature
gpt.c.diff.sig
Description: PGP signature
gpt.c.original.sig
Description: PGP signature
msdos.c.sig
Description: PGP signature
msdos.c.diff.sig
Description: PGP signature
msdos.c.original.sig
Description: PGP signature
_______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel