summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2016-10-19 07:48:16 -0400
committerTom Rini <trini@konsulko.com>2016-10-19 07:48:16 -0400
commit3431b392ad50ff37fa3d6e7715c6a99c74d692dc (patch)
tree53b6785acaa658a60c6a854af4dea9040f826b48
parent68ff827ec74fdca8f17d469f22e1032ed14cb795 (diff)
parent3fb97e267a5e136d8386a7cb1d5b4fe63af518eb (diff)
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
-rw-r--r--arch/arm/cpu/armv8/Kconfig18
-rw-r--r--arch/arm/cpu/armv8/fwcall.c59
-rw-r--r--arch/arm/include/asm/system.h12
-rw-r--r--arch/arm/mach-meson/board.c2
-rw-r--r--arch/avr32/include/asm/linkage.h0
-rw-r--r--arch/m68k/include/asm/linkage.h0
-rw-r--r--arch/microblaze/include/asm/linkage.h0
-rw-r--r--arch/mips/include/asm/linkage.h0
-rw-r--r--arch/nios2/include/asm/linkage.h0
-rw-r--r--arch/openrisc/include/asm/linkage.h0
-rw-r--r--arch/sandbox/include/asm/linkage.h0
-rw-r--r--arch/sh/include/asm/linkage.h0
-rw-r--r--arch/sparc/include/asm/linkage.h0
-rw-r--r--arch/x86/Kconfig27
-rw-r--r--arch/x86/cpu/baytrail/cpu.c1
-rw-r--r--arch/x86/cpu/broadwell/cpu.c1
-rw-r--r--arch/x86/cpu/cpu_x86.c18
-rw-r--r--arch/x86/cpu/ivybridge/model_206ax.c1
-rw-r--r--arch/x86/cpu/u-boot.lds36
-rw-r--r--arch/x86/include/asm/cpu_x86.h13
-rw-r--r--arch/x86/lib/Makefile2
-rw-r--r--arch/x86/lib/sections.c12
-rw-r--r--arch/x86/lib/tables.c9
-rw-r--r--board/xilinx/zynqmp/zynqmp.c5
-rw-r--r--cmd/bootefi.c16
-rw-r--r--drivers/cpu/cpu-uclass.c10
-rw-r--r--include/cpu.h22
-rw-r--r--include/efi.h3
-rw-r--r--include/efi_api.h4
-rw-r--r--include/efi_loader.h39
-rw-r--r--include/smbios.h (renamed from arch/x86/include/asm/smbios.h)8
-rw-r--r--lib/Kconfig33
-rw-r--r--lib/Makefile2
-rw-r--r--lib/efi_loader/Makefile1
-rw-r--r--lib/efi_loader/efi_boottime.c57
-rw-r--r--lib/efi_loader/efi_disk.c13
-rw-r--r--lib/efi_loader/efi_gop.c16
-rw-r--r--lib/efi_loader/efi_memory.c88
-rw-r--r--lib/efi_loader/efi_net.c11
-rw-r--r--lib/efi_loader/efi_runtime.c122
-rw-r--r--lib/efi_loader/efi_smbios.c32
-rw-r--r--lib/smbios.c (renamed from arch/x86/lib/smbios.c)82
-rw-r--r--lib/tables_csum.c20
43 files changed, 653 insertions, 142 deletions
diff --git a/arch/arm/cpu/armv8/Kconfig b/arch/arm/cpu/armv8/Kconfig
index 7e1fc4cbf9..cd2d9bb917 100644
--- a/arch/arm/cpu/armv8/Kconfig
+++ b/arch/arm/cpu/armv8/Kconfig
@@ -21,4 +21,22 @@ config ARMV8_SPIN_TABLE
- 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 079e250cbe..7dfd270029 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 @@ void hvc_call(struct pt_regs *args)
* 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 @@ void smc_call(struct pt_regs *args)
"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 (conduit_smc)
+ if (use_smc_for_psci)
+ smc_call(&regs);
+ else
+ hvc_call(&regs);
+
+ while (1)
+ ;
+}
+
+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 @@ void __noreturn psci_system_reset(bool conduit_smc)
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 c18e1e3a10..b928bd8d17 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -107,15 +107,6 @@ void smp_kick_all_cpus(void);
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 hvc_call(struct pt_regs *args);
*/
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 1dd53e2313..f159cbf849 100644
--- a/arch/arm/mach-meson/board.c
+++ b/arch/arm/mach-meson/board.c
@@ -43,7 +43,7 @@ void dram_init_banksize(void)
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 0000000000..e69de29bb2
--- /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 0000000000..e69de29bb2
--- /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 0000000000..e69de29bb2
--- /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 0000000000..e69de29bb2
--- /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 0000000000..e69de29bb2
--- /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 0000000000..e69de29bb2
--- /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 0000000000..e69de29bb2
--- /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 0000000000..e69de29bb2
--- /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 0000000000..e69de29bb2
--- /dev/null
+++ b/arch/sparc/include/asm/linkage.h
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index ac2d598d66..0884af22a7 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -461,33 +461,6 @@ config GENERATE_ACPI_TABLE
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 2837709d6d..0bb08524f8 100644
--- a/arch/x86/cpu/baytrail/cpu.c
+++ b/arch/x86/cpu/baytrail/cpu.c
@@ -189,6 +189,7 @@ static const struct cpu_ops cpu_x86_baytrail_ops = {
.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 3ba21aacec..6977e86032 100644
--- a/arch/x86/cpu/broadwell/cpu.c
+++ b/arch/x86/cpu/broadwell/cpu.c
@@ -743,6 +743,7 @@ static const struct cpu_ops cpu_x86_broadwell_ops = {
.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 09410416a1..157f3de6d8 100644
--- a/arch/x86/cpu/cpu_x86.c
+++ b/arch/x86/cpu/cpu_x86.c
@@ -15,9 +15,26 @@ DECLARE_GLOBAL_DATA_PTR;
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;
}
@@ -60,6 +77,7 @@ static int cpu_x86_get_count(struct udevice *dev)
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 b0743674ff..09b534255c 100644
--- a/arch/x86/cpu/ivybridge/model_206ax.c
+++ b/arch/x86/cpu/ivybridge/model_206ax.c
@@ -477,6 +477,7 @@ static const struct cpu_ops cpu_x86_model_206ax_ops = {
.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 36f59ea96d..cca536b272 100644
--- a/arch/x86/cpu/u-boot.lds
+++ b/arch/x86/cpu/u-boot.lds
@@ -28,7 +28,10 @@ SECTIONS
}
. = 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 @@ SECTIONS
.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 19404805c5..74b82edceb 100644
--- a/arch/x86/include/asm/cpu_x86.h
+++ b/arch/x86/include/asm/cpu_x86.h
@@ -31,4 +31,17 @@ int cpu_x86_bind(struct udevice *dev);
*/
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 e17f0bb0f2..b9c29226bd 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -28,8 +28,8 @@ obj-y += pirq_routing.o
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 0000000000..6455e0f088
--- /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 9ee6b5e924..025b183d6b 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 @@ static table_write table_write_funcs[] = {
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 566b5e8d2a..ba4dfbb476 100644
--- a/board/xilinx/zynqmp/zynqmp.c
+++ b/board/xilinx/zynqmp/zynqmp.c
@@ -427,8 +427,3 @@ int board_usb_cleanup(int index, enum usb_init_type init)
return 0;
}
#endif
-
-void reset_misc(void)
-{
- psci_system_reset(true);
-}
diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index 21fe42c2cb..c8079c4fe8 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 struct efi_device_path_file_path bootefi_device_path[] = {
}
};
-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 void *copy_fdt(void *fdt)
*/
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 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt)
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 7660f99ef5..c57ac16b3a 100644
--- a/drivers/cpu/cpu-uclass.c
+++ b/drivers/cpu/cpu-uclass.c
@@ -44,6 +44,16 @@ int cpu_get_count(struct udevice *dev)
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 bda53150a6..954257715a 100644
--- a/include/cpu.h
+++ b/include/cpu.h
@@ -21,6 +21,8 @@ struct cpu_platdata {
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 @@ struct cpu_ops {
* @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_info(struct udevice *dev, struct cpu_info *info);
*/
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 5a3b8cf69a..d07187c7dd 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 f572b88079..bdb600e08d 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -201,6 +201,10 @@ struct efi_runtime_services {
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 97388350eb..35b3fe2d39 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -85,6 +85,8 @@ int efi_disk_register(void);
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 @@ void efi_net_set_dhcp_ack(void *pkt, int len);
* 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 @@ void *efi_alloc(uint64_t len, int memory_type);
/* 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 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
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 @@ static inline void ascii2unicode(u16 *unicode, const char *ascii)
* 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
index 623a703693..d582d4f7ab 100644
--- a/arch/x86/include/asm/smbios.h
+++ b/include/smbios.h
@@ -55,6 +55,7 @@ struct __packed smbios_entry {
#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 @@ struct __packed smbios_type3 {
#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 @@ static inline void fill_smbios_header(void *table, int type,
* @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 @@ typedef int (*smbios_write_type)(u32 *addr, int handle);
* @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 0e0d8efd33..b16062fbe3 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -163,6 +163,39 @@ config FDT_FIXUP_PARTITIONS
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 e3383f4046..23e9f1ef11 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_FIT) += fdtdec_common.o
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 += linux_string.o
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 2a3849e31b..12159dd5ce 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -12,3 +12,4 @@ obj-y += efi_memory.o
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 792db39f51..1fdddf4591 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -37,8 +37,9 @@ static bool efi_is_direct_boot = true;
* 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 @@ static struct efi_configuration_table EFI_RUNTIME_DATA efi_conf_table[1];
* 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 @@ void efi_restore_gd(void)
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 @@ efi_status_t EFIAPI efi_get_memory_map_ext(unsigned long *memory_map_size,
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 @@ static struct {
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 struct {
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 @@ static efi_status_t EFIAPI efi_locate_device_path(efi_guid_t *protocol,
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 @@ static const struct efi_boot_services efi_boot_services = {
.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 @@ static const struct efi_boot_services efi_boot_services = {
.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 const struct efi_boot_services efi_boot_services = {
};
-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 d8ddcc9b42..1e3dca46ba 100644
--- a/lib/efi_loader/efi_disk.c
+++ b/lib/efi_loader/efi_disk.c
@@ -35,9 +35,10 @@ struct efi_disk_obj {
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 @@ static efi_status_t efi_disk_open_block(void *handle, efi_guid_t *protocol,
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 @@ static efi_status_t EFIAPI efi_disk_rw_blocks(struct efi_block_io *this,
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 @@ static efi_status_t efi_disk_read_blocks(struct efi_block_io *this,
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 33a3d71767..286ad83097 100644
--- a/lib/efi_loader/efi_gop.c
+++ b/lib/efi_loader/efi_gop.c
@@ -129,6 +129,7 @@ int efi_gop_register(void)
{
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 @@ int efi_gop_register(void)
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 @@ int efi_gop_register(void)
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 80e4e26e05..95aa590c8a 100644
--- a/lib/efi_loader/efi_memory.c
+++ b/lib/efi_loader/efi_memory.c
@@ -34,6 +34,19 @@ void *efi_bounce_buffer;
#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 @@ static void efi_mem_sort(void)
* 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 @@ static int efi_mem_carve_out(struct efi_mem_list *map,
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 @@ static int efi_mem_carve_out(struct efi_mem_list *map,
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 @@ void *efi_alloc(uint64_t len, int memory_type)
efi_status_t efi_free_pages(uint64_t memory, unsigned long pages)
{
- /* We don't free, let's cross our fingers we have plenty RAM */
- return EFI_SUCCESS;
+ 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)
+{
+ 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 @@ efi_status_t efi_get_memory_map(unsigned long *memory_map_size,
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 @@ efi_status_t efi_get_memory_map(unsigned long *memory_map_size,
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 dd3b48570d..3796496caa 100644
--- a/lib/efi_loader/efi_net.c
+++ b/lib/efi_loader/efi_net.c
@@ -152,7 +152,14 @@ static efi_status_t EFIAPI efi_net_transmit(struct efi_simple_network *this,
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 @@ static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this,
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 @@ static efi_status_t efi_net_open_dp(void *handle, efi_guid_t *protocol,
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 99b5ef11c2..dd52755d1d 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 @@ static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_invalid_parameter(void);
#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 @@ struct elf_rela {
* 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 @@ static void EFIAPI efi_reset_system(enum efi_reset_type reset_type,
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 @@ static efi_status_t EFIAPI efi_get_time(struct efi_time *time,
#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 @@ static const struct efi_runtime_detach_list_struct efi_runtime_detach_list[] = {
{
/* 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 @@ static const struct efi_runtime_detach_list_struct efi_runtime_detach_list[] = {
}, {
/* 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 @@ static efi_status_t EFIAPI efi_set_virtual_address_map(
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 @@ static efi_status_t EFIAPI efi_set_virtual_address_map(
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 @@ static efi_status_t EFIAPI efi_set_virtual_address_map(
* 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 @@ static efi_status_t EFIAPI efi_set_virtual_address_map(
* 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 @@ struct efi_runtime_services EFI_RUNTIME_DATA efi_runtime_services = {
.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 0000000000..ac412e7362
--- /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
index 9f3055020b..ce1974d86f 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 @@ static int smbios_string_table_len(char *start)
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 @@ static int smbios_write_type0(u32 *current, int handle)
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 @@ static int smbios_write_type0(u32 *current, int handle)
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 @@ static int smbios_write_type1(u32 *current, int handle)
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 @@ static int smbios_write_type2(u32 *current, int handle)
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 @@ static int smbios_write_type3(u32 *current, int handle)
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 @@ static int smbios_write_type4(u32 *current, int handle)
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 @@ static int smbios_write_type32(u32 *current, int handle)
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 @@ static smbios_write_type smbios_write_funcs[] = {
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 0000000000..340d7b3b11
--- /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;
+}