All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/9] x86 EFI boot stub
@ 2011-08-11 10:59 Matt Fleming
  2011-08-11 10:59 ` [PATCH 1/9] x86: Don't use magic strings for EFI loader signature Matt Fleming
                   ` (9 more replies)
  0 siblings, 10 replies; 16+ messages in thread
From: Matt Fleming @ 2011-08-11 10:59 UTC (permalink / raw)
  To: linux-kernel

From: Matt Fleming <matt.fleming@intel.com>

This series adds support for an EFI boot stub, similar to the existing
BIOS boot stub. The result is that you can boot a bzImage on an EFI
machine without the use of a boot loader by making the bzImage appear
to the EFI firmware to be an EFI application. Also, a single bzImage
can be booted on either a BIOS or EFI machine.

Using the EFI boot stub has the advantage that the kernel is
responsible for configuring the machine to the point where we can
fully boot the kernel, so we are no longer at the mercy of the boot
loader.

This series is also available in the 'x86/efi-stub' branch at,

     git://git.kernel.org/pub/scm/linux/kernel/git/mfleming/linux-2.6.git

Matt Fleming (9):
  x86: Don't use magic strings for EFI loader signature
  efi.h: Add struct definition for boot time services
  efi.h: Add efi_image_loaded_t
  efi.h: Add allocation types for boottime->allocate_pages()
  efi.h: Add graphics protocol guid
  efi.h: Add boottime->locate_handle search types
  efi: Add EFI file I/O data types
  x86, efi: EFI boot stub support
  x86, efi: Make efi_call_phys_prelog() CONFIG_RELOCATABLE-aware

 arch/x86/Kconfig                       |    7 +
 arch/x86/boot/compressed/Makefile      |   10 +-
 arch/x86/boot/compressed/eboot.c       |  779 ++++++++++++++++++++++++++++++++
 arch/x86/boot/compressed/efi_stub_32.S |   87 ++++
 arch/x86/boot/compressed/efi_stub_64.S |    1 +
 arch/x86/boot/compressed/head_32.S     |   13 +
 arch/x86/boot/compressed/head_64.S     |   11 +
 arch/x86/boot/compressed/string.c      |    9 +
 arch/x86/boot/header.S                 |  157 +++++++
 arch/x86/boot/string.c                 |   35 ++
 arch/x86/boot/tools/build.c            |   27 ++
 arch/x86/include/asm/efi.h             |    4 +
 arch/x86/kernel/setup.c                |    7 +-
 arch/x86/platform/efi/efi_32.c         |   22 +-
 include/linux/efi.h                    |  130 ++++++-
 15 files changed, 1282 insertions(+), 17 deletions(-)
 create mode 100644 arch/x86/boot/compressed/eboot.c
 create mode 100644 arch/x86/boot/compressed/efi_stub_32.S
 create mode 100644 arch/x86/boot/compressed/efi_stub_64.S

-- 
1.7.4.4


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 1/9] x86: Don't use magic strings for EFI loader signature
  2011-08-11 10:59 [PATCH 0/9] x86 EFI boot stub Matt Fleming
@ 2011-08-11 10:59 ` Matt Fleming
  2011-08-11 10:59 ` [PATCH 2/9] efi.h: Add struct definition for boot time services Matt Fleming
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Matt Fleming @ 2011-08-11 10:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: Matthew Garrett, H. Peter Anvin

From: Matt Fleming <matt.fleming@linux.intel.com>

Introduce a symbol, EFI_LOADER_SIGNATURE instead of using the magic
strings, which also helps to reduce the amount of ifdeffery.

Cc: Matthew Garrett <mjg@redhat.com>
Cc: "H. Peter Anvin" <hpa@linux.intel.com>
Signed-off-by: Matt Fleming <matt.fleming@linux.intel.com>
---
 arch/x86/include/asm/efi.h |    4 ++++
 arch/x86/kernel/setup.c    |    7 +------
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 7093e4a..844f735 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -3,6 +3,8 @@
 
 #ifdef CONFIG_X86_32
 
+#define EFI_LOADER_SIGNATURE	"EL32"
+
 extern unsigned long asmlinkage efi_call_phys(void *, ...);
 
 #define efi_call_phys0(f)		efi_call_phys(f)
@@ -37,6 +39,8 @@ extern unsigned long asmlinkage efi_call_phys(void *, ...);
 
 #else /* !CONFIG_X86_32 */
 
+#define EFI_LOADER_SIGNATURE	"EL64"
+
 extern u64 efi_call0(void *fp);
 extern u64 efi_call1(void *fp, u64 arg1);
 extern u64 efi_call2(void *fp, u64 arg1, u64 arg2);
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index afaf384..eca164b 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -750,12 +750,7 @@ void __init setup_arch(char **cmdline_p)
 #endif
 #ifdef CONFIG_EFI
 	if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
-#ifdef CONFIG_X86_32
-		     "EL32",
-#else
-		     "EL64",
-#endif
-	 4)) {
+		     EFI_LOADER_SIGNATURE, 4)) {
 		efi_enabled = 1;
 		efi_memblock_x86_reserve_range();
 	}
