diff --git a/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/package.use b/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/package.use
index 7d9d6e8e1b..d44cd8eaec 100644
--- a/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/package.use
+++ b/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/package.use
@@ -39,7 +39,7 @@ net-firewall/ipset -modules
dev-libs/glib -mime
# keep grub build simple
-sys-boot/grub -multislot -nls -themes
+sys-boot/grub -multislot -nls -themes -fonts
# disable "high performance ssh" patch, turn on kerberos
net-misc/openssh -hpn kerberos
diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/README.md b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/README.md
new file mode 100644
index 0000000000..c41786a2bc
--- /dev/null
+++ b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/README.md
@@ -0,0 +1,460 @@
+Flatcar uses a patched version of the GRUB, which implements the functionality to
+read the [Flatcar Container Linux partition table](https://www.flatcar.org/docs/latest/reference/developer-guides/sdk-disk-partitions/#partition-table)
+
+## History
+
+CoreOS Container Linux maintained a fork of the [grub](https://github.com/coreos/grub) and then was referenced
+in the coreos-overlay. Any changes were made through [PRs](https://github.com/coreos/grub/pulls?q=is%3Apr+is%3Aclosed) to the grub repository.
+
+When Flatcar was born, a `grub` repo under the flatcar-linux org was created
+and referenced in the Flatcar's coreos-overlay. Except for a few, now many changes
+where brought into the system.
+
+The repo was maintained at 2.02 version. During the 2.06 migration, the philosophy
+to use a separate repo was scraped, and a single patch file was created. The patch
+files migrated only the essential commits, and dropped all the other commits, which
+were either half-baked, or redundant at the point of migration. The two patches are applied
+on top of the grub sources, and emerge is done.
+
+Given below are the list of commits that were referenced to create the two patches.
+
+## Summary of the patches
+
+The patch starts with adding a new implementation of reading the GPT instead
+of using the traditional module. It provides essential functionality to interact
+with GPT structures on disk, and checking/validating data integrity & GPT specification.
+
+The commits goes on to add the following modules gptprio, gptrepair, and search
+commands by label and partition.
+
+The `gptprio` command which provides a mechanism to prioritize and select the
+next bootable partition based on the GPT attributes and results in flexible
+partition booting. The `gptrepair` command implements the repair functions for
+GPT information on a specified device. Few other functions include searching
+devices by partition label or partition UUID.
+
+## Commits
+
+Below are the commits that are picked to create the two patches for the grub. One is
+descriptive, and other is comprehensive.
+
+
+ (click to expand) The descriptive log for all the commits picked
+
+```
+commit f69a9e0fdcf63ac33906e2753e14152bab2fcd05
+Author: Michael Marineau
+Date: Sun Sep 28 21:26:21 2014 -0700
+
+ gpt: start new GPT module
+
+ This module is a new implementation for reading GUID Partition Tables
+ which is much stricter than the existing part_gpt module and exports GPT
+ data directly instead of the generic grub_partition structure. It will
+ be the basis for modules that need to read/write/update GPT data.
+
+ The current code does nothing more than read and verify the table.
+
+commit c26743a145c918958b862d580c4261735d1c1a6e
+Author: Michael Marineau
+Date: Sat Oct 18 15:39:13 2014 -0700
+
+ gpt: rename misnamed header location fields
+
+ The header location fields refer to 'this header' and 'alternate header'
+ respectively, not 'primary header' and 'backup header'. The previous
+ field names are backwards for the backup header.
+
+commit 94f04a532d2b0e2b81e47a92488ebb1613bda1a0
+Author: Michael Marineau
+Date: Sat Oct 18 16:46:17 2014 -0700
+
+ gpt: record size of of the entries table
+
+ The size of the entries table will be needed later when writing it back
+ to disk. Restructure the entries reading code to flow a little better.
+
+commit 3d066264ac13198e45dc151b863a9aac4c095225
+Author: Michael Marineau
+Date: Sat Oct 18 18:18:17 2014 -0700
+
+ gpt: consolidate crc32 computation code
+
+ The gcrypt API is overly verbose, wrap it up in a helper function to
+ keep this rather common operation easy to use.
+
+commit dab6fac705bdad7e6ec130b24085189bcb15a5c9
+Author: Michael Marineau
+Date: Sat Oct 18 18:21:07 2014 -0700
+
+ gpt: add new repair function to sync up primary and backup tables.
+
+commit 5e1829d4141343617b5e13e84298d118eac15bdf
+Author: Michael Marineau
+Date: Sun Oct 19 14:21:29 2014 -0700
+
+ gpt: add write function and gptrepair command
+
+ The first hint of something practical, a command that can restore any of
+ the GPT structures from the alternate location. New test case must run
+ under QEMU because the loopback device used by the other unit tests does
+ not support writing.
+
+commit 2cd009dffe98c19672394608661767e4c3c84764
+Author: Michael Marineau
+Date: Thu Oct 30 20:55:21 2014 -0700
+
+ gpt: add a new generic GUID type
+
+ In order to do anything with partition GUIDs they need to be stored in a
+ proper structure like the partition type GUIDs. Additionally add an
+ initializer macro to simplify defining both GUID types.
+
+commit 508b02fc8a1fe58413ec8938ed1a7b149b5855fe
+Author: Michael Marineau
+Date: Mon Nov 3 17:14:37 2014 -0800
+
+ gpt: new gptprio.next command for selecting priority based partitions
+
+ Basic usage would look something like this:
+
+ gptprio.next -d usr_dev -u usr_uuid
+ linuxefi ($usr_dev)/boot/vmlinuz mount.usr=PARTUUID=$usr_uuid
+
+ After booting the system should set the 'successful' bit on the
+ partition that was used.
+
+commit f8f6f790aa7448a35c2e3aae2d1a35d9d323a1b2
+Author: Michael Marineau
+Date: Sat Nov 15 13:27:13 2014 -0800
+
+ gpt: split out checksum recomputation
+
+ For basic data modifications the full repair function is overkill.
+
+commit d9bdbc10485a5c6f610569077631294683da4e34
+Author: Michael Marineau
+Date: Thu Nov 27 12:55:53 2014 -0800
+
+ gpt: move gpt guid printing function to common library
+
+commit ffb13159f1e88d8c66954c3dfbeb027f943b3b1d
+Author: Michael Marineau
+Date: Thu Nov 27 14:54:27 2014 -0800
+
+ gpt: switch partition names to a 16 bit type
+
+ In UEFI/GPT strings are UTF-16 so use a uint16 to make dealing with the
+ string practical.
+
+commit febf4666fbabc3ab4eaab32f4972b45b5c64c06d
+Author: Michael Marineau
+Date: Thu Nov 27 15:49:57 2014 -0800
+
+ tests: add some partitions to the gpt unit test data
+
+commit 67475f53e0ac4a844f793296ba2e4af707d5b20e
+Author: Michael Marineau
+Date: Thu Nov 27 16:34:21 2014 -0800
+
+ gpt: add search by partition label and uuid commands
+
+ Builds on the existing filesystem search code. Only for GPT right now.
+
+commit d1270a2ba31cc3dd747d410a907f272ff03a6d68
+Author: Michael Marineau
+Date: Fri Jul 31 15:03:11 2015 -0700
+
+ gpt: clean up little-endian crc32 computation
+
+ - Remove problematic cast from *uint8_t to *uint32_t (alignment issue).
+ - Remove dynamic allocation and associated error handling paths.
+ - Match parameter ordering to existing grub_crypto_hash function.
+
+commit bacbed2c07f4b4e21c70310814a75fa9a1c3a155
+Author: Alex Crawford
+Date: Mon Aug 31 15:23:39 2015 -0700
+
+ gpt: minor cleanup
+
+commit 1545295ad49d2aff2b75c6c0e7db58214351768e
+Author: Alex Crawford
+Date: Mon Aug 31 15:15:48 2015 -0700
+
+ gpt: add search by disk uuid command
+
+commit 6d4ea47541db4e0a1eab81de8843a491973e6b40
+Author: Michael Marineau
+Date: Mon Jul 25 14:59:29 2016 -0700
+
+ gpt: do not use disk sizes GRUB will reject as invalid later on
+
+ GRUB assumes that no disk is ever larger than 1EiB and rejects
+ reads/writes to such locations. Unfortunately this is not conveyed in
+ the usual way with the special GRUB_DISK_SIZE_UNKNOWN value.
+
+commit 99959fa2fb8bfafadc1fa5aec773a8d605a1df4e
+Author: Michael Marineau
+Date: Wed Aug 10 18:26:03 2016 -0700
+
+ gpt: add verbose debug logging
+
+commit f6b89ec3156a549999a13b3d15e9a67b4a9bf824
+Author: Michael Marineau
+Date: Wed Aug 10 18:26:03 2016 -0700
+
+ gpt: improve validation of GPT headers
+
+ Adds basic validation of all the disk locations in the headers, reducing
+ the chance of corrupting weird locations on disk.
+
+commit fa18d3a292bdcd61012d549c61e25d557481a05e
+Author: Michael Marineau
+Date: Thu Aug 11 15:02:21 2016 -0700
+
+ gpt: refuse to write to sector 0
+
+commit b1ef48849c8dc12756793567520dfd3654539a27
+Author: Michael Marineau
+Date: Sat Aug 20 17:42:12 2016 -0700
+
+ gpt: properly detect and repair invalid tables
+
+ GPT_BOTH_VALID is 4 bits so simple a boolean check is not sufficient.
+ This broken condition allowed gptprio to trust bogus disk locations in
+ headers that were marked invalid causing arbitrary disk corruption.
+
+commit 9af98c2bfd31a73b899268e67f01bca785681d52
+Author: Michael Marineau
+Date: Mon Aug 22 16:44:30 2016 -0700
+
+ gptrepair_test: fix typo in cleanup trap
+
+commit d457364d1d811ad262519cf6dde3d098caf7c778
+Author: Michael Marineau
+Date: Mon Aug 22 16:45:10 2016 -0700
+
+ gptprio_test: check GPT is repaired when appropriate
+
+commit 3a3e45823dd677b428ceb40d8963676aff63f8d2
+Author: Michael Marineau
+Date: Mon Aug 22 18:30:56 2016 -0700
+
+ fix checking alternate_lba
+
+commit 72b178950d313d567dfdf11f403199370d81a9f3
+Author: Michael Marineau
+Date: Wed Aug 24 16:14:20 2016 -0700
+
+ gpt: fix partition table indexing and validation
+
+ Portions of the code attempted to handle the fact that GPT entries on
+ disk may be larger than the currently defined struct while others
+ assumed the data could be indexed by the struct size directly. This
+ never came up because no utility uses a size larger than 128 bytes but
+ for the sake of safety we need to do this by the spec.
+
+commit 1d358a2061f40ad89567754f4787d0c76001d48a
+Author: Michael Marineau
+Date: Tue Aug 23 13:09:14 2016 -0700
+
+ gpt: prefer disk size from header over firmware
+
+ The firmware and the OS may disagree on the disk configuration and size.
+ Although such a setup should be avoided users are unlikely to know about
+ the problem, assuming everything behaves like the OS. Tolerate this as
+ best we can and trust the reported on-disk location over the firmware
+ when looking for the backup GPT. If the location is inaccessible report
+ the error as best we can and move on.
+
+commit 2ed905dc03c757c92064486b380f59166cc704e8
+Author: Vito Caputo
+Date: Thu Aug 25 17:21:18 2016 -0700
+
+ gpt: add helper for picking a valid header
+
+ Eliminate some repetition in primary vs. backup header acquisition.
+
+commit 4af1d7a8b7d0cefa41a1ea4df050b161ea6cdf50
+Author: Michael Marineau
+Date: Tue Sep 20 13:06:05 2016 -0700
+
+ gptrepair: fix status checking
+
+ None of these status bit checks were correct. Fix and simplify.
+
+commit a794435ae9f5b1a2e0281d36b10545c6e643fd8d
+Author: Michael Marineau
+Date: Tue Sep 20 12:43:01 2016 -0700
+
+ gpt: use inline functions for checking status bits
+
+ This should prevent bugs like 6078f836 and 4268f3da.
+
+commit 38cc185319b74d7d33ad380fe4d519fb0b0c85a6
+Author: Michael Marineau
+Date: Tue Sep 20 13:40:11 2016 -0700
+
+ gpt: allow repair function to noop
+
+ Simplifies usage a little.
+
+commit 2aeadda52929bb47089ef99c2bad0f928eadeffa
+Author: Michael Marineau
+Date: Wed Sep 21 13:22:06 2016 -0700
+
+ gpt: do not use an enum for status bit values
+
+commit 34652e500d64dc747ca17091b4490f9adf93ff82
+Author: Michael Marineau
+Date: Wed Sep 21 13:44:11 2016 -0700
+
+ gpt: check header and entries status bits together
+
+ Use the new status function which checks *_HEADER_VALID and
+ *_ENTRIES_VALID bits together. It doesn't make sense for the header and
+ entries bits to mismatch so don't allow for it.
+
+commit 753dd9201306e8cd7092a1231ceb194524397b04
+Author: Michael Marineau
+Date: Wed Sep 21 13:52:52 2016 -0700
+
+ gpt: be more careful about relocating backup header
+
+ The header was being relocated without checking the new location is
+ actually safe. If the BIOS thinks the disk is smaller than the OS then
+ repair may relocate the header into allocated space, failing the final
+ validation check. So only move it if the disk has grown.
+
+ Additionally, if the backup is valid then we can assume its current
+ location is good enough and leave it as-is.
+
+commit f1f618740d1379000b04130a632f4d53bc2392b8
+Author: Michael Marineau
+Date: Wed Sep 21 14:33:48 2016 -0700
+
+ gpt: selectively update fields during repair
+
+ Just a little cleanup/refactor to skip touching data we don't need to.
+
+commit 285368e3753b1dbd631c1f5a4a127b7321a6941f
+Author: Michael Marineau
+Date: Wed Sep 21 14:55:19 2016 -0700
+
+ gpt: always revalidate when recomputing checksums
+
+ This ensures all code modifying GPT data include the same sanity check
+ that repair does. If revalidation fails the status flags are left in the
+ appropriate state.
+
+commit f19f5cc49dc00752f6b267c2d580a25c31697afb
+Author: Michael Marineau
+Date: Wed Sep 21 15:01:09 2016 -0700
+
+ gpt: include backup-in-sync check in revalidation
+
+commit 7b25acebc343895adf942975bba5a52ef3408437
+Author: Michael Marineau
+Date: Wed Sep 21 15:29:55 2016 -0700
+
+ gpt: read entries table at the same time as the header
+
+ I personally think this reads easier. Also has the side effect of
+ directly comparing the primary and backup tables instead of presuming
+ they are equal if the crc32 matches.
+
+commit edd01f055a8a8f922491ba7077bf26fcaf015516
+Author: Michael Marineau
+Date: Wed Sep 21 16:02:53 2016 -0700
+
+ gpt: report all revalidation errors
+
+ Before returning an error that the primary or backup GPT is invalid push
+ the existing error onto the stack so the user will be told what is bad.
+
+commit 176fe49cf03ffdd72b8bd174a149032c3867ddde
+Author: Michael Marineau
+Date: Thu Sep 22 10:00:27 2016 -0700
+
+ gpt: rename and update documentation for grub_gpt_update
+
+ The function now does more than just recompute checksums so give it a
+ more general name to reflect that.
+
+commit eb28d32081be2d224874c430345e7ef97bfbba07
+Author: Michael Marineau
+Date: Thu Sep 22 11:18:42 2016 -0700
+
+ gpt: write backup GPT first, skip if inaccessible.
+
+ Writing the primary GPT before the backup may lead to a confusing
+ situation: booting a freshly updated system could consistently fail and
+ next boot will fall back to the old system if writing the primary works
+ but writing the backup fails. If the backup is written first and fails
+ the primary is left in the old state so the next boot will re-try and
+ possibly fail in the exact same way. Making that repeatable should make
+ it easier for users to identify the error.
+
+ Additionally if the firmware and OS disagree on the disk size, making
+ the backup inaccessible to GRUB, then just skip writing the backup.
+ When this happens the automatic call to `coreos-setgoodroot` after boot
+ will take care of repairing the backup.
+
+commit 03b547c21ec3475980a54b71e909034ed5ed5254
+Author: Matthew Garrett
+Date: Thu May 28 11:15:30 2015 -0700
+
+ Add verity hash passthrough
+
+ Read the verity hash from the kernel binary and pass it to the running
+ system via the kernel command line
+```
+
+
+
+ (click to expand) Comprehensive log of the commits
+
+```
+f69a9e0fd gpt: start new GPT module
+c26743a14 gpt: rename misnamed header location fields
+94f04a532 gpt: record size of of the entries table
+3d066264a gpt: consolidate crc32 computation code
+dab6fac70 gpt: add new repair function to sync up primary and backup tables.
+5e1829d41 gpt: add write function and gptrepair command
+2cd009dff gpt: add a new generic GUID type
+508b02fc8 gpt: new gptprio.next command for selecting priority based partitions
+f8f6f790a gpt: split out checksum recomputation
+d9bdbc104 gpt: move gpt guid printing function to common library
+ffb13159f gpt: switch partition names to a 16 bit type
+febf4666f tests: add some partitions to the gpt unit test data
+67475f53e gpt: add search by partition label and uuid commands
+d1270a2ba gpt: clean up little-endian crc32 computation
+bacbed2c0 gpt: minor cleanup
+1545295ad gpt: add search by disk uuid command
+6d4ea4754 gpt: do not use disk sizes GRUB will reject as invalid later on
+99959fa2f gpt: add verbose debug logging
+f6b89ec31 gpt: improve validation of GPT headers
+fa18d3a29 gpt: refuse to write to sector 0
+b1ef48849 gpt: properly detect and repair invalid tables
+9af98c2bf gptrepair_test: fix typo in cleanup trap
+d457364d1 gptprio_test: check GPT is repaired when appropriate
+3a3e45823 fix checking alternate_lba
+72b178950 gpt: fix partition table indexing and validation
+1d358a206 gpt: prefer disk size from header over firmware
+2ed905dc0 gpt: add helper for picking a valid header
+4af1d7a8b gptrepair: fix status checking
+a794435ae gpt: use inline functions for checking status bits
+38cc18531 gpt: allow repair function to noop
+2aeadda52 gpt: do not use an enum for status bit values
+34652e500 gpt: check header and entries status bits together
+753dd9201 gpt: be more careful about relocating backup header
+f1f618740 gpt: selectively update fields during repair
+285368e37 gpt: always revalidate when recomputing checksums
+f19f5cc49 gpt: include backup-in-sync check in revalidation
+7b25acebc gpt: read entries table at the same time as the header
+edd01f055 gpt: report all revalidation errors
+176fe49cf gpt: rename and update documentation for grub_gpt_update
+eb28d3208 gpt: write backup GPT first, skip if inaccessible.
+03b547c21 Add verity hash passthrough
+```
+
diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-add-gpt-partition-scheme.patch b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-add-gpt-partition-scheme.patch
new file mode 100644
index 0000000000..cef57e856a
--- /dev/null
+++ b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-add-gpt-partition-scheme.patch
@@ -0,0 +1,2792 @@
+From 026cab86883e256607f6df30375bfda4468ae71e Mon Sep 17 00:00:00 2001
+From: Sayan Chowdhury
+Date: Thu, 24 Aug 2023 00:00:00 +0530
+Subject: [PATCH] gpt: Add patch to implement the custom GPT module
+
+This module is a new implementation for reading GUID Partition Tables
+which is much stricter than the existing part_gpt module and exports GPT
+data directly instead of the generic grub_partition structure. It will
+be the basis for modules that need to read/write/update GPT data.
+
+This patch also includes the supporting functions like gptprio,
+gptrepair, search commands.
+
+The patch is prepared using the coreos/grub PRs, picking the only
+required ones, and dropping the others. The README.md file in the
+coreos-overlay/sys-boot/grub/ contains more contexual information
+along with the commits used to create the patch.
+
+Authored-by: Michael Marineau
+Signed-off-by: Sayan Chowdhury
+---
+ Makefile.util.def | 30 +
+ grub-core/Makefile.core.def | 25 +
+ grub-core/commands/gptprio.c | 223 +++++++
+ grub-core/commands/gptrepair.c | 110 ++++
+ grub-core/commands/search.c | 49 ++
+ grub-core/commands/search_part_label.c | 5 +
+ grub-core/commands/search_part_uuid.c | 5 +
+ grub-core/commands/search_wrap.c | 12 +
+ grub-core/lib/gpt.c | 757 +++++++++++++++++++++++
+ include/grub/gpt_partition.h | 211 ++++++-
+ include/grub/search.h | 4 +
+ tests/gpt_unit_test.c | 807 +++++++++++++++++++++++++
+ tests/gptprio_test.in | 207 +++++++
+ tests/gptrepair_test.in | 102 ++++
+ 14 files changed, 2530 insertions(+), 17 deletions(-)
+ create mode 100644 grub-core/commands/gptprio.c
+ create mode 100644 grub-core/commands/gptrepair.c
+ create mode 100644 grub-core/commands/search_part_label.c
+ create mode 100644 grub-core/commands/search_part_uuid.c
+ create mode 100644 grub-core/lib/gpt.c
+ create mode 100644 tests/gpt_unit_test.c
+ create mode 100644 tests/gptprio_test.in
+ create mode 100644 tests/gptrepair_test.in
+
+diff --git a/Makefile.util.def b/Makefile.util.def
+index f8b356cc1..07df521ec 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -1211,6 +1211,18 @@ script = {
+ common = tests/syslinux_test.in;
+ };
+
++script = {
++ testcase;
++ name = gptrepair_test;
++ common = tests/gptrepair_test.in;
++};
++
++script = {
++ testcase;
++ name = gptprio_test;
++ common = tests/gptprio_test.in;
++};
++
+ program = {
+ testcase;
+ name = example_unit_test;
+@@ -1288,6 +1300,24 @@ program = {
+ ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
+ };
+
++program = {
++ testcase;
++ name = gpt_unit_test;
++ common = tests/gpt_unit_test.c;
++ common = tests/lib/unit_test.c;
++ common = grub-core/commands/search_part_label.c;
++ common = grub-core/commands/search_part_uuid.c;
++ common = grub-core/disk/host.c;
++ common = grub-core/kern/emu/hostfs.c;
++ common = grub-core/lib/gpt.c;
++ common = grub-core/tests/lib/test.c;
++ ldadd = libgrubmods.a;
++ ldadd = libgrubgcry.a;
++ ldadd = libgrubkern.a;
++ ldadd = grub-core/gnulib/libgnu.a;
++ ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
++};
++
+ program = {
+ name = grub-menulst2cfg;
+ mansection = 1;
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 8022e1c0a..e9baa2144 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -897,6 +897,21 @@ module = {
+ common = commands/gptsync.c;
+ };
+
++module = {
++ name = gptrepair;
++ common = commands/gptrepair.c;
++};
++
++module = {
++ name = gptprio;
++ common = commands/gptprio.c;
++};
++
++module = {
++ name = gpt;
++ common = lib/gpt.c;
++};
++
+ module = {
+ name = halt;
+ nopc = commands/halt.c;
+@@ -1073,6 +1088,16 @@ module = {
+ common = commands/search_label.c;
+ };
+
++module = {
++ name = search_part_uuid;
++ common = commands/search_part_uuid.c;
++};
++
++module = {
++ name = search_part_label;
++ common = commands/search_part_label.c;
++};
++
+ module = {
+ name = setpci;
+ common = commands/setpci.c;
+diff --git a/grub-core/commands/gptprio.c b/grub-core/commands/gptprio.c
+new file mode 100644
+index 000000000..4a24fa62d
+--- /dev/null
++++ b/grub-core/commands/gptprio.c
+@@ -0,0 +1,223 @@
++/* gptprio.c - manage priority based partition selection. */
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 2009 Free Software Foundation, Inc.
++ * Copyright (C) 2014 CoreOS, 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 .
++ */
++
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++
++GRUB_MOD_LICENSE ("GPLv3+");
++
++static const struct grub_arg_option options_next[] = {
++ {"set-device", 'd', 0,
++ N_("Set a variable to the name of selected partition."),
++ N_("VARNAME"), ARG_TYPE_STRING},
++ {"set-uuid", 'u', 0,
++ N_("Set a variable to the GPT UUID of selected partition."),
++ N_("VARNAME"), ARG_TYPE_STRING},
++ {0, 0, 0, 0, 0, 0}
++};
++
++enum options_next
++{
++ NEXT_SET_DEVICE,
++ NEXT_SET_UUID,
++};
++
++static unsigned int
++grub_gptprio_priority (struct grub_gpt_partentry *entry)
++{
++ return (unsigned int) grub_gpt_entry_attribute
++ (entry, GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_PRIORITY, 4);
++}
++
++static unsigned int
++grub_gptprio_tries_left (struct grub_gpt_partentry *entry)
++{
++ return (unsigned int) grub_gpt_entry_attribute
++ (entry, GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_TRIES_LEFT, 4);
++}
++
++static void
++grub_gptprio_set_tries_left (struct grub_gpt_partentry *entry,
++ unsigned int tries_left)
++{
++ grub_gpt_entry_set_attribute
++ (entry, tries_left, GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_TRIES_LEFT, 4);
++}
++
++static unsigned int
++grub_gptprio_successful (struct grub_gpt_partentry *entry)
++{
++ return (unsigned int) grub_gpt_entry_attribute
++ (entry, GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_SUCCESSFUL, 1);
++}
++
++static grub_err_t
++grub_find_next (const char *disk_name,
++ const grub_gpt_part_type_t *part_type,
++ char **part_name, char **part_guid)
++{
++ struct grub_gpt_partentry *part, *part_found = NULL;
++ grub_device_t dev = NULL;
++ grub_gpt_t gpt = NULL;
++ grub_uint32_t i, part_index;
++
++ dev = grub_device_open (disk_name);
++ if (!dev)
++ goto done;
++
++ gpt = grub_gpt_read (dev->disk);
++ if (!gpt)
++ goto done;
++
++ if (grub_gpt_repair (dev->disk, gpt))
++ goto done;
++
++ for (i = 0; (part = grub_gpt_get_partentry (gpt, i)) != NULL; i++)
++ {
++ if (grub_memcmp (part_type, &part->type, sizeof (*part_type)) == 0)
++ {
++ unsigned int priority, tries_left, successful, old_priority = 0;
++
++ priority = grub_gptprio_priority (part);
++ tries_left = grub_gptprio_tries_left (part);
++ successful = grub_gptprio_successful (part);
++
++ if (part_found)
++ old_priority = grub_gptprio_priority (part_found);
++
++ if ((tries_left || successful) && priority > old_priority)
++ {
++ part_index = i;
++ part_found = part;
++ }
++ }
++ }
++
++ if (!part_found)
++ {
++ grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("no such partition"));
++ goto done;
++ }
++
++ if (grub_gptprio_tries_left (part_found))
++ {
++ unsigned int tries_left = grub_gptprio_tries_left (part_found);
++
++ grub_gptprio_set_tries_left (part_found, tries_left - 1);
++
++ if (grub_gpt_update (gpt))
++ goto done;
++
++ if (grub_gpt_write (dev->disk, gpt))
++ goto done;
++ }
++
++ *part_name = grub_xasprintf ("%s,gpt%u", disk_name, part_index + 1);
++ if (!*part_name)
++ goto done;
++
++ *part_guid = grub_gpt_guid_to_str (&part_found->guid);
++ if (!*part_guid)
++ goto done;
++
++ grub_errno = GRUB_ERR_NONE;
++
++done:
++ grub_gpt_free (gpt);
++
++ if (dev)
++ grub_device_close (dev);
++
++ return grub_errno;
++}
++
++
++
++static grub_err_t
++grub_cmd_next (grub_extcmd_context_t ctxt, int argc, char **args)
++{
++ struct grub_arg_list *state = ctxt->state;
++ char *p, *root = NULL, *part_name = NULL, *part_guid = NULL;
++
++ /* TODO: Add a uuid parser and a command line flag for providing type. */
++ grub_gpt_part_type_t part_type = GRUB_GPT_PARTITION_TYPE_USR_X86_64;
++
++ if (!state[NEXT_SET_DEVICE].set || !state[NEXT_SET_UUID].set)
++ {
++ grub_error (GRUB_ERR_INVALID_COMMAND, N_("-d and -u are required"));
++ goto done;
++ }
++
++ if (argc == 0)
++ root = grub_strdup (grub_env_get ("root"));
++ else if (argc == 1)
++ root = grub_strdup (args[0]);
++ else
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unexpected arguments"));
++ goto done;
++ }
++
++ if (!root)
++ goto done;
++
++ /* To make using $root practical strip off the partition name. */
++ p = grub_strchr (root, ',');
++ if (p)
++ *p = '\0';
++
++ if (grub_find_next (root, &part_type, &part_name, &part_guid))
++ goto done;
++
++ if (grub_env_set (state[NEXT_SET_DEVICE].arg, part_name))
++ goto done;
++
++ if (grub_env_set (state[NEXT_SET_UUID].arg, part_guid))
++ goto done;
++
++ grub_errno = GRUB_ERR_NONE;
++
++done:
++ grub_free (root);
++ grub_free (part_name);
++ grub_free (part_guid);
++
++ return grub_errno;
++}
++
++static grub_extcmd_t cmd_next;
++
++GRUB_MOD_INIT(gptprio)
++{
++ cmd_next = grub_register_extcmd ("gptprio.next", grub_cmd_next, 0,
++ N_("-d VARNAME -u VARNAME [DEVICE]"),
++ N_("Select next partition to boot."),
++ options_next);
++}
++
++GRUB_MOD_FINI(gptprio)
++{
++ grub_unregister_extcmd (cmd_next);
++}
+diff --git a/grub-core/commands/gptrepair.c b/grub-core/commands/gptrepair.c
+new file mode 100644
+index 000000000..c17c7346c
+--- /dev/null
++++ b/grub-core/commands/gptrepair.c
+@@ -0,0 +1,110 @@
++/* gptrepair.c - verify and restore GPT info from alternate location. */
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 2009 Free Software Foundation, Inc.
++ * Copyright (C) 2014 CoreOS, 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 .
++ */
++
++#include
++#include
++#include
++#include
++#include
++#include
++
++GRUB_MOD_LICENSE ("GPLv3+");
++
++static char *
++trim_dev_name (char *name)
++{
++ grub_size_t len = grub_strlen (name);
++ if (len && name[0] == '(' && name[len - 1] == ')')
++ {
++ name[len - 1] = '\0';
++ name = name + 1;
++ }
++ return name;
++}
++
++static grub_err_t
++grub_cmd_gptrepair (grub_command_t cmd __attribute__ ((unused)),
++ int argc, char **args)
++{
++ grub_device_t dev = NULL;
++ grub_gpt_t gpt = NULL;
++ char *dev_name;
++
++ if (argc != 1 || !grub_strlen(args[0]))
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
++
++ dev_name = trim_dev_name (args[0]);
++ dev = grub_device_open (dev_name);
++ if (!dev)
++ goto done;
++
++ if (!dev->disk)
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, "not a disk");
++ goto done;
++ }
++
++ gpt = grub_gpt_read (dev->disk);
++ if (!gpt)
++ goto done;
++
++ if (grub_gpt_both_valid (gpt))
++ {
++ grub_printf_ (N_("GPT already valid, %s unmodified.\n"), dev_name);
++ goto done;
++ }
++
++ if (!grub_gpt_primary_valid (gpt))
++ grub_printf_ (N_("Found invalid primary GPT on %s\n"), dev_name);
++
++ if (!grub_gpt_backup_valid (gpt))
++ grub_printf_ (N_("Found invalid backup GPT on %s\n"), dev_name);
++
++ if (grub_gpt_repair (dev->disk, gpt))
++ goto done;
++
++ if (grub_gpt_write (dev->disk, gpt))
++ goto done;
++
++ grub_printf_ (N_("Repaired GPT on %s\n"), dev_name);
++
++done:
++ if (gpt)
++ grub_gpt_free (gpt);
++
++ if (dev)
++ grub_device_close (dev);
++
++ return grub_errno;
++}
++
++static grub_command_t cmd;
++
++GRUB_MOD_INIT(gptrepair)
++{
++ cmd = grub_register_command ("gptrepair", grub_cmd_gptrepair,
++ N_("DEVICE"),
++ N_("Verify and repair GPT on drive DEVICE."));
++}
++
++GRUB_MOD_FINI(gptrepair)
++{
++ grub_unregister_command (cmd);
++}
+diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c
+index ed090b3af..4ad72c5b4 100644
+--- a/grub-core/commands/search.c
++++ b/grub-core/commands/search.c
+@@ -30,6 +30,9 @@
+ #include
+ #include
+ #include
++#if defined(DO_SEARCH_PART_UUID) || defined(DO_SEARCH_PART_LABEL)
++#include
++#endif
+
+ GRUB_MOD_LICENSE ("GPLv3+");
+
+@@ -90,6 +93,44 @@ iterate_device (const char *name, void *data)
+ }
+ grub_free (buf);
+ }
++#elif defined(DO_SEARCH_PART_UUID)
++ {
++ grub_device_t dev;
++ char *quid;
++
++ dev = grub_device_open (name);
++ if (dev)
++ {
++ if (grub_gpt_part_uuid (dev, &quid) == GRUB_ERR_NONE)
++ {
++ if (grub_strcasecmp (quid, ctx->key) == 0)
++ found = 1;
++
++ grub_free (quid);
++ }
++
++ grub_device_close (dev);
++ }
++ }
++#elif defined(DO_SEARCH_PART_LABEL)
++ {
++ grub_device_t dev;
++ char *quid;
++
++ dev = grub_device_open (name);
++ if (dev)
++ {
++ if (grub_gpt_part_label (dev, &quid) == GRUB_ERR_NONE)
++ {
++ if (grub_strcmp (quid, ctx->key) == 0)
++ found = 1;
++
++ grub_free (quid);
++ }
++
++ grub_device_close (dev);
++ }
++ }
+ #else
+ {
+ /* SEARCH_FS_UUID or SEARCH_LABEL */
+@@ -313,6 +354,10 @@ static grub_command_t cmd;
+
+ #ifdef DO_SEARCH_FILE
+ GRUB_MOD_INIT(search_fs_file)
++#elif defined(DO_SEARCH_PART_UUID)
++GRUB_MOD_INIT(search_part_uuid)
++#elif defined(DO_SEARCH_PART_LABEL)
++GRUB_MOD_INIT(search_part_label)
+ #elif defined (DO_SEARCH_FS_UUID)
+ GRUB_MOD_INIT(search_fs_uuid)
+ #else
+@@ -327,6 +372,10 @@ GRUB_MOD_INIT(search_label)
+
+ #ifdef DO_SEARCH_FILE
+ GRUB_MOD_FINI(search_fs_file)
++#elif defined(DO_SEARCH_PART_UUID)
++GRUB_MOD_FINI(search_part_uuid)
++#elif defined(DO_SEARCH_PART_LABEL)
++GRUB_MOD_FINI(search_part_label)
+ #elif defined (DO_SEARCH_FS_UUID)
+ GRUB_MOD_FINI(search_fs_uuid)
+ #else
+diff --git a/grub-core/commands/search_part_label.c b/grub-core/commands/search_part_label.c
+new file mode 100644
+index 000000000..ca906cbd9
+--- /dev/null
++++ b/grub-core/commands/search_part_label.c
+@@ -0,0 +1,5 @@
++#define DO_SEARCH_PART_LABEL 1
++#define FUNC_NAME grub_search_part_label
++#define COMMAND_NAME "search.part_label"
++#define HELP_MESSAGE N_("Search devices by partition label. If VARIABLE is specified, the first device found is set to a variable.")
++#include "search.c"
+diff --git a/grub-core/commands/search_part_uuid.c b/grub-core/commands/search_part_uuid.c
+new file mode 100644
+index 000000000..2d1d3d0d7
+--- /dev/null
++++ b/grub-core/commands/search_part_uuid.c
+@@ -0,0 +1,5 @@
++#define DO_SEARCH_PART_UUID 1
++#define FUNC_NAME grub_search_part_uuid
++#define COMMAND_NAME "search.part_uuid"
++#define HELP_MESSAGE N_("Search devices by partition UUID. If VARIABLE is specified, the first device found is set to a variable.")
++#include "search.c"
+diff --git a/grub-core/commands/search_wrap.c b/grub-core/commands/search_wrap.c
+index 47fc8eb99..d357454a9 100644
+--- a/grub-core/commands/search_wrap.c
++++ b/grub-core/commands/search_wrap.c
+@@ -36,6 +36,10 @@ static const struct grub_arg_option options[] =
+ 0, 0},
+ {"fs-uuid", 'u', 0, N_("Search devices by a filesystem UUID."),
+ 0, 0},
++ {"part-label", 'L', 0, N_("Search devices by a partition label."),
++ 0, 0},
++ {"part-uuid", 'U', 0, N_("Search devices by a partition UUID."),
++ 0, 0},
+ {"set", 's', GRUB_ARG_OPTION_OPTIONAL,
+ N_("Set a variable to the first device found."), N_("VARNAME"),
+ ARG_TYPE_STRING},
+@@ -71,6 +75,8 @@ enum options
+ SEARCH_FILE,
+ SEARCH_LABEL,
+ SEARCH_FS_UUID,
++ SEARCH_PART_LABEL,
++ SEARCH_PART_UUID,
+ SEARCH_SET,
+ SEARCH_NO_FLOPPY,
+ SEARCH_HINT,
+@@ -186,6 +192,12 @@ grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args)
+ else if (state[SEARCH_FS_UUID].set)
+ grub_search_fs_uuid (id, var, state[SEARCH_NO_FLOPPY].set,
+ hints, nhints);
++ else if (state[SEARCH_PART_LABEL].set)
++ grub_search_part_label (id, var, state[SEARCH_NO_FLOPPY].set,
++ hints, nhints);
++ else if (state[SEARCH_PART_UUID].set)
++ grub_search_part_uuid (id, var, state[SEARCH_NO_FLOPPY].set,
++ hints, nhints);
+ else if (state[SEARCH_FILE].set)
+ grub_search_fs_file (id, var, state[SEARCH_NO_FLOPPY].set,
+ hints, nhints);
+diff --git a/grub-core/lib/gpt.c b/grub-core/lib/gpt.c
+new file mode 100644
+index 000000000..098fa65c4
+--- /dev/null
++++ b/grub-core/lib/gpt.c
+@@ -0,0 +1,757 @@
++/* gpt.c - Read/Verify/Write GUID Partition Tables (GPT). */
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 2002,2005,2006,2007,2008 Free Software Foundation, Inc.
++ * Copyright (C) 2014 CoreOS, 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 .
++ */
++
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++
++GRUB_MOD_LICENSE ("GPLv3+");
++
++static grub_uint8_t grub_gpt_magic[] = GRUB_GPT_HEADER_MAGIC;
++
++static grub_err_t
++grub_gpt_read_entries (grub_disk_t disk, grub_gpt_t gpt,
++ struct grub_gpt_header *header,
++ void **ret_entries,
++ grub_size_t *ret_entries_size);
++
++char *
++grub_gpt_guid_to_str (grub_gpt_guid_t *guid)
++{
++ return grub_xasprintf ("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
++ grub_le_to_cpu32 (guid->data1),
++ grub_le_to_cpu16 (guid->data2),
++ grub_le_to_cpu16 (guid->data3),
++ guid->data4[0], guid->data4[1],
++ guid->data4[2], guid->data4[3],
++ guid->data4[4], guid->data4[5],
++ guid->data4[6], guid->data4[7]);
++}
++
++static grub_err_t
++grub_gpt_device_partentry (grub_device_t device,
++ struct grub_gpt_partentry *entry)
++{
++ grub_disk_t disk = device->disk;
++ grub_partition_t p;
++ grub_err_t err;
++
++ if (!disk || !disk->partition)
++ return grub_error (GRUB_ERR_BUG, "not a partition");
++
++ if (grub_strcmp (disk->partition->partmap->name, "gpt"))
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "not a GPT partition");
++
++ p = disk->partition;
++ disk->partition = p->parent;
++ err = grub_disk_read (disk, p->offset, p->index, sizeof (*entry), entry);
++ disk->partition = p;
++
++ return err;
++}
++
++grub_err_t
++grub_gpt_part_label (grub_device_t device, char **label)
++{
++ struct grub_gpt_partentry entry;
++ const grub_size_t name_len = ARRAY_SIZE (entry.name);
++ const grub_size_t label_len = name_len * GRUB_MAX_UTF8_PER_UTF16 + 1;
++ grub_size_t i;
++ grub_uint8_t *end;
++
++ if (grub_gpt_device_partentry (device, &entry))
++ return grub_errno;
++
++ *label = grub_malloc (label_len);
++ if (!*label)
++ return grub_errno;
++
++ for (i = 0; i < name_len; i++)
++ entry.name[i] = grub_le_to_cpu16 (entry.name[i]);
++
++ end = grub_utf16_to_utf8 ((grub_uint8_t *) *label, entry.name, name_len);
++ *end = '\0';
++
++ return GRUB_ERR_NONE;
++}
++
++grub_err_t
++grub_gpt_part_uuid (grub_device_t device, char **uuid)
++{
++ struct grub_gpt_partentry entry;
++
++ if (grub_gpt_device_partentry (device, &entry))
++ return grub_errno;
++
++ *uuid = grub_gpt_guid_to_str (&entry.guid);
++ if (!*uuid)
++ return grub_errno;
++
++ return GRUB_ERR_NONE;
++}
++
++static struct grub_gpt_header *
++grub_gpt_get_header (grub_gpt_t gpt)
++{
++ if (gpt->status & GRUB_GPT_PRIMARY_HEADER_VALID)
++ return &gpt->primary;
++ else if (gpt->status & GRUB_GPT_BACKUP_HEADER_VALID)
++ return &gpt->backup;
++
++ grub_error (GRUB_ERR_BUG, "No valid GPT header");
++ return NULL;
++}
++
++static grub_uint64_t
++grub_gpt_size_to_sectors (grub_gpt_t gpt, grub_size_t size)
++{
++ unsigned int sector_size;
++ grub_uint64_t sectors;
++
++ sector_size = 1U << gpt->log_sector_size;
++ sectors = size / sector_size;
++ if (size % sector_size)
++ sectors++;
++
++ return sectors;
++}
++
++/* Copied from grub-core/kern/disk_common.c grub_disk_adjust_range so we can
++ * avoid attempting to use disk->total_sectors when GRUB won't let us.
++ * TODO: Why is disk->total_sectors not set to GRUB_DISK_SIZE_UNKNOWN? */
++static int
++grub_gpt_disk_size_valid (grub_disk_t disk)
++{
++ grub_disk_addr_t total_sectors;
++
++ /* Transform total_sectors to number of 512B blocks. */
++ total_sectors = disk->total_sectors << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS);
++
++ /* Some drivers have problems with disks above reasonable.
++ Treat unknown as 1EiB disk. While on it, clamp the size to 1EiB.
++ Just one condition is enough since GRUB_DISK_UNKNOWN_SIZE << ls is always
++ above 9EiB.
++ */
++ if (total_sectors > (1ULL << 51))
++ return 0;
++
++ return 1;
++}
++
++static void
++grub_gpt_lecrc32 (grub_uint32_t *crc, const void *data, grub_size_t len)
++{
++ grub_uint32_t crc32_val;
++
++ grub_crypto_hash (GRUB_MD_CRC32, &crc32_val, data, len);
++
++ /* GRUB_MD_CRC32 always uses big endian, gpt is always little. */
++ *crc = grub_swap_bytes32 (crc32_val);
++}
++
++static void
++grub_gpt_header_lecrc32 (grub_uint32_t *crc, struct grub_gpt_header *header)
++{
++ grub_uint32_t old, new;
++
++ /* crc32 must be computed with the field cleared. */
++ old = header->crc32;
++ header->crc32 = 0;
++ grub_gpt_lecrc32 (&new, header, sizeof (*header));
++ header->crc32 = old;
++
++ *crc = new;
++}
++
++/* Make sure the MBR is a protective MBR and not a normal MBR. */
++grub_err_t
++grub_gpt_pmbr_check (struct grub_msdos_partition_mbr *mbr)
++{
++ unsigned int i;
++
++ if (mbr->signature !=
++ grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE))
++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid MBR signature");
++
++ for (i = 0; i < sizeof (mbr->entries); i++)
++ if (mbr->entries[i].type == GRUB_PC_PARTITION_TYPE_GPT_DISK)
++ return GRUB_ERR_NONE;
++
++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid protective MBR");
++}
++
++static grub_uint64_t
++grub_gpt_entries_size (struct grub_gpt_header *gpt)
++{
++ return (grub_uint64_t) grub_le_to_cpu32 (gpt->maxpart) *
++ (grub_uint64_t) grub_le_to_cpu32 (gpt->partentry_size);
++}
++
++static grub_uint64_t
++grub_gpt_entries_sectors (struct grub_gpt_header *gpt,
++ unsigned int log_sector_size)
++{
++ grub_uint64_t sector_bytes, entries_bytes;
++
++ sector_bytes = 1ULL << log_sector_size;
++ entries_bytes = grub_gpt_entries_size (gpt);
++ return grub_divmod64(entries_bytes + sector_bytes - 1, sector_bytes, NULL);
++}
++
++static int
++is_pow2 (grub_uint32_t n)
++{
++ return (n & (n - 1)) == 0;
++}
++
++grub_err_t
++grub_gpt_header_check (struct grub_gpt_header *gpt,
++ unsigned int log_sector_size)
++{
++ grub_uint32_t crc = 0, size;
++ grub_uint64_t start, end;
++
++ if (grub_memcmp (gpt->magic, grub_gpt_magic, sizeof (grub_gpt_magic)) != 0)
++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT signature");
++
++ if (gpt->version != GRUB_GPT_HEADER_VERSION)
++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "unknown GPT version");
++
++ grub_gpt_header_lecrc32 (&crc, gpt);
++ if (gpt->crc32 != crc)
++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT header crc32");
++
++ /* The header size "must be greater than or equal to 92 and must be less
++ * than or equal to the logical block size." */
++ size = grub_le_to_cpu32 (gpt->headersize);
++ if (size < 92U || size > (1U << log_sector_size))
++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT header size");
++
++ /* The partition entry size must be "a value of 128*(2^n) where n is an
++ * integer greater than or equal to zero (e.g., 128, 256, 512, etc.)." */
++ size = grub_le_to_cpu32 (gpt->partentry_size);
++ if (size < 128U || size % 128U || !is_pow2 (size / 128U))
++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT entry size");
++
++ /* The minimum entries table size is specified in terms of bytes,
++ * regardless of how large the individual entry size is. */
++ if (grub_gpt_entries_size (gpt) < GRUB_GPT_DEFAULT_ENTRIES_SIZE)
++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT entry table size");
++
++ /* And of course there better be some space for partitions! */
++ start = grub_le_to_cpu64 (gpt->start);
++ end = grub_le_to_cpu64 (gpt->end);
++ if (start > end)
++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid usable sectors");
++
++ return GRUB_ERR_NONE;
++}
++
++static int
++grub_gpt_headers_equal (grub_gpt_t gpt)
++{
++ /* Assume headers passed grub_gpt_header_check so skip magic and version.
++ * Individual fields must be checked instead of just using memcmp because
++ * crc32, header, alternate, and partitions will all normally differ. */
++
++ if (gpt->primary.headersize != gpt->backup.headersize ||
++ gpt->primary.header_lba != gpt->backup.alternate_lba ||
++ gpt->primary.alternate_lba != gpt->backup.header_lba ||
++ gpt->primary.start != gpt->backup.start ||
++ gpt->primary.end != gpt->backup.end ||
++ gpt->primary.maxpart != gpt->backup.maxpart ||
++ gpt->primary.partentry_size != gpt->backup.partentry_size ||
++ gpt->primary.partentry_crc32 != gpt->backup.partentry_crc32)
++ return 0;
++
++ return grub_memcmp(&gpt->primary.guid, &gpt->backup.guid,
++ sizeof(grub_gpt_guid_t)) == 0;
++}
++
++static grub_err_t
++grub_gpt_check_primary (grub_gpt_t gpt)
++{
++ grub_uint64_t backup, primary, entries, entries_len, start, end;
++
++ primary = grub_le_to_cpu64 (gpt->primary.header_lba);
++ backup = grub_le_to_cpu64 (gpt->primary.alternate_lba);
++ entries = grub_le_to_cpu64 (gpt->primary.partitions);
++ entries_len = grub_gpt_entries_sectors(&gpt->primary, gpt->log_sector_size);
++ start = grub_le_to_cpu64 (gpt->primary.start);
++ end = grub_le_to_cpu64 (gpt->primary.end);
++
++ grub_dprintf ("gpt", "Primary GPT layout:\n"
++ "primary header = 0x%llx backup header = 0x%llx\n"
++ "entries location = 0x%llx length = 0x%llx\n"
++ "first usable = 0x%llx last usable = 0x%llx\n",
++ (unsigned long long) primary,
++ (unsigned long long) backup,
++ (unsigned long long) entries,
++ (unsigned long long) entries_len,
++ (unsigned long long) start,
++ (unsigned long long) end);
++
++ if (grub_gpt_header_check (&gpt->primary, gpt->log_sector_size))
++ return grub_errno;
++ if (primary != 1)
++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid primary GPT LBA");
++ if (entries <= 1 || entries+entries_len > start)
++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid entries location");
++ if (backup <= end)
++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid backup GPT LBA");
++
++ return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_gpt_check_backup (grub_gpt_t gpt)
++{
++ grub_uint64_t backup, primary, entries, entries_len, start, end;
++
++ backup = grub_le_to_cpu64 (gpt->backup.header_lba);
++ primary = grub_le_to_cpu64 (gpt->backup.alternate_lba);
++ entries = grub_le_to_cpu64 (gpt->backup.partitions);
++ entries_len = grub_gpt_entries_sectors(&gpt->backup, gpt->log_sector_size);
++ start = grub_le_to_cpu64 (gpt->backup.start);
++ end = grub_le_to_cpu64 (gpt->backup.end);
++
++ grub_dprintf ("gpt", "Backup GPT layout:\n"
++ "primary header = 0x%llx backup header = 0x%llx\n"
++ "entries location = 0x%llx length = 0x%llx\n"
++ "first usable = 0x%llx last usable = 0x%llx\n",
++ (unsigned long long) primary,
++ (unsigned long long) backup,
++ (unsigned long long) entries,
++ (unsigned long long) entries_len,
++ (unsigned long long) start,
++ (unsigned long long) end);
++
++ if (grub_gpt_header_check (&gpt->backup, gpt->log_sector_size))
++ return grub_errno;
++ if (primary != 1)
++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid primary GPT LBA");
++ if (entries <= end || entries+entries_len > backup)
++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid entries location");
++ if (backup <= end)
++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid backup GPT LBA");
++
++ /* If both primary and backup are valid but differ prefer the primary. */
++ if ((gpt->status & GRUB_GPT_PRIMARY_HEADER_VALID) &&
++ !grub_gpt_headers_equal (gpt))
++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "backup GPT out of sync");
++
++ return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_gpt_read_primary (grub_disk_t disk, grub_gpt_t gpt)
++{
++ grub_disk_addr_t addr;
++
++ /* TODO: The gpt partmap module searches for the primary header instead
++ * of relying on the disk's sector size. For now trust the disk driver
++ * but eventually this code should match the existing behavior. */
++ gpt->log_sector_size = disk->log_sector_size;
++
++ grub_dprintf ("gpt", "reading primary GPT from sector 0x1\n");
++
++ addr = grub_gpt_sector_to_addr (gpt, 1);
++ if (grub_disk_read (disk, addr, 0, sizeof (gpt->primary), &gpt->primary))
++ return grub_errno;
++
++ if (grub_gpt_check_primary (gpt))
++ return grub_errno;
++
++ gpt->status |= GRUB_GPT_PRIMARY_HEADER_VALID;
++
++ if (grub_gpt_read_entries (disk, gpt, &gpt->primary,
++ &gpt->entries, &gpt->entries_size))
++ return grub_errno;
++
++ gpt->status |= GRUB_GPT_PRIMARY_ENTRIES_VALID;
++
++ return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_gpt_read_backup (grub_disk_t disk, grub_gpt_t gpt)
++{
++ void *entries = NULL;
++ grub_size_t entries_size;
++ grub_uint64_t sector;
++ grub_disk_addr_t addr;
++
++ /* Assumes gpt->log_sector_size == disk->log_sector_size */
++ if (gpt->status & GRUB_GPT_PRIMARY_HEADER_VALID)
++ {
++ sector = grub_le_to_cpu64 (gpt->primary.alternate_lba);
++ if (grub_gpt_disk_size_valid (disk) && sector >= disk->total_sectors)
++ return grub_error (GRUB_ERR_OUT_OF_RANGE,
++ "backup GPT located at 0x%llx, "
++ "beyond last disk sector at 0x%llx",
++ (unsigned long long) sector,
++ (unsigned long long) disk->total_sectors - 1);
++ }
++ else if (grub_gpt_disk_size_valid (disk))
++ sector = disk->total_sectors - 1;
++ else
++ return grub_error (GRUB_ERR_OUT_OF_RANGE,
++ "size of disk unknown, cannot locate backup GPT");
++
++ grub_dprintf ("gpt", "reading backup GPT from sector 0x%llx\n",
++ (unsigned long long) sector);
++
++ addr = grub_gpt_sector_to_addr (gpt, sector);
++ if (grub_disk_read (disk, addr, 0, sizeof (gpt->backup), &gpt->backup))
++ return grub_errno;
++
++ if (grub_gpt_check_backup (gpt))
++ return grub_errno;
++
++ /* Ensure the backup header thinks it is located where we found it. */
++ if (grub_le_to_cpu64 (gpt->backup.header_lba) != sector)
++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid backup GPT LBA");
++
++ gpt->status |= GRUB_GPT_BACKUP_HEADER_VALID;
++
++ if (grub_gpt_read_entries (disk, gpt, &gpt->backup,
++ &entries, &entries_size))
++ return grub_errno;
++
++ if (gpt->status & GRUB_GPT_PRIMARY_ENTRIES_VALID)
++ {
++ if (entries_size != gpt->entries_size ||
++ grub_memcmp (entries, gpt->entries, entries_size) != 0)
++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "backup GPT out of sync");
++
++ grub_free (entries);
++ }
++ else
++ {
++ gpt->entries = entries;
++ gpt->entries_size = entries_size;
++ }
++
++ gpt->status |= GRUB_GPT_BACKUP_ENTRIES_VALID;
++
++ return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_gpt_read_entries (grub_disk_t disk, grub_gpt_t gpt,
++ struct grub_gpt_header *header,
++ void **ret_entries,
++ grub_size_t *ret_entries_size)
++{
++ void *entries = NULL;
++ grub_uint32_t count, size, crc;
++ grub_uint64_t sector;
++ grub_disk_addr_t addr;
++ grub_size_t entries_size;
++
++ /* Grub doesn't include calloc, hence the manual overflow check. */
++ count = grub_le_to_cpu32 (header->maxpart);
++ size = grub_le_to_cpu32 (header->partentry_size);
++ entries_size = count *size;
++ if (size && entries_size / size != count)
++ {
++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
++ goto fail;
++ }
++
++ /* Double check that the header was validated properly. */
++ if (entries_size < GRUB_GPT_DEFAULT_ENTRIES_SIZE)
++ return grub_error (GRUB_ERR_BUG, "invalid GPT entries table size");
++
++ entries = grub_malloc (entries_size);
++ if (!entries)
++ goto fail;
++
++ sector = grub_le_to_cpu64 (header->partitions);
++ grub_dprintf ("gpt", "reading GPT %lu entries from sector 0x%llx\n",
++ (unsigned long) count,
++ (unsigned long long) sector);
++
++ addr = grub_gpt_sector_to_addr (gpt, sector);
++ if (grub_disk_read (disk, addr, 0, entries_size, entries))
++ goto fail;
++
++ grub_gpt_lecrc32 (&crc, entries, entries_size);
++ if (crc != header->partentry_crc32)
++ {
++ grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT entry crc32");
++ goto fail;
++ }
++
++ *ret_entries = entries;
++ *ret_entries_size = entries_size;
++ return GRUB_ERR_NONE;
++
++fail:
++ grub_free (entries);
++ return grub_errno;
++}
++
++grub_gpt_t
++grub_gpt_read (grub_disk_t disk)
++{
++ grub_gpt_t gpt;
++
++ grub_dprintf ("gpt", "reading GPT from %s\n", disk->name);
++
++ gpt = grub_zalloc (sizeof (*gpt));
++ if (!gpt)
++ goto fail;
++
++ if (grub_disk_read (disk, 0, 0, sizeof (gpt->mbr), &gpt->mbr))
++ goto fail;
++
++ /* Check the MBR but errors aren't reported beyond the status bit. */
++ if (grub_gpt_pmbr_check (&gpt->mbr))
++ grub_errno = GRUB_ERR_NONE;
++ else
++ gpt->status |= GRUB_GPT_PROTECTIVE_MBR;
++
++ /* If both the primary and backup fail report the primary's error. */
++ if (grub_gpt_read_primary (disk, gpt))
++ {
++ grub_error_push ();
++ grub_gpt_read_backup (disk, gpt);
++ grub_error_pop ();
++ }
++ else
++ grub_gpt_read_backup (disk, gpt);
++
++ /* If either succeeded clear any possible error from the other. */
++ if (grub_gpt_primary_valid (gpt) || grub_gpt_backup_valid (gpt))
++ grub_errno = GRUB_ERR_NONE;
++ else
++ goto fail;
++
++ return gpt;
++
++fail:
++ grub_gpt_free (gpt);
++ return NULL;
++}
++
++struct grub_gpt_partentry *
++grub_gpt_get_partentry (grub_gpt_t gpt, grub_uint32_t n)
++{
++ struct grub_gpt_header *header;
++ grub_size_t offset;
++
++ header = grub_gpt_get_header (gpt);
++ if (!header)
++ return NULL;
++
++ if (n >= grub_le_to_cpu32 (header->maxpart))
++ return NULL;
++
++ offset = (grub_size_t) grub_le_to_cpu32 (header->partentry_size) * n;
++ return (struct grub_gpt_partentry *) ((char *) gpt->entries + offset);
++}
++
++grub_err_t
++grub_gpt_repair (grub_disk_t disk, grub_gpt_t gpt)
++{
++ /* Skip if there is nothing to do. */
++ if (grub_gpt_both_valid (gpt))
++ return GRUB_ERR_NONE;
++
++ grub_dprintf ("gpt", "repairing GPT for %s\n", disk->name);
++
++ if (disk->log_sector_size != gpt->log_sector_size)
++ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
++ "GPT sector size must match disk sector size");
++
++ if (grub_gpt_primary_valid (gpt))
++ {
++ grub_uint64_t backup_header;
++
++ grub_dprintf ("gpt", "primary GPT is valid\n");
++
++ /* Relocate backup to end if disk if the disk has grown. */
++ backup_header = grub_le_to_cpu64 (gpt->primary.alternate_lba);
++ if (grub_gpt_disk_size_valid (disk) &&
++ disk->total_sectors - 1 > backup_header)
++ {
++ backup_header = disk->total_sectors - 1;
++ grub_dprintf ("gpt", "backup GPT header relocated to 0x%llx\n",
++ (unsigned long long) backup_header);
++
++ gpt->primary.alternate_lba = grub_cpu_to_le64 (backup_header);
++ }
++
++ grub_memcpy (&gpt->backup, &gpt->primary, sizeof (gpt->backup));
++ gpt->backup.header_lba = gpt->primary.alternate_lba;
++ gpt->backup.alternate_lba = gpt->primary.header_lba;
++ gpt->backup.partitions = grub_cpu_to_le64 (backup_header -
++ grub_gpt_size_to_sectors (gpt, gpt->entries_size));
++ }
++ else if (grub_gpt_backup_valid (gpt))
++ {
++ grub_dprintf ("gpt", "backup GPT is valid\n");
++
++ grub_memcpy (&gpt->primary, &gpt->backup, sizeof (gpt->primary));
++ gpt->primary.header_lba = gpt->backup.alternate_lba;
++ gpt->primary.alternate_lba = gpt->backup.header_lba;
++ gpt->primary.partitions = grub_cpu_to_le64_compile_time (2);
++ }
++ else
++ return grub_error (GRUB_ERR_BUG, "No valid GPT");
++
++ if (grub_gpt_update (gpt))
++ return grub_errno;
++
++ grub_dprintf ("gpt", "repairing GPT for %s successful\n", disk->name);
++
++ return GRUB_ERR_NONE;
++}
++
++grub_err_t
++grub_gpt_update (grub_gpt_t gpt)
++{
++ grub_uint32_t crc;
++
++ /* Clear status bits, require revalidation of everything. */
++ gpt->status &= ~(GRUB_GPT_PRIMARY_HEADER_VALID |
++ GRUB_GPT_PRIMARY_ENTRIES_VALID |
++ GRUB_GPT_BACKUP_HEADER_VALID |
++ GRUB_GPT_BACKUP_ENTRIES_VALID);
++
++ /* Writing headers larger than our header structure are unsupported. */
++ gpt->primary.headersize =
++ grub_cpu_to_le32_compile_time (sizeof (gpt->primary));
++ gpt->backup.headersize =
++ grub_cpu_to_le32_compile_time (sizeof (gpt->backup));
++
++ grub_gpt_lecrc32 (&crc, gpt->entries, gpt->entries_size);
++ gpt->primary.partentry_crc32 = crc;
++ gpt->backup.partentry_crc32 = crc;
++
++ grub_gpt_header_lecrc32 (&gpt->primary.crc32, &gpt->primary);
++ grub_gpt_header_lecrc32 (&gpt->backup.crc32, &gpt->backup);
++
++ if (grub_gpt_check_primary (gpt))
++ {
++ grub_error_push ();
++ return grub_error (GRUB_ERR_BUG, "Generated invalid GPT primary header");
++ }
++
++ gpt->status |= (GRUB_GPT_PRIMARY_HEADER_VALID |
++ GRUB_GPT_PRIMARY_ENTRIES_VALID);
++
++ if (grub_gpt_check_backup (gpt))
++ {
++ grub_error_push ();
++ return grub_error (GRUB_ERR_BUG, "Generated invalid GPT backup header");
++ }
++
++ gpt->status |= (GRUB_GPT_BACKUP_HEADER_VALID |
++ GRUB_GPT_BACKUP_ENTRIES_VALID);
++
++ return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_gpt_write_table (grub_disk_t disk, grub_gpt_t gpt,
++ struct grub_gpt_header *header)
++{
++ grub_disk_addr_t addr;
++
++ if (grub_le_to_cpu32 (header->headersize) != sizeof (*header))
++ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
++ "Header size is %u, must be %u",
++ grub_le_to_cpu32 (header->headersize),
++ sizeof (*header));
++
++ addr = grub_gpt_sector_to_addr (gpt, grub_le_to_cpu64 (header->header_lba));
++ if (addr == 0)
++ return grub_error (GRUB_ERR_BUG,
++ "Refusing to write GPT header to address 0x0");
++ if (grub_disk_write (disk, addr, 0, sizeof (*header), header))
++ return grub_errno;
++
++ addr = grub_gpt_sector_to_addr (gpt, grub_le_to_cpu64 (header->partitions));
++ if (addr < 2)
++ return grub_error (GRUB_ERR_BUG,
++ "Refusing to write GPT entries to address 0x%llx",
++ (unsigned long long) addr);
++ if (grub_disk_write (disk, addr, 0, gpt->entries_size, gpt->entries))
++ return grub_errno;
++
++ return GRUB_ERR_NONE;
++}
++
++grub_err_t
++grub_gpt_write (grub_disk_t disk, grub_gpt_t gpt)
++{
++ grub_uint64_t backup_header;
++
++ /* TODO: update/repair protective MBRs too. */
++
++ if (!grub_gpt_both_valid (gpt))
++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "Invalid GPT data");
++
++ /* Write the backup GPT first so if writing fails the update is aborted
++ * and the primary is left intact. However if the backup location is
++ * inaccessible we have to just skip and hope for the best, the backup
++ * will need to be repaired in the OS. */
++ backup_header = grub_le_to_cpu64 (gpt->backup.header_lba);
++ if (grub_gpt_disk_size_valid (disk) &&
++ backup_header >= disk->total_sectors)
++ {
++ grub_printf ("warning: backup GPT located at 0x%llx, "
++ "beyond last disk sector at 0x%llx\n",
++ (unsigned long long) backup_header,
++ (unsigned long long) disk->total_sectors - 1);
++ grub_printf ("warning: only writing primary GPT, "
++ "the backup GPT must be repaired from the OS\n");
++ }
++ else
++ {
++ grub_dprintf ("gpt", "writing backup GPT to %s\n", disk->name);
++ if (grub_gpt_write_table (disk, gpt, &gpt->backup))
++ return grub_errno;
++ }
++
++ grub_dprintf ("gpt", "writing primary GPT to %s\n", disk->name);
++ if (grub_gpt_write_table (disk, gpt, &gpt->primary))
++ return grub_errno;
++
++ return GRUB_ERR_NONE;
++}
++
++void
++grub_gpt_free (grub_gpt_t gpt)
++{
++ if (!gpt)
++ return;
++
++ grub_free (gpt->entries);
++ grub_free (gpt);
++}
+diff --git a/include/grub/gpt_partition.h b/include/grub/gpt_partition.h
+index 7a93f4329..5c4372dce 100644
+--- a/include/grub/gpt_partition.h
++++ b/include/grub/gpt_partition.h
+@@ -21,6 +21,7 @@
+
+ #include
+ #include
++#include
+
+ struct grub_gpt_part_guid
+ {
+@@ -30,25 +31,46 @@ struct grub_gpt_part_guid
+ grub_uint8_t data4[8];
+ } GRUB_PACKED;
+ typedef struct grub_gpt_part_guid grub_gpt_part_guid_t;
++typedef struct grub_gpt_part_guid grub_gpt_guid_t;
++typedef struct grub_gpt_part_guid grub_gpt_part_type_t;
+
+-#define GRUB_GPT_PARTITION_TYPE_EMPTY \
+- { 0x0, 0x0, 0x0, \
+- { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } \
++/* Format the raw little-endian GUID as a newly allocated string. */
++char * grub_gpt_guid_to_str (grub_gpt_guid_t *guid);
++
++
++#define GRUB_GPT_GUID_INIT(a, b, c, d1, d2, d3, d4, d5, d6, d7, d8) \
++ { \
++ grub_cpu_to_le32_compile_time (a), \
++ grub_cpu_to_le16_compile_time (b), \
++ grub_cpu_to_le16_compile_time (c), \
++ { d1, d2, d3, d4, d5, d6, d7, d8 } \
+ }
+
++#define GRUB_GPT_PARTITION_TYPE_EMPTY \
++ GRUB_GPT_GUID_INIT (0x0, 0x0, 0x0, \
++ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
++
++#define GRUB_GPT_PARTITION_TYPE_EFI_SYSTEM \
++ GRUB_GPT_GUID_INIT (0xc12a7328, 0xf81f, 0x11d2, \
++ 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b)
++
+ #define GRUB_GPT_PARTITION_TYPE_BIOS_BOOT \
+- { grub_cpu_to_le32_compile_time (0x21686148), \
+- grub_cpu_to_le16_compile_time (0x6449), \
+- grub_cpu_to_le16_compile_time (0x6e6f), \
+- { 0x74, 0x4e, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 } \
+- }
++ GRUB_GPT_GUID_INIT (0x21686148, 0x6449, 0x6e6f, \
++ 0x74, 0x4e, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49)
+
+ #define GRUB_GPT_PARTITION_TYPE_LDM \
+- { grub_cpu_to_le32_compile_time (0x5808C8AAU),\
+- grub_cpu_to_le16_compile_time (0x7E8F), \
+- grub_cpu_to_le16_compile_time (0x42E0), \
+- { 0x85, 0xD2, 0xE1, 0xE9, 0x04, 0x34, 0xCF, 0xB3 } \
+- }
++ GRUB_GPT_GUID_INIT (0x5808c8aa, 0x7e8f, 0x42e0, \
++ 0x85, 0xd2, 0xe1, 0xe9, 0x04, 0x34, 0xcf, 0xb3)
++
++#define GRUB_GPT_PARTITION_TYPE_USR_X86_64 \
++ GRUB_GPT_GUID_INIT (0x5dfbf5f4, 0x2848, 0x4bac, \
++ 0xaa, 0x5e, 0x0d, 0x9a, 0x20, 0xb7, 0x45, 0xa6)
++
++#define GRUB_GPT_HEADER_MAGIC \
++ { 0x45, 0x46, 0x49, 0x20, 0x50, 0x41, 0x52, 0x54 }
++
++#define GRUB_GPT_HEADER_VERSION \
++ grub_cpu_to_le32_compile_time (0x00010000U)
+
+ struct grub_gpt_header
+ {
+@@ -57,11 +79,11 @@ struct grub_gpt_header
+ grub_uint32_t headersize;
+ grub_uint32_t crc32;
+ grub_uint32_t unused1;
+- grub_uint64_t primary;
+- grub_uint64_t backup;
++ grub_uint64_t header_lba;
++ grub_uint64_t alternate_lba;
+ grub_uint64_t start;
+ grub_uint64_t end;
+- grub_uint8_t guid[16];
++ grub_gpt_part_guid_t guid;
+ grub_uint64_t partitions;
+ grub_uint32_t maxpart;
+ grub_uint32_t partentry_size;
+@@ -75,13 +97,168 @@ struct grub_gpt_partentry
+ grub_uint64_t start;
+ grub_uint64_t end;
+ grub_uint64_t attrib;
+- char name[72];
++ grub_uint16_t name[36];
+ } GRUB_PACKED;
+
++enum grub_gpt_part_attr_offset
++{
++ /* Standard partition attribute bits defined by UEFI. */
++ GRUB_GPT_PART_ATTR_OFFSET_REQUIRED = 0,
++ GRUB_GPT_PART_ATTR_OFFSET_NO_BLOCK_IO_PROTOCOL = 1,
++ GRUB_GPT_PART_ATTR_OFFSET_LEGACY_BIOS_BOOTABLE = 2,
++
++ /* De facto standard attribute bits defined by Microsoft and reused by
++ * http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec */
++ GRUB_GPT_PART_ATTR_OFFSET_READ_ONLY = 60,
++ GRUB_GPT_PART_ATTR_OFFSET_NO_AUTO = 63,
++
++ /* Partition attributes for priority based selection,
++ * Currently only valid for PARTITION_TYPE_USR_X86_64.
++ * TRIES_LEFT and PRIORITY are 4 bit wide fields. */
++ GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_PRIORITY = 48,
++ GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_TRIES_LEFT = 52,
++ GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_SUCCESSFUL = 56,
++};
++
++/* Helpers for reading/writing partition attributes. */
++static inline grub_uint64_t
++grub_gpt_entry_attribute (struct grub_gpt_partentry *entry,
++ enum grub_gpt_part_attr_offset offset,
++ unsigned int bits)
++{
++ grub_uint64_t attrib = grub_le_to_cpu64 (entry->attrib);
++
++ return (attrib >> offset) & ((1ULL << bits) - 1);
++}
++
++static inline void
++grub_gpt_entry_set_attribute (struct grub_gpt_partentry *entry,
++ grub_uint64_t value,
++ enum grub_gpt_part_attr_offset offset,
++ unsigned int bits)
++{
++ grub_uint64_t attrib, mask;
++
++ mask = (((1ULL << bits) - 1) << offset);
++ attrib = grub_le_to_cpu64 (entry->attrib) & ~mask;
++ attrib |= ((value << offset) & mask);
++ entry->attrib = grub_cpu_to_le64 (attrib);
++}
++
++/* Basic GPT partmap module. */
+ grub_err_t
+ grub_gpt_partition_map_iterate (grub_disk_t disk,
+ grub_partition_iterate_hook_t hook,
+ void *hook_data);
+
++/* Advanced GPT library. */
++
++/* Status bits for the grub_gpt.status field. */
++#define GRUB_GPT_PROTECTIVE_MBR 0x01
++#define GRUB_GPT_HYBRID_MBR 0x02
++#define GRUB_GPT_PRIMARY_HEADER_VALID 0x04
++#define GRUB_GPT_PRIMARY_ENTRIES_VALID 0x08
++#define GRUB_GPT_BACKUP_HEADER_VALID 0x10
++#define GRUB_GPT_BACKUP_ENTRIES_VALID 0x20
++
++/* UEFI requires the entries table to be at least 16384 bytes for a
++ * total of 128 entries given the standard 128 byte entry size. */
++#define GRUB_GPT_DEFAULT_ENTRIES_SIZE 16384
++#define GRUB_GPT_DEFAULT_ENTRIES_LENGTH \
++ (GRUB_GPT_DEFAULT_ENTRIES_SIZE / sizeof (struct grub_gpt_partentry))
++
++struct grub_gpt
++{
++ /* Bit field indicating which structures on disk are valid. */
++ unsigned status;
++
++ /* Protective or hybrid MBR. */
++ struct grub_msdos_partition_mbr mbr;
++
++ /* Each of the two GPT headers. */
++ struct grub_gpt_header primary;
++ struct grub_gpt_header backup;
++
++ /* Only need one entries table, on disk both copies are identical.
++ * The on disk entry size may be larger than our partentry struct so
++ * the table cannot be indexed directly. */
++ void *entries;
++ grub_size_t entries_size;
++
++ /* Logarithm of sector size, in case GPT and disk driver disagree. */
++ unsigned int log_sector_size;
++};
++typedef struct grub_gpt *grub_gpt_t;
++
++/* Helpers for checking the gpt status field. */
++static inline int
++grub_gpt_mbr_valid (grub_gpt_t gpt)
++{
++ return ((gpt->status & GRUB_GPT_PROTECTIVE_MBR) ||
++ (gpt->status & GRUB_GPT_HYBRID_MBR));
++}
++
++static inline int
++grub_gpt_primary_valid (grub_gpt_t gpt)
++{
++ return ((gpt->status & GRUB_GPT_PRIMARY_HEADER_VALID) &&
++ (gpt->status & GRUB_GPT_PRIMARY_ENTRIES_VALID));
++}
++
++static inline int
++grub_gpt_backup_valid (grub_gpt_t gpt)
++{
++ return ((gpt->status & GRUB_GPT_BACKUP_HEADER_VALID) &&
++ (gpt->status & GRUB_GPT_BACKUP_ENTRIES_VALID));
++}
++
++static inline int
++grub_gpt_both_valid (grub_gpt_t gpt)
++{
++ return grub_gpt_primary_valid (gpt) && grub_gpt_backup_valid (gpt);
++}
++
++/* Translate GPT sectors to GRUB's 512 byte block addresses. */
++static inline grub_disk_addr_t
++grub_gpt_sector_to_addr (grub_gpt_t gpt, grub_uint64_t sector)
++{
++ return (sector << (gpt->log_sector_size - GRUB_DISK_SECTOR_BITS));
++}
++
++/* Allocates and fills new grub_gpt structure, free with grub_gpt_free. */
++grub_gpt_t grub_gpt_read (grub_disk_t disk);
++
++/* Helper for indexing into the entries table.
++ * Returns NULL when the end of the table has been reached. */
++struct grub_gpt_partentry * grub_gpt_get_partentry (grub_gpt_t gpt,
++ grub_uint32_t n);
++
++/* Sync and update primary and backup headers if either are invalid. */
++grub_err_t grub_gpt_repair (grub_disk_t disk, grub_gpt_t gpt);
++
++/* Recompute checksums and revalidate everything, must be called after
++ * modifying any GPT data. */
++grub_err_t grub_gpt_update (grub_gpt_t gpt);
++
++/* Write headers and entry tables back to disk. */
++grub_err_t grub_gpt_write (grub_disk_t disk, grub_gpt_t gpt);
++
++void grub_gpt_free (grub_gpt_t gpt);
++
++grub_err_t grub_gpt_pmbr_check (struct grub_msdos_partition_mbr *mbr);
++grub_err_t grub_gpt_header_check (struct grub_gpt_header *gpt,
++ unsigned int log_sector_size);
++
++
++/* Utilities for simple partition data lookups, usage is intended to
++ * be similar to fs->label and fs->uuid functions. */
++
++/* Return the partition label of the device DEVICE in LABEL.
++ * The label is in a new buffer and should be freed by the caller. */
++grub_err_t grub_gpt_part_label (grub_device_t device, char **label);
++
++/* Return the partition uuid of the device DEVICE in UUID.
++ * The uuid is in a new buffer and should be freed by the caller. */
++grub_err_t grub_gpt_part_uuid (grub_device_t device, char **uuid);
+
+ #endif /* ! GRUB_GPT_PARTITION_HEADER */
+diff --git a/include/grub/search.h b/include/grub/search.h
+index d80347df3..c2f40abe9 100644
+--- a/include/grub/search.h
++++ b/include/grub/search.h
+@@ -25,5 +25,9 @@ void grub_search_fs_uuid (const char *key, const char *var, int no_floppy,
+ char **hints, unsigned nhints);
+ void grub_search_label (const char *key, const char *var, int no_floppy,
+ char **hints, unsigned nhints);
++void grub_search_part_uuid (const char *key, const char *var, int no_floppy,
++ char **hints, unsigned nhints);
++void grub_search_part_label (const char *key, const char *var, int no_floppy,
++ char **hints, unsigned nhints);
+
+ #endif
+diff --git a/tests/gpt_unit_test.c b/tests/gpt_unit_test.c
+new file mode 100644
+index 000000000..53f686912
+--- /dev/null
++++ b/tests/gpt_unit_test.c
+@@ -0,0 +1,807 @@
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 2014 CoreOS, 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 .
++ */
++
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++
++/* from gnulib */
++#include
++
++/* Confirm that the GPT structures conform to the sizes in the spec:
++ * The header size "must be greater than or equal to 92 and must be less
++ * than or equal to the logical block size."
++ * The partition entry size must be "a value of 128*(2^n) where n is an
++ * integer greater than or equal to zero (e.g., 128, 256, 512, etc.)." */
++verify (sizeof (struct grub_gpt_header) == 92);
++verify (sizeof (struct grub_gpt_partentry) == 128);
++
++/* GPT section sizes. */
++#define HEADER_SIZE (sizeof (struct grub_gpt_header))
++#define HEADER_PAD (GRUB_DISK_SECTOR_SIZE - HEADER_SIZE)
++#define ENTRY_SIZE (sizeof (struct grub_gpt_partentry))
++#define TABLE_ENTRIES 0x80
++#define TABLE_SIZE (TABLE_ENTRIES * ENTRY_SIZE)
++#define TABLE_SECTORS (TABLE_SIZE / GRUB_DISK_SECTOR_SIZE)
++
++/* Double check that the table size calculation was valid. */
++verify (TABLE_SECTORS * GRUB_DISK_SECTOR_SIZE == TABLE_SIZE);
++
++/* GPT section locations for a 1MiB disk. */
++#define DISK_SECTORS 0x800
++#define DISK_SIZE (GRUB_DISK_SECTOR_SIZE * DISK_SECTORS)
++#define PRIMARY_HEADER_SECTOR 0x1
++#define PRIMARY_TABLE_SECTOR 0x2
++#define BACKUP_HEADER_SECTOR (DISK_SECTORS - 0x1)
++#define BACKUP_TABLE_SECTOR (BACKUP_HEADER_SECTOR - TABLE_SECTORS)
++
++#define DATA_START_SECTOR (PRIMARY_TABLE_SECTOR + TABLE_SECTORS)
++#define DATA_END_SECTOR (BACKUP_TABLE_SECTOR - 0x1)
++#define DATA_SECTORS (BACKUP_TABLE_SECTOR - DATA_START_SECTOR)
++#define DATA_SIZE (GRUB_DISK_SECTOR_SIZE * DATA_SECTORS)
++
++struct test_disk
++{
++ struct grub_msdos_partition_mbr mbr;
++
++ struct grub_gpt_header primary_header;
++ grub_uint8_t primary_header_pad[HEADER_PAD];
++ struct grub_gpt_partentry primary_entries[TABLE_ENTRIES];
++
++ grub_uint8_t data[DATA_SIZE];
++
++ struct grub_gpt_partentry backup_entries[TABLE_ENTRIES];
++ struct grub_gpt_header backup_header;
++ grub_uint8_t backup_header_pad[HEADER_PAD];
++} GRUB_PACKED;
++
++/* Sanity check that all the above ugly math was correct. */
++verify (sizeof (struct test_disk) == DISK_SIZE);
++
++struct test_data
++{
++ int fd;
++ grub_device_t dev;
++ struct test_disk *raw;
++};
++
++
++/* Sample primary GPT header for a 1MB disk. */
++static const struct grub_gpt_header example_primary = {
++ .magic = GRUB_GPT_HEADER_MAGIC,
++ .version = GRUB_GPT_HEADER_VERSION,
++ .headersize = sizeof (struct grub_gpt_header),
++ .crc32 = grub_cpu_to_le32_compile_time (0xb985abe0),
++ .header_lba = grub_cpu_to_le64_compile_time (PRIMARY_HEADER_SECTOR),
++ .alternate_lba = grub_cpu_to_le64_compile_time (BACKUP_HEADER_SECTOR),
++ .start = grub_cpu_to_le64_compile_time (DATA_START_SECTOR),
++ .end = grub_cpu_to_le64_compile_time (DATA_END_SECTOR),
++ .guid = GRUB_GPT_GUID_INIT(0x69c131ad, 0x67d6, 0x46c6,
++ 0x93, 0xc4, 0x12, 0x4c, 0x75, 0x52, 0x56, 0xac),
++ .partitions = grub_cpu_to_le64_compile_time (PRIMARY_TABLE_SECTOR),
++ .maxpart = grub_cpu_to_le32_compile_time (TABLE_ENTRIES),
++ .partentry_size = grub_cpu_to_le32_compile_time (ENTRY_SIZE),
++ .partentry_crc32 = grub_cpu_to_le32_compile_time (0x074e052c),
++};
++
++static const struct grub_gpt_partentry example_entries[TABLE_ENTRIES] = {
++ {
++ .type = GRUB_GPT_PARTITION_TYPE_EFI_SYSTEM,
++ .guid = GRUB_GPT_GUID_INIT (0xa0f1792e, 0xb4ce, 0x4136, 0xbc, 0xf2,
++ 0x1a, 0xfc, 0x13, 0x3c, 0x28, 0x28),
++ .start = grub_cpu_to_le64_compile_time (DATA_START_SECTOR),
++ .end = grub_cpu_to_le64_compile_time (0x3f),
++ .attrib = 0x0,
++ .name = {
++ grub_cpu_to_le16_compile_time ('E'),
++ grub_cpu_to_le16_compile_time ('F'),
++ grub_cpu_to_le16_compile_time ('I'),
++ grub_cpu_to_le16_compile_time (' '),
++ grub_cpu_to_le16_compile_time ('S'),
++ grub_cpu_to_le16_compile_time ('Y'),
++ grub_cpu_to_le16_compile_time ('S'),
++ grub_cpu_to_le16_compile_time ('T'),
++ grub_cpu_to_le16_compile_time ('E'),
++ grub_cpu_to_le16_compile_time ('M'),
++ 0x0,
++ }
++ },
++ {
++ .type = GRUB_GPT_PARTITION_TYPE_BIOS_BOOT,
++ .guid = GRUB_GPT_GUID_INIT (0x876c898d, 0x1b40, 0x4727, 0xa1, 0x61,
++ 0xed, 0xf9, 0xb5, 0x48, 0x66, 0x74),
++ .start = grub_cpu_to_le64_compile_time (0x40),
++ .end = grub_cpu_to_le64_compile_time (0x7f),
++ .attrib = grub_cpu_to_le64_compile_time (
++ 1ULL << GRUB_GPT_PART_ATTR_OFFSET_LEGACY_BIOS_BOOTABLE),
++ .name = {
++ grub_cpu_to_le16_compile_time ('B'),
++ grub_cpu_to_le16_compile_time ('I'),
++ grub_cpu_to_le16_compile_time ('O'),
++ grub_cpu_to_le16_compile_time ('S'),
++ grub_cpu_to_le16_compile_time (' '),
++ grub_cpu_to_le16_compile_time ('B'),
++ grub_cpu_to_le16_compile_time ('O'),
++ grub_cpu_to_le16_compile_time ('O'),
++ grub_cpu_to_le16_compile_time ('T'),
++ 0x0,
++ }
++ },
++};
++
++/* And the backup header. */
++static const struct grub_gpt_header example_backup = {
++ .magic = GRUB_GPT_HEADER_MAGIC,
++ .version = GRUB_GPT_HEADER_VERSION,
++ .headersize = sizeof (struct grub_gpt_header),
++ .crc32 = grub_cpu_to_le32_compile_time (0x0af785eb),
++ .header_lba = grub_cpu_to_le64_compile_time (BACKUP_HEADER_SECTOR),
++ .alternate_lba = grub_cpu_to_le64_compile_time (PRIMARY_HEADER_SECTOR),
++ .start = grub_cpu_to_le64_compile_time (DATA_START_SECTOR),
++ .end = grub_cpu_to_le64_compile_time (DATA_END_SECTOR),
++ .guid = GRUB_GPT_GUID_INIT(0x69c131ad, 0x67d6, 0x46c6,
++ 0x93, 0xc4, 0x12, 0x4c, 0x75, 0x52, 0x56, 0xac),
++ .partitions = grub_cpu_to_le64_compile_time (BACKUP_TABLE_SECTOR),
++ .maxpart = grub_cpu_to_le32_compile_time (TABLE_ENTRIES),
++ .partentry_size = grub_cpu_to_le32_compile_time (ENTRY_SIZE),
++ .partentry_crc32 = grub_cpu_to_le32_compile_time (0x074e052c),
++};
++
++/* Sample protective MBR for the same 1MB disk. Note, this matches
++ * parted and fdisk behavior. The UEFI spec uses different values. */
++static const struct grub_msdos_partition_mbr example_pmbr = {
++ .entries = {{.flag = 0x00,
++ .start_head = 0x00,
++ .start_sector = 0x01,
++ .start_cylinder = 0x00,
++ .type = 0xee,
++ .end_head = 0xfe,
++ .end_sector = 0xff,
++ .end_cylinder = 0xff,
++ .start = grub_cpu_to_le32_compile_time (0x1),
++ .length = grub_cpu_to_le32_compile_time (DISK_SECTORS - 0x1),
++ }},
++ .signature = grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE),
++};
++
++/* If errors are left in grub's error stack things can get confused. */
++static void
++assert_error_stack_empty (void)
++{
++ do
++ {
++ grub_test_assert (grub_errno == GRUB_ERR_NONE,
++ "error on stack: %s", grub_errmsg);
++ }
++ while (grub_error_pop ());
++}
++
++static grub_err_t
++execute_command2 (const char *name, const char *arg1, const char *arg2)
++{
++ grub_command_t cmd;
++ grub_err_t err;
++ char *argv[2];
++
++ cmd = grub_command_find (name);
++ if (!cmd)
++ grub_fatal ("can't find command %s", name);
++
++ argv[0] = strdup (arg1);
++ argv[1] = strdup (arg2);
++ err = (cmd->func) (cmd, 2, argv);
++ free (argv[0]);
++ free (argv[1]);
++
++ return err;
++}
++
++static void
++sync_disk (struct test_data *data)
++{
++ if (msync (data->raw, DISK_SIZE, MS_SYNC | MS_INVALIDATE) < 0)
++ grub_fatal ("Syncing disk failed: %s", strerror (errno));
++
++ grub_disk_cache_invalidate_all ();
++}
++
++static void
++reset_disk (struct test_data *data)
++{
++ memset (data->raw, 0, DISK_SIZE);
++
++ /* Initialize image with valid example tables. */
++ memcpy (&data->raw->mbr, &example_pmbr, sizeof (data->raw->mbr));
++ memcpy (&data->raw->primary_header, &example_primary,
++ sizeof (data->raw->primary_header));
++ memcpy (&data->raw->primary_entries, &example_entries,
++ sizeof (data->raw->primary_entries));
++ memcpy (&data->raw->backup_entries, &example_entries,
++ sizeof (data->raw->backup_entries));
++ memcpy (&data->raw->backup_header, &example_backup,
++ sizeof (data->raw->backup_header));
++
++ sync_disk (data);
++}
++
++static void
++open_disk (struct test_data *data)
++{
++ const char *loop = "loop0";
++ char template[] = "/tmp/grub_gpt_test.XXXXXX";
++ char host[sizeof ("(host)") + sizeof (template)];
++
++ data->fd = mkstemp (template);
++ if (data->fd < 0)
++ grub_fatal ("Creating %s failed: %s", template, strerror (errno));
++
++ if (ftruncate (data->fd, DISK_SIZE) < 0)
++ {
++ int err = errno;
++ unlink (template);
++ grub_fatal ("Resizing %s failed: %s", template, strerror (err));
++ }
++
++ data->raw = mmap (NULL, DISK_SIZE, PROT_READ | PROT_WRITE,
++ MAP_SHARED, data->fd, 0);
++ if (data->raw == MAP_FAILED)
++ {
++ int err = errno;
++ unlink (template);
++ grub_fatal ("Maping %s failed: %s", template, strerror (err));
++ }
++
++ snprintf (host, sizeof (host), "(host)%s", template);
++ if (execute_command2 ("loopback", loop, host) != GRUB_ERR_NONE)
++ {
++ unlink (template);
++ grub_fatal ("loopback %s %s failed: %s", loop, host, grub_errmsg);
++ }
++
++ if (unlink (template) < 0)
++ grub_fatal ("Unlinking %s failed: %s", template, strerror (errno));
++
++ reset_disk (data);
++
++ data->dev = grub_device_open (loop);
++ if (!data->dev)
++ grub_fatal ("Opening %s failed: %s", loop, grub_errmsg);
++}
++
++static void
++close_disk (struct test_data *data)
++{
++ char *loop;
++
++ assert_error_stack_empty ();
++
++ if (munmap (data->raw, DISK_SIZE) || close (data->fd))
++ grub_fatal ("Closing disk image failed: %s", strerror (errno));
++
++ loop = strdup (data->dev->disk->name);
++ grub_test_assert (grub_device_close (data->dev) == GRUB_ERR_NONE,
++ "Closing disk device failed: %s", grub_errmsg);
++
++ grub_test_assert (execute_command2 ("loopback", "-d", loop) ==
++ GRUB_ERR_NONE, "loopback -d %s failed: %s", loop,
++ grub_errmsg);
++
++ free (loop);
++}
++
++static grub_gpt_t
++read_disk (struct test_data *data)
++{
++ grub_gpt_t gpt;
++
++ gpt = grub_gpt_read (data->dev->disk);
++ if (gpt == NULL)
++ grub_fatal ("grub_gpt_read failed: %s", grub_errmsg);
++
++ return gpt;
++}
++
++static void
++pmbr_test (void)
++{
++ struct grub_msdos_partition_mbr mbr;
++
++ memset (&mbr, 0, sizeof (mbr));
++
++ /* Empty is invalid. */
++ grub_gpt_pmbr_check (&mbr);
++ grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE,
++ "unexpected error: %s", grub_errmsg);
++ grub_errno = GRUB_ERR_NONE;
++
++ /* A table without a protective partition is invalid. */
++ mbr.signature = grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE);
++ grub_gpt_pmbr_check (&mbr);
++ grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE,
++ "unexpected error: %s", grub_errmsg);
++ grub_errno = GRUB_ERR_NONE;
++
++ /* A table with a protective type is ok. */
++ memcpy (&mbr, &example_pmbr, sizeof (mbr));
++ grub_gpt_pmbr_check (&mbr);
++ grub_test_assert (grub_errno == GRUB_ERR_NONE,
++ "unexpected error: %s", grub_errmsg);
++ grub_errno = GRUB_ERR_NONE;
++}
++
++static void
++header_test (void)
++{
++ struct grub_gpt_header primary, backup;
++
++ /* Example headers should be valid. */
++ memcpy (&primary, &example_primary, sizeof (primary));
++ grub_gpt_header_check (&primary, GRUB_DISK_SECTOR_BITS);
++ grub_test_assert (grub_errno == GRUB_ERR_NONE,
++ "unexpected error: %s", grub_errmsg);
++ grub_errno = GRUB_ERR_NONE;
++
++ memcpy (&backup, &example_backup, sizeof (backup));
++ grub_gpt_header_check (&backup, GRUB_DISK_SECTOR_BITS);
++ grub_test_assert (grub_errno == GRUB_ERR_NONE,
++ "unexpected error: %s", grub_errmsg);
++ grub_errno = GRUB_ERR_NONE;
++
++ /* Twiddle the GUID to invalidate the CRC. */
++ primary.guid.data1 = 0;
++ grub_gpt_header_check (&primary, GRUB_DISK_SECTOR_BITS);
++ grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE,
++ "unexpected error: %s", grub_errmsg);
++ grub_errno = GRUB_ERR_NONE;
++
++ backup.guid.data1 = 0;
++ grub_gpt_header_check (&backup, GRUB_DISK_SECTOR_BITS);
++ grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE,
++ "unexpected error: %s", grub_errmsg);
++ grub_errno = GRUB_ERR_NONE;
++}
++
++static void
++read_valid_test (void)
++{
++ struct test_data data;
++ grub_gpt_t gpt;
++
++ open_disk (&data);
++ gpt = read_disk (&data);
++ grub_test_assert (gpt->status == (GRUB_GPT_PROTECTIVE_MBR |
++ GRUB_GPT_PRIMARY_HEADER_VALID |
++ GRUB_GPT_PRIMARY_ENTRIES_VALID |
++ GRUB_GPT_BACKUP_HEADER_VALID |
++ GRUB_GPT_BACKUP_ENTRIES_VALID),
++ "unexpected status: 0x%02x", gpt->status);
++ grub_gpt_free (gpt);
++ close_disk (&data);
++}
++
++static void
++read_invalid_entries_test (void)
++{
++ struct test_data data;
++ grub_gpt_t gpt;
++
++ open_disk (&data);
++
++ /* Corrupt the first entry in both tables. */
++ memset (&data.raw->primary_entries[0], 0x55,
++ sizeof (data.raw->primary_entries[0]));
++ memset (&data.raw->backup_entries[0], 0x55,
++ sizeof (data.raw->backup_entries[0]));
++ sync_disk (&data);
++
++ gpt = grub_gpt_read (data.dev->disk);
++ grub_test_assert (gpt == NULL, "no error reported for corrupt entries");
++ grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE,
++ "unexpected error: %s", grub_errmsg);
++ grub_errno = GRUB_ERR_NONE;
++
++ close_disk (&data);
++}
++
++static void
++read_fallback_test (void)
++{
++ struct test_data data;
++ grub_gpt_t gpt;
++
++ open_disk (&data);
++
++ /* Corrupt the primary header. */
++ memset (&data.raw->primary_header.guid, 0x55,
++ sizeof (data.raw->primary_header.guid));
++ sync_disk (&data);
++ gpt = read_disk (&data);
++ grub_test_assert ((gpt->status & GRUB_GPT_PRIMARY_HEADER_VALID) == 0,
++ "unreported corrupt primary header");
++ grub_gpt_free (gpt);
++ reset_disk (&data);
++
++ /* Corrupt the backup header. */
++ memset (&data.raw->backup_header.guid, 0x55,
++ sizeof (data.raw->backup_header.guid));
++ sync_disk (&data);
++ gpt = read_disk (&data);
++ grub_test_assert ((gpt->status & GRUB_GPT_BACKUP_HEADER_VALID) == 0,
++ "unreported corrupt backup header");
++ grub_gpt_free (gpt);
++ reset_disk (&data);
++
++ /* Corrupt the primary entry table. */
++ memset (&data.raw->primary_entries[0], 0x55,
++ sizeof (data.raw->primary_entries[0]));
++ sync_disk (&data);
++ gpt = read_disk (&data);
++ grub_test_assert ((gpt->status & GRUB_GPT_PRIMARY_ENTRIES_VALID) == 0,
++ "unreported corrupt primary entries table");
++ grub_gpt_free (gpt);
++ reset_disk (&data);
++
++ /* Corrupt the backup entry table. */
++ memset (&data.raw->backup_entries[0], 0x55,
++ sizeof (data.raw->backup_entries[0]));
++ sync_disk (&data);
++ gpt = read_disk (&data);
++ grub_test_assert ((gpt->status & GRUB_GPT_BACKUP_ENTRIES_VALID) == 0,
++ "unreported corrupt backup entries table");
++ grub_gpt_free (gpt);
++ reset_disk (&data);
++
++ /* If primary is corrupt and disk size is unknown fallback fails. */
++ memset (&data.raw->primary_header.guid, 0x55,
++ sizeof (data.raw->primary_header.guid));
++ sync_disk (&data);
++ data.dev->disk->total_sectors = GRUB_DISK_SIZE_UNKNOWN;
++ gpt = grub_gpt_read (data.dev->disk);
++ grub_test_assert (gpt == NULL, "no error reported");
++ grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE,
++ "unexpected error: %s", grub_errmsg);
++ grub_errno = GRUB_ERR_NONE;
++
++ close_disk (&data);
++}
++
++static void
++repair_test (void)
++{
++ struct test_data data;
++ grub_gpt_t gpt;
++
++ open_disk (&data);
++
++ /* Erase/Repair primary. */
++ memset (&data.raw->primary_header, 0, sizeof (data.raw->primary_header));
++ sync_disk (&data);
++ gpt = read_disk (&data);
++ grub_gpt_repair (data.dev->disk, gpt);
++ grub_test_assert (grub_errno == GRUB_ERR_NONE,
++ "repair failed: %s", grub_errmsg);
++ if (memcmp (&gpt->primary, &example_primary, sizeof (gpt->primary)))
++ {
++ printf ("Invalid restored primary header:\n");
++ hexdump (16, (char*)&gpt->primary, sizeof (gpt->primary));
++ printf ("Expected primary header:\n");
++ hexdump (16, (char*)&example_primary, sizeof (example_primary));
++ grub_test_assert (0, "repair did not restore primary header");
++ }
++ grub_gpt_free (gpt);
++ reset_disk (&data);
++
++ /* Erase/Repair backup. */
++ memset (&data.raw->backup_header, 0, sizeof (data.raw->backup_header));
++ sync_disk (&data);
++ gpt = read_disk (&data);
++ grub_gpt_repair (data.dev->disk, gpt);
++ grub_test_assert (grub_errno == GRUB_ERR_NONE,
++ "repair failed: %s", grub_errmsg);
++ if (memcmp (&gpt->backup, &example_backup, sizeof (gpt->backup)))
++ {
++ printf ("Invalid restored backup header:\n");
++ hexdump (16, (char*)&gpt->backup, sizeof (gpt->backup));
++ printf ("Expected backup header:\n");
++ hexdump (16, (char*)&example_backup, sizeof (example_backup));
++ grub_test_assert (0, "repair did not restore backup header");
++ }
++ grub_gpt_free (gpt);
++ reset_disk (&data);
++
++ close_disk (&data);
++}
++
++/* Finding/reading/writing the backup GPT may be difficult if the OS and
++ * BIOS report different sizes for the same disk. We need to gracefully
++ * recognize this and avoid causing trouble for the OS. */
++static void
++weird_disk_size_test (void)
++{
++ struct test_data data;
++ grub_gpt_t gpt;
++
++ open_disk (&data);
++
++ /* Chop off 65536 bytes (128 512B sectors) which may happen when the
++ * BIOS thinks you are using a software RAID system that reserves that
++ * area for metadata when in fact you are not and using the bare disk. */
++ grub_test_assert(data.dev->disk->total_sectors == DISK_SECTORS,
++ "unexpected disk size: 0x%llx",
++ (unsigned long long) data.dev->disk->total_sectors);
++ data.dev->disk->total_sectors -= 128;
++
++ gpt = read_disk (&data);
++ assert_error_stack_empty ();
++ /* Reading the alternate_lba should have been blocked and reading
++ * the (new) end of disk should have found no useful data. */
++ grub_test_assert ((gpt->status & GRUB_GPT_BACKUP_HEADER_VALID) == 0,
++ "unreported missing backup header");
++
++ /* We should be able to reconstruct the backup header and the location
++ * of the backup should remain unchanged, trusting the GPT data over
++ * what the BIOS is telling us. Further changes are left to the OS. */
++ grub_gpt_repair (data.dev->disk, gpt);
++ grub_test_assert (grub_errno == GRUB_ERR_NONE,
++ "repair failed: %s", grub_errmsg);
++ grub_test_assert (memcmp (&gpt->primary, &example_primary,
++ sizeof (gpt->primary)) == 0,
++ "repair corrupted primary header");
++
++ grub_gpt_free (gpt);
++ close_disk (&data);
++}
++
++static void
++iterate_partitions_test (void)
++{
++ struct test_data data;
++ struct grub_gpt_partentry *p;
++ grub_gpt_t gpt;
++ grub_uint32_t n;
++
++ open_disk (&data);
++ gpt = read_disk (&data);
++
++ for (n = 0; (p = grub_gpt_get_partentry (gpt, n)) != NULL; n++)
++ grub_test_assert (memcmp (p, &example_entries[n], sizeof (*p)) == 0,
++ "unexpected partition %d data", n);
++
++ grub_test_assert (n == TABLE_ENTRIES, "unexpected partition limit: %d", n);
++
++ grub_gpt_free (gpt);
++ close_disk (&data);
++}
++
++static void
++large_partitions_test (void)
++{
++ struct test_data data;
++ struct grub_gpt_partentry *p;
++ grub_gpt_t gpt;
++ grub_uint32_t n;
++
++ open_disk (&data);
++
++ /* Double the entry size, cut the number of entries in half. */
++ data.raw->primary_header.maxpart =
++ data.raw->backup_header.maxpart =
++ grub_cpu_to_le32_compile_time (TABLE_ENTRIES/2);
++ data.raw->primary_header.partentry_size =
++ data.raw->backup_header.partentry_size =
++ grub_cpu_to_le32_compile_time (ENTRY_SIZE*2);
++ data.raw->primary_header.partentry_crc32 =
++ data.raw->backup_header.partentry_crc32 =
++ grub_cpu_to_le32_compile_time (0xf2c45af8);
++ data.raw->primary_header.crc32 = grub_cpu_to_le32_compile_time (0xde00cc8f);
++ data.raw->backup_header.crc32 = grub_cpu_to_le32_compile_time (0x6d72e284);
++
++ memset (&data.raw->primary_entries, 0,
++ sizeof (data.raw->primary_entries));
++ for (n = 0; n < TABLE_ENTRIES/2; n++)
++ memcpy (&data.raw->primary_entries[n*2], &example_entries[n],
++ sizeof (data.raw->primary_entries[0]));
++ memcpy (&data.raw->backup_entries, &data.raw->primary_entries,
++ sizeof (data.raw->backup_entries));
++
++ sync_disk(&data);
++ gpt = read_disk (&data);
++
++ for (n = 0; (p = grub_gpt_get_partentry (gpt, n)) != NULL; n++)
++ grub_test_assert (memcmp (p, &example_entries[n], sizeof (*p)) == 0,
++ "unexpected partition %d data", n);
++
++ grub_test_assert (n == TABLE_ENTRIES/2, "unexpected partition limit: %d", n);
++
++ grub_gpt_free (gpt);
++
++ /* Editing memory beyond the entry structure should still change the crc. */
++ data.raw->primary_entries[1].attrib = 0xff;
++
++ sync_disk(&data);
++ gpt = read_disk (&data);
++ grub_test_assert (gpt->status == (GRUB_GPT_PROTECTIVE_MBR |
++ GRUB_GPT_PRIMARY_HEADER_VALID |
++ GRUB_GPT_BACKUP_HEADER_VALID |
++ GRUB_GPT_BACKUP_ENTRIES_VALID),
++ "unexpected status: 0x%02x", gpt->status);
++ grub_gpt_free (gpt);
++
++ close_disk (&data);
++}
++
++static void
++invalid_partsize_test (void)
++{
++ struct grub_gpt_header header = {
++ .magic = GRUB_GPT_HEADER_MAGIC,
++ .version = GRUB_GPT_HEADER_VERSION,
++ .headersize = sizeof (struct grub_gpt_header),
++ .crc32 = grub_cpu_to_le32_compile_time (0x1ff2a054),
++ .header_lba = grub_cpu_to_le64_compile_time (PRIMARY_HEADER_SECTOR),
++ .alternate_lba = grub_cpu_to_le64_compile_time (BACKUP_HEADER_SECTOR),
++ .start = grub_cpu_to_le64_compile_time (DATA_START_SECTOR),
++ .end = grub_cpu_to_le64_compile_time (DATA_END_SECTOR),
++ .guid = GRUB_GPT_GUID_INIT(0x69c131ad, 0x67d6, 0x46c6,
++ 0x93, 0xc4, 0x12, 0x4c, 0x75, 0x52, 0x56, 0xac),
++ .partitions = grub_cpu_to_le64_compile_time (PRIMARY_TABLE_SECTOR),
++ .maxpart = grub_cpu_to_le32_compile_time (TABLE_ENTRIES),
++ /* Triple the entry size, which is not valid. */
++ .partentry_size = grub_cpu_to_le32_compile_time (ENTRY_SIZE*3),
++ .partentry_crc32 = grub_cpu_to_le32_compile_time (0x074e052c),
++ };
++
++ grub_gpt_header_check(&header, GRUB_DISK_SECTOR_BITS);
++ grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE,
++ "unexpected error: %s", grub_errmsg);
++ grub_test_assert (strcmp(grub_errmsg, "invalid GPT entry size") == 0,
++ "unexpected error: %s", grub_errmsg);
++ grub_errno = GRUB_ERR_NONE;
++}
++
++static void
++search_part_label_test (void)
++{
++ struct test_data data;
++ const char *test_result;
++ char *expected_result;
++
++ open_disk (&data);
++
++ expected_result = grub_xasprintf ("%s,gpt1", data.dev->disk->name);
++ grub_env_unset ("test_result");
++ grub_search_part_label ("EFI SYSTEM", "test_result", 0, NULL, 0);
++ test_result = grub_env_get ("test_result");
++ grub_test_assert (test_result && strcmp (test_result, expected_result) == 0,
++ "wrong device: %s (%s)", test_result, expected_result);
++ grub_free (expected_result);
++
++ expected_result = grub_xasprintf ("%s,gpt2", data.dev->disk->name);
++ grub_env_unset ("test_result");
++ grub_search_part_label ("BIOS BOOT", "test_result", 0, NULL, 0);
++ test_result = grub_env_get ("test_result");
++ grub_test_assert (test_result && strcmp (test_result, expected_result) == 0,
++ "wrong device: %s (%s)", test_result, expected_result);
++ grub_free (expected_result);
++
++ grub_env_unset ("test_result");
++ grub_search_part_label ("bogus name", "test_result", 0, NULL, 0);
++ test_result = grub_env_get ("test_result");
++ grub_test_assert (test_result == NULL,
++ "unexpected device: %s", test_result);
++ grub_test_assert (grub_errno == GRUB_ERR_FILE_NOT_FOUND,
++ "unexpected error: %s", grub_errmsg);
++ grub_errno = GRUB_ERR_NONE;
++
++ close_disk (&data);
++}
++
++static void
++search_part_uuid_test (void)
++{
++ struct test_data data;
++ const char gpt1_uuid[] = "A0F1792E-B4CE-4136-BCF2-1AFC133C2828";
++ const char gpt2_uuid[] = "876c898d-1b40-4727-a161-edf9b5486674";
++ const char bogus_uuid[] = "1534c928-c50e-4866-9daf-6a9fd7918a76";
++ const char *test_result;
++ char *expected_result;
++
++ open_disk (&data);
++
++ expected_result = grub_xasprintf ("%s,gpt1", data.dev->disk->name);
++ grub_env_unset ("test_result");
++ grub_search_part_uuid (gpt1_uuid, "test_result", 0, NULL, 0);
++ test_result = grub_env_get ("test_result");
++ grub_test_assert (test_result && strcmp (test_result, expected_result) == 0,
++ "wrong device: %s (%s)", test_result, expected_result);
++ grub_free (expected_result);
++
++ expected_result = grub_xasprintf ("%s,gpt2", data.dev->disk->name);
++ grub_env_unset ("test_result");
++ grub_search_part_uuid (gpt2_uuid, "test_result", 0, NULL, 0);
++ test_result = grub_env_get ("test_result");
++ grub_test_assert (test_result && strcmp (test_result, expected_result) == 0,
++ "wrong device: %s (%s)", test_result, expected_result);
++ grub_free (expected_result);
++
++ grub_env_unset ("test_result");
++ grub_search_part_uuid (bogus_uuid, "test_result", 0, NULL, 0);
++ test_result = grub_env_get ("test_result");
++ grub_test_assert (test_result == NULL,
++ "unexpected device: %s", test_result);
++ grub_test_assert (grub_errno == GRUB_ERR_FILE_NOT_FOUND,
++ "unexpected error: %s", grub_errmsg);
++ grub_errno = GRUB_ERR_NONE;
++
++ close_disk (&data);
++}
++
++void
++grub_unit_test_init (void)
++{
++ grub_init_all ();
++ grub_hostfs_init ();
++ grub_host_init ();
++ grub_test_register ("gpt_pmbr_test", pmbr_test);
++ grub_test_register ("gpt_header_test", header_test);
++ grub_test_register ("gpt_read_valid_test", read_valid_test);
++ grub_test_register ("gpt_read_invalid_test", read_invalid_entries_test);
++ grub_test_register ("gpt_read_fallback_test", read_fallback_test);
++ grub_test_register ("gpt_repair_test", repair_test);
++ grub_test_register ("gpt_iterate_partitions_test", iterate_partitions_test);
++ grub_test_register ("gpt_large_partitions_test", large_partitions_test);
++ grub_test_register ("gpt_invalid_partsize_test", invalid_partsize_test);
++ grub_test_register ("gpt_weird_disk_size_test", weird_disk_size_test);
++ grub_test_register ("gpt_search_part_label_test", search_part_label_test);
++ grub_test_register ("gpt_search_uuid_test", search_part_uuid_test);
++}
++
++void
++grub_unit_test_fini (void)
++{
++ grub_test_unregister ("gpt_pmbr_test");
++ grub_test_unregister ("gpt_header_test");
++ grub_test_unregister ("gpt_read_valid_test");
++ grub_test_unregister ("gpt_read_invalid_test");
++ grub_test_unregister ("gpt_read_fallback_test");
++ grub_test_unregister ("gpt_repair_test");
++ grub_test_unregister ("gpt_iterate_partitions_test");
++ grub_test_unregister ("gpt_large_partitions_test");
++ grub_test_unregister ("gpt_invalid_partsize_test");
++ grub_test_unregister ("gpt_weird_disk_size_test");
++ grub_test_unregister ("gpt_search_part_label_test");
++ grub_test_unregister ("gpt_search_part_uuid_test");
++ grub_fini_all ();
++}
+diff --git a/tests/gptprio_test.in b/tests/gptprio_test.in
+new file mode 100644
+index 000000000..c5cf0f3b7
+--- /dev/null
++++ b/tests/gptprio_test.in
+@@ -0,0 +1,207 @@
++#! /bin/bash
++set -e
++
++# Copyright (C) 2010 Free Software Foundation, Inc.
++# Copyright (C) 2014 CoreOS, 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 .
++
++sgdisk=sgdisk
++grubshell=@builddir@/grub-shell
++
++if ! which "${sgdisk}" >/dev/null 2>&1; then
++ echo "sgdisk not installed; cannot test gptprio."
++ exit 77
++fi
++
++. "@builddir@/grub-core/modinfo.sh"
++
++case "${grub_modinfo_target_cpu}-${grub_modinfo_platform}" in
++ mips-qemu_mips | mipsel-qemu_mips | i386-qemu | i386-multiboot | i386-coreboot | mipsel-loongson)
++ disk=ata0
++ ;;
++ powerpc-ieee1275)
++ disk=ieee1275//pci@80000000/mac-io@4/ata-3@20000/disk@0
++ # FIXME: QEMU firmware has bugs which prevent it from accessing hard disk w/o recognised label.
++ exit 0
++ ;;
++ sparc64-ieee1275)
++ disk=ieee1275//pci@1fe\,0/pci-ata@5/ide0@500/disk@0
++ # FIXME: QEMU firmware has bugs which prevent it from accessing hard disk w/o recognised label.
++ exit 0
++ ;;
++ i386-ieee1275)
++ disk=ieee1275/d
++ # FIXME: QEMU firmware has bugs which prevent it from accessing hard disk w/o recognised label.
++ exit 0
++ ;;
++ mips-arc)
++ # FIXME: ARC firmware has bugs which prevent it from accessing hard disk w/o dvh disklabel.
++ exit 0 ;;
++ mipsel-arc)
++ disk=arc/scsi0/disk0/rdisk0
++ ;;
++ *)
++ disk=hd0
++ ;;
++esac
++img1="`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"`" || exit 1
++trap "rm -f '${img1}'" EXIT
++
++prio_type="5dfbf5f4-2848-4bac-aa5e-0d9a20b745a6"
++declare -a prio_uuid
++prio_uuid[2]="9b003904-d006-4ab3-97f1-73f547b7af1a"
++prio_uuid[3]="1aa5a658-5b02-414d-9b71-f7e6c151f0cd"
++prio_uuid[4]="8aa0240d-98af-42b0-b32a-ccbe0572d62b"
++
++create_disk_image () {
++ size=$1
++ rm -f "${img1}"
++ dd if=/dev/zero of="${img1}" bs=512 count=1 seek=$((size - 1)) status=none
++ ${sgdisk} \
++ -n 1:0:+1 -c 1:ESP -t 1:ef00 \
++ -n 2:0:+1 -c 2:A -t 2:"${prio_type}" -u 2:"${prio_uuid[2]}" \
++ -n 3:0:+1 -c 3:B -t 3:"${prio_type}" -u 3:"${prio_uuid[3]}" \
++ -n 4:0:+1 -c 4:C -t 4:"${prio_type}" -u 4:"${prio_uuid[4]}" \
++ "${img1}" >/dev/null
++}
++
++wipe_disk_area () {
++ sector=$1
++ size=$2
++ dd if=/dev/zero of="${img1}" bs=512 count=${size} seek=${sector} conv=notrunc status=none
++}
++
++is_zero () {
++ sector=$1
++ size=$2
++ cmp -s -i $((sector * 512)) -n $((size * 512)) /dev/zero "${img1}"
++}
++
++check_is_zero () {
++ sector=$1
++ size=$2
++ if ! is_zero "$@"; then
++ echo "$size sector(s) starting at $sector should be all zero"
++ exit 1
++ fi
++}
++
++check_not_zero () {
++ sector=$1
++ size=$2
++ if is_zero "$@"; then
++ echo "$size sector(s) starting at $sector should not be all zero"
++ exit 1
++ fi
++}
++
++fmt_prio () {
++ priority=$(( ( $1 & 15 ) << 48 ))
++ tries=$(( ( $2 & 15 ) << 52 ))
++ success=$(( ( $3 & 1 ) << 56 ))
++ printf %016x $(( priority | tries | success ))
++}
++
++set_prio () {
++ part="$1"
++ attr=$(fmt_prio $2 $3 $4)
++ ${sgdisk} -A "${part}:=:${attr}" "${img1}" >/dev/null
++}
++
++check_prio () {
++ part="$1"
++ expect=$(fmt_prio $2 $3 $4)
++ result=$(LANG=C ${sgdisk} -i "${part}" "${img1}" 2>&1 \
++ | awk '/^Attribute flags: / {print $3}')
++ if [[ "${expect}" != "${result}" ]]; then
++ echo "Partition ${part} has attributes ${result:-??}, not ${expect}"
++ exit 1
++ fi
++}
++
++run_next() {
++ "${grubshell}" --disk="${img1}" --modules=gptprio <.
++
++parted=parted
++grubshell=@builddir@/grub-shell
++
++. "@builddir@/grub-core/modinfo.sh"
++
++case "${grub_modinfo_target_cpu}-${grub_modinfo_platform}" in
++ mips-qemu_mips | mipsel-qemu_mips | i386-qemu | i386-multiboot | i386-coreboot | mipsel-loongson)
++ disk=ata0
++ ;;
++ powerpc-ieee1275)
++ disk=ieee1275//pci@80000000/mac-io@4/ata-3@20000/disk@0
++ # FIXME: QEMU firmware has bugs which prevent it from accessing hard disk w/o recognised label.
++ exit 0
++ ;;
++ sparc64-ieee1275)
++ disk=ieee1275//pci@1fe\,0/pci-ata@5/ide0@500/disk@0
++ # FIXME: QEMU firmware has bugs which prevent it from accessing hard disk w/o recognised label.
++ exit 0
++ ;;
++ i386-ieee1275)
++ disk=ieee1275/d
++ # FIXME: QEMU firmware has bugs which prevent it from accessing hard disk w/o recognised label.
++ exit 0
++ ;;
++ mips-arc)
++ # FIXME: ARC firmware has bugs which prevent it from accessing hard disk w/o dvh disklabel.
++ exit 0 ;;
++ mipsel-arc)
++ disk=arc/scsi0/disk0/rdisk0
++ ;;
++ *)
++ disk=hd0
++ ;;
++esac
++img1="`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"`" || exit 1
++img2="`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"`" || exit 1
++trap "rm -f '${img1}' '${img2}'" EXIT
++
++create_disk_image () {
++ size=$1
++ rm -f "${img1}"
++ dd if=/dev/zero of="${img1}" bs=512 count=1 seek=$((size - 1)) status=none
++ ${parted} -a none -s "${img1}" mklabel gpt
++ cp "${img1}" "${img2}"
++}
++
++wipe_disk_area () {
++ sector=$1
++ size=$2
++ dd if=/dev/zero of="${img2}" bs=512 count=${size} seek=${sector} conv=notrunc status=none
++}
++
++do_repair () {
++ output="`echo "gptrepair ($disk)" | "${grubshell}" --disk="${img2}"`"
++ if echo "${output}" | grep ^error; then
++ return 1
++ fi
++ if echo "${output}" | grep -v GPT; then
++ echo "Unexpected output ${output}"
++ return 1
++ fi
++ echo "${output}"
++}
++
++echo "Nothing to repair:"
++create_disk_image 100
++do_repair
++cmp "${img1}" "${img2}"
++echo
++
++echo "Repair primary (MBR left intact)"
++create_disk_image 100
++wipe_disk_area 1 1
++do_repair
++cmp "${img1}" "${img2}"
++echo
++
++echo "Repair backup"
++create_disk_image 100
++wipe_disk_area 99 1
++do_repair
++cmp "${img1}" "${img2}"
++echo
+--
+2.34.1
+
diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-add-verity-hash.patch b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-add-verity-hash.patch
new file mode 100644
index 0000000000..ed892d90dd
--- /dev/null
+++ b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-add-verity-hash.patch
@@ -0,0 +1,134 @@
+From 14d4760aacb8896f99422c06d100e5231e09e797 Mon Sep 17 00:00:00 2001
+From: Sayan Chowdhury
+Date: Thu, 24 Aug 2023 00:00:00 +0530
+Subject: Add verity hash passthrough
+
+Read the verity hash from the kernel binary and pass it to the running
+system via the kernel command line
+
+The patch is prepared using the coreos/grub PRs, picking the only
+required ones, and dropping the others. The README.md file in the
+coreos-overlay/sys-boot/grub/ contains more contexual information
+along with the commits used to create the patch.
+
+Authored-by: Matthew Garrett
+Signed-off-by: Sayan Chowdhury
+---
+ grub-core/loader/arm64/linux.c | 6 +++-
+ grub-core/loader/i386/linux.c | 3 ++
+ include/grub/verity-hash.h | 51 ++++++++++++++++++++++++++++++++++
+ 3 files changed, 59 insertions(+), 1 deletion(-)
+ create mode 100644 include/grub/verity-hash.h
+
+diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
+index ef3e9f944..17bed4e15 100644
+--- a/grub-core/loader/arm64/linux.c
++++ b/grub-core/loader/arm64/linux.c
+@@ -34,6 +34,8 @@
+ #include
+ #include
+
++#include
++
+ GRUB_MOD_LICENSE ("GPLv3+");
+
+ static grub_dl_t my_mod;
+@@ -333,7 +335,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+
+ grub_dprintf ("linux", "kernel @ %p\n", kernel_addr);
+
+- cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE);
++ cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE)
++ + VERITY_CMDLINE_LENGTH;
+ linux_args = grub_malloc (cmdline_size);
+ if (!linux_args)
+ {
+@@ -350,6 +353,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+
+ if (grub_errno == GRUB_ERR_NONE)
+ {
++ grub_pass_verity_hash (kernel_addr, linux_args, cmdline_size);
+ grub_loader_set (grub_linux_boot, grub_linux_unload, 0);
+ loaded = 1;
+ }
+diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c
+index 9f74a96b1..1c76ac5bf 100644
+--- a/grub-core/loader/i386/linux.c
++++ b/grub-core/loader/i386/linux.c
+@@ -38,6 +38,8 @@
+ #include
+ #include
+
++#include
++
+ GRUB_MOD_LICENSE ("GPLv3+");
+
+ #ifdef GRUB_MACHINE_PCBIOS
+@@ -1006,6 +1008,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ goto fail;
+ }
+
++ grub_pass_verity_hash(&lh, linux_cmdline, maximal_cmdline_size);
+ len = prot_file_size;
+ if (grub_file_read (file, prot_mode_mem, len) != len && !grub_errno)
+ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+diff --git a/include/grub/verity-hash.h b/include/grub/verity-hash.h
+new file mode 100644
+index 000000000..448d9aff0
+--- /dev/null
++++ b/include/grub/verity-hash.h
+@@ -0,0 +1,51 @@
++/* CoreOS verity hash */
++
++#define VERITY_ARG " verity.usrhash="
++#define VERITY_ARG_LENGTH (sizeof (VERITY_ARG) - 1)
++#define VERITY_HASH_LENGTH 64
++#define VERITY_CMDLINE_LENGTH ((VERITY_ARG_LENGTH)+(VERITY_HASH_LENGTH))
++
++#if defined(__aarch64__)
++# define VERITY_HASH_OFFSET 512
++#elif defined(__i386__) || defined(__amd64__)
++# define VERITY_HASH_OFFSET 0x40
++#else
++# error Unsupported arch
++#endif
++
++
++/**
++ * grub_pass_verity_hash - Reads the CoreOS verity hash value from a well known
++ * kernel image offset and adds a kernel command line argument for it.
++ *
++ * @pImage: Kernel image buffer.
++ * @cmdline: Kernel command line buffer.
++ * @cmdline_max_len: Kernel command line buffer length.
++ */
++
++static inline void grub_pass_verity_hash(const void *pImage,
++ char *cmdline,
++ grub_size_t cmdline_max_len)
++{
++ const char *buf = pImage;
++ grub_size_t cmdline_len;
++ int i;
++
++ for (i=VERITY_HASH_OFFSET; i '9') // Not a number
++ if (buf[i] < 'a' || buf[i] > 'f') // Not a hex letter
++ return;
++ }
++
++ cmdline_len = grub_strlen(cmdline);
++ if (cmdline_len + VERITY_CMDLINE_LENGTH > cmdline_max_len)
++ return;
++
++ grub_memcpy (cmdline + cmdline_len, VERITY_ARG, VERITY_ARG_LENGTH);
++ cmdline_len += VERITY_ARG_LENGTH;
++ grub_memcpy (cmdline + cmdline_len, buf + VERITY_HASH_OFFSET,
++ VERITY_HASH_LENGTH);
++ cmdline_len += VERITY_HASH_LENGTH;
++ cmdline[cmdline_len] = '\0';
++}
+--
+2.34.1
+
diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/grub-2.06-r7.ebuild b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/grub-2.06-r7.ebuild
index c56c06edbc..df7a8afb62 100644
--- a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/grub-2.06-r7.ebuild
+++ b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/grub-2.06-r7.ebuild
@@ -72,6 +72,8 @@ PATCHES=(
"${FILESDIR}"/grub-2.06-fs-ext2-ignore-checksum-seed.patch
"${FILESDIR}"/grub-2.06-riscv.patch
"${FILESDIR}"/grub-2.06-locale.patch
+ "${FILESDIR}"/grub-2.06-add-verity-hash.patch
+ "${FILESDIR}"/grub-2.06-add-gpt-partition-scheme.patch
)
DEJAVU=dejavu-sans-ttf-2.37
@@ -89,6 +91,9 @@ IUSE="device-mapper doc efiemu +fonts mount nls sdl test +themes truetype libzfs
GRUB_ALL_PLATFORMS=( coreboot efi-32 efi-64 emu ieee1275 loongson multiboot
qemu qemu-mips pc uboot xen xen-32 xen-pvh )
+
+# Flatcar: Add arm64 to the list of platforms
+GRUB_ALL_PLATFORMS+=( arm64 )
IUSE+=" ${GRUB_ALL_PLATFORMS[@]/#/grub_platforms_}"
REQUIRED_USE="
@@ -104,6 +109,7 @@ BDEPEND="
sys-devel/bison
sys-apps/help2man
sys-apps/texinfo
+ grub_platforms_arm64? ( cross-aarch64-cros-linux-gnu/gcc )
fonts? (
media-libs/freetype:2
virtual/pkgconfig
@@ -210,6 +216,7 @@ grub_configure() {
efi*) platform=efi ;;
xen-pvh) platform=xen_pvh ;;
xen*) platform=xen ;;
+ arm64*) platform=efi ;;
guessed) ;;
*) platform=${MULTIBUILD_VARIANT} ;;
esac
diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/grub-2.12_rc1-r1.ebuild b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/grub-2.12_rc1-r1.ebuild
deleted file mode 100644
index 6ca17da645..0000000000
--- a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/grub-2.12_rc1-r1.ebuild
+++ /dev/null
@@ -1,344 +0,0 @@
-# Copyright 1999-2023 Gentoo Authors
-# Distributed under the terms of the GNU General Public License v2
-
-EAPI=7
-
-# This ebuild uses 3 special global variables:
-# GRUB_BOOTSTRAP: Depend on python and invoke bootstrap (gnulib).
-# GRUB_AUTOGEN: Depend on python and invoke autogen.sh.
-# GRUB_AUTORECONF: Inherit autotools and invoke eautoreconf.
-#
-# When applying patches:
-# If gnulib is updated, set GRUB_BOOTSTRAP=1
-# If gentpl.py or *.def is updated, set GRUB_AUTOGEN=1
-# If gnulib, gentpl.py, *.def, or any autotools files are updated, set GRUB_AUTORECONF=1
-#
-# If any of the above applies to a user patch, the user should set the
-# corresponding variable in make.conf or the environment.
-
-if [[ ${PV} == 9999 ]]; then
- GRUB_AUTORECONF=1
- GRUB_BOOTSTRAP=1
-fi
-
-PYTHON_COMPAT=( python3_{9..11} )
-WANT_LIBTOOL=none
-VERIFY_SIG_OPENPGP_KEY_PATH="${BROOT}"/usr/share/openpgp-keys/dkiper.gpg
-
-if [[ -n ${GRUB_AUTOGEN} || -n ${GRUB_BOOTSTRAP} ]]; then
- inherit python-any-r1
-fi
-
-if [[ -n ${GRUB_AUTORECONF} ]]; then
- inherit autotools
-fi
-
-inherit bash-completion-r1 flag-o-matic multibuild optfeature toolchain-funcs verify-sig
-
-MY_P=${P}
-if [[ ${PV} != 9999 ]]; then
- if [[ ${PV} == *_alpha* || ${PV} == *_beta* || ${PV} == *_rc* ]]; then
- # The quote style is to work with <=bash-4.2 and >=bash-4.3 #503860
- MY_P=${P/_/'~'}
- SRC_URI="
- https://alpha.gnu.org/gnu/${PN}/${MY_P}.tar.xz
- verify-sig? ( https://alpha.gnu.org/gnu/${PN}/${MY_P}.tar.xz.sig )
- "
- S=${WORKDIR}/${MY_P}
- else
- SRC_URI="
- mirror://gnu/${PN}/${P}.tar.xz
- verify-sig? ( mirror://gnu/${PN}/${P}.tar.xz.sig )
- "
- S=${WORKDIR}/${P%_*}
- fi
- #KEYWORDS="~amd64 ~arm ~arm64 ~ia64 ~ppc ~ppc64 ~riscv ~sparc ~x86"
-else
- inherit git-r3
- EGIT_REPO_URI="https://git.savannah.gnu.org/git/grub.git"
-fi
-
-PATCHES=(
- "${FILESDIR}"/gfxpayload.patch
- "${FILESDIR}"/grub-2.02_beta2-KERNEL_GLOBS.patch
- "${FILESDIR}"/grub-2.06-test-words.patch
- "${FILESDIR}"/grub-2.12_rc1-util-grub.d-25_bli.in-fix-shebang-on-unmerged-usr.patch
-)
-
-DEJAVU=dejavu-sans-ttf-2.37
-UNIFONT=unifont-15.0.06
-SRC_URI+=" fonts? ( mirror://gnu/unifont/${UNIFONT}/${UNIFONT}.pcf.gz )
- themes? ( mirror://sourceforge/dejavu/${DEJAVU}.zip )"
-
-DESCRIPTION="GNU GRUB boot loader"
-HOMEPAGE="https://www.gnu.org/software/grub/"
-
-# Includes licenses for dejavu and unifont
-LICENSE="GPL-3+ BSD MIT fonts? ( GPL-2-with-font-exception ) themes? ( CC-BY-SA-3.0 BitstreamVera )"
-SLOT="2/${PVR}"
-IUSE="device-mapper doc efiemu +fonts mount nls sdl test +themes truetype libzfs"
-
-GRUB_ALL_PLATFORMS=( coreboot efi-32 efi-64 emu ieee1275 loongson multiboot
- qemu qemu-mips pc uboot xen xen-32 xen-pvh )
-IUSE+=" ${GRUB_ALL_PLATFORMS[@]/#/grub_platforms_}"
-
-REQUIRED_USE="
- grub_platforms_coreboot? ( fonts )
- grub_platforms_qemu? ( fonts )
- grub_platforms_ieee1275? ( fonts )
- grub_platforms_loongson? ( fonts )
-"
-
-BDEPEND="
- ${PYTHON_DEPS}
- >=sys-devel/flex-2.5.35
- sys-devel/bison
- sys-apps/help2man
- sys-apps/texinfo
- fonts? (
- media-libs/freetype:2
- virtual/pkgconfig
- )
- test? (
- app-admin/genromfs
- app-arch/cpio
- app-arch/lzop
- app-emulation/qemu
- dev-libs/libisoburn
- sys-apps/miscfiles
- sys-block/parted
- sys-fs/squashfs-tools
- )
- themes? (
- app-arch/unzip
- media-libs/freetype:2
- virtual/pkgconfig
- )
- truetype? ( virtual/pkgconfig )
- verify-sig? ( sec-keys/openpgp-keys-danielkiper )
-"
-DEPEND="
- app-arch/xz-utils
- >=sys-libs/ncurses-5.2-r5:0=
- grub_platforms_emu? (
- sdl? ( media-libs/libsdl )
- )
- device-mapper? ( >=sys-fs/lvm2-2.02.45 )
- libzfs? ( sys-fs/zfs:= )
- mount? ( sys-fs/fuse:0 )
- truetype? ( media-libs/freetype:2= )
- ppc? ( >=sys-apps/ibm-powerpc-utils-1.3.5 )
- ppc64? ( >=sys-apps/ibm-powerpc-utils-1.3.5 )
-"
-RDEPEND="${DEPEND}
- kernel_linux? (
- grub_platforms_efi-32? ( sys-boot/efibootmgr )
- grub_platforms_efi-64? ( sys-boot/efibootmgr )
- )
- !sys-boot/grub:0
- nls? ( sys-devel/gettext )
-"
-
-RESTRICT="!test? ( test ) test? ( userpriv )"
-
-QA_EXECSTACK="usr/bin/grub-emu* usr/lib/grub/*"
-QA_PRESTRIPPED="usr/lib/grub/.*"
-QA_MULTILIB_PATHS="usr/lib/grub/.*"
-QA_WX_LOAD="usr/lib/grub/*"
-
-pkg_setup() {
- :
-}
-
-src_unpack() {
- if [[ ${PV} == 9999 ]]; then
- git-r3_src_unpack
- pushd "${P}" >/dev/null || die
- local GNULIB_URI="https://git.savannah.gnu.org/git/gnulib.git"
- local GNULIB_REVISION=$(source bootstrap.conf >/dev/null; echo "${GNULIB_REVISION}")
- git-r3_fetch "${GNULIB_URI}" "${GNULIB_REVISION}"
- git-r3_checkout "${GNULIB_URI}" gnulib
- popd >/dev/null || die
- elif use verify-sig; then
- verify-sig_verify_detached "${DISTDIR}"/${MY_P}.tar.xz{,.sig}
- fi
- default
-}
-
-src_prepare() {
- default
-
- if [[ -n ${GRUB_AUTOGEN} || -n ${GRUB_BOOTSTRAP} ]]; then
- python_setup
- else
- export PYTHON=true
- fi
-
- if [[ -n ${GRUB_BOOTSTRAP} ]]; then
- eautopoint --force
- AUTOPOINT=: AUTORECONF=: ./bootstrap || die
- elif [[ -n ${GRUB_AUTOGEN} ]]; then
- FROM_BOOTSTRAP=1 ./autogen.sh || die
- fi
-
- if [[ -n ${GRUB_AUTORECONF} ]]; then
- eautoreconf
- fi
-}
-
-grub_do() {
- multibuild_foreach_variant run_in_build_dir "$@"
-}
-
-grub_do_once() {
- multibuild_for_best_variant run_in_build_dir "$@"
-}
-
-grub_configure() {
- local platform
-
- case ${MULTIBUILD_VARIANT} in
- efi*) platform=efi ;;
- xen-pvh) platform=xen_pvh ;;
- xen*) platform=xen ;;
- guessed) ;;
- *) platform=${MULTIBUILD_VARIANT} ;;
- esac
-
- case ${MULTIBUILD_VARIANT} in
- *-32)
- if [[ ${CTARGET:-${CHOST}} == x86_64* ]]; then
- local CTARGET=i386
- fi ;;
- *-64)
- if [[ ${CTARGET:-${CHOST}} == i?86* ]]; then
- local CTARGET=x86_64
- local -x TARGET_CFLAGS="-Os -march=x86-64 ${TARGET_CFLAGS}"
- local -x TARGET_CPPFLAGS="-march=x86-64 ${TARGET_CPPFLAGS}"
- fi ;;
- esac
-
- local myeconfargs=(
- --disable-werror
- --program-prefix=
- --libdir="${EPREFIX}"/usr/lib
- $(use_enable device-mapper)
- $(use_enable mount grub-mount)
- $(use_enable nls)
- $(use_enable themes grub-themes)
- $(use_enable truetype grub-mkfont)
- $(use_enable libzfs)
- $(use_enable sdl grub-emu-sdl)
- ${platform:+--with-platform=}${platform}
-
- # Let configure detect this where supported
- $(usex efiemu '' '--disable-efiemu')
- )
-
- if use fonts; then
- ln -rs "${WORKDIR}/${UNIFONT}.pcf" unifont.pcf || die
- fi
-
- if use themes; then
- ln -rs "${WORKDIR}/${DEJAVU}/ttf/DejaVuSans.ttf" DejaVuSans.ttf || die
- fi
-
- local ECONF_SOURCE="${S}"
- econf "${myeconfargs[@]}"
-}
-
-src_configure() {
- # Bug 508758.
- replace-flags -O3 -O2
-
- # Workaround for bug 829165.
- filter-ldflags -pie
-
- # We don't want to leak flags onto boot code.
- export HOST_CCASFLAGS=${CCASFLAGS}
- export HOST_CFLAGS=${CFLAGS}
- export HOST_CPPFLAGS=${CPPFLAGS}
- export HOST_LDFLAGS=${LDFLAGS}
- unset CCASFLAGS CFLAGS CPPFLAGS LDFLAGS
-
- tc-ld-disable-gold #439082 #466536 #526348
- export TARGET_LDFLAGS="${TARGET_LDFLAGS} ${LDFLAGS}"
- unset LDFLAGS
-
- tc-export CC NM OBJCOPY RANLIB STRIP
- tc-export BUILD_CC BUILD_PKG_CONFIG
-
- # Force configure to use flex & bison, bug 887211.
- export LEX=flex
- unset YACC
-
- MULTIBUILD_VARIANTS=()
- local p
- for p in "${GRUB_ALL_PLATFORMS[@]}"; do
- use "grub_platforms_${p}" && MULTIBUILD_VARIANTS+=( "${p}" )
- done
- [[ ${#MULTIBUILD_VARIANTS[@]} -eq 0 ]] && MULTIBUILD_VARIANTS=( guessed )
- grub_do grub_configure
-}
-
-src_compile() {
- # Sandbox bug 404013.
- use libzfs && addpredict /etc/dfs:/dev/zfs
-
- grub_do emake
- use doc && grub_do_once emake -C docs html
-}
-
-src_test() {
- # The qemu dependency is a bit complex.
- # You will need to adjust QEMU_SOFTMMU_TARGETS to match the cpu/platform.
- local SANDBOX_WRITE=${SANDBOX_WRITE}
- addwrite /dev
- grub_do emake -j1 check
-}
-
-src_install() {
- grub_do emake install DESTDIR="${D}" bashcompletiondir="$(get_bashcompdir)"
- use doc && grub_do_once emake -C docs install-html DESTDIR="${D}"
-
- einstalldocs
-
- insinto /etc/default
- newins "${FILESDIR}"/grub.default-4 grub
-
- # https://bugs.gentoo.org/231935
- dostrip -x /usr/lib/grub
-}
-
-pkg_postinst() {
- elog "For information on how to configure GRUB2 please refer to the guide:"
- elog " https://wiki.gentoo.org/wiki/GRUB2_Quick_Start"
-
- if [[ -n ${REPLACING_VERSIONS} ]]; then
- local v
- for v in ${REPLACING_VERSIONS}; do
- if ver_test -gt ${v}; then
- ewarn
- ewarn "Re-run grub-install to update installed boot code!"
- ewarn "Re-run grub-mkconfig to update grub.cfg!"
- ewarn
- break
- fi
- done
- else
- elog
- optfeature "detecting other operating systems (grub-mkconfig)" sys-boot/os-prober
- optfeature "creating rescue media (grub-mkrescue)" dev-libs/libisoburn
- optfeature "enabling RAID device detection" sys-fs/mdadm
- fi
-
- if has_version 'sys-boot/grub:0'; then
- elog "A migration guide for GRUB Legacy users is available:"
- elog " https://wiki.gentoo.org/wiki/GRUB2_Migration"
- fi
-
- if has_version sys-boot/os-prober; then
- ewarn "Due to security concerns, os-prober is disabled by default."
- ewarn "Set GRUB_DISABLE_OS_PROBER=false in /etc/default/grub to enable it."
- fi
-}
diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/grub-9999.ebuild b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/grub-9999.ebuild
deleted file mode 100644
index 8d6f9d06e4..0000000000
--- a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/grub-9999.ebuild
+++ /dev/null
@@ -1,332 +0,0 @@
-# Copyright 1999-2023 Gentoo Authors
-# Distributed under the terms of the GNU General Public License v2
-
-EAPI=7
-
-# This ebuild uses 3 special global variables:
-# GRUB_BOOTSTRAP: Depend on python and invoke bootstrap (gnulib).
-# GRUB_AUTOGEN: Depend on python and invoke autogen.sh.
-# GRUB_AUTORECONF: Inherit autotools and invoke eautoreconf.
-#
-# When applying patches:
-# If gnulib is updated, set GRUB_BOOTSTRAP=1
-# If gentpl.py or *.def is updated, set GRUB_AUTOGEN=1
-# If gnulib, gentpl.py, *.def, or any autotools files are updated, set GRUB_AUTORECONF=1
-#
-# If any of the above applies to a user patch, the user should set the
-# corresponding variable in make.conf or the environment.
-
-if [[ ${PV} == 9999 ]]; then
- GRUB_AUTORECONF=1
- GRUB_BOOTSTRAP=1
-fi
-
-PYTHON_COMPAT=( python3_{9..11} )
-WANT_LIBTOOL=none
-
-if [[ -n ${GRUB_AUTOGEN} || -n ${GRUB_BOOTSTRAP} ]]; then
- inherit python-any-r1
-fi
-
-if [[ -n ${GRUB_AUTORECONF} ]]; then
- inherit autotools
-fi
-
-inherit bash-completion-r1 flag-o-matic multibuild optfeature toolchain-funcs
-
-if [[ ${PV} != 9999 ]]; then
- if [[ ${PV} == *_alpha* || ${PV} == *_beta* || ${PV} == *_rc* ]]; then
- # The quote style is to work with <=bash-4.2 and >=bash-4.3 #503860
- MY_P=${P/_/'~'}
- SRC_URI="https://alpha.gnu.org/gnu/${PN}/${MY_P}.tar.xz"
- S=${WORKDIR}/${MY_P}
- else
- SRC_URI="mirror://gnu/${PN}/${P}.tar.xz"
- S=${WORKDIR}/${P%_*}
- fi
- KEYWORDS="~amd64 ~arm ~arm64 ~ia64 ~ppc ~ppc64 ~riscv ~sparc ~x86"
-else
- inherit git-r3
- EGIT_REPO_URI="https://git.savannah.gnu.org/git/grub.git"
-fi
-
-PATCHES=(
- "${FILESDIR}"/gfxpayload.patch
- "${FILESDIR}"/grub-2.02_beta2-KERNEL_GLOBS.patch
- "${FILESDIR}"/grub-2.06-test-words.patch
-)
-
-DEJAVU=dejavu-sans-ttf-2.37
-UNIFONT=unifont-15.0.06
-SRC_URI+=" fonts? ( mirror://gnu/unifont/${UNIFONT}/${UNIFONT}.pcf.gz )
- themes? ( mirror://sourceforge/dejavu/${DEJAVU}.zip )"
-
-DESCRIPTION="GNU GRUB boot loader"
-HOMEPAGE="https://www.gnu.org/software/grub/"
-
-# Includes licenses for dejavu and unifont
-LICENSE="GPL-3+ BSD MIT fonts? ( GPL-2-with-font-exception ) themes? ( CC-BY-SA-3.0 BitstreamVera )"
-SLOT="2/${PVR}"
-IUSE="device-mapper doc efiemu +fonts mount nls sdl test +themes truetype libzfs"
-
-GRUB_ALL_PLATFORMS=( coreboot efi-32 efi-64 emu ieee1275 loongson multiboot
- qemu qemu-mips pc uboot xen xen-32 xen-pvh )
-IUSE+=" ${GRUB_ALL_PLATFORMS[@]/#/grub_platforms_}"
-
-REQUIRED_USE="
- grub_platforms_coreboot? ( fonts )
- grub_platforms_qemu? ( fonts )
- grub_platforms_ieee1275? ( fonts )
- grub_platforms_loongson? ( fonts )
-"
-
-BDEPEND="
- ${PYTHON_DEPS}
- >=sys-devel/flex-2.5.35
- sys-devel/bison
- sys-apps/help2man
- sys-apps/texinfo
- fonts? (
- media-libs/freetype:2
- virtual/pkgconfig
- )
- test? (
- app-admin/genromfs
- app-arch/cpio
- app-arch/lzop
- app-emulation/qemu
- dev-libs/libisoburn
- sys-apps/miscfiles
- sys-block/parted
- sys-fs/squashfs-tools
- )
- themes? (
- app-arch/unzip
- media-libs/freetype:2
- virtual/pkgconfig
- )
- truetype? ( virtual/pkgconfig )
-"
-DEPEND="
- app-arch/xz-utils
- >=sys-libs/ncurses-5.2-r5:0=
- grub_platforms_emu? (
- sdl? ( media-libs/libsdl )
- )
- device-mapper? ( >=sys-fs/lvm2-2.02.45 )
- libzfs? ( sys-fs/zfs:= )
- mount? ( sys-fs/fuse:0 )
- truetype? ( media-libs/freetype:2= )
- ppc? ( >=sys-apps/ibm-powerpc-utils-1.3.5 )
- ppc64? ( >=sys-apps/ibm-powerpc-utils-1.3.5 )
-"
-RDEPEND="${DEPEND}
- kernel_linux? (
- grub_platforms_efi-32? ( sys-boot/efibootmgr )
- grub_platforms_efi-64? ( sys-boot/efibootmgr )
- )
- !sys-boot/grub:0
- nls? ( sys-devel/gettext )
-"
-
-RESTRICT="!test? ( test ) test? ( userpriv )"
-
-QA_EXECSTACK="usr/bin/grub-emu* usr/lib/grub/*"
-QA_PRESTRIPPED="usr/lib/grub/.*"
-QA_MULTILIB_PATHS="usr/lib/grub/.*"
-QA_WX_LOAD="usr/lib/grub/*"
-
-pkg_setup() {
- :
-}
-
-src_unpack() {
- if [[ ${PV} == 9999 ]]; then
- git-r3_src_unpack
- pushd "${P}" >/dev/null || die
- local GNULIB_URI="https://git.savannah.gnu.org/git/gnulib.git"
- local GNULIB_REVISION=$(source bootstrap.conf >/dev/null; echo "${GNULIB_REVISION}")
- git-r3_fetch "${GNULIB_URI}" "${GNULIB_REVISION}"
- git-r3_checkout "${GNULIB_URI}" gnulib
- popd >/dev/null || die
- fi
- default
-}
-
-src_prepare() {
- default
-
- if [[ -n ${GRUB_AUTOGEN} || -n ${GRUB_BOOTSTRAP} ]]; then
- python_setup
- else
- export PYTHON=true
- fi
-
- if [[ -n ${GRUB_BOOTSTRAP} ]]; then
- eautopoint --force
- AUTOPOINT=: AUTORECONF=: ./bootstrap || die
- elif [[ -n ${GRUB_AUTOGEN} ]]; then
- FROM_BOOTSTRAP=1 ./autogen.sh || die
- fi
-
- if [[ -n ${GRUB_AUTORECONF} ]]; then
- eautoreconf
- fi
-}
-
-grub_do() {
- multibuild_foreach_variant run_in_build_dir "$@"
-}
-
-grub_do_once() {
- multibuild_for_best_variant run_in_build_dir "$@"
-}
-
-grub_configure() {
- local platform
-
- case ${MULTIBUILD_VARIANT} in
- efi*) platform=efi ;;
- xen-pvh) platform=xen_pvh ;;
- xen*) platform=xen ;;
- guessed) ;;
- *) platform=${MULTIBUILD_VARIANT} ;;
- esac
-
- case ${MULTIBUILD_VARIANT} in
- *-32)
- if [[ ${CTARGET:-${CHOST}} == x86_64* ]]; then
- local CTARGET=i386
- fi ;;
- *-64)
- if [[ ${CTARGET:-${CHOST}} == i?86* ]]; then
- local CTARGET=x86_64
- local -x TARGET_CFLAGS="-Os -march=x86-64 ${TARGET_CFLAGS}"
- local -x TARGET_CPPFLAGS="-march=x86-64 ${TARGET_CPPFLAGS}"
- fi ;;
- esac
-
- local myeconfargs=(
- --disable-werror
- --program-prefix=
- --libdir="${EPREFIX}"/usr/lib
- $(use_enable device-mapper)
- $(use_enable mount grub-mount)
- $(use_enable nls)
- $(use_enable themes grub-themes)
- $(use_enable truetype grub-mkfont)
- $(use_enable libzfs)
- $(use_enable sdl grub-emu-sdl)
- ${platform:+--with-platform=}${platform}
-
- # Let configure detect this where supported
- $(usex efiemu '' '--disable-efiemu')
- )
-
- if use fonts; then
- ln -rs "${WORKDIR}/${UNIFONT}.pcf" unifont.pcf || die
- fi
-
- if use themes; then
- ln -rs "${WORKDIR}/${DEJAVU}/ttf/DejaVuSans.ttf" DejaVuSans.ttf || die
- fi
-
- local ECONF_SOURCE="${S}"
- econf "${myeconfargs[@]}"
-}
-
-src_configure() {
- # Bug 508758.
- replace-flags -O3 -O2
-
- # Workaround for bug 829165.
- filter-ldflags -pie
-
- # We don't want to leak flags onto boot code.
- export HOST_CCASFLAGS=${CCASFLAGS}
- export HOST_CFLAGS=${CFLAGS}
- export HOST_CPPFLAGS=${CPPFLAGS}
- export HOST_LDFLAGS=${LDFLAGS}
- unset CCASFLAGS CFLAGS CPPFLAGS LDFLAGS
-
- tc-ld-disable-gold #439082 #466536 #526348
- export TARGET_LDFLAGS="${TARGET_LDFLAGS} ${LDFLAGS}"
- unset LDFLAGS
-
- tc-export CC NM OBJCOPY RANLIB STRIP
- tc-export BUILD_CC BUILD_PKG_CONFIG
-
- # Force configure to use flex & bison, bug 887211.
- export LEX=flex
- unset YACC
-
- MULTIBUILD_VARIANTS=()
- local p
- for p in "${GRUB_ALL_PLATFORMS[@]}"; do
- use "grub_platforms_${p}" && MULTIBUILD_VARIANTS+=( "${p}" )
- done
- [[ ${#MULTIBUILD_VARIANTS[@]} -eq 0 ]] && MULTIBUILD_VARIANTS=( guessed )
- grub_do grub_configure
-}
-
-src_compile() {
- # Sandbox bug 404013.
- use libzfs && addpredict /etc/dfs:/dev/zfs
-
- grub_do emake
- use doc && grub_do_once emake -C docs html
-}
-
-src_test() {
- # The qemu dependency is a bit complex.
- # You will need to adjust QEMU_SOFTMMU_TARGETS to match the cpu/platform.
- local SANDBOX_WRITE=${SANDBOX_WRITE}
- addwrite /dev
- grub_do emake -j1 check
-}
-
-src_install() {
- grub_do emake install DESTDIR="${D}" bashcompletiondir="$(get_bashcompdir)"
- use doc && grub_do_once emake -C docs install-html DESTDIR="${D}"
-
- einstalldocs
-
- insinto /etc/default
- newins "${FILESDIR}"/grub.default-4 grub
-
- # https://bugs.gentoo.org/231935
- dostrip -x /usr/lib/grub
-}
-
-pkg_postinst() {
- elog "For information on how to configure GRUB2 please refer to the guide:"
- elog " https://wiki.gentoo.org/wiki/GRUB2_Quick_Start"
-
- if [[ -n ${REPLACING_VERSIONS} ]]; then
- local v
- for v in ${REPLACING_VERSIONS}; do
- if ver_test -gt ${v}; then
- ewarn
- ewarn "Re-run grub-install to update installed boot code!"
- ewarn "Re-run grub-mkconfig to update grub.cfg!"
- ewarn
- break
- fi
- done
- else
- elog
- optfeature "detecting other operating systems (grub-mkconfig)" sys-boot/os-prober
- optfeature "creating rescue media (grub-mkrescue)" dev-libs/libisoburn
- optfeature "enabling RAID device detection" sys-fs/mdadm
- fi
-
- if has_version 'sys-boot/grub:0'; then
- elog "A migration guide for GRUB Legacy users is available:"
- elog " https://wiki.gentoo.org/wiki/GRUB2_Migration"
- fi
-
- if has_version sys-boot/os-prober; then
- ewarn "Due to security concerns, os-prober is disabled by default."
- ewarn "Set GRUB_DISABLE_OS_PROBER=false in /etc/default/grub to enable it."
- fi
-}