aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2012-06-27 18:34:57 +0100
committerMatt Fleming <matt.fleming@intel.com>2012-08-08 11:21:09 +0100
commitaa925098a5887a2925e7b6396b3483ed86c69cc0 (patch)
tree61a9a5782defb6453819c680a8ae883b634b88dc
parente056a22a2c933068616b2e0250d2a2c29602dd23 (diff)
downloadefilinux-aa925098a5887a2925e7b6396b3483ed86c69cc0.tar.gz
bzimage: Hand off initialisation to the EFI boot stubnext
Linux kernel v3.6-rc1 support an "EFI handover protocol" that allows most of the initialisation necessary for booting a kernel under EFI to be performed by a boot stub in the kernel image itself. Use the boot stub if it is supported by the kernel. Signed-off-by: Matt Fleming <matt.fleming@intel.com>
-rw-r--r--loaders/bzimage/bzimage.c9
-rw-r--r--loaders/bzimage/bzimage.h1
-rw-r--r--loaders/bzimage/i386.h15
-rw-r--r--loaders/bzimage/x86_64.h16
4 files changed, 41 insertions, 0 deletions
diff --git a/loaders/bzimage/bzimage.c b/loaders/bzimage/bzimage.c
index 3b9c560..efdb884 100644
--- a/loaders/bzimage/bzimage.c
+++ b/loaders/bzimage/bzimage.c
@@ -323,6 +323,15 @@ load_kernel(EFI_HANDLE image, CHAR16 *name, char *_cmdline)
memcpy((char *)boot_params, (char *)buf, 2 * 512);
boot_params->hdr.code32_start = (UINT32)((UINT64)kernel_start);
+ /*
+ * Use the kernel's EFI boot stub by invoking the handover
+ * protocol.
+ */
+ if (buf->hdr.version >= 0x20b) {
+ handover_jump(image, boot_params, kernel_start);
+ goto out;
+ }
+
err = setup_graphics(buf);
if (err != EFI_SUCCESS)
goto out;
diff --git a/loaders/bzimage/bzimage.h b/loaders/bzimage/bzimage.h
index 9d84725..cd11fd3 100644
--- a/loaders/bzimage/bzimage.h
+++ b/loaders/bzimage/bzimage.h
@@ -78,6 +78,7 @@ struct setup_header {
UINT64 setup_data;
UINT64 pref_address;
UINT32 init_size;
+ UINT32 handover_offset;
} __attribute__((packed));
struct efi_info {
diff --git a/loaders/bzimage/i386.h b/loaders/bzimage/i386.h
index 6f1cf8f..593e2af 100644
--- a/loaders/bzimage/i386.h
+++ b/loaders/bzimage/i386.h
@@ -42,4 +42,19 @@ static inline void kernel_jump(EFI_PHYSICAL_ADDRESS kernel_start,
:: "m" (boot_params), "m" (kernel_start));
}
+static inline void handover_jump(EFI_HANDLE image, struct boot_params *bp,
+ EFI_PHYSICAL_ADDRESS kernel_start)
+{
+ kernel_start += bp->hdr.handover_offset;
+
+ asm volatile ("cli \n"
+ "pushl %0 \n"
+ "pushl %1 \n"
+ "pushl %2 \n"
+ "movl %3, %%ecx \n"
+ "jmp *%%ecx \n"
+ :: "m" (bp), "m" (ST),
+ "m" (image), "m" (kernel_start));
+}
+
#endif /* __I386_H__ */
diff --git a/loaders/bzimage/x86_64.h b/loaders/bzimage/x86_64.h
index a7ba3af..b63710e 100644
--- a/loaders/bzimage/x86_64.h
+++ b/loaders/bzimage/x86_64.h
@@ -33,6 +33,7 @@
#define EFI_LOADER_SIGNATURE "EL64"
typedef void(*kernel_func)(void *, struct boot_params *);
+typedef void(*handover_func)(void *, EFI_SYSTEM_TABLE *, struct boot_params *);
static inline void kernel_jump(EFI_PHYSICAL_ADDRESS kernel_start,
struct boot_params *boot_params)
@@ -51,4 +52,19 @@ static inline void kernel_jump(EFI_PHYSICAL_ADDRESS kernel_start,
kf(NULL, boot_params);
}
+static inline void handover_jump(EFI_HANDLE image, struct boot_params *bp,
+ EFI_PHYSICAL_ADDRESS kernel_start)
+{
+ UINT32 offset = bp->hdr.handover_offset;
+ handover_func hf;
+
+ asm volatile ("cli");
+
+ /* The 64-bit kernel entry is 512 bytes after the start. */
+ kernel_start += 512;
+
+ hf = (handover_func)(kernel_start + offset);
+ hf(image, ST, bp);
+}
+
#endif /* __X86_64_H__ */