-- 
1.7.4.4


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 2/9] efi.h: Add struct definition for boot time services
  2011-08-11 10:59 [PATCH 0/9] x86 EFI boot stub Matt Fleming
  2011-08-11 10:59 ` [PATCH 1/9] x86: Don't use magic strings for EFI loader signature Matt Fleming
@ 2011-08-11 10:59 ` Matt Fleming
  2011-08-11 10:59 ` [PATCH 3/9] efi.h: Add efi_image_loaded_t Matt Fleming
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Matt Fleming @ 2011-08-11 10:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: Matthew Garrett, H. Peter Anvin

From: Matt Fleming <matt.fleming@linux.intel.com>

With the forthcoming efi stub code we're gonna need to access boot
time services so let's define a struct so we can access the functions.

Cc: Matthew Garrett <mjg@redhat.com>
Cc: "H. Peter Anvin" <hpa@linux.intel.com>
Signed-off-by: Matt Fleming <matt.fleming@linux.intel.com>
---
 include/linux/efi.h |   53 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 52 insertions(+), 1 deletions(-)

diff --git a/include/linux/efi.h b/include/linux/efi.h
index 2362a0b..9547597 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -139,6 +139,57 @@ typedef struct {
 } efi_time_cap_t;
 
 /*
+ * EFI Boot Services table
+ */
+typedef struct {
+	efi_table_hdr_t hdr;
+	void *raise_tpl;
+	void *restore_tpl;
+	void *allocate_pages;
+	void *free_pages;
+	void *get_memory_map;
+	void *allocate_pool;
+	void *free_pool;
+	void *create_event;
+	void *set_timer;
+	void *wait_for_event;
+	void *signal_event;
+	void *close_event;
+	void *check_event;
+	void *install_protocol_interface;
+	void *reinstall_protocol_interface;
+	void *uninstall_protocol_interface;
+	void *handle_protocol;
+	void *__reserved;
+	void *register_protocol_notify;
+	void *locate_handle;
+	void *locate_device_path;
+	void *install_configuration_table;
+	void *load_image;
+	void *start_image;
+	void *exit;
+	void *unload_image;
+	void *exit_boot_services;
+	void *get_next_monotonic_count;
+	void *stall;
+	void *set_watchdog_timer;
+	void *connect_controller;
+	void *disconnect_controller;
+	void *open_protocol;
+	void *close_protocol;
+	void *open_protocol_information;
+	void *protocols_per_handle;
+	void *locate_handle_buffer;
+	void *locate_protocol;
+	void *install_multiple_protocol_interfaces;
+	void *uninstall_multiple_protocol_interfaces;
+	void *calculate_crc32;
+	void *copy_mem;
+	void *set_mem;
+	void *create_event_ex;
+} efi_boot_services_t;
+
+/*
  * Types and defines for EFI ResetSystem
  */
 #define EFI_RESET_COLD 0
@@ -261,7 +312,7 @@ typedef struct {
 	unsigned long stderr_handle;
 	unsigned long stderr;
 	efi_runtime_services_t *runtime;
-	unsigned long boottime;
+	efi_boot_services_t *boottime;
 	unsigned long nr_tables;
 	unsigned long tables;
 } efi_system_table_t;
-- 
1.7.4.4


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 3/9] efi.h: Add efi_image_loaded_t
  2011-08-11 10:59 [PATCH 0/9] x86 EFI boot stub Matt Fleming
  2011-08-11 10:59 ` [PATCH 1/9] x86: Don't use magic strings for EFI loader signature Matt Fleming
  2011-08-11 10:59 ` [PATCH 2/9] efi.h: Add struct definition for boot time services Matt Fleming
@ 2011-08-11 10:59 ` Matt Fleming
  2011-08-11 10:59 ` [PATCH 4/9] efi.h: Add allocation types for boottime->allocate_pages() Matt Fleming
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Matt Fleming @ 2011-08-11 10:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: Matthew Garrett, H. Peter Anvin

From: Matt Fleming <matt.fleming@linux.intel.com>

Add the EFI loaded image structure and protocol guid which are
required by the x86 EFI boot stub. The EFI boot stub uses the
structure to figure out where it was loaded in memory and to pass
command line arguments to the kernel.

Cc: Matthew Garrett <mjg@redhat.com>
Cc: "H. Peter Anvin" <hpa@linux.intel.com>
Signed-off-by: Matt Fleming <matt.fleming@linux.intel.com>
---
 include/linux/efi.h |   19 +++++++++++++++++++
 1 files changed, 19 insertions(+), 0 deletions(-)

diff --git a/include/linux/efi.h b/include/linux/efi.h
index 9547597..d10a639 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -287,6 +287,9 @@ typedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **capsules,
 #define LINUX_EFI_CRASH_GUID \
     EFI_GUID(  0xcfc8fc79, 0xbe2e, 0x4ddc, 0x97, 0xf0, 0x9f, 0x98, 0xbf, 0xe2, 0x98, 0xa0 )
 
+#define LOADED_IMAGE_PROTOCOL_GUID \
+    EFI_GUID(  0x5b1b31a1, 0x9562, 0x11d2, 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b )
+
 typedef struct {
 	efi_guid_t guid;
 	unsigned long table;
@@ -326,6 +329,22 @@ struct efi_memory_map {
 	unsigned long desc_size;
 };
 
+typedef struct {
+	u32 revision;
+	void *parent_handle;
+	efi_system_table_t *system_table;
+	void *device_handle;
+	void *file_path;
+	void *reserved;
+	u32 load_options_size;
+	void *load_options;
+	void *image_base;
+	u64 image_size;
+	unsigned int image_code_type;
+	unsigned int image_data_type;
+	unsigned long unload;
+} efi_loaded_image_t;
+
 #define EFI_INVALID_TABLE_ADDR		(~0UL)
 
 /*
-- 
1.7.4.4


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 4/9] efi.h: Add allocation types for boottime->allocate_pages()
  2011-08-11 10:59 [PATCH 0/9] x86 EFI boot stub Matt Fleming
                   ` (2 preceding siblings ...)
  2011-08-11 10:59 ` [PATCH 3/9] efi.h: Add efi_image_loaded_t Matt Fleming
@ 2011-08-11 10:59 ` Matt Fleming
  2011-08-11 10:59 ` [PATCH 5/9] efi.h: Add graphics protocol guid Matt Fleming
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Matt Fleming @ 2011-08-11 10:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: Matthew Garrett, H. Peter Anvin

From: Matt Fleming <matt.fleming@linux.intel.com>

Add the allocation types detailed in section 6.2 - "AllocatePages()"
of the UEFI 2.3 specification. These definitions will be used by the
x86 EFI boot stub which needs to allocate memory during boot.

Cc: Matthew Garrett <mjg@redhat.com>
Cc: "H. Peter Anvin" <hpa@linux.intel.com>
Signed-off-by: Matt Fleming <matt.fleming@linux.intel.com>
---
 include/linux/efi.h |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/include/linux/efi.h b/include/linux/efi.h
index d10a639..cd28c7a 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -109,6 +109,14 @@ typedef struct {
 	u32 imagesize;
 } efi_capsule_header_t;
 
+/*
+ * Allocation types for calls to boottime->allocate_pages.
+ */
+#define EFI_ALLOCATE_ANY_PAGES		0
+#define EFI_ALLOCATE_MAX_ADDRESS	1
+#define EFI_ALLOCATE_ADDRESS		2
+#define EFI_MAX_ALLOCATE_TYPE		3
+
 typedef int (*efi_freemem_callback_t) (u64 start, u64 end, void *arg);
 
 /*
-- 
1.7.4.4


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 5/9] efi.h: Add graphics protocol guid
  2011-08-11 10:59 [PATCH 0/9] x86 EFI boot stub Matt Fleming
                   ` (3 preceding siblings ...)
  2011-08-11 10:59 ` [PATCH 4/9] efi.h: Add allocation types for boottime->allocate_pages() Matt Fleming
@ 2011-08-11 10:59 ` Matt Fleming
  2011-08-11 10:59 ` [PATCH 6/9] efi.h: Add boottime->locate_handle search types Matt Fleming
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Matt Fleming @ 2011-08-11 10:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: Matthew Garrett, H. Peter Anvin

From: Matt Fleming <matt.fleming@linux.intel.com>

The x86 EFI boot stub uses this guid when initialising graphics during
boot.

Cc: Matthew Garrett <mjg@redhat.com>
Cc: "H. Peter Anvin" <hpa@linux.intel.com>
Signed-off-by: Matt Fleming <matt.fleming@linux.intel.com>
---
 include/linux/efi.h |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/include/linux/efi.h b/include/linux/efi.h
index cd28c7a..379efe8 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -298,6 +298,9 @@ typedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **capsules,
 #define LOADED_IMAGE_PROTOCOL_GUID \
     EFI_GUID(  0x5b1b31a1, 0x9562, 0x11d2, 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b )
 
+#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID \
+    EFI_GUID(  0x9042a9de, 0x23dc, 0x4a38, 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a )
+
 typedef struct {
 	efi_guid_t guid;
 	unsigned long table;
-- 
1.7.4.4


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 6/9] efi.h: Add boottime->locate_handle search types
  2011-08-11 10:59 [PATCH 0/9] x86 EFI boot stub Matt Fleming
                   ` (4 preceding siblings ...)
  2011-08-11 10:59 ` [PATCH 5/9] efi.h: Add graphics protocol guid Matt Fleming
@ 2011-08-11 10:59 ` Matt Fleming
  2011-08-11 10:59 ` [PATCH 7/9] efi: Add EFI file I/O data types Matt Fleming
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Matt Fleming @ 2011-08-11 10:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: Matthew Garrett, H. Peter Anvin

From: Matt Fleming <matt.fleming@linux.intel.com>

The x86 EFI boot stub needs to locate handles for various protocols.

Cc: Matthew Garrett <mjg@redhat.com>
Cc: "H. Peter Anvin" <hpa@linux.intel.com>
Signed-off-by: Matt Fleming <matt.fleming@linux.intel.com>
---
 include/linux/efi.h |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/include/linux/efi.h b/include/linux/efi.h
index 379efe8..d06e0ae 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -466,6 +466,13 @@ extern int __init efi_setup_pcdp_console(char *);
 #define EFI_VARIABLE_RUNTIME_ACCESS     0x0000000000000004
 
 /*
+ * The type of search to perform when calling boottime->locate_handle
+ */
+#define EFI_LOCATE_ALL_HANDLES			0
+#define EFI_LOCATE_BY_REGISTER_NOTIFY		1
+#define EFI_LOCATE_BY_PROTOCOL			2
+
+/*
  * EFI Device Path information
  */
 #define EFI_DEV_HW			0x01
-- 
1.7.4.4


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 7/9] efi: Add EFI file I/O data types
  2011-08-11 10:59 [PATCH 0/9] x86 EFI boot stub Matt Fleming
                   ` (5 preceding siblings ...)
  2011-08-11 10:59 ` [PATCH 6/9] efi.h: Add boottime->locate_handle search types Matt Fleming
@ 2011-08-11 10:59 ` Matt Fleming
  2011-08-11 10:59 ` [PATCH 8/9] x86, efi: EFI boot stub support Matt Fleming
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Matt Fleming @ 2011-08-11 10:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: Matthew Garrett, H. Peter Anvin

From: Matt Fleming <matt.fleming@intel.com>

The x86 EFI stub needs to access files, for example when loading
initrd's. Add the required data types.

Cc: Matthew Garrett <mjg@redhat.com>
Cc: "H. Peter Anvin" <hpa@linux.intel.com>
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
---
 include/linux/efi.h |   40 ++++++++++++++++++++++++++++++++++++++++
 1 files changed, 40 insertions(+), 0 deletions(-)

diff --git a/include/linux/efi.h b/include/linux/efi.h
index d06e0ae..0e9e674 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -301,6 +301,12 @@ typedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **capsules,
 #define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID \
     EFI_GUID(  0x9042a9de, 0x23dc, 0x4a38, 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a )
 
+#define EFI_FILE_INFO_ID \
+    EFI_GUID(  0x9576e92, 0x6d3f, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b )
+
+#define EFI_FILE_SYSTEM_GUID \
+    EFI_GUID(  0x964e5b22, 0x6459, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b )
+
 typedef struct {
 	efi_guid_t guid;
 	unsigned long table;
@@ -356,6 +362,40 @@ typedef struct {
 	unsigned long unload;
 } efi_loaded_image_t;
 
+typedef struct {
+	u64 revision;
+	void *open_volume;
+} efi_file_io_interface_t;
+
+typedef struct {
+	u64 size;
+	u64 file_size;
+	u64 phys_size;
+	efi_time_t create_time;
+	efi_time_t last_access_time;
+	efi_time_t modification_time;
+	u64 attribute;
+	efi_char16_t filename[1];
+} efi_file_info_t;
+
+typedef struct {
+	u64 revision;
+	void *open;
+	void *close;
+	void *delete;
+	void *read;
+	void *write;
+	void *get_position;
+	void *set_position;
+	void *get_info;
+	void *set_info;
+	void *flush;
+} efi_file_handle_t;
+
+#define EFI_FILE_MODE_READ	0x0000000000000001
+#define EFI_FILE_MODE_WRITE	0x0000000000000002
+#define EFI_FILE_MODE_CREATE	0x8000000000000000
+
 #define EFI_INVALID_TABLE_ADDR		(~0UL)
 
 /*
-- 
1.7.4.4


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 8/9] x86, efi: EFI boot stub support
  2011-08-11 10:59 [PATCH 0/9] x86 EFI boot stub Matt Fleming
                   ` (6 preceding siblings ...)
  2011-08-11 10:59 ` [PATCH 7/9] efi: Add EFI file I/O data types Matt Fleming
@ 2011-08-11 10:59 ` Matt Fleming
  2011-08-11 18:09   ` Andi Kleen
  2011-08-11 10:59 ` [PATCH 9/9] x86, efi: Make efi_call_phys_prelog() CONFIG_RELOCATABLE-aware Matt Fleming
  2011-08-11 13:05 ` [PATCH 0/9] x86 EFI boot stub Maarten Lankhorst
  9 siblings, 1 reply; 16+ messages in thread
From: Matt Fleming @ 2011-08-11 10:59 UTC (permalink / raw)
  To: linux-kernel
  Cc: H. Peter Anvin, Thomas Gleixner, Ingo Molnar, Mike Waychison,
	Matthew Garrett

From: Matt Fleming <matt.fleming@linux.intel.com>

There is currently a large divide between kernel development and the
development of EFI boot loaders. The idea behind this patch is to give
the kernel developers full control over the EFI boot process. As
H. Peter Anvin put it,

"The 'kernel carries its own stub' approach been very successful in
dealing with BIOS, and would make a lot of sense to me for EFI as
well."

This patch introduces an EFI boot stub that allows an x86 bzImage to
be loaded and executed by EFI firmware. The bzImage appears to the
firmware as an EFI application. Luckily there are enough free bits
within the bzImage header so that it can masquerade as an EFI
application, thereby coercing the EFI firmware into loading it and
jumping to its entry point. The beauty of this masquerading approach
is that both BIOS and EFI boot loaders can still load and run the same
bzImage, thereby allowing a single kernel image to work in any boot
environment.

The EFI boot stub supports multiple initrds, but they must exist on
the same partition as the bzImage. Command-line arguments for the
kernel can be appended after the bzImage name when run from the EFI
shell, e.g.

Shell> bzImage console=ttyS0 root=/dev/sdb initrd=initrd.img

Cc: H. Peter Anvin <hpa@linux.intel.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Mike Waychison <mikew@google.com>
Cc: Matthew Garrett <mjg@redhat.com>
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
---
 arch/x86/Kconfig                       |    7 +
 arch/x86/boot/compressed/Makefile      |   10 +-
 arch/x86/boot/compressed/eboot.c       |  779 ++++++++++++++++++++++++++++++++
 arch/x86/boot/compressed/efi_stub_32.S |   87 ++++
 arch/x86/boot/compressed/efi_stub_64.S |    1 +
 arch/x86/boot/compressed/head_32.S     |   13 +
 arch/x86/boot/compressed/head_64.S     |   11 +
 arch/x86/boot/compressed/string.c      |    9 +
 arch/x86/boot/header.S                 |  157 +++++++
 arch/x86/boot/string.c                 |   35 ++
 arch/x86/boot/tools/build.c            |   27 ++
 11 files changed, 1135 insertions(+), 1 deletions(-)
 create mode 100644 arch/x86/boot/compressed/eboot.c
 create mode 100644 arch/x86/boot/compressed/efi_stub_32.S
 create mode 100644 arch/x86/boot/compressed/efi_stub_64.S

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 6a47bb2..d40c876 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1466,6 +1466,13 @@ config EFI
 	  resultant kernel should continue to boot on existing non-EFI
 	  platforms.
 
+config EFI_STUB
+       bool "EFI stub support"
+       depends on EFI
+       ---help---
+          This kernel feature allows a bzImage to be loaded directly
+	  by EFI firmware without the use of a bootloader.
+
 config SECCOMP
 	def_bool y
 	prompt "Enable seccomp to safely compute untrusted bytecode"
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index 09664ef..b123b9a 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -23,7 +23,15 @@ LDFLAGS_vmlinux := -T
 
 hostprogs-y	:= mkpiggy
 
-$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o $(obj)/string.o $(obj)/cmdline.o $(obj)/early_serial_console.o $(obj)/piggy.o FORCE
+VMLINUX_OBJS = $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \
+	$(obj)/string.o $(obj)/cmdline.o $(obj)/early_serial_console.o \
+	$(obj)/piggy.o
+
+ifeq ($(CONFIG_EFI_STUB), y)
+	VMLINUX_OBJS += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o
+endif
+
+$(obj)/vmlinux: $(VMLINUX_OBJS) FORCE
 	$(call if_changed,ld)
 	@:
 
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
new file mode 100644
index 0000000..885568f
--- /dev/null
+++ b/arch/x86/boot/compressed/eboot.c
@@ -0,0 +1,779 @@
+/* -----------------------------------------------------------------------
+ *
+ *   Copyright 2011 Intel Corporation; author Matt Fleming
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <linux/efi.h>
+#include <asm/efi.h>
+#include <asm/setup.h>
+#include <asm/desc.h>
+
+#define EFI_PAGE_SIZE		(1UL << EFI_PAGE_SHIFT)
+
+#define PIXEL_RGB_RESERVED_8BIT_PER_COLOR		0
+#define PIXEL_BGR_RESERVED_8BIT_PER_COLOR		1
+#define PIXEL_BIT_MASK					2
+#define PIXEL_BLT_ONLY					3
+#define PIXEL_FORMAT_MAX				4
+
+typedef struct {
+	u32 red_mask;
+	u32 green_mask;
+	u32 blue_mask;
+	u32 reserved_mask;
+} efi_pixel_bitmask_t;
+
+typedef struct {
+	u32 version;
+	u32 horizontal_resolution;
+	u32 vertical_resolution;
+	int pixel_format;
+	efi_pixel_bitmask_t pixel_information;
+	u32 pixels_per_scan_line;
+} __attribute__((packed)) efi_graphics_output_mode_information_t;
+
+typedef struct {
+	u32 max_mode;
+	u32 mode;
+	unsigned long info;
+	unsigned long size_of_info;
+	u64 frame_buffer_base;
+	unsigned long frame_buffer_size;
+} __attribute__((packed)) efi_graphics_output_protocol_mode_t;
+
+typedef struct {
+	void *query_mode;
+	unsigned long set_mode;
+	unsigned long blt;
+	efi_graphics_output_protocol_mode_t *mode;
+} efi_graphics_output_protocol_t;
+
+static efi_system_table_t *sys_table;
+
+/*
+ * When the kernel decompresses itself it will expand to higher
+ * addresses. So, we need to have a way to allocate memory safely
+ * below the decompress address.
+ */
+static efi_status_t low_alloc(unsigned long size, unsigned long align,
+			      unsigned long *addr)
+{
+	unsigned long map_size, key, desc_size;
+	efi_memory_desc_t *map;
+	efi_status_t status;
+	unsigned long nr_pages;
+	u32 desc_version;
+	int i;
+
+	nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
+
+	map_size = sizeof(*map) * 32;
+
+again:
+	map_size += sizeof(*map);
+	status = efi_call_phys3(sys_table->boottime->allocate_pool,
+				EFI_LOADER_DATA, map_size, (void **)&map);
+	if (status != EFI_SUCCESS)
+		goto fail;
+
+	status = efi_call_phys5(sys_table->boottime->get_memory_map, &map_size,
+				map, &key, &desc_size, &desc_version);
+	if (status == EFI_BUFFER_TOO_SMALL) {
+		efi_call_phys1(sys_table->boottime->free_pool, map);
+		goto again;
+	}
+
+	if (status != EFI_SUCCESS)
+		goto free_pool;
+
+	for (i = 0; i < map_size / desc_size; i++) {
+		efi_memory_desc_t *desc;
+		u64 start, end;
+
+		desc = (efi_memory_desc_t *)((unsigned long)map + (i * desc_size));
+
+		if (desc->type != EFI_CONVENTIONAL_MEMORY)
+			continue;
+
+		if (desc->num_pages < nr_pages)
+			continue;
+
+		start = desc->phys_addr;
+		end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT);
+
+		/*
+		 * Don't allocate at 0x0. It will confuse code that
+		 * checks pointers against NULL. Skip the first 8
+		 * bytes so we start at a nice even number.
+		 */
+		if (start == 0x0) {
+			start += 8;
+
+			/* Check for tiny memory regions */
+			if (start >= end)
+				continue;
+		}
+
+		start = round_up(start, align);
+		if ((start + size) > end)
+			continue;
+
+		status = efi_call_phys4(sys_table->boottime->allocate_pages,
+					EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
+					nr_pages, &start);
+		if (status == EFI_SUCCESS) {
+			*addr = start;
+			break;
+		}
+	}
+
+	if (i == map_size / desc_size)
+		status = EFI_NOT_FOUND;
+
+free_pool:
+	efi_call_phys1(sys_table->boottime->free_pool, map);
+fail:
+	return status;
+}
+
+static void low_free(unsigned long size, unsigned long addr)
+{
+	unsigned long nr_pages;
+
+	nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
+	efi_call_phys2(sys_table->boottime->free_pages, addr, size);
+}
+
+static void find_bits(unsigned long mask, u8 *pos, u8 *size)
+{
+        u8 first, len;
+
+	first = 0;
+	len = 0;
+
+	if (mask) {
+		while (!(mask & 0x1)) {
+			mask = mask >> 1;
+			first++;
+		}
+
+		while (mask & 0x1) {
+			mask = mask >> 1;
+			len++;
+		}
+	}
+
+        *pos = first;
+        *size = len;
+}
+
+static void setup_graphics(struct boot_params *boot_params,
+			   efi_guid_t *proto, void **gop_handle,
+			   unsigned long size)
+{
+	efi_graphics_output_mode_information_t *info;
+	efi_graphics_output_protocol_t *gop;
+	unsigned long nr_gops;
+	struct screen_info *si;
+	efi_status_t status;
+	int i;
+
+	nr_gops = size / sizeof(void *);
+	for (i = 0; i < nr_gops; i++) {
+		void **h = &gop_handle[i];
+
+		status = efi_call_phys3(sys_table->boottime->handle_protocol,
+					*h, proto, &gop);
+		if (status != EFI_SUCCESS)
+			continue;
+
+		status = efi_call_phys4(gop->query_mode, gop, gop->mode->mode,
+					&size, &info);
+		if (status == EFI_SUCCESS)
+			break;
+	}
+
+	if (i == nr_gops)
+		return;
+
+	/* We found a GOP! */
+	si = &boot_params->screen_info;
+
+	si->orig_x = 0;
+	si->orig_y = 0;
+	si->orig_video_page = 0;
+	si->orig_video_mode = 0;
+	si->orig_video_cols = 0;
+	si->orig_video_ega_bx = 0;
+	si->orig_video_lines = 0;
+
+	/* EFI framebuffer */
+	si->orig_video_isVGA = 0x70;
+
+	si->orig_video_points = 0;
+
+	si->lfb_width = info->horizontal_resolution;
+	si->lfb_height = info->vertical_resolution;
+	si->lfb_base = gop->mode->frame_buffer_base;
+	si->lfb_size = gop->mode->frame_buffer_size;
+	si->pages = 1;
+	si->vesapm_seg = 0;
+	si->vesapm_off = 0;
+
+	if (info->pixel_format == PIXEL_RGB_RESERVED_8BIT_PER_COLOR) {
+		si->lfb_depth = 32;
+		si->lfb_linelength = info->pixels_per_scan_line * 4;
+		si->red_size = 8;
+		si->red_pos = 0;
+		si->green_size = 8;
+		si->green_pos = 8;
+		si->blue_size = 8;
+		si->blue_pos = 16;
+		si->rsvd_size = 8;
+		si->rsvd_pos = 24;
+
+	} else if (info->pixel_format == PIXEL_BGR_RESERVED_8BIT_PER_COLOR) {
+		si->lfb_depth = 32;
+		si->lfb_linelength = info->pixels_per_scan_line * 4;
+		si->red_size = 8;
+		si->red_pos = 16;
+		si->green_size = 8;
+		si->green_pos = 8;
+		si->blue_size = 8;
+		si->blue_pos = 0;
+		si->rsvd_size = 8;
+		si->rsvd_pos = 24;
+	} else if (info->pixel_format == PIXEL_BIT_MASK) {
+		si->lfb_linelength = (info->pixels_per_scan_line * si->lfb_depth) / 8;
+		find_bits(info->pixel_information.red_mask,
+			  &si->red_pos, &si->red_size);
+		find_bits(info->pixel_information.green_mask,
+			  &si->green_pos, &si->green_size);
+		find_bits(info->pixel_information.blue_mask,
+			  &si->blue_pos, &si->blue_size);
+		find_bits(info->pixel_information.reserved_mask,
+			  &si->rsvd_pos, &si->rsvd_size);
+		si->lfb_depth = si->red_size + si->green_size +
+			si->blue_size + si->rsvd_size;
+	} else {
+		si->lfb_depth = 4;
+		si->lfb_linelength = si->lfb_width / 2;
+		si->red_size = 0;
+		si->red_pos = 0;
+		si->green_size = 0;
+		si->green_pos = 0;
+		si->blue_size = 0;
+		si->blue_pos = 0;
+		si->rsvd_size = 0;
+		si->rsvd_pos = 0;
+	}
+}
+
+struct initrd {
+	efi_file_handle_t *handle;
+	u64 size;
+};
+
+/*
+ * Check the cmdline for a LILO-style initrd= arguments.
+ *
+ * We only support loading an initrd from the same filesystem as the
+ * kernel image.
+ */
+static efi_status_t handle_ramdisks(efi_loaded_image_t *image,
+				    struct setup_header *hdr)
+{
+	struct initrd *initrds;
+	unsigned long initrd_addr;
+	efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
+	u64 initrd_total;
+	efi_file_io_interface_t *io;
+	efi_file_handle_t *fh;
+	efi_status_t status;
+	int nr_initrds;
+	char *str;
+	int i, j, k;
+
+	initrd_addr = 0;
+	initrd_total = 0;
+
+	str = (char *)(unsigned long)hdr->cmd_line_ptr;
+
+	j = 0;			/* See close_handles */
+
+	if (!str || !*str)
+		return EFI_SUCCESS;
+
+	for (nr_initrds = 0; *str; nr_initrds++) {
+		str = strstr(str, "initrd=");
+		if (!str)
+			break;
+
+		str += 7;
+
+		/* Skip any leading slashes */
+		while (*str == '/' || *str == '\\')
+			str++;
+		
+		while (*str && *str != ' ')
+			str++;
+
+		if (*str == ' ')
+			str++;
+	}
+
+	status = efi_call_phys3(sys_table->boottime->allocate_pool,
+				EFI_LOADER_DATA,
+				nr_initrds * sizeof(*initrds),
+				&initrds);
+	if (status != EFI_SUCCESS)
+		goto fail;
+
+	str = (char *)(unsigned long)hdr->cmd_line_ptr;
+	for (i = 0; i < nr_initrds; i++) {
+		struct initrd *initrd;
+		efi_file_handle_t *h;
+		efi_file_info_t *info;
+		efi_char16_t filename[256];
+		unsigned long info_sz;
+		efi_guid_t info_guid = EFI_FILE_INFO_ID;
+		efi_char16_t *p;
+
+		str = strstr(str, "initrd=");
+		if (!str)
+			break;
+
+		str += 7;
+
+		initrd = &initrds[i];
+		p = filename;
+
+		/* Skip any leading slashes */
+		while (*str == '/' || *str == '\\')
+			str++;
+		
+		while (*str && *str != ' ') {
+			if (p >= filename + sizeof(filename))
+				break;
+
+			*p++ = *str++;
+		}
+
+		if (*str == ' ')
+			str++;
+
+		*p = '\0';
+
+		/* Only open the volume once. */
+		if (!i) {
+			efi_boot_services_t *boottime;
+
+			boottime = sys_table->boottime;
+
+			status = efi_call_phys3(boottime->handle_protocol,
+					image->device_handle, &fs_proto, &io);
+			if (status != EFI_SUCCESS)
+				goto free_initrds;
+
+			status = efi_call_phys2(io->open_volume, io, &fh);
+			if (status != EFI_SUCCESS)
+				goto free_initrds;
+		}
+
+		status = efi_call_phys5(fh->open, fh, &h, filename,
+					EFI_FILE_MODE_READ, (u64)0);
+		if (status != EFI_SUCCESS)
+			goto close_handles;
+
+		initrd->handle = h;
+
+		info_sz = 0;
+		status = efi_call_phys4(h->get_info, h, &info_guid,
+					&info_sz, NULL);
+		if (status != EFI_BUFFER_TOO_SMALL)
+			goto close_handles;
+
+grow:
+		status = efi_call_phys3(sys_table->boottime->allocate_pool,
+					EFI_LOADER_DATA, info_sz, &info);
+		if (status != EFI_SUCCESS)
+			goto close_handles;
+
+		status = efi_call_phys4(h->get_info, h, &info_guid,
+					&info_sz, info);
+		if (status == EFI_BUFFER_TOO_SMALL) {
+			efi_call_phys1(sys_table->boottime->free_pool, info);
+			goto grow;
+		}
+
+		if (status != EFI_SUCCESS) {
+			efi_call_phys1(sys_table->boottime->free_pool, info);
+			goto close_handles;
+		}
+
+		initrd->size = info->file_size;
+		initrd_total += info->file_size;
+
+		efi_call_phys1(sys_table->boottime->free_pool, info);
+	}
+
+	if (initrd_total) {
+		unsigned long addr;
+
+		/*
+		 * Multiple initrd's need to be at consecutive
+		 * addresses in memory, so allocate enough memory for
+		 * all the initrd's.
+		 */
+		status = low_alloc(initrd_total, 0x1000, &initrd_addr);
+		if (status != EFI_SUCCESS)
+			goto close_handles;
+
+		if (initrd_addr > hdr->initrd_addr_max) {
+			status = EFI_INVALID_PARAMETER;
+			goto free_initrd_total;
+		}
+
+		addr = initrd_addr;
+		for (j = 0; j < nr_initrds; j++) {
+			u64 size;
+
+			size = initrds[j].size;
+			status = efi_call_phys3(fh->read, initrds[j].handle,
+						&size, addr);
+			if (status != EFI_SUCCESS)
+				goto free_initrd_total;
+
+			efi_call_phys1(fh->close, initrds[j].handle);
+
+			addr += size;
+		}
+
+	}
+
+	efi_call_phys1(sys_table->boottime->free_pool, initrds);
+
+	hdr->ramdisk_image = initrd_addr;
+	hdr->ramdisk_size = initrd_total;
+
+	return status;
+
+free_initrd_total:
+	low_free(initrd_total, initrd_addr);
+
+close_handles:
+	for (k = j; k < nr_initrds; k++)
+		efi_call_phys1(fh->close, initrds[k].handle);
+free_initrds:
+	efi_call_phys1(sys_table->boottime->free_pool, initrds);
+fail:
+	hdr->ramdisk_image = 0;
+	hdr->ramdisk_size = 0;
+
+	return status;
+}
+
+/*
+ * Because the x86 boot code expects to be passed a boot_params we
+ * need to create one ourselves (usually the bootloader would create
+ * one for us).
+ */
+static efi_status_t make_boot_params(struct boot_params *boot_params,
+				     efi_loaded_image_t *image,
+				     void *handle)
+{
+	struct screen_info *si = &boot_params->screen_info;
+	struct efi_info *efi = &boot_params->efi_info;
+	struct apm_bios_info *bi = &boot_params->apm_bios_info;
+	struct sys_desc_table *sdt = &boot_params->sys_desc_table;
+	struct e820entry *e820_map = &boot_params->e820_map[0];
+	struct e820entry *prev = NULL;
+	struct setup_header *hdr = &boot_params->hdr;
+	unsigned long size, key, desc_size, _size;
+	efi_guid_t graphics_proto = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
+	efi_memory_desc_t *mem_map;
+	void *options = image->load_options;
+	u32 options_size = image->load_options_size;
+	void **gop_handle = NULL;
+	efi_status_t status;
+	__u32 desc_version;
+	unsigned long rows, cols;
+	unsigned int row, col, mode;
+	unsigned long cmdline;
+	u8 nr_entries;
+	u16 *s2;
+	u8 *s1;
+	int i;
+
+	hdr->type_of_loader = 0x21;
+
+	status = low_alloc(options_size, 1, &cmdline);
+	if (status != EFI_SUCCESS)
+		goto fail;
+
+	hdr->cmd_line_ptr = cmdline;
+
+	/* Convert unicode cmdline to ascii */
+	s1 = (u8 *)(unsigned long)hdr->cmd_line_ptr;
+	s2 = (u16 *)options;
+	
+	if (s2 && options_size) {
+		/* Skip first word, that's the kernel name */
+		while (*s2 && *s2 != ' ' && *s2 != '\n') {
+			options_size--;
+			s2++;
+		}
+
+		/* skip space */
+		if (*s2 == ' ') {
+			options_size--;
+			s2++;
+		}
+
+		while (options_size-- != 0) {
+			*s1++ = *s2++;
+			hdr->cmdline_size++;
+		}
+
+		*s1 = '\0';
+	}
+
+	hdr->ramdisk_image = 0;
+	hdr->ramdisk_size = 0;
+
+	status = handle_ramdisks(image, hdr);
+	if (status != EFI_SUCCESS)
+		goto free_cmdline;
+
+	/* See if we have graphics output protocol */
+	size = 0;
+	status = efi_call_phys5(sys_table->boottime->locate_handle,
+				EFI_LOCATE_BY_PROTOCOL, &graphics_proto,
+				NULL, &size, gop_handle);
+
+	if (status != EFI_SUCCESS && status != EFI_BUFFER_TOO_SMALL)
+		goto free_cmdline;
+
+	status = efi_call_phys3(sys_table->boottime->allocate_pool,
+				EFI_LOADER_DATA, size, &gop_handle);
+	if (status != EFI_SUCCESS)
+		goto free_cmdline;
+
+	status = efi_call_phys5(sys_table->boottime->locate_handle,
+				EFI_LOCATE_BY_PROTOCOL, &graphics_proto,
+				NULL, &size, gop_handle);
+	if (status == EFI_SUCCESS)
+		setup_graphics(boot_params, &graphics_proto, gop_handle, size);
+
+	efi_call_phys1(sys_table->boottime->free_pool, gop_handle);
+
+	/* Clear APM BIOS info */
+	memset(bi, 0, sizeof(*bi));
+
+	memset(sdt, 0, sizeof(*sdt));
+
+	memcpy(&efi->efi_loader_signature, EFI_LOADER_SIGNATURE, sizeof(__u32));
+
+	size = sizeof(*mem_map) * 32;
+
+again:
+	size += sizeof(*mem_map);
+	_size = size;
+	status = low_alloc(size, 1, (unsigned long *)&mem_map);
+	if (status != EFI_SUCCESS)
+		goto free_cmdline;
+
+	status = efi_call_phys5(sys_table->boottime->get_memory_map, &size,
+				mem_map, &key, &desc_size, &desc_version);
+	if (status == EFI_BUFFER_TOO_SMALL) {
+		low_free(_size, (unsigned long)mem_map);
+		goto again;
+	}
+
+	if (status != EFI_SUCCESS)
+		goto free_mem_map;
+
+	efi->efi_systab = (unsigned long)sys_table;
+	efi->efi_memdesc_size = desc_size;
+	efi->efi_memdesc_version = desc_version;
+	efi->efi_memmap = (unsigned long)mem_map;
+	efi->efi_memmap_size = size;
+
+#ifdef CONFIG_X86_64
+	efi->efi_systab_hi = (unsigned long)sys_table >> 32;
+	efi->efi_memmap_hi = (unsigned long)mem_map >> 32;
+#endif
+
+	/* Might as well exit boot services now */
+	status = efi_call_phys2(sys_table->boottime->exit_boot_services,
+				handle, key);
+	if (status != EFI_SUCCESS)
+		goto free_mem_map;
+
+	/* Historic? */
+	boot_params->alt_mem_k = 32 * 1024;
+
+	/*
+	 * Convert the EFI memory map to E820.
+	 */
+	nr_entries = 0;
+	for (i = 0; i < size / desc_size; i++) {
+		efi_memory_desc_t *d;
+		unsigned int e820_type = 0;
+
+		d = (efi_memory_desc_t *)((unsigned long)mem_map + (i * desc_size));
+		switch(d->type) {
+		case EFI_RESERVED_TYPE:
+		case EFI_RUNTIME_SERVICES_CODE:
+		case EFI_RUNTIME_SERVICES_DATA:
+		case EFI_MEMORY_MAPPED_IO:
+		case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
+		case EFI_PAL_CODE:
+			e820_type = E820_RESERVED;
+			break;
+
+		case EFI_UNUSABLE_MEMORY:
+			e820_type = E820_UNUSABLE;
+			break;
+
+		case EFI_ACPI_RECLAIM_MEMORY:
+			e820_type = E820_ACPI;
+			break;
+
+		case EFI_LOADER_CODE:
+		case EFI_LOADER_DATA:
+		case EFI_BOOT_SERVICES_CODE:
+		case EFI_BOOT_SERVICES_DATA:
+		case EFI_CONVENTIONAL_MEMORY:
+			e820_type = E820_RAM;
+			break;
+
+		case EFI_ACPI_MEMORY_NVS:
+			e820_type = E820_NVS;
+			break;
+
+		default:
+			continue;
+		}
+
+		/* Merge adjacent mappings */
+		if (prev && prev->type == e820_type &&
+		    (prev->addr + prev->size) == d->phys_addr)
+			prev->size += d->num_pages << 12;
+		else {
+			e820_map->addr = d->phys_addr;
+			e820_map->size = d->num_pages << 12;
+			e820_map->type = e820_type;
+			prev = e820_map++;
+			nr_entries++;
+		}
+	}
+
+	boot_params->e820_entries = nr_entries;
+
+	return EFI_SUCCESS;
+
+free_mem_map:
+	low_free(_size, (unsigned long)mem_map);
+free_cmdline:
+	low_free(options_size, hdr->cmd_line_ptr);
+fail:
+	return status;
+}
+
+/*
+ * On success we return a pointer to a boot_params structure, and NULL
+ * on failure.
+ */
+struct boot_params *efi_main(void *handle, efi_system_table_t *_table)
+{
+	efi_loaded_image_t *image;
+	struct boot_params *boot_params;
+	efi_status_t status;
+	struct setup_header *hdr;
+	efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
+	struct desc_ptr *gdt, *idt;
+	u64 *desc;
+
+	sys_table = _table;
+
+	/* Check if we were booted by the EFI firmware */
+	if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
+		goto fail;
+
+	status = efi_call_phys3(sys_table->boottime->handle_protocol,
+				handle, &proto, (void *)&image);
+	if (status != EFI_SUCCESS)
+		goto fail;
+
+	status = low_alloc(0x4000, 1, (unsigned long *)&boot_params);
+	if (status != EFI_SUCCESS)
+		goto fail;
+
+	memset(boot_params, 0x0, 0x4000);
+
+	/* Copy first two sectors to boot_params */
+	memcpy(boot_params, image->image_base, 1024);
+
+	hdr = &boot_params->hdr;
+	hdr->code32_start = (__u32)(unsigned long)image->image_base;
+
+	status = efi_call_phys3(sys_table->boottime->allocate_pool,
+				EFI_LOADER_DATA, sizeof(*gdt),
+				(void **)&gdt);
+	if (status != EFI_SUCCESS)
+		goto fail;
+
+	gdt->size = 0x800;
+	status = low_alloc(gdt->size, 8, (unsigned long *)&gdt->address);
+	if (status != EFI_SUCCESS)
+		goto fail;
+
+	status = efi_call_phys3(sys_table->boottime->allocate_pool,
+				EFI_LOADER_DATA, sizeof(*idt),
+				(void **)&idt);
+	if (status != EFI_SUCCESS)
+		goto fail;
+
+	idt->size = 0;
+	idt->address = 0;
+
+	status = make_boot_params(boot_params, image, handle);
+	if (status != EFI_SUCCESS)
+		goto fail;
+
+	memset((char *)gdt->address, 0x0, gdt->size);
+	desc = (u64 *)gdt->address;
+
+	/*
+	 * 4Gb - (0x100000*0x1000 = 4Gb)
+	 * base address=0
+	 * code read/exec
+	 * granularity=4096, 386 (+5th nibble of limit)
+	 */
+	desc[2] = 0x00cf9a000000ffff;
+
+	/*
+	 * 4Gb - (0x100000*0x1000 = 4Gb)
+	 * base address=0
+	 * data read/write
+	 * granularity=4096, 386 (+5th nibble of limit)
+	 */
+	desc[3] = 0x00cf92000000ffff;
+
+	/* Task segment value */
+	desc[4] = 0x0080890000000000;
+
+	asm volatile ("lidt %0" :: "m" (*idt));
+	asm volatile ("lgdt %0" :: "m" (*gdt));
+
+	asm volatile("cli");
+
+	return boot_params;
+fail:
+	return NULL;
+}
diff --git a/arch/x86/boot/compressed/efi_stub_32.S b/arch/x86/boot/compressed/efi_stub_32.S
new file mode 100644
index 0000000..5047cd9
--- /dev/null
+++ b/arch/x86/boot/compressed/efi_stub_32.S
@@ -0,0 +1,87 @@
+/*
+ * EFI call stub for IA32.
+ *
+ * This stub allows us to make EFI calls in physical mode with interrupts
+ * turned off. Note that this implementation is different from the one in
+ * arch/x86/platform/efi/efi_stub_32.S because we're _already_ in physical
+ * mode at this point.
+ */
+
+#include <linux/linkage.h>
+#include <asm/page_types.h>
+
+/*
+ * efi_call_phys(void *, ...) is a function with variable parameters.
+ * All the callers of this function assure that all the parameters are 4-bytes.
+ */
+
+/*
+ * In gcc calling convention, EBX, ESP, EBP, ESI and EDI are all callee save.
+ * So we'd better save all of them at the beginning of this function and restore
+ * at the end no matter how many we use, because we can not assure EFI runtime
+ * service functions will comply with gcc calling convention, too.
+ */
+
+.text
+ENTRY(efi_call_phys)
+	/*
+	 * 0. The function can only be called in Linux kernel. So CS has been
+	 * set to 0x0010, DS and SS have been set to 0x0018. In EFI, I found
+	 * the values of these registers are the same. And, the corresponding
+	 * GDT entries are identical. So I will do nothing about segment reg
+	 * and GDT, but change GDT base register in prelog and epilog.
+	 */
+
+	/*
+	 * 1. Because we haven't been relocated by this point we need to
+	 * use relative addressing.
+	 */
+	call	1f
+1:	popl	%edx
+	subl	$1b, %edx
+
+	/*
+	 * 2. Now on the top of stack is the return
+	 * address in the caller of efi_call_phys(), then parameter 1,
+	 * parameter 2, ..., param n. To make things easy, we save the return
+	 * address of efi_call_phys in a global variable.
+	 */
+	popl	%ecx
+	movl	%ecx, saved_return_addr(%edx)
+	/* get the function pointer into ECX*/
+	popl	%ecx
+	movl	%ecx, efi_rt_function_ptr(%edx)
+
+	/*
+	 * 3. Call the physical function.
+	 */
+	call	*%ecx
+
+	/*
+	 * 4. Balance the stack. And because EAX contain the return value,
+	 * we'd better not clobber it. We need to calculate our address
+	 * again because %ecx and %edx are not preserved across EFI function
+	 * calls.
+	 */
+	call	1f
+1:	popl	%edx
+	subl	$1b, %edx
+
+	movl	efi_rt_function_ptr(%edx), %ecx
+	pushl	%ecx
+
+	/*
+	 * 10. Push the saved return address onto the stack and return.
+	 */
+	movl	saved_return_addr(%edx), %ecx
+	pushl	%ecx
+	ret
+ENDPROC(efi_call_phys)
+.previous
+
+.data
+saved_return_addr:
+	.long 0
+efi_rt_function_ptr:
+	.long 0
+
diff --git a/arch/x86/boot/compressed/efi_stub_64.S b/arch/x86/boot/compressed/efi_stub_64.S
new file mode 100644
index 0000000..cedc60d
--- /dev/null
+++ b/arch/x86/boot/compressed/efi_stub_64.S
@@ -0,0 +1 @@
+#include "../../platform/efi/efi_stub_64.S"
diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S
index 67a655a..2fe23a4 100644
--- a/arch/x86/boot/compressed/head_32.S
+++ b/arch/x86/boot/compressed/head_32.S
@@ -32,6 +32,19 @@
 
 	__HEAD
 ENTRY(startup_32)
+#ifdef CONFIG_EFI_STUB
+	/*
+	 * We don't need the return address, so set up the stack so
+	 * efi_main() can find its arugments.
+	 */
+	add	$0x4, %esp
+
+	call	efi_main
+	cmpl	$0, %eax
+	je	1f
+	movl	%eax, %esi
+1:
+#endif
 	cld
 	/*
 	 * Test KEEP_SEGMENTS flag to see if the bootloader is asking
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
index 35af09d..09a3606 100644
--- a/arch/x86/boot/compressed/head_64.S
+++ b/arch/x86/boot/compressed/head_64.S
@@ -199,6 +199,17 @@ ENTRY(startup_64)
 	 * an identity mapped page table being provied that maps our
 	 * entire text+data+bss and hopefully all of memory.
 	 */
+#ifdef CONFIG_EFI_STUB
+	pushq	%rsi
+	mov	%rcx, %rdi
+	mov	%rdx, %rsi
+	call	efi_main
+	popq	%rsi
+	cmpq	$0,%rax
+	je	1f
+	movq	%rax,%rsi
+1:
+#endif
 
 	/* Setup data segments. */
 	xorl	%eax, %eax
diff --git a/arch/x86/boot/compressed/string.c b/arch/x86/boot/compressed/string.c
index 19b3e69..ffb9c5c 100644
--- a/arch/x86/boot/compressed/string.c
+++ b/arch/x86/boot/compressed/string.c
@@ -1,2 +1,11 @@
 #include "misc.h"
+
+int memcmp(const void *s1, const void *s2, size_t len)
+{
+	u8 diff;
+	asm("repe; cmpsb; setnz %0"
+	    : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len));
+	return diff;
+}
+
 #include "../string.c"
diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index 93e689f..dc2f0e9 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -45,6 +45,11 @@ SYSSEG		= 0x1000		/* historical load address >> 4 */
 
 	.global bootsect_start
 bootsect_start:
+#ifdef CONFIG_EFI_STUB
+	# "MZ", MS-DOS header
+	.byte 0x4d
+	.byte 0x5a
+#endif
 
 	# Normalize the start address
 	ljmp	$BOOTSEG, $start2
@@ -79,6 +84,14 @@ bs_die:
 	# invoke the BIOS reset code...
 	ljmp	$0xf000,$0xfff0
 
+#ifdef CONFIG_EFI_STUB
+	.org	0x3c
+	#
+	# Offset to the PE header.
+	#
+	.long	pe_header
+#endif /* CONFIG_EFI_STUB */
+
 	.section ".bsdata", "a"
 bugger_off_msg:
 	.ascii	"Direct booting from floppy is no longer supported.\r\n"
@@ -87,6 +100,140 @@ bugger_off_msg:
 	.ascii	"Remove disk and press any key to reboot . . .\r\n"
 	.byte	0
 
+#ifdef CONFIG_EFI_STUB
+pe_header:
+	.ascii	"PE"
+	.word 	0
+
+coff_header:
+#ifdef CONFIG_X86_32
+	.word	0x14c				# i386
+#else
+	.word	0x8664				# x86-64
+#endif
+	.word	2				# nr_sections
+	.long	0 				# TimeDateStamp
+	.long	0				# PointerToSymbolTable
+	.long	1				# NumberOfSymbols
+	.word	section_table - optional_header	# SizeOfOptionalHeader
+#ifdef CONFIG_X86_32
+	.word	0x306				# Characteristics.
+						# IMAGE_FILE_32BIT_MACHINE |
+						# IMAGE_FILE_DEBUG_STRIPPED |
+						# IMAGE_FILE_EXECUTABLE_IMAGE |
+						# IMAGE_FILE_LINE_NUMS_STRIPPED
+#else
+	.word	0x206				# Characteristics
+						# IMAGE_FILE_DEBUG_STRIPPED |
+						# IMAGE_FILE_EXECUTABLE_IMAGE |
+						# IMAGE_FILE_LINE_NUMS_STRIPPED
+#endif
+
+optional_header:
+#ifdef CONFIG_X86_32
+	.word	0x10b				# PE32 format
+#else
+	.word	0x20b 				# PE32+ format
+#endif
+	.byte	0x02				# MajorLinkerVersion
+	.byte	0x14				# MinorLinkerVersion
+	.long	0				# SizeOfCode
+	.long	0				# SizeOfInitializedData
+	.long	0				# SizeOfUninitializedData
+#ifdef CONFIG_X86_32
+	.long	0x3400				# AddressOfEntryPoint
+	.long	0x0000				# BaseOfCode
+#else
+	.long	0x3800				# AddressOfEntryPoint
+	.long	0x0000				# BaseOfCode
+#endif
+#ifdef CONFIG_X86_32
+	.long	0				# data
+#endif
+
+extra_header_fields:
+#ifdef CONFIG_X86_32
+	.long	0				# ImageBase
+#else
+	.quad	0				# ImageBase
+#endif
+	.long	0x1000				# SectionAlignment
+	.long	0x2000				# FileAlignment
+	.word	0				# MajorOperatingSystemVersion
+	.word	0				# MinorOperatingSystemVersion
+	.word	0				# MajorImageVersion
+	.word	0				# MinorImageVersion
+	.word	0				# MajorSubsystemVersion
+	.word	0				# MinorSubsystemVersion
+	.long	0				# Win32VersionValue
+
+	#
+	# The size of the bzImage is written in tools/build.c
+	#
+	.long	0				# SizeOfImage
+
+	.long	0x200				# SizeOfHeaders
+	.long	0				# CheckSum
+	.word	0xa				# Subsystem (EFI application)
+	.word	0				# DllCharacteristics
+#ifdef CONFIG_X86_32
+	.long	0				# SizeOfStackReserve
+	.long	0				# SizeOfStackCommit
+	.long	0				# SizeOfHeapReserve
+	.long	0				# SizeOfHeapCommit
+#else
+	.quad	0				# SizeOfStackReserve
+	.quad	0				# SizeOfStackCommit
+	.quad	0				# SizeOfHeapReserve
+	.quad	0				# SizeOfHeapCommit
+#endif
+	.long	0				# LoaderFlags
+	.long	0x1				# NumberOfRvaAndSizes
+
+	.quad	0				# ExportTable
+	.quad	0				# ImportTable
+	.quad	0				# ResourceTable
+	.quad	0				# ExceptionTable
+	.quad	0				# CertificationTable
+	.quad	0				# BaseRelocationTable
+
+	# Section table
+section_table:
+	.ascii	".text"
+	.byte	0
+	.byte	0
+	.byte	0
+	.long	0
+	.long	0x0				# startup_{32,64}
+	.long	0				# Size of initialized data
+						# on disk
+	.long	0x0				# startup_{32,64}
+	.long	0				# PointerToRelocations
+	.long	0				# PointerToLineNumbers
+	.word	0				# NumberOfRelocations
+	.word	0				# NumberOfLineNumbers
+	.long	0x60500020			# Characteristics (section flags)
+
+	#
+	# The EFI application loader requires a relocation section
+	# because EFI applications are relocatable and not having
+	# this section seems to confuse it. But since we don't need
+	# the loader to fixup any relocs for us just fill it with a
+	# single dummy reloc.
+	#
+	.ascii	".reloc"
+	.byte	0
+	.byte	0
+	.long	reloc_end - reloc_start
+	.long	reloc_start
+	.long	reloc_end - reloc_start		# SizeOfRawData
+	.long	reloc_start			# PointerToRawData
+	.long	0				# PointerToRelocations
+	.long	0				# PointerToLineNumbers
+	.word	0				# NumberOfRelocations
+	.word	0				# NumberOfLineNumbers
+	.long	0x42100040			# Characteristics (section flags)
+#endif /* CONFIG_EFI_STUB */
 
 	# Kernel attributes; used by setup.  This is part 1 of the
 	# header, from the old boot sector.
@@ -318,3 +465,13 @@ die:
 setup_corrupt:
 	.byte	7
 	.string	"No setup signature found...\n"
+
+	.data
+dummy:	.long	0
+
+	.section .reloc
+reloc_start:
+	.long	dummy - reloc_start
+	.long	10
+	.word	0
+reloc_end:
diff --git a/arch/x86/boot/string.c b/arch/x86/boot/string.c
index 3cbc405..574dedf 100644
--- a/arch/x86/boot/string.c
+++ b/arch/x86/boot/string.c
@@ -111,3 +111,38 @@ unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int bas
 
 	return result;
 }
+
+/**
+ * strlen - Find the length of a string
+ * @s: The string to be sized
+ */
+size_t strlen(const char *s)
+{
+	const char *sc;
+
+	for (sc = s; *sc != '\0'; ++sc)
+		/* nothing */;
+	return sc - s;
+}
+
+/**
+ * strstr - Find the first substring in a %NUL terminated string
+ * @s1: The string to be searched
+ * @s2: The string to search for
+ */
+char *strstr(const char *s1, const char *s2)
+{
+	size_t l1, l2;
+
+	l2 = strlen(s2);
+	if (!l2)
+		return (char *)s1;
+	l1 = strlen(s1);
+	while (l1 >= l2) {
+		l1--;
+		if (!memcmp(s1, s2, l2))
+			return (char *)s1;
+		s1++;
+	}
+	return NULL;
+}
diff --git a/arch/x86/boot/tools/build.c b/arch/x86/boot/tools/build.c
index fdc60a0..6088c6b 100644
--- a/arch/x86/boot/tools/build.c
+++ b/arch/x86/boot/tools/build.c
@@ -135,6 +135,7 @@ static void usage(void)
 
 int main(int argc, char ** argv)
 {
+	unsigned int file_sz, pe_header;
 	unsigned int i, sz, setup_sectors;
 	int c;
 	u32 sys_size;
@@ -194,6 +195,32 @@ int main(int argc, char ** argv)
 	buf[0x1f6] = sys_size >> 16;
 	buf[0x1f7] = sys_size >> 24;
 
+#ifdef CONFIG_EFI_STUB
+	file_sz = sz + i + ((sys_size * 16) - sz);
+
+	pe_header = *(unsigned int *)&buf[0x3c];
+
+	/* Size of code */
+	*(unsigned int *)&buf[pe_header + 0x1c] = file_sz;
+
+	/* Size of image */
+	*(unsigned int *)&buf[pe_header + 0x50] = file_sz;
+
+#ifdef CONFIG_X86_32
+	/* .text size */
+	*(unsigned int *)&buf[pe_header + 0xb0] = file_sz;
+
+	/* .text size of initialised data */
+	*(unsigned int *)&buf[pe_header + 0xb8] = file_sz;
+#else
+	/* .text size */
+	*(unsigned int *)&buf[pe_header + 0xc0] = file_sz;
+
+	/* .text size of initialised data */
+	*(unsigned int *)&buf[pe_header + 0xc8] = file_sz;
+#endif /* CONFIG_X86_32 */
+#endif /* CONFIG_EFI_STUB */
+
 	crc = partial_crc32(buf, i, crc);
 	if (fwrite(buf, 1, i, stdout) != i)
 		die("Writing setup failed");
-- 
1.7.4.4


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 9/9] x86, efi: Make efi_call_phys_prelog() CONFIG_RELOCATABLE-aware
  2011-08-11 10:59 [PATCH 0/9] x86 EFI boot stub Matt Fleming
                   ` (7 preceding siblings ...)
  2011-08-11 10:59 ` [PATCH 8/9] x86, efi: EFI boot stub support Matt Fleming
@ 2011-08-11 10:59 ` Matt Fleming
  2011-08-11 13:05 ` [PATCH 0/9] x86 EFI boot stub Maarten Lankhorst
  9 siblings, 0 replies; 16+ messages in thread
From: Matt Fleming @ 2011-08-11 10:59 UTC (permalink / raw)
  To: linux-kernel
  Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Matthew Garrett

From: Matt Fleming <matt.fleming@linux.intel.com>

efi_call_phys_prelog() assumes that the kernel was loaded at a
physical address within the first 8MB of ram, usually
0x1000000. However, this isn't the case with a CONFIG_RELOCATABLE=y
kernel which could have been loaded anywhere in the physical address
space.

Replace the hardcoded pgd_index(0) and pgd_index(PAGE_OFFSET) with the
runtime addresses of the kernel in the physical and virtual space,
respectively.

Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Matthew Garrett <mjg@redhat.com>
Signed-off-by: Matt Fleming <matt.fleming@linux.intel.com>
---
 arch/x86/platform/efi/efi_32.c |   22 +++++++++++++---------
 1 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/arch/x86/platform/efi/efi_32.c b/arch/x86/platform/efi/efi_32.c
index 5cab48e..1156e9a 100644
--- a/arch/x86/platform/efi/efi_32.c
+++ b/arch/x86/platform/efi/efi_32.c
@@ -44,8 +44,12 @@ void efi_call_phys_prelog(void)
 {
 	unsigned long cr4;
 	unsigned long temp;
+	unsigned long phys_addr, virt_addr;
 	struct desc_ptr gdt_descr;
 
+	virt_addr = (unsigned long)_text;
+	phys_addr = virt_addr - PAGE_OFFSET;
+
 	local_irq_save(efi_rt_eflags);
 
 	/*
@@ -57,18 +61,18 @@ void efi_call_phys_prelog(void)
 
 	if (cr4 & X86_CR4_PAE) {
 		efi_bak_pg_dir_pointer[0].pgd =
-		    swapper_pg_dir[pgd_index(0)].pgd;
-		swapper_pg_dir[0].pgd =
-		    swapper_pg_dir[pgd_index(PAGE_OFFSET)].pgd;
+		    swapper_pg_dir[pgd_index(phys_addr)].pgd;
+		swapper_pg_dir[pgd_index(phys_addr)].pgd =
+		    swapper_pg_dir[pgd_index(virt_addr)].pgd;
 	} else {
 		efi_bak_pg_dir_pointer[0].pgd =
-		    swapper_pg_dir[pgd_index(0)].pgd;
+		    swapper_pg_dir[pgd_index(phys_addr)].pgd;
 		efi_bak_pg_dir_pointer[1].pgd =
-		    swapper_pg_dir[pgd_index(0x400000)].pgd;
-		swapper_pg_dir[pgd_index(0)].pgd =
-		    swapper_pg_dir[pgd_index(PAGE_OFFSET)].pgd;
-		temp = PAGE_OFFSET + 0x400000;
-		swapper_pg_dir[pgd_index(0x400000)].pgd =
+		    swapper_pg_dir[pgd_index(phys_addr + 0x400000)].pgd;
+		swapper_pg_dir[pgd_index(phys_addr)].pgd =
+		    swapper_pg_dir[pgd_index(virt_addr)].pgd;
+		temp = virt_addr + 0x400000;
+		swapper_pg_dir[pgd_index(phys_addr + 0x400000)].pgd =
 		    swapper_pg_dir[pgd_index(temp)].pgd;
 	}
 
-- 
1.7.4.4


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/9] x86 EFI boot stub
  2011-08-11 10:59 [PATCH 0/9] x86 EFI boot stub Matt Fleming
                   ` (8 preceding siblings ...)
  2011-08-11 10:59 ` [PATCH 9/9] x86, efi: Make efi_call_phys_prelog() CONFIG_RELOCATABLE-aware Matt Fleming
@ 2011-08-11 13:05 ` Maarten Lankhorst
  2011-08-11 15:14   ` Matt Fleming
  9 siblings, 1 reply; 16+ messages in thread
From: Maarten Lankhorst @ 2011-08-11 13:05 UTC (permalink / raw)
  To: Matt Fleming; +Cc: linux-kernel

On 08/11/2011 12:59 PM, Matt Fleming wrote:
> From: Matt Fleming <matt.fleming@intel.com>
>
> This series adds support for an EFI boot stub, similar to the existing
> BIOS boot stub. The result is that you can boot a bzImage on an EFI
> machine without the use of a boot loader by making the bzImage appear
> to the EFI firmware to be an EFI application. Also, a single bzImage
> can be booted on either a BIOS or EFI machine.
>
> Using the EFI boot stub has the advantage that the kernel is
> responsible for configuring the machine to the point where we can
> fully boot the kernel, so we are no longer at the mercy of the boot
> loader.
>
Fails to boot here. I thought changing characteristics from 0x60500020 to 0xe0500020 would help, but no. :/
This change would make the code section writable.

FileAlignment you use is probably wrong, I think it should be 0x200 not 0x2000 .

Maybe you need to add a data section and fix SizeOfInitializedData too?

It just hangs on a blinking cursor, no idea if it actually started executing anything yet or not, since nothing is printed out.

~Maarten


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/9] x86 EFI boot stub
  2011-08-11 13:05 ` [PATCH 0/9] x86 EFI boot stub Maarten Lankhorst
