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
|
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.
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
grub-core/loader/efi/fdt.c | 35 ++++++++++++++++++++++++++++++++++-
include/grub/efi/api.h | 22 ++++++++++++++++++++++
2 files changed, 56 insertions(+), 1 deletion(-)
diff --git a/grub-core/loader/efi/fdt.c b/grub-core/loader/efi/fdt.c
index 57ee81686..58e95eb05 100644
--- a/grub-core/loader/efi/fdt.c
+++ b/grub-core/loader/efi/fdt.c
@@ -29,6 +29,7 @@
static void *loaded_fdt;
static void *fdt;
+static grub_efi_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"
@@ -36,6 +37,38 @@ static void *fdt;
sizeof (FDT_ADDR_CELLS_STRING) + \
sizeof (FDT_SIZE_CELLS_STRING))
+static void *grub_fdt_fixup (void)
+{
+ 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 loaded_fdt;
+
+ grub_dprintf ("linux", "EFI_DT_FIXUP_PROTOCOL available\n");
+
+ status = efi_call_4 (dt_fixup_prot->fixup, dt_fixup_prot, loaded_fdt, &size,
+ GRUB_EFI_DT_APPLY_FIXUPS | GRUB_EFI_DT_RESERVE_MEMORY);
+ if (status != GRUB_EFI_BUFFER_TOO_SMALL)
+ return loaded_fdt;
+
+ fixup_fdt = grub_realloc (loaded_fdt, size);
+ if (!fixup_fdt)
+ return loaded_fdt;
+ loaded_fdt = fixup_fdt;
+
+ status = efi_call_4 (dt_fixup_prot->fixup, dt_fixup_prot, loaded_fdt, &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 loaded_fdt;
+}
+
void *
grub_fdt_load (grub_size_t additional_size)
{
@@ -49,7 +82,7 @@ grub_fdt_load (grub_size_t additional_size)
}
if (loaded_fdt)
- raw_fdt = loaded_fdt;
+ raw_fdt = grub_fdt_fixup();
else
raw_fdt = grub_efi_get_firmware_fdt();
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
index 34109861a..8101df0df 100644
--- a/include/grub/efi/api.h
+++ b/include/grub/efi/api.h
@@ -334,6 +334,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 } \
@@ -1641,6 +1646,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;
@@ -1704,6 +1716,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 (*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
{
grub_efi_status_t (*verify) (void *buffer, grub_uint32_t size);
--
2.30.0
|