Merge tag 'signed-efi-next' of git://github.com/agraf/u-boot

Patch queue for efi - 2016-10-19

Highlights this time around:

  - Add run time service (power control) support for PSCI (fixed in v3)
  - Add efi gop pointer exposure
  - SMBIOS support for EFI (on ARM)
  - efi pool memory unmap support (needed for 4.8)
  - initial x86 efi payload support (fixed up in v2)
  - various bug fixes

Signed-off-by: Tom Rini <trini@konsulko.com>

Conflicts:
	include/tables_csum.h
diff --git a/arch/arm/cpu/armv8/Kconfig b/arch/arm/cpu/armv8/Kconfig
index 7e1fc4c..cd2d9bb 100644
--- a/arch/arm/cpu/armv8/Kconfig
+++ b/arch/arm/cpu/armv8/Kconfig
@@ -21,4 +21,22 @@
 	    - Reserve the code for the spin-table and the release address
 	      via a /memreserve/ region in the Device Tree.
 
+config PSCI_RESET
+	bool "Use PSCI for reset and shutdown"
+	default y
+	depends on !ARCH_EXYNOS7 && !ARCH_BCM283X && !TARGET_LS2080A_EMU && \
+		   !TARGET_LS2080A_SIMU && !TARGET_LS2080AQDS && \
+		   !TARGET_LS2080ARDB && !TARGET_LS1012AQDS && \
+		   !TARGET_LS1012ARDB && !TARGET_LS1012AFRDM && \
+		   !TARGET_LS1043ARDB && !ARCH_UNIPHIER && !ARCH_SNAPDRAGON && \
+		   !TARGET_S32V234EVB
+	help
+	  Most armv8 systems have PSCI support enabled in EL3, either through
+	  ARM Trusted Firmware or other firmware.
+
+	  On these systems, we do not need to implement system reset manually,
+	  but can instead rely on higher level firmware to deal with it.
+
+	  Select Y here to make use of PSCI calls for system reset
+
 endif
diff --git a/arch/arm/cpu/armv8/fwcall.c b/arch/arm/cpu/armv8/fwcall.c
index 079e250..7dfd270 100644
--- a/arch/arm/cpu/armv8/fwcall.c
+++ b/arch/arm/cpu/armv8/fwcall.c
@@ -6,6 +6,7 @@
 
 #include <asm-offsets.h>
 #include <config.h>
+#include <efi_loader.h>
 #include <version.h>
 #include <asm/macro.h>
 #include <asm/psci.h>
@@ -17,7 +18,7 @@
  * x0~x7: input arguments
  * x0~x3: output arguments
  */