@ 2011-08-11 15:14   ` Matt Fleming
  2011-08-11 17:55     ` Maarten Lankhorst
  0 siblings, 1 reply; 16+ messages in thread
From: Matt Fleming @ 2011-08-11 15:14 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: linux-kernel

On Thu, 2011-08-11 at 15:05 +0200, Maarten Lankhorst wrote:
> On 08/11/2011 12:59 PM, Matt Fleming wrote:
> > From: Matt Fleming <matt.fleming@intel.com>
> >
> > This series adds support for an EFI boot stub, similar to the existing
> > BIOS boot stub. The result is that you can boot a bzImage on an EFI
> > machine without the use of a boot loader by making the bzImage appear
> > to the EFI firmware to be an EFI application. Also, a single bzImage
> > can be booted on either a BIOS or EFI machine.
> >
> > Using the EFI boot stub has the advantage that the kernel is
> > responsible for configuring the machine to the point where we can
> > fully boot the kernel, so we are no longer at the mercy of the boot
> > loader.
> >
> Fails to boot here. I thought changing characteristics from 0x60500020 to 0xe0500020 would help, but no. :/
> This change would make the code section writable.

Thanks for testing out the patches Maarten!

> FileAlignment you use is probably wrong, I think it should be 0x200 not 0x2000 .

