]> git.proxmox.com Git - grub2.git/blame - debian/patches/linuxefi.patch
New upstream release candidate (2.04~rc1)
[grub2.git] / debian / patches / linuxefi.patch
CommitLineData
8be00ff3 1From 3b2f0fe2c4f9d1f4734ad33d0b57a77e0036a68d Mon Sep 17 00:00:00 2001
0cdf09fd
CW
2From: Matthew Garrett <mjg@redhat.com>
3Date: Mon, 13 Jan 2014 12:13:15 +0000
4Subject: Add "linuxefi" loader which avoids ExitBootServices
5
2a15f519
CW
6Origin: vendor, http://pkgs.fedoraproject.org/cgit/grub2.git/tree/grub2-linuxefi.patch
7Forwarded: no
8be00ff3 8Last-Update: 2019-05-26
2a15f519 9
0cdf09fd
CW
10Patch-Name: linuxefi.patch
11---
8be00ff3 12 grub-core/Makefile.core.def | 7 +
201a3447 13 grub-core/kern/efi/mm.c | 32 +++
8be00ff3 14 grub-core/loader/i386/efi/linux.c | 375 ++++++++++++++++++++++++++++++
0cdf09fd 15 include/grub/efi/efi.h | 3 +
8be00ff3 16 4 files changed, 417 insertions(+)
0cdf09fd
CW
17 create mode 100644 grub-core/loader/i386/efi/linux.c
18
19diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
8be00ff3 20index 474a63e68..67a98abbb 100644
2a15f519
CW
21--- a/grub-core/Makefile.core.def
22+++ b/grub-core/Makefile.core.def
8be00ff3 23@@ -1849,6 +1849,13 @@ module = {
201a3447 24 enable = x86_64_efi;
2a15f519
CW
25 };
26
201a3447 27+module = {
2a15f519
CW
28+ name = linuxefi;
29+ efi = loader/i386/efi/linux.c;
2a15f519
CW
30+ enable = i386_efi;
31+ enable = x86_64_efi;
32+};
33+
201a3447 34 module = {
2a15f519
CW
35 name = chain;
36 efi = loader/efi/chainloader.c;
0cdf09fd 37diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
8be00ff3 38index b02fab1b1..a9e37108c 100644
2a15f519
CW
39--- a/grub-core/kern/efi/mm.c
40+++ b/grub-core/kern/efi/mm.c
8be00ff3
CW
41@@ -113,6 +113,38 @@ grub_efi_drop_alloc (grub_efi_physical_address_t address,
42 }
43 }
2a15f519
CW
44
45+/* Allocate pages below a specified address */
46+void *
47+grub_efi_allocate_pages_max (grub_efi_physical_address_t max,
48+ grub_efi_uintn_t pages)
49+{
50+ grub_efi_status_t status;
51+ grub_efi_boot_services_t *b;
52+ grub_efi_physical_address_t address = max;
53+
54+ if (max > 0xffffffff)
55+ return 0;
56+
57+ b = grub_efi_system_table->boot_services;
58+ status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, GRUB_EFI_LOADER_DATA, pages, &address);
59+
60+ if (status != GRUB_EFI_SUCCESS)
61+ return 0;
62+
63+ if (address == 0)
64+ {
65+ /* Uggh, the address 0 was allocated... This is too annoying,
66+ so reallocate another one. */
67+ address = max;
68+ status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, GRUB_EFI_LOADER_DATA, pages, &address);
69+ grub_efi_free_pages (0, pages);
70+ if (status != GRUB_EFI_SUCCESS)
71+ return 0;
72+ }
73+
74+ return (void *) ((grub_addr_t) address);
75+}
76+
77 /* Allocate pages. Return the pointer to the first of allocated pages. */
78 void *
8be00ff3 79 grub_efi_allocate_pages_real (grub_efi_physical_address_t address,
0cdf09fd
CW
80diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
81new file mode 100644
8be00ff3 82index 000000000..dd376ce03
2a15f519
CW
83--- /dev/null
84+++ b/grub-core/loader/i386/efi/linux.c
8be00ff3 85@@ -0,0 +1,375 @@
2a15f519
CW
86+/*
87+ * GRUB -- GRand Unified Bootloader
88+ * Copyright (C) 2012 Free Software Foundation, Inc.
89+ *
90+ * GRUB is free software: you can redistribute it and/or modify
91+ * it under the terms of the GNU General Public License as published by
92+ * the Free Software Foundation, either version 3 of the License, or
93+ * (at your option) any later version.
94+ *
95+ * GRUB is distributed in the hope that it will be useful,
96+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
97+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
98+ * GNU General Public License for more details.
99+ *
100+ * You should have received a copy of the GNU General Public License
101+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
102+ */
103+
104+#include <grub/loader.h>
105+#include <grub/file.h>
106+#include <grub/err.h>
8be00ff3 107+#include <grub/misc.h>
2a15f519
CW
108+#include <grub/types.h>
109+#include <grub/mm.h>
110+#include <grub/cpu/linux.h>
111+#include <grub/command.h>
112+#include <grub/i18n.h>
113+#include <grub/lib/cmdline.h>
8be00ff3 114+#include <grub/linux.h>
2a15f519
CW
115+#include <grub/efi/efi.h>
116+
117+GRUB_MOD_LICENSE ("GPLv3+");
118+
119+static grub_dl_t my_mod;
120+static int loaded;
121+static void *kernel_mem;
122+static grub_uint64_t kernel_size;
123+static grub_uint8_t *initrd_mem;
124+static grub_uint32_t handover_offset;
125+struct linux_kernel_params *params;
126+static char *linux_cmdline;
127+
128+#define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12)
129+
130+#define SHIM_LOCK_GUID \
131+ { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} }
132+
133+struct grub_efi_shim_lock
134+{
135+ grub_efi_status_t (*verify) (void *buffer, grub_uint32_t size);
136+};
137+typedef struct grub_efi_shim_lock grub_efi_shim_lock_t;
138+
139+static grub_efi_boolean_t
140+grub_linuxefi_secure_validate (void *data, grub_uint32_t size)
141+{
142+ grub_efi_guid_t guid = SHIM_LOCK_GUID;
143+ grub_efi_shim_lock_t *shim_lock;
8be00ff3 144+ grub_efi_status_t status;
2a15f519 145+
8be00ff3 146+ grub_dprintf ("linuxefi", "Locating shim protocol\n");
2a15f519
CW
147+ shim_lock = grub_efi_locate_protocol(&guid, NULL);
148+
149+ if (!shim_lock)
8be00ff3
CW
150+ {
151+ grub_dprintf ("linuxefi", "shim not available\n");
152+ return 0;
153+ }
2a15f519 154+
8be00ff3
CW
155+ grub_dprintf ("linuxefi", "Asking shim to verify kernel signature\n");
156+ status = shim_lock->verify(data, size);
157+ if (status == GRUB_EFI_SUCCESS)
158+ {
159+ grub_dprintf ("linuxefi", "Kernel signature verification passed\n");
160+ return 1;
161+ }
2a15f519 162+
8be00ff3
CW
163+ grub_dprintf ("linuxefi", "Kernel signature verification failed (0x%lx)\n",
164+ (unsigned long) status);
2a15f519
CW
165+ return 0;
166+}
167+
168+typedef void(*handover_func)(void *, grub_efi_system_table_t *, struct linux_kernel_params *);
169+
170+static grub_err_t
171+grub_linuxefi_boot (void)
172+{
173+ handover_func hf;
174+ int offset = 0;
175+
176+#ifdef __x86_64__
177+ offset = 512;
178+#endif
179+
180+ hf = (handover_func)((char *)kernel_mem + handover_offset + offset);
181+
182+ asm volatile ("cli");
183+
184+ hf (grub_efi_image_handle, grub_efi_system_table, params);
185+
186+ /* Not reached */
187+ return GRUB_ERR_NONE;
188+}
189+
190+static grub_err_t
191+grub_linuxefi_unload (void)
192+{
193+ grub_dl_unref (my_mod);
194+ loaded = 0;
195+ if (initrd_mem)
9e060a25 196+ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)initrd_mem, BYTES_TO_PAGES(params->ramdisk_size));
2a15f519 197+ if (linux_cmdline)
9e060a25 198+ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)linux_cmdline, BYTES_TO_PAGES(params->cmdline_size + 1));
2a15f519 199+ if (kernel_mem)
9e060a25 200+ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)kernel_mem, BYTES_TO_PAGES(kernel_size));
2a15f519 201+ if (params)
9e060a25 202+ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)params, BYTES_TO_PAGES(16384));
2a15f519
CW
203+ return GRUB_ERR_NONE;
204+}
205+
206+static grub_err_t
207+grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
208+ int argc, char *argv[])
209+{
2a15f519 210+ grub_size_t size = 0;
8be00ff3 211+ struct grub_linux_initrd_context initrd_ctx;
2a15f519
CW
212+
213+ if (argc == 0)
214+ {
215+ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
216+ goto fail;
217+ }
218+
219+ if (!loaded)
220+ {
221+ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first"));
222+ goto fail;
223+ }
224+
8be00ff3 225+ if (grub_initrd_init (argc, argv, &initrd_ctx))
2a15f519
CW
226+ goto fail;
227+
8be00ff3 228+ size = grub_get_initrd_size (&initrd_ctx);
2a15f519
CW
229+
230+ initrd_mem = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(size));
231+
232+ if (!initrd_mem)
233+ {
234+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd"));
235+ goto fail;
236+ }
237+
8be00ff3
CW
238+ grub_dprintf ("linuxefi", "initrd_mem = %lx\n", (unsigned long) initrd_mem);
239+
2a15f519 240+ params->ramdisk_size = size;
9e060a25 241+ params->ramdisk_image = (grub_uint32_t)(grub_addr_t) initrd_mem;
2a15f519 242+
8be00ff3
CW
243+ if (grub_initrd_load (&initrd_ctx, argv, initrd_mem))
244+ goto fail;
2a15f519
CW
245+
246+ params->ramdisk_size = size;
247+
248+ fail:
8be00ff3 249+ grub_initrd_close (&initrd_ctx);
2a15f519
CW
250+
251+ if (initrd_mem && grub_errno)
9e060a25 252+ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)initrd_mem, BYTES_TO_PAGES(size));
2a15f519
CW
253+
254+ return grub_errno;
255+}
256+
257+static grub_err_t
258+grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
259+ int argc, char *argv[])
260+{
261+ grub_file_t file = 0;
8be00ff3 262+ struct linux_i386_kernel_header lh;
2a15f519
CW
263+ grub_ssize_t len, start, filelen;
264+ void *kernel;
265+
266+ grub_dl_ref (my_mod);
267+
268+ if (argc == 0)
269+ {
270+ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
271+ goto fail;
272+ }
273+
8be00ff3 274+ file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL);
2a15f519
CW
275+ if (! file)
276+ goto fail;
277+
278+ filelen = grub_file_size (file);
279+
280+ kernel = grub_malloc(filelen);
281+
282+ if (!kernel)
283+ {
284+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer"));
285+ goto fail;
286+ }
287+
288+ if (grub_file_read (file, kernel, filelen) != filelen)
289+ {
290+ grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), argv[0]);
291+ goto fail;
292+ }
293+
294+ if (! grub_linuxefi_secure_validate (kernel, filelen))
295+ {
296+ grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]);
297+ grub_free (kernel);
298+ goto fail;
299+ }
300+
301+ grub_file_seek (file, 0);
302+
303+ grub_free(kernel);
304+
305+ params = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(16384));
306+
307+ if (! params)
308+ {
309+ grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters");
310+ goto fail;
311+ }
312+
8be00ff3
CW
313+ grub_dprintf ("linuxefi", "params = %lx\n", (unsigned long) params);
314+
93f7216b 315+ grub_memset (params, 0, 16384);
2a15f519
CW
316+
317+ if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
318+ {
319+ if (!grub_errno)
320+ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
321+ argv[0]);
322+ goto fail;
323+ }
324+
325+ if (lh.boot_flag != grub_cpu_to_le16 (0xaa55))
326+ {
327+ grub_error (GRUB_ERR_BAD_OS, N_("invalid magic number"));
328+ goto fail;
329+ }
330+
331+ if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS)
332+ {
333+ grub_error (GRUB_ERR_BAD_OS, N_("too many setup sectors"));
334+ goto fail;
335+ }
336+
337+ if (lh.version < grub_cpu_to_le16 (0x020b))
338+ {
339+ grub_error (GRUB_ERR_BAD_OS, N_("kernel too old"));
340+ goto fail;
341+ }
342+
343+ if (!lh.handover_offset)
344+ {
345+ grub_error (GRUB_ERR_BAD_OS, N_("kernel doesn't support EFI handover"));
346+ goto fail;
347+ }
348+
349+ linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff,
350+ BYTES_TO_PAGES(lh.cmdline_size + 1));
351+
352+ if (!linux_cmdline)
353+ {
354+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline"));
355+ goto fail;
356+ }
357+
8be00ff3
CW
358+ grub_dprintf ("linuxefi", "linux_cmdline = %lx\n",
359+ (unsigned long) linux_cmdline);
360+
2a15f519 361+ grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
8be00ff3
CW
362+ {
363+ grub_err_t err;
364+ err = grub_create_loader_cmdline (argc, argv,
365+ linux_cmdline
366+ + sizeof (LINUX_IMAGE) - 1,
367+ lh.cmdline_size
368+ - (sizeof (LINUX_IMAGE) - 1),
369+ GRUB_VERIFY_KERNEL_CMDLINE);
370+ if (err)
371+ goto fail;
372+ }
2a15f519 373+
9e060a25 374+ lh.cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline;
2a15f519
CW
375+
376+ handover_offset = lh.handover_offset;
377+
378+ start = (lh.setup_sects + 1) * 512;
379+ len = grub_file_size(file) - start;
380+
8be00ff3 381+ kernel_mem = grub_efi_allocate_fixed(lh.pref_address,
2a15f519
CW
382+ BYTES_TO_PAGES(lh.init_size));
383+
384+ if (!kernel_mem)
385+ kernel_mem = grub_efi_allocate_pages_max(0x3fffffff,
386+ BYTES_TO_PAGES(lh.init_size));
387+
388+ if (!kernel_mem)
389+ {
390+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel"));
391+ goto fail;
392+ }
393+
8be00ff3
CW
394+ grub_dprintf ("linuxefi", "kernel_mem = %lx\n", (unsigned long) kernel_mem);
395+
2a15f519
CW
396+ if (grub_file_seek (file, start) == (grub_off_t) -1)
397+ {
398+ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
399+ argv[0]);
400+ goto fail;
401+ }
402+
403+ if (grub_file_read (file, kernel_mem, len) != len && !grub_errno)
404+ {
405+ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
406+ argv[0]);
407+ }
408+
409+ if (grub_errno == GRUB_ERR_NONE)
410+ {
411+ grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0);
412+ loaded = 1;
9e060a25 413+ lh.code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem;
2a15f519
CW
414+ }
415+
93f7216b 416+ grub_memcpy (params, &lh, 2 * 512);
2a15f519
CW
417+
418+ params->type_of_loader = 0x21;
419+
420+ fail:
421+
422+ if (file)
423+ grub_file_close (file);
424+
425+ if (grub_errno != GRUB_ERR_NONE)
426+ {
427+ grub_dl_unref (my_mod);
428+ loaded = 0;
429+ }
430+
431+ if (linux_cmdline && !loaded)
9e060a25 432+ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)linux_cmdline, BYTES_TO_PAGES(lh.cmdline_size + 1));
2a15f519
CW
433+
434+ if (kernel_mem && !loaded)
9e060a25 435+ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)kernel_mem, BYTES_TO_PAGES(kernel_size));
2a15f519
CW
436+
437+ if (params && !loaded)
9e060a25 438+ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)params, BYTES_TO_PAGES(16384));
2a15f519
CW
439+
440+ return grub_errno;
441+}
442+
443+static grub_command_t cmd_linux, cmd_initrd;
444+
445+GRUB_MOD_INIT(linuxefi)
446+{
447+ cmd_linux =
448+ grub_register_command ("linuxefi", grub_cmd_linux,
449+ 0, N_("Load Linux."));
450+ cmd_initrd =
451+ grub_register_command ("initrdefi", grub_cmd_initrd,
452+ 0, N_("Load initrd."));
453+ my_mod = mod;
454+}
455+
456+GRUB_MOD_FINI(linuxefi)
457+{
458+ grub_unregister_command (cmd_linux);
459+ grub_unregister_command (cmd_initrd);
460+}
0cdf09fd 461diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
8be00ff3 462index a237952b3..085ee0524 100644
2a15f519
CW
463--- a/include/grub/efi/efi.h
464+++ b/include/grub/efi/efi.h
8be00ff3 465@@ -47,6 +47,9 @@ EXPORT_FUNC(grub_efi_allocate_fixed) (grub_efi_physical_address_t address,
2a15f519 466 grub_efi_uintn_t pages);
8be00ff3
CW
467 void *
468 EXPORT_FUNC(grub_efi_allocate_any_pages) (grub_efi_uintn_t pages);
2a15f519
CW
469+void *
470+EXPORT_FUNC(grub_efi_allocate_pages_max) (grub_efi_physical_address_t max,
471+ grub_efi_uintn_t pages);
472 void EXPORT_FUNC(grub_efi_free_pages) (grub_efi_physical_address_t address,
473 grub_efi_uintn_t pages);
8be00ff3 474 grub_efi_uintn_t EXPORT_FUNC(grub_efi_find_mmap_size) (void);