-void hvc_call(struct pt_regs *args)
+static void __efi_runtime hvc_call(struct pt_regs *args)
 {
 	asm volatile(
 		"ldr x0, %0\n"
@@ -51,7 +52,7 @@
  * x0~x3: output arguments
  */
 
-void smc_call(struct pt_regs *args)
+void __efi_runtime smc_call(struct pt_regs *args)
 {
 	asm volatile(
 		"ldr x0, %0\n"
@@ -75,13 +76,36 @@
 		  "x16", "x17");
 }
 
-void __noreturn psci_system_reset(bool conduit_smc)
+/*
+ * For now, all systems we support run at least in EL2 and thus
+ * trigger PSCI calls to EL3 using SMC. If anyone ever wants to
+ * use PSCI on U-Boot running below a hypervisor, please detect
+ * this and set the flag accordingly.
+ */
+static const __efi_runtime_data bool use_smc_for_psci = true;
+
+void __noreturn __efi_runtime psci_system_reset(void)
 {
 	struct pt_regs regs;
 
 	regs.regs[0] = ARM_PSCI_0_2_FN_SYSTEM_RESET;
 
+	if (use_smc_for_psci)
+		smc_call(&regs);
+	else
+		hvc_call(&regs);
+
+	while (1)
+		;
+}
+
-	if (conduit_smc)
+void __noreturn __efi_runtime psci_system_off(void)
+{
+	struct pt_regs regs;
+
+	regs.regs[0] = ARM_PSCI_0_2_FN_SYSTEM_OFF;
+
+	if (use_smc_for_psci)
 		smc_call(&regs);
 	else
 		hvc_call(&regs);
@@ -89,3 +113,30 @@
 	while (1)
 		;
 }
+
+#ifdef CONFIG_PSCI_RESET
+void reset_misc(void)
+{
+	psci_system_reset();
+}
+
+#ifdef CONFIG_EFI_LOADER
+void __efi_runtime EFIAPI efi_reset_system(
+			enum efi_reset_type reset_type,
+			efi_status_t reset_status,
+			unsigned long data_size, void *reset_data)
+{
+	switch (reset_type) {
+	case EFI_RESET_COLD:
+	case EFI_RESET_WARM:
+		psci_system_reset();
+		break;
+	case EFI_RESET_SHUTDOWN:
+		psci_system_off();
+		break;
+	}
+
+	while (1) { }
+}
+#endif /* CONFIG_EFI_LOADER */
+#endif /* CONFIG_PSCI_RESET */
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index c18e1e3..b928bd8 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -107,15 +107,6 @@
 void flush_l3_cache(void);
 
 /*
- *Issue a hypervisor call in accordance with ARM "SMC Calling convention",
- * DEN0028A
- *
- * @args: input and output arguments
- *
- */
-void hvc_call(struct pt_regs *args);
-
-/*
  *Issue a secure monitor call in accordance with ARM "SMC Calling convention",
  * DEN0028A
  *
@@ -124,7 +115,8 @@
  */
 void smc_call(struct pt_regs *args);
 
-void __noreturn psci_system_reset(bool smc);
+void __noreturn psci_system_reset(void);
+void __noreturn psci_system_off(void);
 
 #endif	/* __ASSEMBLY__ */
 
diff --git a/arch/arm/mach-meson/board.c b/arch/arm/mach-meson/board.c
index 1dd53e2..f159cbf 100644
--- a/arch/arm/mach-meson/board.c
+++ b/arch/arm/mach-meson/board.c
@@ -43,7 +43,7 @@
 
 void reset_cpu(ulong addr)
 {
-	psci_system_reset(true);
+	psci_system_reset();
 }
 
 static struct mm_region gxbb_mem_map[] = {
diff --git a/arch/avr32/include/asm/linkage.h b/arch/avr32/include/asm/linkage.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/arch/avr32/include/asm/linkage.h
diff --git a/arch/m68k/include/asm/linkage.h b/arch/m68k/include/asm/linkage.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/arch/m68k/include/asm/linkage.h
diff --git a/arch/microblaze/include/asm/linkage.h b/arch/microblaze/include/asm/linkage.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/arch/microblaze/include/asm/linkage.h
diff --git a/arch/mips/include/asm/linkage.h b/arch/mips/include/asm/linkage.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/arch/mips/include/asm/linkage.h
diff --git a/arch/nios2/include/asm/linkage.h b/arch/nios2/include/asm/linkage.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/arch/nios2/include/asm/linkage.h
diff --git a/arch/openrisc/include/asm/linkage.h b/arch/openrisc/include/asm/linkage.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/arch/openrisc/include/asm/linkage.h
diff --git a/arch/sandbox/include/asm/linkage.h b/arch/sandbox/include/asm/linkage.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/arch/sandbox/include/asm/linkage.h
diff --git a/arch/sh/include/asm/linkage.h b/arch/sh/include/asm/linkage.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/arch/sh/include/asm/linkage.h
diff --git a/arch/sparc/include/asm/linkage.h b/arch/sparc/include/asm/linkage.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/arch/sparc/include/asm/linkage.h
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index ac2d598..0884af2 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -461,33 +461,6 @@
 	  by the operating system. It defines platform-independent interfaces
 	  for configuration and power management monitoring.
 
-config GENERATE_SMBIOS_TABLE
-	bool "Generate an SMBIOS (System Management BIOS) table"
-	default y
-	help
-	  The System Management BIOS (SMBIOS) specification addresses how
-	  motherboard and system vendors present management information about
-	  their products in a standard format by extending the BIOS interface
-	  on Intel architecture systems.
-
-	  Check http://www.dmtf.org/standards/smbios for details.
-
-config SMBIOS_MANUFACTURER
-	string "SMBIOS Manufacturer"
-	depends on GENERATE_SMBIOS_TABLE
-	default SYS_VENDOR
-	help
-	  The board manufacturer to store in SMBIOS structures.
-	  Change this to override the default one (CONFIG_SYS_VENDOR).
-
-config SMBIOS_PRODUCT_NAME
-	string "SMBIOS Product Name"
-	depends on GENERATE_SMBIOS_TABLE
-	default SYS_BOARD
-	help
-	  The product name to store in SMBIOS structures.
-	  Change this to override the default one (CONFIG_SYS_BOARD).
-
 endmenu
 
 config MAX_PIRQ_LINKS
diff --git a/arch/x86/cpu/baytrail/cpu.c b/arch/x86/cpu/baytrail/cpu.c
index 2837709..0bb0852 100644
--- a/arch/x86/cpu/baytrail/cpu.c
+++ b/arch/x86/cpu/baytrail/cpu.c
@@ -189,6 +189,7 @@
 	.get_desc	= cpu_x86_get_desc,
 	.get_info	= baytrail_get_info,
 	.get_count	= baytrail_get_count,
+	.get_vendor	= cpu_x86_get_vendor,
 };
 
 static const struct udevice_id cpu_x86_baytrail_ids[] = {
diff --git a/arch/x86/cpu/broadwell/cpu.c b/arch/x86/cpu/broadwell/cpu.c
index 3ba21aa..6977e86 100644
--- a/arch/x86/cpu/broadwell/cpu.c
+++ b/arch/x86/cpu/broadwell/cpu.c
@@ -743,6 +743,7 @@
 	.get_desc	= cpu_x86_get_desc,
 	.get_info	= broadwell_get_info,
 	.get_count	= broadwell_get_count,
+	.get_vendor	= cpu_x86_get_vendor,
 };
 
 static const struct udevice_id cpu_x86_broadwell_ids[] = {
diff --git a/arch/x86/cpu/cpu_x86.c b/arch/x86/cpu/cpu_x86.c
index 0941041..157f3de 100644
--- a/arch/x86/cpu/cpu_x86.c
+++ b/arch/x86/cpu/cpu_x86.c
@@ -15,13 +15,30 @@
 int cpu_x86_bind(struct udevice *dev)
 {
 	struct cpu_platdata *plat = dev_get_parent_platdata(dev);
+	struct cpuid_result res;
 
 	plat->cpu_id = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
 				      "intel,apic-id", -1);
+	plat->family = gd->arch.x86;
+	res = cpuid(1);
+	plat->id[0] = res.eax;
+	plat->id[1] = res.edx;
 
 	return 0;
 }
 
+int cpu_x86_get_vendor(struct udevice *dev, char *buf, int size)
+{
+	const char *vendor = cpu_vendor_name(gd->arch.x86_vendor);
+
+	if (size < (strlen(vendor) + 1))
+		return -ENOSPC;
+
+	strcpy(buf, vendor);
+
+	return 0;
+}
+
 int cpu_x86_get_desc(struct udevice *dev, char *buf, int size)
 {
 	if (size < CPU_MAX_NAME_LEN)
@@ -60,6 +77,7 @@
 static const struct cpu_ops cpu_x86_ops = {
 	.get_desc	= cpu_x86_get_desc,
 	.get_count	= cpu_x86_get_count,
+	.get_vendor	= cpu_x86_get_vendor,
 };
 
 static const struct udevice_id cpu_x86_ids[] = {
diff --git a/arch/x86/cpu/ivybridge/model_206ax.c b/arch/x86/cpu/ivybridge/model_206ax.c
index b074367..09b5342 100644
--- a/arch/x86/cpu/ivybridge/model_206ax.c
+++ b/arch/x86/cpu/ivybridge/model_206ax.c
@@ -477,6 +477,7 @@
 	.get_desc	= cpu_x86_get_desc,
 	.get_info	= model_206ax_get_info,
 	.get_count	= model_206ax_get_count,
+	.get_vendor	= cpu_x86_get_vendor,
 };
 
 static const struct udevice_id cpu_x86_model_206ax_ids[] = {
diff --git a/arch/x86/cpu/u-boot.lds b/arch/x86/cpu/u-boot.lds
index 36f59ea..cca536b 100644
--- a/arch/x86/cpu/u-boot.lds
+++ b/arch/x86/cpu/u-boot.lds
@@ -28,7 +28,10 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
+	.rodata : {
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+		KEEP(*(.rodata.efi.init));
+	}
 
 	. = ALIGN(4);
 	.data : { *(.data*) }
@@ -40,6 +43,37 @@
 	.got : { *(.got*) }
 
 	. = ALIGN(4);
+
+	.__efi_runtime_start : {
+		*(.__efi_runtime_start)
+	}
+
+	.efi_runtime : {
+		*(efi_runtime_text)
+		*(efi_runtime_data)
+	}
+
+	.__efi_runtime_stop : {
+		*(.__efi_runtime_stop)
+	}
+
+	.efi_runtime_rel_start :
+	{
+		*(.__efi_runtime_rel_start)
+	}
+
+	.efi_runtime_rel : {
+		*(.relefi_runtime_text)
+		*(.relefi_runtime_data)
+	}
+
+	.efi_runtime_rel_stop :
+	{
+		*(.__efi_runtime_rel_stop)
+	}
+
+	. = ALIGN(4);
+
 	__data_end = .;
 	__init_end = .;
 
diff --git a/arch/x86/include/asm/cpu_x86.h b/arch/x86/include/asm/cpu_x86.h
index 1940480..74b82ed 100644
--- a/arch/x86/include/asm/cpu_x86.h
+++ b/arch/x86/include/asm/cpu_x86.h
@@ -31,4 +31,17 @@
  */
 int cpu_x86_get_desc(struct udevice *dev, char *buf, int size);
 
+/**
+ * cpu_x86_get_vendor() - Get a vendor string for an x86 CPU
+ *
+ * This uses cpu_vendor_name() and is suitable to use as the get_vendor()
+ * method for the CPU uclass.
+ *
+ * @dev:	Device to check (UCLASS_CPU)
+ * @buf:	Buffer to place string
+ * @size:	Size of string space
+ * @return:	0 if OK, -ENOSPC if buffer is too small, other -ve on error
+ */
+int cpu_x86_get_vendor(struct udevice *dev, char *buf, int size);
+
 #endif /* _ASM_CPU_X86_H */
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index e17f0bb..b9c2922 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -28,8 +28,8 @@
 obj-y	+= relocate.o
 obj-y += physmem.o
 obj-$(CONFIG_X86_RAMTEST) += ramtest.o
+obj-y	+= sections.o
 obj-y += sfi.o
-obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += smbios.o
 obj-y	+= string.o
 ifndef CONFIG_QEMU
 obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o
diff --git a/arch/x86/lib/sections.c b/arch/x86/lib/sections.c
new file mode 100644
index 0000000..6455e0f
--- /dev/null
+++ b/arch/x86/lib/sections.c
@@ -0,0 +1,12 @@
+/*
+ * Copyright 2013 Albert ARIBAUD <albert.u.boot@aribaud.net>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+char __efi_runtime_start[0] __attribute__((section(".__efi_runtime_start")));
+char __efi_runtime_stop[0] __attribute__((section(".__efi_runtime_stop")));
+char __efi_runtime_rel_start[0]
+		__attribute__((section(".__efi_runtime_rel_start")));
+char __efi_runtime_rel_stop[0]
+		__attribute__((section(".__efi_runtime_rel_stop")));
diff --git a/arch/x86/lib/tables.c b/arch/x86/lib/tables.c
index 9ee6b5e..025b183 100644
--- a/arch/x86/lib/tables.c
+++ b/arch/x86/lib/tables.c
@@ -5,13 +5,18 @@
  */
 
 #include <common.h>
+#include <smbios.h>
 #include <asm/sfi.h>
 #include <asm/mpspec.h>
-#include <asm/smbios.h>
 #include <asm/tables.h>
 #include <asm/acpi_table.h>
 #include <asm/coreboot_tables.h>
 
+static u32 write_smbios_table_wrapper(u32 addr)
+{
+	return write_smbios_table(addr);
+}
+
 /**
  * Function prototype to write a specific configuration table
  *
@@ -34,7 +39,7 @@
 	write_acpi_tables,
 #endif
 #ifdef CONFIG_GENERATE_SMBIOS_TABLE
-	write_smbios_table,
+	write_smbios_table_wrapper,
 #endif
 };
 
diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c
index 566b5e8..ba4dfbb 100644
--- a/board/xilinx/zynqmp/zynqmp.c
+++ b/board/xilinx/zynqmp/zynqmp.c
@@ -427,8 +427,3 @@
 	return 0;
 }
 #endif
-
-void reset_misc(void)
-{
-	psci_system_reset(true);
-}
diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index 21fe42c..c8079c4 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -15,6 +15,8 @@
 #include <libfdt_env.h>
 #include <memalign.h>
 #include <asm/global_data.h>
+#include <asm-generic/sections.h>
+#include <linux/linkage.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -52,7 +54,7 @@
 	}
 };
 
-static efi_status_t bootefi_open_dp(void *handle, efi_guid_t *protocol,
+static efi_status_t EFIAPI bootefi_open_dp(void *handle, efi_guid_t *protocol,
 			void **protocol_interface, void *agent_handle,
 			void *controller_handle, uint32_t attributes)
 {
@@ -145,7 +147,8 @@
  */
 static unsigned long do_bootefi_exec(void *efi, void *fdt)
 {
-	ulong (*entry)(void *image_handle, struct efi_system_table *st);
+	ulong (*entry)(void *image_handle, struct efi_system_table *st)
+		asmlinkage;
 	ulong fdt_pages, fdt_size, fdt_start, fdt_end;
 	bootm_headers_t img = { 0 };
 
@@ -204,7 +207,16 @@
 
 	if (!memcmp(bootefi_device_path[0].str, "N\0e\0t", 6))
 		loaded_image_info.device_handle = nethandle;
+	else
+		loaded_image_info.device_handle = bootefi_device_path;
 #endif
+#ifdef CONFIG_GENERATE_SMBIOS_TABLE
+	efi_smbios_register();
+#endif
+
+	/* Initialize EFI runtime services */
+	efi_reset_system_init();
+	efi_get_time_init();
 
 	/* Call our payload! */
 	debug("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry);
diff --git a/drivers/cpu/cpu-uclass.c b/drivers/cpu/cpu-uclass.c
index 7660f99..c57ac16 100644
--- a/drivers/cpu/cpu-uclass.c
+++ b/drivers/cpu/cpu-uclass.c
@@ -44,6 +44,16 @@
 	return ops->get_count(dev);
 }
 
+int cpu_get_vendor(struct udevice *dev, char *buf, int size)
+{
+	struct cpu_ops *ops = cpu_get_ops(dev);
+
+	if (!ops->get_vendor)
+		return -ENOSYS;
+
+	return ops->get_vendor(dev, buf, size);
+}
+
 U_BOOT_DRIVER(cpu_bus) = {
 	.name	= "cpu_bus",
 	.id	= UCLASS_SIMPLE_BUS,
diff --git a/include/cpu.h b/include/cpu.h
index bda5315..9542577 100644
--- a/include/cpu.h
+++ b/include/cpu.h
@@ -21,6 +21,8 @@
 	int cpu_id;
 	int ucode_version;
 	ulong device_id;
+	u16 family;		/* DMTF CPU Family */
+	u32 id[2];		/* DMTF CPU Processor IDs */
 };
 
 /* CPU features - mostly just a placeholder for now */
@@ -71,6 +73,16 @@
 	 * @return CPU count if OK, -ve on error
 	 */
 	int (*get_count)(struct udevice *dev);
+
+	/**
+	 * get_vendor() - Get vendor name of a CPU
+	 *
+	 * @dev:	Device to check (UCLASS_CPU)
+	 * @buf:	Buffer to place string
+	 * @size:	Size of string space
+	 * @return 0 if OK, -ENOSPC if buffer is too small, other -ve on error
+	 */
+	int (*get_vendor)(struct udevice *dev, char *buf, int size);
 };
 
 #define cpu_get_ops(dev)        ((struct cpu_ops *)(dev)->driver->ops)
@@ -102,4 +114,14 @@
  */
 int cpu_get_count(struct udevice *dev);
 
+/**
+ * cpu_get_vendor() - Get vendor name of a CPU
+ *
+ * @dev:	Device to check (UCLASS_CPU)
+ * @buf:	Buffer to place string
+ * @size:	Size of string space
+ * @return 0 if OK, -ENOSPC if buffer is too small, other -ve on error
+ */
+int cpu_get_vendor(struct udevice *dev, char *buf, int size);
+
 #endif
diff --git a/include/efi.h b/include/efi.h
index 5a3b8cf..d07187c 100644
--- a/include/efi.h
+++ b/include/efi.h
@@ -15,6 +15,7 @@
 #ifndef _EFI_H
 #define _EFI_H
 
+#include <linux/linkage.h>
 #include <linux/string.h>
 #include <linux/types.h>
 
@@ -22,7 +23,7 @@
 /* EFI uses the Microsoft ABI which is not the default for GCC */
 #define EFIAPI __attribute__((ms_abi))
 #else
-#define EFIAPI
+#define EFIAPI asmlinkage
 #endif
 
 struct efi_device_path;
diff --git a/include/efi_api.h b/include/efi_api.h
index f572b88..bdb600e 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -201,6 +201,10 @@
 	EFI_GUID(0xb1b621d5, 0xf19c, 0x41a5, \
 		 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0)
 
+#define SMBIOS_TABLE_GUID \
+	EFI_GUID(0xeb9d2d31, 0x2d88, 0x11d3,  \
+		 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
+
 struct efi_configuration_table
 {
 	efi_guid_t guid;
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 9738835..35b3fe2 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -85,6 +85,8 @@
 int efi_gop_register(void);
 /* Called by bootefi to make the network interface available */
 int efi_net_register(void **handle);
+/* Called by bootefi to make SMBIOS tables available */
+void efi_smbios_register(void);
 
 /* Called by networking code to memorize the dhcp ack package */
 void efi_net_set_dhcp_ack(void *pkt, int len);
@@ -93,7 +95,7 @@
  * Stub implementation for a protocol opener that just returns the handle as
  * interface
  */
-efi_status_t efi_return_handle(void *handle,
+efi_status_t EFIAPI efi_return_handle(void *handle,
 		efi_guid_t *protocol, void **protocol_interface,
 		void *agent_handle, void *controller_handle,
 		uint32_t attributes);
@@ -117,8 +119,13 @@
 /* More specific EFI memory allocator, called by EFI payloads */
 efi_status_t efi_allocate_pages(int type, int memory_type, unsigned long pages,
 				uint64_t *memory);
-/* EFI memory free function. Not implemented today */
+/* EFI memory free function. */
 efi_status_t efi_free_pages(uint64_t memory, unsigned long pages);
+/* EFI memory allocator for small allocations */
+efi_status_t efi_allocate_pool(int pool_type, unsigned long size,
+			       void **buffer);
+/* EFI pool memory free function. */
+efi_status_t efi_free_pool(void *buffer);
 /* Returns the EFI memory map */
 efi_status_t efi_get_memory_map(unsigned long *memory_map_size,
 				struct efi_mem_desc *memory_map,
@@ -130,6 +137,8 @@
 			    bool overlap_only_ram);
 /* Called by board init to initialize the EFI memory map */
 int efi_memory_init(void);
+/* Adds new or overrides configuration table entry to the system table */
+efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *table);
 
 #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
 extern void *efi_bounce_buffer;
@@ -147,14 +156,32 @@
  * Use these to indicate that your code / data should go into the EFI runtime
  * section and thus still be available when the OS is running
  */
-#define EFI_RUNTIME_DATA __attribute__ ((section ("efi_runtime_data")))
-#define EFI_RUNTIME_TEXT __attribute__ ((section ("efi_runtime_text")))
+#define __efi_runtime_data __attribute__ ((section ("efi_runtime_data")))
+#define __efi_runtime __attribute__ ((section ("efi_runtime_text")))
+
+/* Call this with mmio_ptr as the _pointer_ to a pointer to an MMIO region
+ * to make it available at runtime */
+void efi_add_runtime_mmio(void *mmio_ptr, u64 len);
+
+/* Boards may provide the functions below to implement RTS functionality */
+
+void __efi_runtime EFIAPI efi_reset_system(
+			enum efi_reset_type reset_type,
+			efi_status_t reset_status,
+			unsigned long data_size, void *reset_data);
+void efi_reset_system_init(void);
+
+efi_status_t __efi_runtime EFIAPI efi_get_time(
+			struct efi_time *time,
+			struct efi_time_cap *capabilities);
+void efi_get_time_init(void);
 
 #else /* defined(EFI_LOADER) && !defined(CONFIG_SPL_BUILD) */
 
 /* Without CONFIG_EFI_LOADER we don't have a runtime section, stub it out */
-#define EFI_RUNTIME_DATA
-#define EFI_RUNTIME_TEXT
+#define __efi_runtime_data
+#define __efi_runtime
+static inline void efi_add_runtime_mmio(void **mmio_ptr, u64 len) { }
 
 /* No loader configured, stub out EFI_ENTRY */
 static inline void efi_restore_gd(void) { }
diff --git a/arch/x86/include/asm/smbios.h b/include/smbios.h
similarity index 94%
rename from arch/x86/include/asm/smbios.h
rename to include/smbios.h
index 623a703..d582d4f 100644
--- a/arch/x86/include/asm/smbios.h
+++ b/include/smbios.h
@@ -55,6 +55,7 @@
 #define BIOS_CHARACTERISTICS_SELECTABLE_BOOT	(1 << 16)
 
 #define BIOS_CHARACTERISTICS_EXT1_ACPI		(1 << 0)
+#define BIOS_CHARACTERISTICS_EXT1_UEFI		(1 << 3)
 #define BIOS_CHARACTERISTICS_EXT2_TARGET	(1 << 2)
 
 struct __packed smbios_type0 {
@@ -139,6 +140,9 @@
 #define SMBIOS_PROCESSOR_STATUS_ENABLED	1
 #define SMBIOS_PROCESSOR_UPGRADE_NONE	6
 
+#define SMBIOS_PROCESSOR_FAMILY_OTHER	1
+#define SMBIOS_PROCESSOR_FAMILY_UNKNOWN	2
+
 struct __packed smbios_type4 {
 	u8 type;
 	u8 length;
@@ -221,7 +225,7 @@
  * @handle:	the structure's handle, a unique 16-bit number
  * @return:	size of the structure
  */
-typedef int (*smbios_write_type)(u32 *addr, int handle);
+typedef int (*smbios_write_type)(uintptr_t *addr, int handle);
 
 /**
  * write_smbios_table() - Write SMBIOS table
@@ -231,6 +235,6 @@
  * @addr:	start address to write SMBIOS table
  * @return:	end address of SMBIOS table
  */
-u32 write_smbios_table(u32 addr);
+uintptr_t write_smbios_table(uintptr_t addr);
 
 #endif /* _SMBIOS_H_ */
diff --git a/lib/Kconfig b/lib/Kconfig
index 0e0d8ef..b16062f 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -163,6 +163,39 @@
 	  using partition info defined in the 'mtdparts' environment
 	  variable.
 
+menu "System tables"
+	depends on (!EFI && !SYS_COREBOOT) || (ARM && EFI_LOADER)
+
+config GENERATE_SMBIOS_TABLE
+	bool "Generate an SMBIOS (System Management BIOS) table"
+	default y
+	depends on X86 || EFI_LOADER
+	help
+	  The System Management BIOS (SMBIOS) specification addresses how
+	  motherboard and system vendors present management information about
+	  their products in a standard format by extending the BIOS interface
+	  on Intel architecture systems.
+
+	  Check http://www.dmtf.org/standards/smbios for details.
+
+config SMBIOS_MANUFACTURER
+	string "SMBIOS Manufacturer"
+	depends on GENERATE_SMBIOS_TABLE
+	default SYS_VENDOR
+	help
+	  The board manufacturer to store in SMBIOS structures.
+	  Change this to override the default one (CONFIG_SYS_VENDOR).
+
+config SMBIOS_PRODUCT_NAME
+	string "SMBIOS Product Name"
+	depends on GENERATE_SMBIOS_TABLE
+	default SYS_BOARD
+	help
+	  The product name to store in SMBIOS structures.
+	  Change this to override the default one (CONFIG_SYS_BOARD).
+
+endmenu
+
 source lib/efi/Kconfig
 source lib/efi_loader/Kconfig
 
diff --git a/lib/Makefile b/lib/Makefile
index e3383f4..23e9f1e 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -27,6 +27,7 @@
 obj-$(CONFIG_TEST_FDTDEC) += fdtdec_test.o
 obj-$(CONFIG_GZIP) += gunzip.o
 obj-$(CONFIG_GZIP_COMPRESSED) += gzip.o
+obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += smbios.o
 obj-y += initcall.o
 obj-$(CONFIG_LMB) += lmb.o
 obj-y += ldiv.o
@@ -73,6 +74,7 @@
 obj-y += membuff.o
 obj-$(CONFIG_REGEX) += slre.o
 obj-y += string.o
+obj-y += tables_csum.o
 obj-y += time.o
 obj-$(CONFIG_TRACE) += trace.o
 obj-$(CONFIG_LIB_UUID) += uuid.o
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index 2a3849e..12159dd 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -12,3 +12,4 @@
 obj-$(CONFIG_LCD) += efi_gop.o
 obj-$(CONFIG_PARTITIONS) += efi_disk.o
 obj-$(CONFIG_NET) += efi_net.o
+obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += efi_smbios.o
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index 792db39..1fdddf4 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -37,8 +37,9 @@
  * In most cases we want to pass an FDT to the payload, so reserve one slot of
  * config table space for it. The pointer gets populated by do_bootefi_exec().
  */
-static struct efi_configuration_table EFI_RUNTIME_DATA efi_conf_table[1];
+static struct efi_configuration_table __efi_runtime_data efi_conf_table[2];
 
+#ifdef CONFIG_ARM
 /*
  * The "gd" pointer lives in a register on ARM and AArch64 that we declare
  * fixed when compiling U-Boot. However, the payload does not know about that
@@ -46,16 +47,20 @@
  * EFI callback entry/exit.
  */
 static volatile void *efi_gd, *app_gd;
+#endif
 
 /* Called from do_bootefi_exec() */
 void efi_save_gd(void)
 {
+#ifdef CONFIG_ARM
 	efi_gd = gd;
+#endif
 }
 
 /* Called on every callback entry */
 void efi_restore_gd(void)
 {
+#ifdef CONFIG_ARM
 	/* Only restore if we're already in EFI context */
 	if (!efi_gd)
 		return;
@@ -63,12 +68,16 @@
 	if (gd != efi_gd)
 		app_gd = gd;
 	gd = efi_gd;
+#endif
 }
 
 /* Called on every callback exit */
 efi_status_t efi_exit_func(efi_status_t ret)
 {
+#ifdef CONFIG_ARM
 	gd = app_gd;
+#endif
+
 	return ret;
 }
 
@@ -130,22 +139,23 @@
 	return EFI_EXIT(r);
 }
 
-static efi_status_t EFIAPI efi_allocate_pool(int pool_type, unsigned long size,
-					     void **buffer)
+static efi_status_t EFIAPI efi_allocate_pool_ext(int pool_type,
+						 unsigned long size,
+						 void **buffer)
 {
 	efi_status_t r;
 
 	EFI_ENTRY("%d, %ld, %p", pool_type, size, buffer);
-	r = efi_allocate_pages(0, pool_type, (size + 0xfff) >> 12, (void*)buffer);
+	r = efi_allocate_pool(pool_type, size, buffer);
 	return EFI_EXIT(r);
 }
 
-static efi_status_t EFIAPI efi_free_pool(void *buffer)
+static efi_status_t EFIAPI efi_free_pool_ext(void *buffer)
 {
 	efi_status_t r;
 
 	EFI_ENTRY("%p", buffer);
-	r = efi_free_pages((ulong)buffer, 0);
+	r = efi_free_pool(buffer);
 	return EFI_EXIT(r);
 }
 
@@ -159,7 +169,7 @@
 	u32 trigger_time;
 	u64 trigger_next;
 	unsigned long notify_tpl;
-	void (*notify_function) (void *event, void *context);
+	void (EFIAPI *notify_function) (void *event, void *context);
 	void *notify_context;
 } efi_event = {
 	/* Disable timers on bootup */
@@ -168,7 +178,8 @@
 
 static efi_status_t EFIAPI efi_create_event(
 			enum efi_event_type type, ulong notify_tpl,
-			void (*notify_function) (void *event, void *context),
+			void (EFIAPI *notify_function) (void *event,
+							void *context),
 			void *notify_context, void **event)
 {
 	EFI_ENTRY("%d, 0x%lx, %p, %p", type, notify_tpl, notify_function,
@@ -375,31 +386,35 @@
 	return EFI_EXIT(EFI_NOT_FOUND);
 }
 
-static efi_status_t EFIAPI efi_install_configuration_table(efi_guid_t *guid,
-							   void *table)
+efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *table)
 {
 	int i;
 
-	EFI_ENTRY("%p, %p", guid, table);
-
 	/* Check for guid override */
 	for (i = 0; i < systab.nr_tables; i++) {
 		if (!guidcmp(guid, &efi_conf_table[i].guid)) {
 			efi_conf_table[i].table = table;
-			return EFI_EXIT(EFI_SUCCESS);
+			return EFI_SUCCESS;
 		}
 	}
 
 	/* No override, check for overflow */
 	if (i >= ARRAY_SIZE(efi_conf_table))
-		return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+		return EFI_OUT_OF_RESOURCES;
 
 	/* Add a new entry */
 	memcpy(&efi_conf_table[i].guid, guid, sizeof(*guid));
 	efi_conf_table[i].table = table;
-	systab.nr_tables = i;
+	systab.nr_tables = i + 1;
 
-	return EFI_EXIT(EFI_SUCCESS);
+	return EFI_SUCCESS;
+}
+
+static efi_status_t EFIAPI efi_install_configuration_table_ext(efi_guid_t *guid,
+							       void *table)
+{
+	EFI_ENTRY("%p, %p", guid, table);
+	return EFI_EXIT(efi_install_configuration_table(guid, table));
 }
 
 static efi_status_t EFIAPI efi_load_image(bool boot_policy,
@@ -734,8 +749,8 @@
 	.allocate_pages = efi_allocate_pages_ext,
 	.free_pages = efi_free_pages_ext,
 	.get_memory_map = efi_get_memory_map_ext,
-	.allocate_pool = efi_allocate_pool,
-	.free_pool = efi_free_pool,
+	.allocate_pool = efi_allocate_pool_ext,
+	.free_pool = efi_free_pool_ext,
 	.create_event = efi_create_event,
 	.set_timer = efi_set_timer,
 	.wait_for_event = efi_wait_for_event,
@@ -750,7 +765,7 @@
 	.register_protocol_notify = efi_register_protocol_notify,
 	.locate_handle = efi_locate_handle,
 	.locate_device_path = efi_locate_device_path,
-	.install_configuration_table = efi_install_configuration_table,
+	.install_configuration_table = efi_install_configuration_table_ext,
 	.load_image = efi_load_image,
 	.start_image = efi_start_image,
 	.exit = efi_exit,
@@ -775,10 +790,10 @@
 };
 
 
-static uint16_t EFI_RUNTIME_DATA firmware_vendor[] =
+static uint16_t __efi_runtime_data firmware_vendor[] =
 	{ 'D','a','s',' ','U','-','b','o','o','t',0 };
 
-struct efi_system_table EFI_RUNTIME_DATA systab = {
+struct efi_system_table __efi_runtime_data systab = {
 	.hdr = {
 		.signature = EFI_SYSTEM_TABLE_SIGNATURE,
 		.revision = 0x20005, /* 2.5 */
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
index d8ddcc9..1e3dca4 100644
--- a/lib/efi_loader/efi_disk.c
+++ b/lib/efi_loader/efi_disk.c
@@ -35,9 +35,10 @@
 	const struct blk_desc *desc;
 };
 
-static efi_status_t efi_disk_open_block(void *handle, efi_guid_t *protocol,
-			void **protocol_interface, void *agent_handle,
-			void *controller_handle, uint32_t attributes)
+static efi_status_t EFIAPI efi_disk_open_block(void *handle,
+			efi_guid_t *protocol, void **protocol_interface,
+			void *agent_handle, void *controller_handle,
+			uint32_t attributes)
 {
 	struct efi_disk_obj *diskobj = handle;
 
@@ -46,7 +47,7 @@
 	return EFI_SUCCESS;
 }
 
-static efi_status_t efi_disk_open_dp(void *handle, efi_guid_t *protocol,
+static efi_status_t EFIAPI efi_disk_open_dp(void *handle, efi_guid_t *protocol,
 			void **protocol_interface, void *agent_handle,
 			void *controller_handle, uint32_t attributes)
 {
@@ -108,7 +109,7 @@
 	return EFI_EXIT(EFI_SUCCESS);
 }
 
-static efi_status_t efi_disk_read_blocks(struct efi_block_io *this,
+static efi_status_t EFIAPI efi_disk_read_blocks(struct efi_block_io *this,
 			u32 media_id, u64 lba, unsigned long buffer_size,
 			void *buffer)
 {
@@ -143,7 +144,7 @@
 	return EFI_EXIT(r);
 }
 
-static efi_status_t efi_disk_write_blocks(struct efi_block_io *this,
+static efi_status_t EFIAPI efi_disk_write_blocks(struct efi_block_io *this,
 			u32 media_id, u64 lba, unsigned long buffer_size,
 			void *buffer)
 {
diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c
index 33a3d71..286ad83 100644
--- a/lib/efi_loader/efi_gop.c
+++ b/lib/efi_loader/efi_gop.c
@@ -129,6 +129,7 @@
 {
 	struct efi_gop_obj *gopobj;
 	u32 bpix, col, row;
+	u64 fb_base, fb_size;
 
 #ifdef CONFIG_DM_VIDEO
 	struct udevice *vdev;
@@ -141,11 +142,16 @@
 	bpix = priv->bpix;
 	col = video_get_xsize(vdev);
 	row = video_get_ysize(vdev);
+	fb_base = (uintptr_t)priv->fb;
+	fb_size = priv->fb_size;
 #else
+	int line_len;
 
 	bpix = panel_info.vl_bpix;
 	col = panel_info.vl_col;
 	row = panel_info.vl_row;
+	fb_base = gd->fb_base;
+	fb_size = lcd_get_size(&line_len);
 #endif
 
 	switch (bpix) {
@@ -177,6 +183,16 @@
 	gopobj->mode.info = &gopobj->info;
 	gopobj->mode.info_size = sizeof(gopobj->info);
 
+#ifdef CONFIG_DM_VIDEO
+	if (bpix == VIDEO_BPP32) {
+#else
+	if (bpix == LCD_COLOR32) {
+#endif
+		/* With 32bit color space we can directly expose the fb */
+		gopobj->mode.fb_base = fb_base;
+		gopobj->mode.fb_size = fb_size;
+	}
+
 	gopobj->info.version = 0;
 	gopobj->info.width = col;
 	gopobj->info.height = row;
diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
index 80e4e26..95aa590 100644
--- a/lib/efi_loader/efi_memory.c
+++ b/lib/efi_loader/efi_memory.c
@@ -34,6 +34,19 @@
 #endif
 
 /*
+ * U-Boot services each EFI AllocatePool request as a separate
+ * (multiple) page allocation.  We have to track the number of pages
+ * to be able to free the correct amount later.
+ * EFI requires 8 byte alignment for pool allocations, so we can
+ * prepend each allocation with an 64 bit header tracking the
+ * allocation size, and hand out the remainder to the caller.
+ */
+struct efi_pool_allocation {
+	u64 num_pages;
+	char data[];
+};
+
+/*
  * Sorts the memory list from highest address to lowest address
  *
  * When allocating memory we should always start from the highest
@@ -62,9 +75,17 @@
  * Unmaps all memory occupied by the carve_desc region from the
  * list entry pointed to by map.
  *
- * Returns 1 if carving was performed or 0 if the regions don't overlap.
- * Returns -1 if it would affect non-RAM regions but overlap_only_ram is set.
- * Carving is only guaranteed to complete when all regions return 0.
+ * Returns EFI_CARVE_NO_OVERLAP if the regions don't overlap.
+ * Returns EFI_CARVE_OVERLAPS_NONRAM if the carve and map overlap,
+ *    and the map contains anything but free ram.
+ *    (only when overlap_only_ram is true)
+ * Returns EFI_CARVE_LOOP_AGAIN if the mapping list should be traversed
+ *    again, as it has been altered
+ * Returns the number of overlapping pages. The pages are removed from
+ *     the mapping list.
+ *
+ * In case of EFI_CARVE_OVERLAPS_NONRAM it is the callers responsibility
+ * to readd the already carved out pages to the mapping.
  */
 static int efi_mem_carve_out(struct efi_mem_list *map,
 			     struct efi_mem_desc *carve_desc,
@@ -95,10 +116,13 @@
 		if (map_end == carve_end) {
 			/* Full overlap, just remove map */
 			list_del(&map->link);
+			free(map);
+		} else {
+			map->desc.physical_start = carve_end;
+			map->desc.num_pages = (map_end - carve_end)
+					      >> EFI_PAGE_SHIFT;
 		}
 
-		map_desc->physical_start = carve_end;
-		map_desc->num_pages = (map_end - carve_end) >> EFI_PAGE_SHIFT;
 		return (carve_end - carve_start) >> EFI_PAGE_SHIFT;
 	}
 
@@ -114,7 +138,8 @@
 	newmap->desc = map->desc;
 	newmap->desc.physical_start = carve_start;
 	newmap->desc.num_pages = (map_end - carve_start) >> EFI_PAGE_SHIFT;
-        list_add_tail(&newmap->link, &efi_mem);
+	/* Insert before current entry (descending address order) */
+	list_add_tail(&newmap->link, &map->link);
 
 	/* Shrink the map to [ map_start ... carve_start ] */
 	map_desc->num_pages = (carve_start - map_start) >> EFI_PAGE_SHIFT;
@@ -315,8 +340,52 @@
 
 efi_status_t efi_free_pages(uint64_t memory, unsigned long pages)
 {
+	uint64_t r = 0;
+
+	r = efi_add_memory_map(memory, pages, EFI_CONVENTIONAL_MEMORY, false);
+	/* Merging of adjacent free regions is missing */
+
+	if (r == memory)
+		return EFI_SUCCESS;
+
+	return EFI_NOT_FOUND;
+}
+
+efi_status_t efi_allocate_pool(int pool_type, unsigned long size,
+			       void **buffer)
+{
+	efi_status_t r;
+	efi_physical_addr_t t;
+	u64 num_pages = (size + sizeof(u64) + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT;
+
+	if (size == 0) {
+		*buffer = NULL;
+		return EFI_SUCCESS;
+	}
+
+	r = efi_allocate_pages(0, pool_type, num_pages, &t);
+
+	if (r == EFI_SUCCESS) {
+		struct efi_pool_allocation *alloc = (void *)(uintptr_t)t;
+		alloc->num_pages = num_pages;
+		*buffer = alloc->data;
+	}
+
+	return r;
+}
+
+efi_status_t efi_free_pool(void *buffer)
+{
-	/* We don't free, let's cross our fingers we have plenty RAM */
-	return EFI_SUCCESS;
+	efi_status_t r;
+	struct efi_pool_allocation *alloc;
+
+	alloc = container_of(buffer, struct efi_pool_allocation, data);
+	/* Sanity check, was the supplied address returned by allocate_pool */
+	assert(((uintptr_t)alloc & EFI_PAGE_MASK) == 0);
+
+	r = efi_free_pages((uintptr_t)alloc, alloc->num_pages);
+
+	return r;
 }
 
 efi_status_t efi_get_memory_map(unsigned long *memory_map_size,
@@ -328,6 +397,7 @@
 	ulong map_size = 0;
 	int map_entries = 0;
 	struct list_head *lhandle;
+	unsigned long provided_map_size = *memory_map_size;
 
 	list_for_each(lhandle, &efi_mem)
 		map_entries++;
@@ -342,7 +412,7 @@
 	if (descriptor_version)
 		*descriptor_version = EFI_MEMORY_DESCRIPTOR_VERSION;
 
-	if (*memory_map_size < map_size)
+	if (provided_map_size < map_size)
 		return EFI_BUFFER_TOO_SMALL;
 
 	/* Copy list into array */
diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
index dd3b485..3796496 100644
--- a/lib/efi_loader/efi_net.c
+++ b/lib/efi_loader/efi_net.c
@@ -152,7 +152,14 @@
 		return EFI_EXIT(EFI_INVALID_PARAMETER);
 	}
 
+#ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
+	/* Ethernet packets always fit, just bounce */
+	memcpy(efi_bounce_buffer, buffer, buffer_size);
+	net_send_packet(efi_bounce_buffer, buffer_size);
+#else
 	net_send_packet(buffer, buffer_size);
+#endif
+
 	new_tx_packet = buffer;
 
 	return EFI_EXIT(EFI_SUCCESS);
@@ -191,7 +198,7 @@
 	return EFI_EXIT(EFI_SUCCESS);
 }
 
-static efi_status_t efi_net_open_dp(void *handle, efi_guid_t *protocol,
+static efi_status_t EFIAPI efi_net_open_dp(void *handle, efi_guid_t *protocol,
 			void **protocol_interface, void *agent_handle,
 			void *controller_handle, uint32_t attributes)
 {
@@ -203,7 +210,7 @@
 	return EFI_SUCCESS;
 }
 
-static efi_status_t efi_net_open_pxe(void *handle, efi_guid_t *protocol,
+static efi_status_t EFIAPI efi_net_open_pxe(void *handle, efi_guid_t *protocol,
 			void **protocol_interface, void *agent_handle,
 			void *controller_handle, uint32_t attributes)
 {
diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
index 99b5ef1..dd52755 100644
--- a/lib/efi_loader/efi_runtime.c
+++ b/lib/efi_loader/efi_runtime.c
@@ -16,9 +16,19 @@
 /* For manual relocation support */
 DECLARE_GLOBAL_DATA_PTR;
 
-static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_unimplemented(void);
-static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_device_error(void);
-static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_invalid_parameter(void);
+struct efi_runtime_mmio_list {
+	struct list_head link;
+	void **ptr;
+	u64 paddr;
+	u64 len;
+};
+
+/* This list contains all runtime available mmio regions */
+LIST_HEAD(efi_runtime_mmio);
+
+static efi_status_t __efi_runtime EFIAPI efi_unimplemented(void);
+static efi_status_t __efi_runtime EFIAPI efi_device_error(void);
+static efi_status_t __efi_runtime EFIAPI efi_invalid_parameter(void);
 
 #ifdef CONFIG_SYS_CACHELINE_SIZE
 #define EFI_CACHELINE_SIZE CONFIG_SYS_CACHELINE_SIZE
@@ -34,6 +44,10 @@
 #elif defined(CONFIG_ARM)
 #define R_RELATIVE	23
 #define R_MASK		0xffULL
+#elif defined(CONFIG_X86)
+#include <asm/elf.h>
+#define R_RELATIVE	R_386_RELATIVE
+#define R_MASK		0xffULL
 #else
 #error Need to add relocation awareness
 #endif
@@ -55,9 +69,10 @@
  * handle a good number of runtime callbacks
  */
 
-static void EFIAPI efi_reset_system(enum efi_reset_type reset_type,
-				    efi_status_t reset_status,
-				    unsigned long data_size, void *reset_data)
+static void EFIAPI efi_reset_system_boottime(
+			enum efi_reset_type reset_type,
+			efi_status_t reset_status,
+			unsigned long data_size, void *reset_data)
 {
 	EFI_ENTRY("%d %lx %lx %p", reset_type, reset_status, data_size,
 		  reset_data);
@@ -72,11 +87,12 @@
 		break;
 	}
 
-	EFI_EXIT(EFI_SUCCESS);
+	while (1) { }
 }
 
-static efi_status_t EFIAPI efi_get_time(struct efi_time *time,
-					struct efi_time_cap *capabilities)
+static efi_status_t EFIAPI efi_get_time_boottime(
+			struct efi_time *time,
+			struct efi_time_cap *capabilities)
 {
 #if defined(CONFIG_CMD_DATE) && defined(CONFIG_DM_RTC)
 	struct rtc_time tm;
@@ -107,6 +123,33 @@
 #endif
 }
 
+/* Boards may override the helpers below to implement RTS functionality */
+
+void __weak __efi_runtime EFIAPI efi_reset_system(
+			enum efi_reset_type reset_type,
+			efi_status_t reset_status,
+			unsigned long data_size, void *reset_data)
+{
+	/* Nothing we can do */
+	while (1) { }
+}
+
+void __weak efi_reset_system_init(void)
+{
+}
+
+efi_status_t __weak __efi_runtime EFIAPI efi_get_time(
+			struct efi_time *time,
+			struct efi_time_cap *capabilities)
+{
+	/* Nothing we can do */
+	return EFI_DEVICE_ERROR;
+}
+
+void __weak efi_get_time_init(void)
+{
+}
+
 struct efi_runtime_detach_list_struct {
 	void *ptr;
 	void *patchto;
@@ -116,7 +159,7 @@
 	{
 		/* do_reset is gone */
 		.ptr = &efi_runtime_services.reset_system,
-		.patchto = NULL,
+		.patchto = efi_reset_system,
 	}, {
 		/* invalidate_*cache_all are gone */
 		.ptr = &efi_runtime_services.set_virtual_address_map,
@@ -124,7 +167,7 @@
 	}, {
 		/* RTC accessors are gone */
 		.ptr = &efi_runtime_services.get_time,
-		.patchto = &efi_device_error,
+		.patchto = &efi_get_time,
 	}, {
 		/* Clean up system table */
 		.ptr = &systab.con_in,
@@ -233,12 +276,39 @@
 	EFI_ENTRY("%lx %lx %x %p", memory_map_size, descriptor_size,
 		  descriptor_version, virtmap);
 
+	/* Rebind mmio pointers */
+	for (i = 0; i < n; i++) {
+		struct efi_mem_desc *map = (void*)virtmap +
+					   (descriptor_size * i);
+		struct list_head *lhandle;
+		efi_physical_addr_t map_start = map->physical_start;
+		efi_physical_addr_t map_len = map->num_pages << EFI_PAGE_SHIFT;
+		efi_physical_addr_t map_end = map_start + map_len;
+
+		/* Adjust all mmio pointers in this region */
+		list_for_each(lhandle, &efi_runtime_mmio) {
+			struct efi_runtime_mmio_list *lmmio;
+
+			lmmio = list_entry(lhandle,
+					   struct efi_runtime_mmio_list,
+					   link);
+			if ((map_start <= lmmio->paddr) &&
+			    (map_end >= lmmio->paddr)) {
+				u64 off = map->virtual_start - map_start;
+				uintptr_t new_addr = lmmio->paddr + off;
+				*lmmio->ptr = (void *)new_addr;
+			}
+		}
+	}
+
+	/* Move the actual runtime code over */
 	for (i = 0; i < n; i++) {
 		struct efi_mem_desc *map;
 
 		map = (void*)virtmap + (descriptor_size * i);
 		if (map->type == EFI_RUNTIME_SERVICES_CODE) {
-			ulong new_offset = map->virtual_start - (runtime_start - gd->relocaddr);
+			ulong new_offset = map->virtual_start -
+					   (runtime_start - gd->relocaddr);
 
 			efi_runtime_relocate(new_offset, map);
 			/* Once we're virtual, we can no longer handle
@@ -251,6 +321,20 @@
 	return EFI_EXIT(EFI_INVALID_PARAMETER);
 }
 
+void efi_add_runtime_mmio(void *mmio_ptr, u64 len)
+{
+	struct efi_runtime_mmio_list *newmmio;
+
+	u64 pages = (len + EFI_PAGE_SIZE - 1) >> EFI_PAGE_SHIFT;
+	efi_add_memory_map(*(uintptr_t *)mmio_ptr, pages, EFI_MMAP_IO, false);
+
+	newmmio = calloc(1, sizeof(*newmmio));
+	newmmio->ptr = mmio_ptr;
+	newmmio->paddr = *(uintptr_t *)mmio_ptr;
+	newmmio->len = len;
+	list_add_tail(&newmmio->link, &efi_runtime_mmio);
+}
+
 /*
  * In the second stage, U-Boot has disappeared. To isolate our runtime code
  * that at this point still exists from the rest, we put it into a special
@@ -262,7 +346,7 @@
  * function or variable below this line.
  *
  * Please keep everything fully self-contained and annotated with
- * EFI_RUNTIME_TEXT and EFI_RUNTIME_DATA markers.
+ * __efi_runtime and __efi_runtime_data markers.
  */
 
 /*
@@ -271,28 +355,28 @@
  * address map calls.
  */
 
-static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_unimplemented(void)
+static efi_status_t __efi_runtime EFIAPI efi_unimplemented(void)
 {
 	return EFI_UNSUPPORTED;
 }
 
-static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_device_error(void)
+static efi_status_t __efi_runtime EFIAPI efi_device_error(void)
 {
 	return EFI_DEVICE_ERROR;
 }
 
-static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_invalid_parameter(void)
+static efi_status_t __efi_runtime EFIAPI efi_invalid_parameter(void)
 {
 	return EFI_INVALID_PARAMETER;
 }
 
-struct efi_runtime_services EFI_RUNTIME_DATA efi_runtime_services = {
+struct efi_runtime_services __efi_runtime_data efi_runtime_services = {
 	.hdr = {
 		.signature = EFI_RUNTIME_SERVICES_SIGNATURE,
 		.revision = EFI_RUNTIME_SERVICES_REVISION,
 		.headersize = sizeof(struct efi_table_hdr),
 	},
-	.get_time = &efi_get_time,
+	.get_time = &efi_get_time_boottime,
 	.set_time = (void *)&efi_device_error,
 	.get_wakeup_time = (void *)&efi_unimplemented,
 	.set_wakeup_time = (void *)&efi_unimplemented,
@@ -302,5 +386,5 @@
 	.get_next_variable = (void *)&efi_device_error,
 	.set_variable = (void *)&efi_device_error,
 	.get_next_high_mono_count = (void *)&efi_device_error,
-	.reset_system = &efi_reset_system,
+	.reset_system = &efi_reset_system_boottime,
 };
diff --git a/lib/efi_loader/efi_smbios.c b/lib/efi_loader/efi_smbios.c
new file mode 100644
index 0000000..ac412e7
--- /dev/null
+++ b/lib/efi_loader/efi_smbios.c
@@ -0,0 +1,32 @@
+/*
+ *  EFI application tables support
+ *
+ *  Copyright (c) 2016 Alexander Graf
+ *
+ *  SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <efi_loader.h>
+#include <inttypes.h>
+#include <smbios.h>
+
+static const efi_guid_t smbios_guid = SMBIOS_TABLE_GUID;
+
+void efi_smbios_register(void)
+{
+	/* Map within the low 32 bits, to allow for 32bit SMBIOS tables */
+	uint64_t dmi = 0xffffffff;
+	/* Reserve 4kb for SMBIOS */
+	uint64_t pages = 1;
+	int memtype = EFI_RUNTIME_SERVICES_DATA;
+
+	if (efi_allocate_pages(1, memtype, pages, &dmi) != EFI_SUCCESS)
+		return;
+
+	/* Generate SMBIOS tables */
+	write_smbios_table(dmi);
+
+	/* And expose them to our EFI payload */
+	efi_install_configuration_table(&smbios_guid, (void*)(uintptr_t)dmi);
+}
diff --git a/arch/x86/lib/smbios.c b/lib/smbios.c
similarity index 78%
rename from arch/x86/lib/smbios.c
rename to lib/smbios.c
index 9f30550..ce1974d 100644
--- a/arch/x86/lib/smbios.c
+++ b/lib/smbios.c
@@ -7,10 +7,14 @@
  */
 
 #include <common.h>
+#include <smbios.h>
+#include <tables_csum.h>
 #include <version.h>
-#include <asm/cpu.h>
-#include <asm/smbios.h>
-#include <asm/tables.h>
+#ifdef CONFIG_CPU
+#include <cpu.h>
+#include <dm.h>
+#include <dm/uclass-internal.h>
+#endif
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -69,7 +73,7 @@
 	return len + 1;
 }
 
-static int smbios_write_type0(u32 *current, int handle)
+static int smbios_write_type0(uintptr_t *current, int handle)
 {
 	struct smbios_type0 *t = (struct smbios_type0 *)*current;
 	int len = sizeof(struct smbios_type0);
@@ -79,14 +83,20 @@
 	t->vendor = smbios_add_string(t->eos, "U-Boot");
 	t->bios_ver = smbios_add_string(t->eos, PLAIN_VERSION);
 	t->bios_release_date = smbios_add_string(t->eos, U_BOOT_DMI_DATE);
+#ifdef CONFIG_ROM_SIZE
 	t->bios_rom_size = (CONFIG_ROM_SIZE / 65536) - 1;
+#endif
 	t->bios_characteristics = BIOS_CHARACTERISTICS_PCI_SUPPORTED |
 				  BIOS_CHARACTERISTICS_SELECTABLE_BOOT |
 				  BIOS_CHARACTERISTICS_UPGRADEABLE;
 #ifdef CONFIG_GENERATE_ACPI_TABLE
 	t->bios_characteristics_ext1 = BIOS_CHARACTERISTICS_EXT1_ACPI;
 #endif
+#ifdef CONFIG_EFI_LOADER
+	t->bios_characteristics_ext1 |= BIOS_CHARACTERISTICS_EXT1_UEFI;
+#endif
 	t->bios_characteristics_ext2 = BIOS_CHARACTERISTICS_EXT2_TARGET;
+
 	t->bios_major_release = 0xff;
 	t->bios_minor_release = 0xff;
 	t->ec_major_release = 0xff;
@@ -98,15 +108,20 @@
 	return len;
 }
 
-static int smbios_write_type1(u32 *current, int handle)
+static int smbios_write_type1(uintptr_t *current, int handle)
 {
 	struct smbios_type1 *t = (struct smbios_type1 *)*current;
 	int len = sizeof(struct smbios_type1);
+	char *serial_str = getenv("serial#");
 
 	memset(t, 0, sizeof(struct smbios_type1));
 	fill_smbios_header(t, SMBIOS_SYSTEM_INFORMATION, len, handle);
 	t->manufacturer = smbios_add_string(t->eos, CONFIG_SMBIOS_MANUFACTURER);
 	t->product_name = smbios_add_string(t->eos, CONFIG_SMBIOS_PRODUCT_NAME);
+	if (serial_str) {
+		strncpy((char*)t->uuid, serial_str, sizeof(t->uuid));
+		t->serial_number = smbios_add_string(t->eos, serial_str);
+	}
 
 	len = t->length + smbios_string_table_len(t->eos);
 	*current += len;
@@ -114,7 +129,7 @@
 	return len;
 }
 
-static int smbios_write_type2(u32 *current, int handle)
+static int smbios_write_type2(uintptr_t *current, int handle)
 {
 	struct smbios_type2 *t = (struct smbios_type2 *)*current;
 	int len = sizeof(struct smbios_type2);
@@ -132,7 +147,7 @@
 	return len;
 }
 
-static int smbios_write_type3(u32 *current, int handle)
+static int smbios_write_type3(uintptr_t *current, int handle)
 {
 	struct smbios_type3 *t = (struct smbios_type3 *)*current;
 	int len = sizeof(struct smbios_type3);
@@ -152,26 +167,47 @@
 	return len;
 }
 
-static int smbios_write_type4(u32 *current, int handle)
+static void smbios_write_type4_dm(struct smbios_type4 *t)
+{
+	u16 processor_family = SMBIOS_PROCESSOR_FAMILY_UNKNOWN;
+	const char *vendor = "Unknown";
+	const char *name = "Unknown";
+
+#ifdef CONFIG_CPU
+	char processor_name[49];
+	char vendor_name[49];
+	struct udevice *dev = NULL;
+
+	uclass_find_first_device(UCLASS_CPU, &dev);
+	if (dev) {
+		struct cpu_platdata *plat = dev_get_parent_platdata(dev);
+
+		if (plat->family)
+			processor_family = plat->family;
+		t->processor_id[0] = plat->id[0];
+		t->processor_id[1] = plat->id[1];
+
+		if (!cpu_get_vendor(dev, vendor_name, sizeof(vendor_name)))
+			vendor = vendor_name;
+		if (!cpu_get_desc(dev, processor_name, sizeof(processor_name)))
+			name = processor_name;
+	}
+#endif
+
+	t->processor_family = processor_family;
+	t->processor_manufacturer = smbios_add_string(t->eos, vendor);
+	t->processor_version = smbios_add_string(t->eos, name);
+}
+
+static int smbios_write_type4(uintptr_t *current, int handle)
 {
 	struct smbios_type4 *t = (struct smbios_type4 *)*current;
 	int len = sizeof(struct smbios_type4);
-	const char *vendor;
-	char *name;
-	char processor_name[CPU_MAX_NAME_LEN];
-	struct cpuid_result res;
 
 	memset(t, 0, sizeof(struct smbios_type4));
 	fill_smbios_header(t, SMBIOS_PROCESSOR_INFORMATION, len, handle);
 	t->processor_type = SMBIOS_PROCESSOR_TYPE_CENTRAL;
-	t->processor_family = gd->arch.x86;
-	vendor = cpu_vendor_name(gd->arch.x86_vendor);
-	t->processor_manufacturer = smbios_add_string(t->eos, vendor);
-	res = cpuid(1);
-	t->processor_id[0] = res.eax;
-	t->processor_id[1] = res.edx;
-	name = cpu_get_name(processor_name);
-	t->processor_version = smbios_add_string(t->eos, name);
+	smbios_write_type4_dm(t);
 	t->status = SMBIOS_PROCESSOR_STATUS_ENABLED;
 	t->processor_upgrade = SMBIOS_PROCESSOR_UPGRADE_NONE;
 	t->l1_cache_handle = 0xffff;
@@ -185,7 +221,7 @@
 	return len;
 }
 
-static int smbios_write_type32(u32 *current, int handle)
+static int smbios_write_type32(uintptr_t *current, int handle)
 {
 	struct smbios_type32 *t = (struct smbios_type32 *)*current;
 	int len = sizeof(struct smbios_type32);
@@ -198,7 +234,7 @@
 	return len;
 }
 
-static int smbios_write_type127(u32 *current, int handle)
+static int smbios_write_type127(uintptr_t *current, int handle)
 {
 	struct smbios_type127 *t = (struct smbios_type127 *)*current;
 	int len = sizeof(struct smbios_type127);
@@ -221,7 +257,7 @@
 	smbios_write_type127
 };
 
-u32 write_smbios_table(u32 addr)
+uintptr_t write_smbios_table(uintptr_t addr)
 {
 	struct smbios_entry *se;
 	u32 tables;
diff --git a/lib/tables_csum.c b/lib/tables_csum.c
new file mode 100644
index 0000000..340d7b3
--- /dev/null
+++ b/lib/tables_csum.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/ctype.h>
+
+u8 table_compute_checksum(void *v, int len)
+{
+	u8 *bytes = v;
+	u8 checksum = 0;
+	int i;
+
+	for (i = 0; i < len; i++)
+		checksum -= bytes[i];
+
+	return checksum;
+}