Yep, thanks. That looks like a typo.

> Maybe you need to add a data section and fix SizeOfInitializedData too?

Hmm.. possibly. Is this on x86-64?

> It just hangs on a blinking cursor, no idea if it actually started executing anything yet or not, since nothing is printed out.

Hmm.. do you have early printk enabled? Can you hook up a serial console
to this machine?

-- 
Matt Fleming, Intel Open Source Technology Center


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/9] x86 EFI boot stub
  2011-08-11 15:14   ` Matt Fleming
@ 2011-08-11 17:55     ` Maarten Lankhorst
  2011-08-26 12:29       ` Matt Fleming
  0 siblings, 1 reply; 16+ messages in thread
From: Maarten Lankhorst @ 2011-08-11 17:55 UTC (permalink / raw)
  To: Matt Fleming; +Cc: linux-kernel

Hey,

On 08/11/2011 05:14 PM, Matt Fleming wrote:
> On Thu, 2011-08-11 at 15:05 +0200, Maarten Lankhorst wrote:
>> On 08/11/2011 12:59 PM, Matt Fleming wrote:
>>> From: Matt Fleming <matt.fleming@intel.com>
>>>
>>> This series adds support for an EFI boot stub, similar to the existing
>>> BIOS boot stub. The result is that you can boot a bzImage on an EFI
>>> machine without the use of a boot loader by making the bzImage appear
>>> to the EFI firmware to be an EFI application. Also, a single bzImage
>>> can be booted on either a BIOS or EFI machine.
>>>
>>> Using the EFI boot stub has the advantage that the kernel is
>>> responsible for configuring the machine to the point where we can
>>> fully boot the kernel, so we are no longer at the mercy of the boot
>>> loader.
>>>
>> Fails to boot here. I thought changing characteristics from 0x60500020 to 0xe0500020 would help, but no. :/
>> This change would make the code section writable.
> Thanks for testing out the patches Maarten!
>
>> FileAlignment you use is probably wrong, I think it should be 0x200 not 0x2000 .
> Yep, thanks. That looks like a typo.
>
>> Maybe you need to add a data section and fix SizeOfInitializedData too?
> Hmm.. possibly. Is this on x86-64?
Yeah the system I'm testing on is 64-bits, if it you get this one working I can check if my old mac mini supports 32-bits efi too.
>> It just hangs on a blinking cursor, no idea if it actually started executing anything yet or not, since nothing is printed out.
> Hmm.. do you have early printk enabled? Can you hook up a serial console
> to this machine?
>
I get no output on serial console with vmlinuz.efi so it crashes before 'early console in decompress_kernel' is printed.

~Maarten

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 8/9] x86, efi: EFI boot stub support
  2011-08-11 10:59 ` [PATCH 8/9] x86, efi: EFI boot stub support Matt Fleming
