1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
From: Heinrich Schuchardt <xypron.glpk@gmx.de>
Date: Fri, 29 Jan 2021 07:36:42 +0100
Subject: efi: EFI Device Tree Fixup Protocol
Device-trees are used to convey information about hardware to the operating
system. Some of the properties are only known at boot time. (One example of
such a property is the number of the boot hart on RISC-V systems.) Therefore
the firmware applies fix-ups to the original device-tree. Some nodes and
properties are added or altered.
When using GRUB's device-tree command the same fix-ups have to be applied.
The EFI Device Tree Fixup Protocol allows to pass the loaded device tree
to the firmware for this purpose.
The protocol can
* add nodes and update properties
* reserve memory according to the /reserved-memory node and the memory
reservation block
* install the device-tree as configuration table
With the patch GRUB checks if the protocol is installed and invokes it if
available. (LP: #1965796)
Link: https://lists.gnu.org/archive/html/grub-devel/2021-02/msg00013.html
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Signed-off-by: Julian Andres Klode <julian.klode@canonical.com>
---
grub-core/loader/efi/fdt.c | 37 +++++++++++++++++++++++++++++++++++++
include/grub/efi/api.h | 22 ++++++++++++++++++++++
2 files changed, 59 insertions(+)
diff --git a/grub-core/loader/efi/fdt.c b/grub-core/loader/efi/fdt.c
index b4a0447..948ef7e 100644
--- a/grub-core/loader/efi/fdt.c
+++ b/grub-core/loader/efi/fdt.c
@@ -32,6 +32,7 @@
static void *loaded_fdt;
static void *fdt;
+static grub_guid_t dt_fixup_guid = GRUB_EFI_DT_FIXUP_PROTOCOL_GUID;
#define FDT_ADDR_CELLS_STRING "#address-cells"
#define FDT_SIZE_CELLS_STRING "#size-cells"
@@ -46,6 +47,41 @@ static const struct grub_arg_option options_fdtdump[] = {
{0, 0, 0, 0, 0, 0}
};
+static void *
+grub_fdt_fixup (void *blob)
+{
+ grub_efi_dt_fixup_t *dt_fixup_prot;
+ grub_efi_uintn_t size = 0;
+ grub_efi_status_t status;
+ void *fixup_fdt;
+
+ dt_fixup_prot = grub_efi_locate_protocol (&dt_fixup_guid, 0);
+ if (!dt_fixup_prot)
+ return blob;
+
+ grub_dprintf ("linux", "EFI_DT_FIXUP_PROTOCOL available\n");
+
+ status = dt_fixup_prot->fixup (dt_fixup_prot, blob, &size,
+ GRUB_EFI_DT_APPLY_FIXUPS
+ | GRUB_EFI_DT_RESERVE_MEMORY);
+ if (status != GRUB_EFI_BUFFER_TOO_SMALL)
+ return blob;
+
+ fixup_fdt = grub_realloc (blob, size);
+ if (!fixup_fdt)
+ return blob;
+ blob = fixup_fdt;
+
+ status = dt_fixup_prot->fixup (dt_fixup_prot, blob, &size,
+ GRUB_EFI_DT_APPLY_FIXUPS
+ | GRUB_EFI_DT_RESERVE_MEMORY);
+
+ if (status == GRUB_EFI_SUCCESS)
+ grub_dprintf ("linux", "Device tree fixed up via EFI_DT_FIXUP_PROTOCOL\n");
+
+ return blob;
+}
+
void *
grub_fdt_load (grub_size_t additional_size)
{
@@ -170,6 +206,7 @@ out:
if (blob)
{
grub_dprintf ("fdt", "Device-tree %s loaded\n", argv[0]);
+ blob = grub_fdt_fixup (blob);
if (grub_errno == GRUB_ERR_NONE)
loaded_fdt = blob;
else
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
index 5c2be0f..c9980af 100644
--- a/include/grub/efi/api.h
+++ b/include/grub/efi/api.h
@@ -354,6 +354,11 @@
{ 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0 } \
}
+#define GRUB_EFI_DT_FIXUP_PROTOCOL_GUID \
+ { 0xe617d64c, 0xfe08, 0x46da, \
+ { 0xf4, 0xdc, 0xbb, 0xd5, 0x87, 0x0c, 0x73, 0x00 } \
+ }
+
#define GRUB_EFI_VENDOR_APPLE_GUID \
{ 0x2B0585EB, 0xD8B8, 0x49A9, \
{ 0x8B, 0x8C, 0xE2, 0x1B, 0x01, 0xAE, 0xF2, 0xB7 } \
@@ -1924,6 +1929,13 @@ enum
GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST = 0x10,
};
+enum
+ {
+ GRUB_EFI_DT_APPLY_FIXUPS = 0x01,
+ GRUB_EFI_DT_RESERVE_MEMORY = 0x02,
+ GRUB_EFI_EFI_DT_INSTALL_TABLE = 0x04,
+ };
+
struct grub_efi_simple_network
{
grub_uint64_t revision;
@@ -2006,6 +2018,16 @@ struct grub_efi_block_io
};
typedef struct grub_efi_block_io grub_efi_block_io_t;
+struct grub_efi_dt_fixup
+{
+ grub_efi_uint64_t revision;
+ grub_efi_status_t (__grub_efi_api *fixup) (struct grub_efi_dt_fixup *this,
+ void *fdt,
+ grub_efi_uintn_t *buffer_size,
+ grub_uint32_t flags);
+};
+typedef struct grub_efi_dt_fixup grub_efi_dt_fixup_t;
+
struct grub_efi_shim_lock_protocol
{
/*
|