@@ -1531,6 +1531,7 @@ module = {
i386_xen = lib/i386/xen/relocator.S;
x86_64_xen = lib/x86_64/xen/relocator.S;
xen = lib/i386/relocator_common_c.c;
+ x86_64_efi = lib/x86_64/efi/relocator.c;
extra_dist = lib/i386/relocator_common.S;
extra_dist = kern/powerpc/cache_flush.S;
@@ -73,6 +73,14 @@ VARIABLE(grub_relocator64_rsp)
movq %rax, %rsp
+ /*
+ * Here is grub_relocator64_efi_start() entry point.
+ * Following code is shared between grub_relocator64_efi_start()
+ * and grub_relocator64_start().
+ *
+ * Think twice before changing anything below!!!
+ */
+VARIABLE(grub_relocator64_efi_start)
/* mov imm64, %rax */
.byte 0x48
.byte 0xb8
@@ -120,6 +128,9 @@ LOCAL(jump_addr):
VARIABLE(grub_relocator64_rip)
.quad 0
+ /* Here grub_relocator64_efi_start() ends. Ufff... */
+VARIABLE(grub_relocator64_efi_end)
+
#ifndef __x86_64__
.p2align 4
LOCAL(gdt):
new file mode 100644
@@ -0,0 +1,80 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ * Copyright (C) 2016 Oracle and/or its affiliates. All rights reserved.
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+
+#include <grub/types.h>
+#include <grub/err.h>
+
+#include <grub/i386/relocator.h>
+#include <grub/relocator_private.h>
+
+extern grub_uint64_t grub_relocator64_rax;
+extern grub_uint64_t grub_relocator64_rbx;
+extern grub_uint64_t grub_relocator64_rcx;
+extern grub_uint64_t grub_relocator64_rdx;
+extern grub_uint64_t grub_relocator64_rip;
+extern grub_uint64_t grub_relocator64_rsi;
+
+extern grub_uint8_t grub_relocator64_efi_start;
+extern grub_uint8_t grub_relocator64_efi_end;
+
+#define RELOCATOR_SIZEOF(x) (&grub_relocator##x##_end - &grub_relocator##x##_start)
+
+grub_err_t
+grub_relocator64_efi_boot (struct grub_relocator *rel,
+ struct grub_relocator64_efi_state state)
+{
+ grub_err_t err;
+ void *relst;
+ grub_relocator_chunk_t ch;
+
+ /*
+ * 64-bit relocator code may live above 4 GiB quite well.
+ * However, I do not want ask for problems. Just in case.
+ */
+ err = grub_relocator_alloc_chunk_align (rel, &ch, 0,
+ 0x100000000 - RELOCATOR_SIZEOF (64_efi),
+ RELOCATOR_SIZEOF (64_efi), 16,
+ GRUB_RELOCATOR_PREFERENCE_NONE, 1);
+ if (err)
+ return err;
+
+ /* Do not touch %rsp! It points to EFI created stack. */
+ grub_relocator64_rax = state.rax;
+ grub_relocator64_rbx = state.rbx;
+ grub_relocator64_rcx = state.rcx;
+ grub_relocator64_rdx = state.rdx;
+ grub_relocator64_rip = state.rip;
+ grub_relocator64_rsi = state.rsi;
+
+ grub_memmove (get_virtual_current_address (ch), &grub_relocator64_efi_start,
+ RELOCATOR_SIZEOF (64_efi));
+
+ err = grub_relocator_prepare_relocs (rel, get_physical_target_address (ch),
+ &relst, NULL);
+ if (err)
+ return err;
+
+ ((void (*) (void)) relst) ();
+
+ /* Not reached. */
+ return GRUB_ERR_NONE;
+}
@@ -118,6 +118,48 @@ grub_multiboot_set_video_mode (void)
return err;
}
+#ifdef GRUB_MACHINE_EFI
+#ifdef __x86_64__
+#define grub_relocator_efi_boot grub_relocator64_efi_boot
+#define grub_relocator_efi_state grub_relocator64_efi_state
+#endif
+#endif
+
+#ifdef grub_relocator_efi_boot
+static void
+efi_boot (struct grub_relocator *rel,
+ grub_uint32_t target)
+{
+ struct grub_relocator_efi_state state_efi = MULTIBOOT_EFI_INITIAL_STATE;
+
+ state_efi.MULTIBOOT_EFI_ENTRY_REGISTER = grub_multiboot_payload_eip;
+ state_efi.MULTIBOOT_EFI_MBI_REGISTER = target;
+
+ grub_relocator_efi_boot (rel, state_efi);
+}
+#else
+#define grub_efi_is_finished 1
+static void
+efi_boot (struct grub_relocator *rel __attribute__ ((unused)),
+ grub_uint32_t target __attribute__ ((unused)))
+{
+}
+#endif
+
+#if defined (__i386__) || defined (__x86_64__)
+static void
+normal_boot (struct grub_relocator *rel, struct grub_relocator32_state state)
+{
+ grub_relocator32_boot (rel, state, 0);
+}
+#else
+static void
+normal_boot (struct grub_relocator *rel, struct grub_relocator32_state state)
+{
+ grub_relocator32_boot (rel, state);
+}
+#endif
+
static grub_err_t
grub_multiboot_boot (void)
{
@@ -131,11 +173,10 @@ grub_multiboot_boot (void)
if (err)
return err;
-#if defined (__i386__) || defined (__x86_64__)
- grub_relocator32_boot (grub_multiboot_relocator, state, 0);
-#else
- grub_relocator32_boot (grub_multiboot_relocator, state);
-#endif
+ if (grub_efi_is_finished)
+ normal_boot (grub_multiboot_relocator, state);
+ else
+ efi_boot (grub_multiboot_relocator, state.MULTIBOOT_MBI_REGISTER);
/* Not reached. */
return GRUB_ERR_NONE;
@@ -107,8 +107,8 @@ grub_multiboot_load (grub_file_t file, const char *filename)
grub_err_t err;
struct multiboot_header_tag *tag;
struct multiboot_header_tag_address *addr_tag = NULL;
- int entry_specified = 0;
- grub_addr_t entry = 0;
+ int entry_specified = 0, efi_entry_specified = 0;
+ grub_addr_t entry = 0, efi_entry = 0;
grub_uint32_t console_required = 0;
struct multiboot_header_tag_framebuffer *fbtag = NULL;
int accepted_consoles = GRUB_MULTIBOOT_CONSOLE_EGA_TEXT;
@@ -192,6 +192,13 @@ grub_multiboot_load (grub_file_t file, const char *filename)
entry = ((struct multiboot_header_tag_entry_address *) tag)->entry_addr;
break;
+ case MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64:
+#if defined (GRUB_MACHINE_EFI) && defined (__x86_64__)
+ efi_entry_specified = 1;
+ efi_entry = ((struct multiboot_header_tag_entry_address *) tag)->entry_addr;
+#endif
+ break;
+
case MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS:
if (!(((struct multiboot_header_tag_console_flags *) tag)->console_flags
& MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED))
@@ -211,7 +218,9 @@ grub_multiboot_load (grub_file_t file, const char *filename)
break;
case MULTIBOOT_HEADER_TAG_EFI_BS:
+#ifdef GRUB_MACHINE_EFI
keep_bs = 1;
+#endif
break;
default:
@@ -224,7 +233,7 @@ grub_multiboot_load (grub_file_t file, const char *filename)
break;
}
- if (addr_tag && !entry_specified)
+ if (addr_tag && !entry_specified && !(keep_bs && efi_entry_specified))
{
grub_free (buffer);
return grub_error (GRUB_ERR_UNKNOWN_OS,
@@ -287,7 +296,9 @@ grub_multiboot_load (grub_file_t file, const char *filename)
}
}
- if (entry_specified)
+ if (keep_bs && efi_entry_specified)
+ grub_multiboot_payload_eip = efi_entry;
+ else if (entry_specified)
grub_multiboot_payload_eip = entry;
if (fbtag)
@@ -30,6 +30,17 @@
#define MULTIBOOT_MBI_REGISTER ebx
#define MULTIBOOT_ARCHITECTURE_CURRENT MULTIBOOT_ARCHITECTURE_I386
+#ifdef GRUB_MACHINE_EFI
+#ifdef __x86_64__
+#define MULTIBOOT_EFI_INITIAL_STATE { .rax = MULTIBOOT_BOOTLOADER_MAGIC, \
+ .rcx = 0, \
+ .rdx = 0, \
+ }
+#define MULTIBOOT_EFI_ENTRY_REGISTER rip
+#define MULTIBOOT_EFI_MBI_REGISTER rbx
+#endif
+#endif
+
#define MULTIBOOT_ELF32_MACHINE EM_386
#define MULTIBOOT_ELF64_MACHINE EM_X86_64
@@ -65,6 +65,20 @@ struct grub_relocator64_state
grub_addr_t cr3;
};
+#ifdef GRUB_MACHINE_EFI
+#ifdef __x86_64__
+struct grub_relocator64_efi_state
+{
+ grub_uint64_t rax;
+ grub_uint64_t rbx;
+ grub_uint64_t rcx;
+ grub_uint64_t rdx;
+ grub_uint64_t rip;
+ grub_uint64_t rsi;
+};
+#endif
+#endif
+
grub_err_t grub_relocator16_boot (struct grub_relocator *rel,
struct grub_relocator16_state state);
@@ -76,4 +90,11 @@ grub_err_t grub_relocator64_boot (struct grub_relocator *rel,
struct grub_relocator64_state state,
grub_addr_t min_addr, grub_addr_t max_addr);
+#ifdef GRUB_MACHINE_EFI
+#ifdef __x86_64__
+grub_err_t grub_relocator64_efi_boot (struct grub_relocator *rel,
+ struct grub_relocator64_efi_state state);
+#endif
+#endif
+
#endif /* ! GRUB_RELOCATOR_CPU_HEADER */
@@ -69,6 +69,7 @@
#define MULTIBOOT_HEADER_TAG_FRAMEBUFFER 5
#define MULTIBOOT_HEADER_TAG_MODULE_ALIGN 6
#define MULTIBOOT_HEADER_TAG_EFI_BS 7
+#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 9
#define MULTIBOOT_ARCHITECTURE_I386 0
#define MULTIBOOT_ARCHITECTURE_MIPS32 4