@ 2011-08-11 18:09   ` Andi Kleen
  2011-08-17 11:46     ` Matt Fleming
  0 siblings, 1 reply; 16+ messages in thread
From: Andi Kleen @ 2011-08-11 18:09 UTC (permalink / raw)
  To: Matt Fleming
  Cc: linux-kernel, H. Peter Anvin, Thomas Gleixner, Ingo Molnar,
	Mike Waychison, Matthew Garrett

Matt Fleming <matt@console-pimps.org> writes:
> +
> +	status = efi_call_phys3(sys_table->boottime->allocate_pool,
> +				EFI_LOADER_DATA, sizeof(*idt),
> +				(void **)&idt);
> +	if (status != EFI_SUCCESS)
> +		goto fail;
> +
> +	idt->size = 0;
> +	idt->address = 0;
> +
> +	status = make_boot_params(boot_params, image, handle);
> +	if (status != EFI_SUCCESS)
> +		goto fail;
> +
> +	memset((char *)gdt->address, 0x0, gdt->size);
> +	desc = (u64 *)gdt->address;
> +
> +	/*
> +	 * 4Gb - (0x100000*0x1000 = 4Gb)
> +	 * base address=0
> +	 * code read/exec
> +	 * granularity=4096, 386 (+5th nibble of limit)
> +	 */
> +	desc[2] = 0x00cf9a000000ffff;
> +
> +	/*
> +	 * 4Gb - (0x100000*0x1000 = 4Gb)
> +	 * base address=0
> +	 * data read/write
> +	 * granularity=4096, 386 (+5th nibble of limit)
> +	 */
> +	desc[3] = 0x00cf92000000ffff;
> +
> +	/* Task segment value */
> +	desc[4] = 0x0080890000000000;

