summaryrefslogtreecommitdiff
path: root/lib
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 /lib
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
Diffstat (limited to 'lib')
-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.c305
-rw-r--r--lib/tables_csum.c20
12 files changed, 643 insertions, 57 deletions
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/lib/smbios.c b/lib/smbios.c
new file mode 100644
index 0000000000..ce1974d86f
--- /dev/null
+++ b/lib/smbios.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * Adapted from coreboot src/arch/x86/smbios.c
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <smbios.h>
+#include <tables_csum.h>
+#include <version.h>
+#ifdef CONFIG_CPU
+#include <cpu.h>
+#include <dm.h>
+#include <dm/uclass-internal.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * smbios_add_string() - add a string to the string area
+ *
+ * This adds a string to the string area which is appended directly after
+ * the formatted portion of an SMBIOS structure.
+ *
+ * @start: string area start address
+ * @str: string to add
+ * @return: string number in the string area
+ */
+static int smbios_add_string(char *start, const char *str)
+{
+ int i = 1;
+ char *p = start;
+
+ for (;;) {
+ if (!*p) {
+ strcpy(p, str);
+ p += strlen(str);
+ *p++ = '\0';
+ *p++ = '\0';
+
+ return i;
+ }
+
+ if (!strcmp(p, str))
+ return i;
+
+ p += strlen(p) + 1;
+ i++;
+ }
+}
+
+/**
+ * smbios_string_table_len() - compute the string area size
+ *
+ * This computes the size of the string area including the string terminator.
+ *
+ * @start: string area start address
+ * @return: string area size
+ */
+static int smbios_string_table_len(char *start)
+{
+ char *p = start;
+ int i, len = 0;
+
+ while (*p) {
+ i = strlen(p) + 1;
+ p += i;
+ len += i;
+ }
+
+ return len + 1;
+}
+
+static int smbios_write_type0(uintptr_t *current, int handle)
+{
+ struct smbios_type0 *t = (struct smbios_type0 *)*current;
+ int len = sizeof(struct smbios_type0);
+
+ memset(t, 0, sizeof(struct smbios_type0));
+ fill_smbios_header(t, SMBIOS_BIOS_INFORMATION, len, 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;
+ t->ec_minor_release = 0xff;
+
+ len = t->length + smbios_string_table_len(t->eos);
+ *current += len;
+
+ return len;
+}
+
+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;
+
+ return len;
+}
+
+static int smbios_write_type2(uintptr_t *current, int handle)
+{
+ struct smbios_type2 *t = (struct smbios_type2 *)*current;
+ int len = sizeof(struct smbios_type2);
+
+ memset(t, 0, sizeof(struct smbios_type2));
+ fill_smbios_header(t, SMBIOS_BOARD_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);
+ t->feature_flags = SMBIOS_BOARD_FEATURE_HOSTING;
+ t->board_type = SMBIOS_BOARD_MOTHERBOARD;
+
+ len = t->length + smbios_string_table_len(t->eos);
+ *current += len;
+
+ return len;
+}
+
+static int smbios_write_type3(uintptr_t *current, int handle)
+{
+ struct smbios_type3 *t = (struct smbios_type3 *)*current;
+ int len = sizeof(struct smbios_type3);
+
+ memset(t, 0, sizeof(struct smbios_type3));
+ fill_smbios_header(t, SMBIOS_SYSTEM_ENCLOSURE, len, handle);
+ t->manufacturer = smbios_add_string(t->eos, CONFIG_SMBIOS_MANUFACTURER);
+ t->chassis_type = SMBIOS_ENCLOSURE_DESKTOP;
+ t->bootup_state = SMBIOS_STATE_SAFE;
+ t->power_supply_state = SMBIOS_STATE_SAFE;
+ t->thermal_state = SMBIOS_STATE_SAFE;
+ t->security_status = SMBIOS_SECURITY_NONE;
+
+ len = t->length + smbios_string_table_len(t->eos);
+ *current += len;
+
+ return len;
+}
+
+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);
+
+ memset(t, 0, sizeof(struct smbios_type4));
+ fill_smbios_header(t, SMBIOS_PROCESSOR_INFORMATION, len, handle);
+ t->processor_type = SMBIOS_PROCESSOR_TYPE_CENTRAL;
+ smbios_write_type4_dm(t);
+ t->status = SMBIOS_PROCESSOR_STATUS_ENABLED;
+ t->processor_upgrade = SMBIOS_PROCESSOR_UPGRADE_NONE;
+ t->l1_cache_handle = 0xffff;
+ t->l2_cache_handle = 0xffff;
+ t->l3_cache_handle = 0xffff;
+ t->processor_family2 = t->processor_family;
+
+ len = t->length + smbios_string_table_len(t->eos);
+ *current += len;
+
+ return len;
+}
+
+static int smbios_write_type32(uintptr_t *current, int handle)
+{
+ struct smbios_type32 *t = (struct smbios_type32 *)*current;
+ int len = sizeof(struct smbios_type32);
+
+ memset(t, 0, sizeof(struct smbios_type32));
+ fill_smbios_header(t, SMBIOS_SYSTEM_BOOT_INFORMATION, len, handle);
+
+ *current += len;
+
+ return len;
+}
+
+static int smbios_write_type127(uintptr_t *current, int handle)
+{
+ struct smbios_type127 *t = (struct smbios_type127 *)*current;
+ int len = sizeof(struct smbios_type127);
+
+ memset(t, 0, sizeof(struct smbios_type127));
+ fill_smbios_header(t, SMBIOS_END_OF_TABLE, len, handle);
+
+ *current += len;
+
+ return len;
+}
+
+static smbios_write_type smbios_write_funcs[] = {
+ smbios_write_type0,
+ smbios_write_type1,
+ smbios_write_type2,
+ smbios_write_type3,
+ smbios_write_type4,
+ smbios_write_type32,
+ smbios_write_type127
+};
+
+uintptr_t write_smbios_table(uintptr_t addr)
+{
+ struct smbios_entry *se;
+ u32 tables;
+ int len = 0;
+ int max_struct_size = 0;
+ int handle = 0;
+ char *istart;
+ int isize;
+ int i;
+
+ /* 16 byte align the table address */
+ addr = ALIGN(addr, 16);
+
+ se = (struct smbios_entry *)addr;
+ memset(se, 0, sizeof(struct smbios_entry));
+
+ addr += sizeof(struct smbios_entry);
+ addr = ALIGN(addr, 16);
+ tables = addr;
+
+ /* populate minimum required tables */
+ for (i = 0; i < ARRAY_SIZE(smbios_write_funcs); i++) {
+ int tmp = smbios_write_funcs[i](&addr, handle++);
+ max_struct_size = max(max_struct_size, tmp);
+ len += tmp;
+ }
+
+ memcpy(se->anchor, "_SM_", 4);
+ se->length = sizeof(struct smbios_entry);
+ se->major_ver = SMBIOS_MAJOR_VER;
+ se->minor_ver = SMBIOS_MINOR_VER;
+ se->max_struct_size = max_struct_size;
+ memcpy(se->intermediate_anchor, "_DMI_", 5);
+ se->struct_table_length = len;
+ se->struct_table_address = tables;
+ se->struct_count = handle;
+
+ /* calculate checksums */
+ istart = (char *)se + SMBIOS_INTERMEDIATE_OFFSET;
+ isize = sizeof(struct smbios_entry) - SMBIOS_INTERMEDIATE_OFFSET;
+ se->intermediate_checksum = table_compute_checksum(istart, isize);
+ se->checksum = table_compute_checksum(se, sizeof(struct smbios_entry));
+
+ return addr;
+}
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;
+}