2008-02-17 Robert Millan * partmap/gpt.c: Include `'. (grub_gpt_partition_type_empty): Redefine with macro from `'. (gpt_partition_map_iterate): Adjust partition type comparison. Export `entry' as partmap-specific `part.data' struct. (grub_gpt_header, grub_gpt_partentry): Move from here ... * include/grub/gpt_partition.h (grub_gpt_header) (grub_gpt_partentry): ... to here (new file). * util/i386/pc/grub-setup.c: Include `'. (grub_gpt_partition_type_bios_boot): New const variable, defined with macro from `'. (setup): Replace `first_start' with `embed_region', which keeps track of the embed region (and is partmap-agnostic). Replace find_first_partition_start() with find_usable_region(), which finds a usable region for embedding using partmap-specific knowledge (supports PC/MSDOS and GPT). Fix all assumptions that the embed region start at sector 1, using `embed_region.start' from now on. Similarly, use `embed_region.end' rather than `first_start' to calculate available size. In grub_util_info() message, replace "into after the MBR" with an indication of the specific sector our embed region starts at. diff -x '*~' -Nurp ../grub2/partmap/gpt.c ./partmap/gpt.c --- ../grub2/partmap/gpt.c 2007-07-21 19:32:30.000000000 -0400 +++ ./partmap/gpt.c 2008-02-16 19:49:14.000000000 -0500 @@ -1,7 +1,7 @@ /* gpt.c - Read GUID Partition Tables (GPT). */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2005,2006,2007 Free Software Foundation, Inc. + * 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 @@ -23,41 +23,14 @@ #include #include #include - -struct grub_gpt_header -{ - grub_uint8_t magic[8]; - grub_uint32_t version; - grub_uint32_t headersize; - grub_uint32_t crc32; - grub_uint32_t unused1; - grub_uint64_t primary; - grub_uint64_t backup; - grub_uint64_t start; - grub_uint64_t end; - grub_uint8_t guid[16]; - grub_uint64_t partitions; - grub_uint32_t maxpart; - grub_uint32_t partentry_size; - grub_uint32_t partentry_crc32; -} __attribute__ ((packed)); - -struct grub_gpt_partentry -{ - grub_uint8_t type[16]; - grub_uint8_t guid[16]; - grub_uint64_t start; - grub_uint64_t end; - grub_uint8_t attrib; - char name[72]; -} __attribute__ ((packed)); +#include static grub_uint8_t grub_gpt_magic[8] = { 45, 46, 49, 20, 50, 41, 52, 54 }; -static grub_uint8_t grub_gpt_partition_type_empty[16] = { 0 }; +static const grub_gpt_part_type_t grub_gpt_partition_type_empty = GRUB_GPT_PARTITION_TYPE_EMPTY; static struct grub_partition_map grub_gpt_partition_map; @@ -114,7 +87,7 @@ gpt_partition_map_iterate (grub_disk_t d sizeof (entry), (char *) &entry)) return grub_errno; - if (grub_memcmp (grub_gpt_partition_type_empty, entry.type, + 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. */ @@ -124,6 +97,7 @@ gpt_partition_map_iterate (grub_disk_t d part.offset = entries; part.index = partno; part.partmap = &grub_gpt_partition_map; + part.data = &entry; grub_dprintf ("gpt", "GPT entry %d: start=%lld, length=%lld\n", partno, part.start, part.len); diff -x '*~' -Nurp ../grub2/include/grub/gpt_partition.h ./include/grub/gpt_partition.h --- ../grub2/include/grub/gpt_partition.h 1969-12-31 19:00:00.000000000 -0500 +++ ./include/grub/gpt_partition.h 2008-02-16 19:46:30.000000000 -0500 @@ -0,0 +1,71 @@ +/* + * 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 . + */ + +#ifndef GRUB_GPT_PARTITION_HEADER +#define GRUB_GPT_PARTITION_HEADER 1 + +#include + +struct grub_gpt_part_type +{ + grub_uint32_t data1; + grub_uint16_t data2; + grub_uint16_t data3; + grub_uint8_t data4[8]; +} __attribute__ ((aligned(8))); +typedef struct grub_gpt_part_type grub_gpt_part_type_t; + +#define GRUB_GPT_PARTITION_TYPE_EMPTY \ + { 0x0, 0x0, 0x0, \ + { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } \ + } + +#define GRUB_GPT_PARTITION_TYPE_BIOS_BOOT \ + { 0x6b6f6f4c, 0x6449, 0x6e6f, \ + { 0x74, 0x4e, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 } \ + } + +struct grub_gpt_header +{ + grub_uint8_t magic[8]; + grub_uint32_t version; + grub_uint32_t headersize; + grub_uint32_t crc32; + grub_uint32_t unused1; + grub_uint64_t primary; + grub_uint64_t backup; + grub_uint64_t start; + grub_uint64_t end; + grub_uint8_t guid[16]; + grub_uint64_t partitions; + grub_uint32_t maxpart; + grub_uint32_t partentry_size; + grub_uint32_t partentry_crc32; +} __attribute__ ((packed)); + +struct grub_gpt_partentry +{ + grub_gpt_part_type_t type; + grub_uint8_t guid[16]; + grub_uint64_t start; + grub_uint64_t end; + grub_uint8_t attrib; + char name[72]; +} __attribute__ ((packed)); + +#endif /* ! GRUB_GPT_PARTITION_HEADER */ diff -x '*~' -Nurp ../grub2/util/i386/pc/grub-setup.c ./util/i386/pc/grub-setup.c --- ../grub2/util/i386/pc/grub-setup.c 2008-02-16 18:45:53.000000000 -0500 +++ ./util/i386/pc/grub-setup.c 2008-02-16 19:47:21.000000000 -0500 @@ -1,7 +1,7 @@ /* grub-setup.c - make GRUB usable */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007 Free Software Foundation, Inc. + * Copyright (C) 1999,2000,2001,2002,2003,2004,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 @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -34,6 +35,8 @@ #include #include +static const grub_gpt_part_type_t grub_gpt_partition_type_bios_boot = GRUB_GPT_PARTITION_TYPE_BIOS_BOOT; + #include #include @@ -106,7 +109,8 @@ setup (const char *prefix, const char *d grub_uint16_t last_length = GRUB_DISK_SECTOR_SIZE; grub_file_t file; FILE *fp; - unsigned long first_start = ~0UL; + struct { grub_uint64_t start; grub_uint64_t end; } embed_region; + embed_region.start = embed_region.end = ~0UL; int able_to_embed = 1; auto void NESTED_FUNC_ATTR save_first_sector (grub_disk_addr_t sector, unsigned offset, @@ -114,25 +118,37 @@ setup (const char *prefix, const char *d auto void NESTED_FUNC_ATTR save_blocklists (grub_disk_addr_t sector, unsigned offset, unsigned length); - auto int find_first_partition_start (grub_disk_t disk, - const grub_partition_t p); - - int find_first_partition_start (grub_disk_t disk __attribute__ ((unused)), - const grub_partition_t p) + auto int find_usable_region (grub_disk_t disk, + const grub_partition_t p); + int find_usable_region (grub_disk_t disk __attribute__ ((unused)), + const grub_partition_t p) { if (! strcmp (p->partmap->name, "pc_partition_map")) { struct grub_pc_partition *pcdata = p->data; + /* There's always an embed region, and it starts right after the MBR. */ + embed_region.start = 1; + + /* For its end offset, include as many dummy partitions as we can. */ if (! grub_pc_partition_is_empty (pcdata->dos_type) && ! grub_pc_partition_is_bsd (pcdata->dos_type) - && first_start > p->start) - first_start = p->start; + && embed_region.end > p->start) + embed_region.end = p->start; } else - /* In other partition maps, the region after MBR and before first - partition is not reserved (on GPT, it contains the primary header). */ - first_start = 0; + { + struct grub_gpt_partentry *gptdata = p->data; + + /* If there's an embed region, it is in a dedicated partition. */ + if (! memcmp (&gptdata->type, &grub_gpt_partition_type_bios_boot, 16)) + { + embed_region.start = p->start; + embed_region.end = p->start + p->len; + + return 1; + } + } return 0; } @@ -262,15 +278,15 @@ setup (const char *prefix, const char *d try to embed the core image into after the MBR. */ if (dest_dev->disk->has_partitions && ! dest_dev->disk->partition) { - grub_partition_iterate (dest_dev->disk, find_first_partition_start); + grub_partition_iterate (dest_dev->disk, find_usable_region); /* If there is enough space... */ - if ((unsigned long) core_sectors + 1 <= first_start) + if ((unsigned long) core_sectors <= embed_region.end - embed_region.start) { - grub_util_info ("will embed the core image into after the MBR"); - + grub_util_info ("will embed the core image at sector 0x%llx", embed_region.start); + /* The first blocklist contains the whole sectors. */ - first_block->start = grub_cpu_to_le64 (2); + first_block->start = grub_cpu_to_le64 (embed_region.start + 1); first_block->len = grub_cpu_to_le16 (core_sectors - 1); first_block->segment = grub_cpu_to_le16 (GRUB_BOOT_MACHINE_KERNEL_SEG @@ -316,13 +332,13 @@ setup (const char *prefix, const char *d strcpy (install_prefix, prefix); /* Write the core image onto the disk. */ - if (grub_disk_write (dest_dev->disk, 1, 0, core_size, core_img)) + if (grub_disk_write (dest_dev->disk, embed_region.start, 0, core_size, core_img)) grub_util_error ("%s", grub_errmsg); /* The boot image and the core image are on the same drive, so there is no need to specify the boot drive explicitly. */ *boot_drive = 0xff; - *kernel_sector = grub_cpu_to_le64 (1); + *kernel_sector = grub_cpu_to_le64 (embed_region.start); /* If the root device is different from the destination device, it is necessary to embed the root drive explicitly. */