The code would benefit from more variables/defines and less magic numbers.

I assume this is all virtual, otherwise it would be really scary.

> +	asm volatile ("lidt %0" :: "m" (*idt));
> +	asm volatile ("lgdt %0" :: "m" (*gdt));
> +
> +	asm volatile("cli");

::: "memory" to avoid moving

> +
> +	return boot_params;
> +fail:
> +	return NULL;

Does the caller actually something useful here for NULL? Better to have
messages when any of this fails.

> +int memcmp(const void *s1, const void *s2, size_t len)
> +{
> +	u8 diff;
> +	asm("repe; cmpsb; setnz %0"
> +	    : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len));

This doesn't describe to gcc that the inline assembler 
reads s1 and s2. At the minimum add a memory clobber.

> +
> +/**
> + * strlen - Find the length of a string
> + * @s: The string to be sized
> + */
> +size_t strlen(const char *s)
> +{
> +	const char *sc;
> +
> +	for (sc = s; *sc != '\0'; ++sc)
> +		/* nothing */;
> +	return sc - s;
> +}

Why not just link in/#include lib/string.c ? 


-Andi
-- 
ak@linux.intel.com -- Speaking for myself only

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 8/9] x86, efi: EFI boot stub support
  2011-08-11 18:09   ` Andi Kleen
@ 2011-08-17 11:46     ` Matt Fleming
  0 siblings, 0 replies; 16+ messages in thread
From: Matt Fleming @ 2011-08-17 11:46 UTC (permalink / raw)
  To: Andi Kleen
  Cc: linux-kernel, H. Peter Anvin, Thomas Gleixner, Ingo Molnar,
	Mike Waychison, Matthew Garrett

On Thu, 2011-08-11 at 11:09 -0700, Andi Kleen wrote: 
> Matt Fleming <matt@console-pimps.org> writes:
> > +
> > +	status = efi_call_phys3(sys_table->boottime->allocate_pool,
> > +				EFI_LOADER_DATA, sizeof(*idt),
> > +				(void **)&idt);
> > +	if (status != EFI_SUCCESS)
> > +		goto fail;
> > +
> > +	idt->size = 0;
> > +	idt->address = 0;
> > +
> > +	status = make_boot_params(boot_params, image, handle);
> > +	if (status != EFI_SUCCESS)
> > +		goto fail;
> > +
> > +	memset((char *)gdt->address, 0x0, gdt->size);
> > +	desc = (u64 *)gdt->address;
> > +
> > +	/*
> > +	 * 4Gb - (0x100000*0x1000 = 4Gb)
> > +	 * base address=0
> > +	 * code read/exec
> > +	 * granularity=4096, 386 (+5th nibble of limit)
> > +	 */
> > +	desc[2] = 0x00cf9a000000ffff;
> > +
> > +	/*
> > +	 * 4Gb - (0x100000*0x1000 = 4Gb)
> > +	 * base address=0
> > +	 * data read/write
> > +	 * granularity=4096, 386 (+5th nibble of limit)
> > +	 */
> > +	desc[3] = 0x00cf92000000ffff;
> > +
> > +	/* Task segment value */
> > +	desc[4] = 0x0080890000000000;
> 
> The code would benefit from more variables/defines and less magic numbers.

Yeah, good point. I'll update that.

> I assume this is all virtual, otherwise it would be really scary.

What do you mean by virtual?

> > +	asm volatile ("lidt %0" :: "m" (*idt));
> > +	asm volatile ("lgdt %0" :: "m" (*gdt));
> > +
> > +	asm volatile("cli");
> 
> ::: "memory" to avoid moving

What do you mean? What will be moved?

> > +
> > +	return boot_params;
> > +fail:
> > +	return NULL;
> 
> Does the caller actually something useful here for NULL? Better to have
> messages when any of this fails.

Yes, the caller uses the return value to figure out whether it should
fall back to the usual non-EFI bzImage boot procedure.

> > +int memcmp(const void *s1, const void *s2, size_t len)
> > +{
> > +	u8 diff;
> > +	asm("repe; cmpsb; setnz %0"
> > +	    : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len));
> 
> This doesn't describe to gcc that the inline assembler 
> reads s1 and s2. At the minimum add a memory clobber.

Confused. The "+" constraint indicates that the register will be both
read from and written to. Why is the memory clobber required? We're not
modifying memory.

> > +
> > +/**
> > + * strlen - Find the length of a string
> > + * @s: The string to be sized
> > + */
> > +size_t strlen(const char *s)
> > +{
> > +	const char *sc;
> > +
> > +	for (sc = s; *sc != '\0'; ++sc)
> > +		/* nothing */;
> > +	return sc - s;
> > +}
> 
> Why not just link in/#include lib/string.c ? 

I did try to #include it originally but there was various compiler
errors that sent me running in the other direction, e.g.

In file included from arch/x86/boot/compressed/../string.c:83:0,
                 from arch/x86/boot/compressed/string.c:12:
arch/x86/boot/compressed/../../../../lib/string.c: In function ‘strlcat’:
arch/x86/boot/compressed/../../../../lib/string.c:223:2: warning: asm operand 0 probably doesn’t match constraints
arch/x86/boot/compressed/../../../../lib/string.c:223:2: error: impossible constraint in ‘asm’
make[2]: *** [arch/x86/boot/compressed/string.o] Error 1
make[1]: *** [arch/x86/boot/compressed/vmlinux] Error 2

This is with CONFIG_DEBUG_BUGVERBOSE=y.

Thanks for the review!

-- 
Matt Fleming, Intel Open Source Technology Center



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/9] x86 EFI boot stub
  2011-08-11 17:55     ` Maarten Lankhorst
@ 2011-08-26 12:29       ` Matt Fleming
  0 siblings, 0 replies; 16+ messages in thread
From: Matt Fleming @ 2011-08-26 12:29 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: linux-kernel

On Thu, 2011-08-11 at 19:55 +0200, Maarten Lankhorst wrote: 
> > Hmm.. do you have early printk enabled? Can you hook up a serial console
> > to this machine?
> >
> I get no output on serial console with vmlinuz.efi so it crashes
> before 'early console in decompress_kernel' is printed.

Hey Maarten, sorry I took so long to respond to this.

OK, so you don't get any output on the serial console. Were you passing
"console=" on the kernel cmdline? If so, the best way to debug this hang
is to add,

	efi_call_phys4(sys_table->runtime->reset_system, EFI_RESET_COLD,
			EFI_SUCCESS, 0, NULL);

just after we setup 'sys_table' in efi_main(). If your machine resets,
then we at least know that the firmware loaded the bzImage correctly.

P.S which machine is this and what is the output of the 'ver' command?

-- 
Matt Fleming, Intel Open Source Technology Center


^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2011-08-26 12:29 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-08-11 10:59 [PATCH 0/9] x86 EFI boot stub Matt Fleming
2011-08-11 10:59 ` [PATCH 1/9] x86: Don't use magic strings for EFI loader signature Matt Fleming
2011-08-11 10:59 ` [PATCH 2/9] efi.h: Add struct definition for boot time services Matt Fleming
2011-08-11 10:59 ` [PATCH 3/9] efi.h: Add efi_image_loaded_t Matt Fleming
2011-08-11 10:59 ` [PATCH 4/9] efi.h: Add allocation types for boottime->allocate_pages() Matt Fleming
2011-08-11 10:59 ` [PATCH 5/9] efi.h: Add graphics protocol guid Matt Fleming
2011-08-11 10:59 ` [PATCH 6/9] efi.h: Add boottime->locate_handle search types Matt Fleming
2011-08-11 10:59 ` [PATCH 7/9] efi: Add EFI file I/O data types Matt Fleming
2011-08-11 10:59 ` [PATCH 8/9] x86, efi: EFI boot stub support Matt Fleming
2011-08-11 18:09   ` Andi Kleen
2011-08-17 11:46     ` Matt Fleming
2011-08-11 10:59 ` [PATCH 9/9] x86, efi: Make efi_call_phys_prelog() CONFIG_RELOCATABLE-aware Matt Fleming
2011-08-11 13:05 ` [PATCH 0/9] x86 EFI boot stub Maarten Lankhorst
2011-08-11 15:14   ` Matt Fleming
2011-08-11 17:55     ` Maarten Lankhorst
2011-08-26 12:29       ` Matt Fleming

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.