From 852efbf5bd3047b12c1926564d792a7a1cea9eac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Sat, 1 Oct 2016 23:32:23 +0200 Subject: efi_loader: Update description of internal efi_mem_carve_out MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In 74c16acce30bb882ad5951829d8dafef8eea564c the return values where changed, but the description was kept. Signed-off-by: Stefan Brüns Reviewed-by: Alexander Graf Signed-off-by: Alexander Graf diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 80e4e26..ebe8e94 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -62,9 +62,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, -- cgit v0.10.2 From bdf5c1b3607bd6384ac5319caad2d8107130ace1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Sun, 9 Oct 2016 22:17:07 +0200 Subject: efi_loader: Fix memory map size check to avoid out-of-bounds access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current efi_get_memory_map() function overwrites the map_size property before reading its value. That way the sanity check whether our memory map fits into the given array always succeeds, potentially overwriting arbitrary payload memory. This patch moves the property update write after its sanity check, so that the check actually verifies the correct value. So far this has not triggered any known bugs, but we're better off safe than sorry. If the buffer is to small, the returned memory_map_size indicates the required size to the caller. Signed-off-by: Stefan Brüns Reviewed-by: Alexander Graf Signed-off-by: Alexander Graf diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index ebe8e94..1d23783 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -336,6 +336,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++; @@ -350,7 +351,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 */ -- cgit v0.10.2 From 991d62fa73a35598a8939a83dd84369168220d35 Mon Sep 17 00:00:00 2001 From: Robin Randhawa Date: Tue, 13 Sep 2016 18:36:53 +0100 Subject: efi_loader: Fix crash on 32-bit systems A type mismatch in the efi_allocate_pool boot service flow causes hazardous memory scribbling on 32-bit systems. This is efi_allocate_pool's prototype: static efi_status_t EFIAPI efi_allocate_pool(int pool_type, unsigned long size, void **buffer); Internally, it invokes efi_allocate_pages as follows: efi_allocate_pages(0, pool_type, (size + 0xfff) >> 12, (void*)buffer); This is efi_allocate_pages' prototype: efi_status_t efi_allocate_pages(int type, int memory_type, unsigned long pages, uint64_t *memory); The problem: efi_allocate_pages does this internally: *memory = addr; This fix in efi_allocate_pool uses a transitional uintptr_t cast to ensure the correct outcome, irrespective of the system's native word size. This was observed when bootefi'ing the EFI instance of FreeBSD's first stage bootstrap (boot1.efi) on a 32-bit ARM platform (Qemu VExpress + Cortex-a9). Signed-off-by: Robin Randhawa Signed-off-by: Alexander Graf diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 792db39..a11100f 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -134,9 +134,11 @@ static efi_status_t EFIAPI efi_allocate_pool(int pool_type, unsigned long size, void **buffer) { efi_status_t r; + efi_physical_addr_t t; EFI_ENTRY("%d, %ld, %p", pool_type, size, buffer); - r = efi_allocate_pages(0, pool_type, (size + 0xfff) >> 12, (void*)buffer); + r = efi_allocate_pages(0, pool_type, (size + 0xfff) >> 12, &t); + *buffer = (void *)(uintptr_t)t; return EFI_EXIT(r); } -- cgit v0.10.2 From ead1274b7f9578e346b3cdcb3d9e2002ef8f0e75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Sun, 9 Oct 2016 22:17:18 +0200 Subject: efi_loader: Move efi_allocate_pool implementation to efi_memory.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We currently handle efi_allocate_pool() in our boot time service file. In the following patch, pool allocation will receive additional internal semantics that we should preserve inside efi_memory.c instead. As foundation for those changes, split the function into an externally facing efi_allocate_pool_ext() for use by payloads and an internal helper efi_allocate_pool() in efi_memory.c that handles the actual allocation. While at it, change the magic 0xfff / 12 constants to the more obvious EFI_PAGE_MASK/SHIFT defines. Signed-off-by: Stefan Brüns Reviewed-by: Alexander Graf Signed-off-by: Alexander Graf diff --git a/include/efi_loader.h b/include/efi_loader.h index 9738835..f0473ab 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -119,6 +119,9 @@ 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_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); /* Returns the EFI memory map */ efi_status_t efi_get_memory_map(unsigned long *memory_map_size, struct efi_mem_desc *memory_map, diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index a11100f..05b93e8 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -130,15 +130,14 @@ 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_physical_addr_t t; EFI_ENTRY("%d, %ld, %p", pool_type, size, buffer); - r = efi_allocate_pages(0, pool_type, (size + 0xfff) >> 12, &t); - *buffer = (void *)(uintptr_t)t; + r = efi_allocate_pool(pool_type, size, buffer); return EFI_EXIT(r); } @@ -736,7 +735,7 @@ 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, + .allocate_pool = efi_allocate_pool_ext, .free_pool = efi_free_pool, .create_event = efi_create_event, .set_timer = efi_set_timer, diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 1d23783..be642f1 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -327,6 +327,20 @@ efi_status_t efi_free_pages(uint64_t memory, unsigned long pages) return EFI_SUCCESS; } +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 + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; + + r = efi_allocate_pages(0, pool_type, num_pages, &t); + if (r == EFI_SUCCESS) + *buffer = (void *)(uintptr_t)t; + + return r; +} + efi_status_t efi_get_memory_map(unsigned long *memory_map_size, struct efi_mem_desc *memory_map, unsigned long *map_key, -- cgit v0.10.2 From 42417bc84d1d56f739d43d562773d4821cf1bf47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Sun, 9 Oct 2016 22:17:26 +0200 Subject: efi_loader: Track size of pool allocations to allow freeing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need a functional free_pool implementation, as otherwise each allocate_pool causes growth of the memory descriptor table. Different to free_pages, free_pool does not provide the size for the to be freed allocation, thus we have to track the size ourselves. As the only EFI requirement for pool allocation is an alignment of 8 bytes, we can keep allocating a range using the page allocator, reserve the first 8 bytes for our bookkeeping and hand out the remainder to the caller. This saves us from having to use any independent data structures for tracking. To simplify the conversion between pool allocations and the corresponding page allocation, we create an auxiliary struct efi_pool_allocation. Given the allocation size free_pool size can handoff freeing the page range, which was indirectly allocated by a call to allocate_pool, to free_pages. Signed-off-by: Stefan Brüns Reviewed-by: Alexander Graf Signed-off-by: Alexander Graf diff --git a/include/efi_loader.h b/include/efi_loader.h index f0473ab..3dad24e 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -122,6 +122,8 @@ 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, diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 05b93e8..6c8d93b 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -141,12 +141,12 @@ static efi_status_t EFIAPI efi_allocate_pool_ext(int pool_type, 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); } @@ -736,7 +736,7 @@ static const struct efi_boot_services efi_boot_services = { .free_pages = efi_free_pages_ext, .get_memory_map = efi_get_memory_map_ext, .allocate_pool = efi_allocate_pool_ext, - .free_pool = efi_free_pool, + .free_pool = efi_free_pool_ext, .create_event = efi_create_event, .set_timer = efi_set_timer, .wait_for_event = efi_wait_for_event, diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index be642f1..de28db6 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 @@ -332,11 +345,34 @@ efi_status_t efi_allocate_pool(int pool_type, unsigned long size, { efi_status_t r; efi_physical_addr_t t; - u64 num_pages = (size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; + 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) - *buffer = (void *)(uintptr_t)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; } -- cgit v0.10.2 From b61d857b2ff3b0b099ef187d7ceebe26ea788578 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Sat, 1 Oct 2016 23:32:27 +0200 Subject: efi_loader: Readd freed pages to memory pool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently each allocation creates a new mapping. Readding the mapping as free memory (EFI_CONVENTIONAL_MEMORY) potentially allows to hand out an existing mapping, thus limiting the number of mapping descriptors in the memory map. Mitigates a problem with current (4.8rc7) linux kernels when doing an efi_get_memory map, resulting in an infinite loop. Space for the memory map is reserved with allocate_pool (implicitly creating a new mapping) and filled. If there is insufficient slack space (8 entries) in the map, the space is freed and a new round is started, with space for one more entry. As each round increases requirement and allocation by exactly one, there is never enough slack space. (At least 32 entries are allocated, so as long as there are less than 24 entries, there is enough slack). Earlier kernels reserved no slack, and did less allocations, so this problem was not visible. Signed-off-by: Stefan Brüns Reviewed-by: Alexander Graf Signed-off-by: Alexander Graf diff --git a/include/efi_loader.h b/include/efi_loader.h index 3dad24e..94397af 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -117,7 +117,7 @@ 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, diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index de28db6..d3a2ffd 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -336,8 +336,15 @@ 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, -- cgit v0.10.2 From b6a951727504d4159467ac98434849f81aaf9ffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Sat, 1 Oct 2016 23:32:28 +0200 Subject: efi_loader: Keep memory mapping sorted when splitting an entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code assumes sorted mappings in descending address order. When splitting a mapping, insert the new part next to the current mapping. Signed-off-by: Stefan Brüns Reviewed-by: Alexander Graf Signed-off-by: Alexander Graf diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index d3a2ffd..742bc90 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -135,7 +135,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; -- cgit v0.10.2 From 511d0b97ef709d13da4922fb694d55ef9a5ef641 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Sat, 1 Oct 2016 23:32:29 +0200 Subject: efi_loader: Do not leak memory when unlinking a mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As soon as a mapping is unlinked from the list, there are no further references to it, so it should be freed. If it not unlinked, update the start address and length. Signed-off-by: Stefan Brüns Reviewed-by: Alexander Graf Signed-off-by: Alexander Graf diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 742bc90..95aa590 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -116,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; } -- cgit v0.10.2 From 80a4800ee1526a4a46cd02b3ea2fd37eebb77504 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 16 Aug 2016 21:08:45 +0200 Subject: efi_loader: Allow boards to implement get_time and reset_system EFI allows an OS to leverage firmware drivers while the OS is running. In the generic code we so far had to stub those implementations out, because we would need board specific knowledge about MMIO setups for it. However, boards can easily implement those themselves. This patch provides the framework so that a board can implement its own versions of get_time and reset_system which would actually do something useful. While at it we also introduce a simple way for code to reserve MMIO pointers as runtime available. Signed-off-by: Alexander Graf diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 21fe42c..38c3b41 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -206,6 +206,10 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt) loaded_image_info.device_handle = nethandle; #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/include/efi_loader.h b/include/efi_loader.h index 94397af..1e4eb46 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -155,11 +155,29 @@ static inline void ascii2unicode(u16 *unicode, const char *ascii) #define EFI_RUNTIME_DATA __attribute__ ((section ("efi_runtime_data"))) #define EFI_RUNTIME_TEXT __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_TEXT 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_TEXT 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 +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/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 99b5ef1..f73e6d9 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -16,6 +16,16 @@ /* For manual relocation support */ DECLARE_GLOBAL_DATA_PTR; +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_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); @@ -55,9 +65,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 +83,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 +119,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_TEXT 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_TEXT 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 +155,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 +163,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 +272,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 +317,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 @@ -292,7 +372,7 @@ struct efi_runtime_services EFI_RUNTIME_DATA efi_runtime_services = { .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 +382,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, }; -- cgit v0.10.2 From 51bfb5b6f522b1fbe453c18df03648d72b08131f Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 16 Aug 2016 21:08:46 +0200 Subject: arm: Disable HVC PSCI calls by default All systems that are running on armv8 are running bare metal with firmware that implements PSCI running in EL3. That means we don't really need to expose the hypercall variants of them. This patch leaves the code in, but makes the code explicit enough to have the compiler optimize it out. With this we don't need to worry about hvc vs smc calling convention when calling psci helper functions. Signed-off-by: Alexander Graf Reviewed-by: Simon Glass diff --git a/arch/arm/cpu/armv8/fwcall.c b/arch/arm/cpu/armv8/fwcall.c index 079e250..6bb68f2 100644 --- a/arch/arm/cpu/armv8/fwcall.c +++ b/arch/arm/cpu/armv8/fwcall.c @@ -17,7 +17,7 @@ * x0~x7: input arguments * x0~x3: output arguments */ -void hvc_call(struct pt_regs *args) +static void hvc_call(struct pt_regs *args) { asm volatile( "ldr x0, %0\n" @@ -75,13 +75,21 @@ 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 bool use_smc_for_psci = true; + +void __noreturn 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(®s); else hvc_call(®s); diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index c18e1e3..5166c65 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,7 @@ 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); #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 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/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index 566b5e8..94132f8 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -430,5 +430,5 @@ int board_usb_cleanup(int index, enum usb_init_type init) void reset_misc(void) { - psci_system_reset(true); + psci_system_reset(); } -- cgit v0.10.2 From 3ee655ed83ada67912cbbd14b6685bc0c7102553 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 16 Aug 2016 21:08:47 +0200 Subject: arm: Add PSCI shutdown function Using PSCI you can not only reset the system, you can also shut it down! This patch exposes a function to do exactly that to whatever code wants to make use of it. Signed-off-by: Alexander Graf Reviewed-by: Simon Glass diff --git a/arch/arm/cpu/armv8/fwcall.c b/arch/arm/cpu/armv8/fwcall.c index 6bb68f2..b3ef7c0 100644 --- a/arch/arm/cpu/armv8/fwcall.c +++ b/arch/arm/cpu/armv8/fwcall.c @@ -97,3 +97,18 @@ void __noreturn psci_system_reset(void) while (1) ; } + +void __noreturn 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(®s); + else + hvc_call(®s); + + while (1) + ; +} diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index 5166c65..b928bd8 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -116,6 +116,7 @@ void flush_l3_cache(void); void smc_call(struct pt_regs *args); void __noreturn psci_system_reset(void); +void __noreturn psci_system_off(void); #endif /* __ASSEMBLY__ */ -- cgit v0.10.2 From 8069821fc2cb55a458efef1c4c614810302b6ab2 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 16 Aug 2016 21:08:48 +0200 Subject: arm: Provide common PSCI based reset handler 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. The exclude list seems excessive right now, but NXP is working on providing an in-tree PSCI implementation, so that all NXP systems can eventually use PSCI as well. Signed-off-by: Alexander Graf [agraf: fix meson] Reviewed-by: Simon Glass 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 @@ 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 b3ef7c0..c57b15f 100644 --- a/arch/arm/cpu/armv8/fwcall.c +++ b/arch/arm/cpu/armv8/fwcall.c @@ -112,3 +112,10 @@ void __noreturn psci_system_off(void) while (1) ; } + +#ifdef CONFIG_PSCI_RESET +void reset_misc(void) +{ + psci_system_reset(); +} +#endif /* CONFIG_PSCI_RESET */ diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index 94132f8..ba4dfbb 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(); -} -- cgit v0.10.2 From b6575f34e20ddc40baa391c2db0e1e015e942af2 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 16 Aug 2016 21:08:49 +0200 Subject: efi_loader: Add generic PSCI RTS Now that we have generic PSCI reset and shutdown support in place, we can advertise those as EFI Run Time Services, allowing efi applications and OSs to reset and shut down systems. Signed-off-by: Alexander Graf Reviewed-by: Simon Glass diff --git a/arch/arm/cpu/armv8/fwcall.c b/arch/arm/cpu/armv8/fwcall.c index c57b15f..64539f9 100644 --- a/arch/arm/cpu/armv8/fwcall.c +++ b/arch/arm/cpu/armv8/fwcall.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -17,7 +18,7 @@ * x0~x7: input arguments * x0~x3: output arguments */ -static void hvc_call(struct pt_regs *args) +static void EFI_RUNTIME_TEXT hvc_call(struct pt_regs *args) { asm volatile( "ldr x0, %0\n" @@ -51,7 +52,7 @@ static void hvc_call(struct pt_regs *args) * x0~x3: output arguments */ -void smc_call(struct pt_regs *args) +void EFI_RUNTIME_TEXT smc_call(struct pt_regs *args) { asm volatile( "ldr x0, %0\n" @@ -81,9 +82,9 @@ void smc_call(struct pt_regs *args) * use PSCI on U-Boot running below a hypervisor, please detect * this and set the flag accordingly. */ -static const bool use_smc_for_psci = true; +static const EFI_RUNTIME_DATA bool use_smc_for_psci = true; -void __noreturn psci_system_reset(void) +void __noreturn EFI_RUNTIME_TEXT psci_system_reset(void) { struct pt_regs regs; @@ -98,7 +99,7 @@ void __noreturn psci_system_reset(void) ; } -void __noreturn psci_system_off(void) +void __noreturn EFI_RUNTIME_TEXT psci_system_off(void) { struct pt_regs regs; @@ -118,4 +119,24 @@ void reset_misc(void) { psci_system_reset(); } + +#ifdef CONFIG_EFI_LOADER +void EFI_RUNTIME_TEXT 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 */ -- cgit v0.10.2 From 712cd2987489fe62aedeb24730e730871b1eb627 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 6 Sep 2016 14:26:27 +0200 Subject: efi_loader: Allow bouncing for network So far bounce buffers were only used for disk I/O, but network I/O may suffer from the same problem. On platforms that have problems doing DMA on high addresses, let's also bounce outgoing network packets. Incoming ones always already get bounced. This patch fixes EFI PXE boot on ZynqMP for me. Signed-off-by: Alexander Graf diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index dd3b485..6a8a0d7 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); -- cgit v0.10.2 From 8f661a5b662af05d4d6da32dc0a3437542f6e866 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 7 Jun 2016 00:57:05 +0200 Subject: efi_loader: gop: Expose fb when 32bpp When we're running in 32bpp mode, expose the frame buffer address to our payloads so that Linux efifb can pick it up. Signed-off-by: Alexander Graf 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 @@ 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; -- cgit v0.10.2 From 1befb38b868248dda4e84a57aa779f7e8c0b85c0 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 19 Aug 2016 01:23:21 +0200 Subject: x86: Move table csum into separate file We need the checksum function without all the other table functionality soon, so let's split it out into its own C file. Signed-off-by: Alexander Graf Reviewed-by: Simon Glass Reviewed-by: Bin Meng diff --git a/arch/x86/include/asm/tables.h b/arch/x86/include/asm/tables.h index ae9f0d0..81f98f2 100644 --- a/arch/x86/include/asm/tables.h +++ b/arch/x86/include/asm/tables.h @@ -7,6 +7,8 @@ #ifndef _X86_TABLES_H_ #define _X86_TABLES_H_ +#include + /* * All x86 tables happen to like the address range from 0xf0000 to 0x100000. * We use 0xf0000 as the starting address to store those tables, including diff --git a/arch/x86/lib/tables.c b/arch/x86/lib/tables.c index f92111e..9ee6b5e 100644 --- a/arch/x86/lib/tables.c +++ b/arch/x86/lib/tables.c @@ -38,18 +38,6 @@ static table_write table_write_funcs[] = { #endif }; -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; -} - void table_fill_string(char *dest, const char *src, size_t n, char pad) { int start, len; diff --git a/include/tables_csum.h b/include/tables_csum.h new file mode 100644 index 0000000..a021efb --- /dev/null +++ b/include/tables_csum.h @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2015, Bin Meng + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _TABLES_CSUM_H_ +#define _TABLES_CSUM_H_ + +u8 table_compute_checksum(void *v, int len); + +#endif diff --git a/lib/Makefile b/lib/Makefile index e3383f4..3842e7d 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -73,6 +73,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/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 + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +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; +} -- cgit v0.10.2 From 4b6dddc294a58fd9010926719e5c907beebf9b4d Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 19 Aug 2016 01:23:23 +0200 Subject: x86: Move smbios generation into arch independent directory We will need the SMBIOS generation function on ARM as well going forward, so let's move it into a non arch specific location. Signed-off-by: Alexander Graf Reviewed-by: Bin Meng Reviewed-by: Simon Glass 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 @@ 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/include/asm/smbios.h b/arch/x86/include/asm/smbios.h deleted file mode 100644 index 623a703..0000000 --- a/arch/x86/include/asm/smbios.h +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright (C) 2015, Bin Meng - * - * Adapted from coreboot src/include/smbios.h - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef _SMBIOS_H_ -#define _SMBIOS_H_ - -/* SMBIOS spec version implemented */ -#define SMBIOS_MAJOR_VER 3 -#define SMBIOS_MINOR_VER 0 - -/* SMBIOS structure types */ -enum { - SMBIOS_BIOS_INFORMATION = 0, - SMBIOS_SYSTEM_INFORMATION = 1, - SMBIOS_BOARD_INFORMATION = 2, - SMBIOS_SYSTEM_ENCLOSURE = 3, - SMBIOS_PROCESSOR_INFORMATION = 4, - SMBIOS_CACHE_INFORMATION = 7, - SMBIOS_SYSTEM_SLOTS = 9, - SMBIOS_PHYS_MEMORY_ARRAY = 16, - SMBIOS_MEMORY_DEVICE = 17, - SMBIOS_MEMORY_ARRAY_MAPPED_ADDRESS = 19, - SMBIOS_SYSTEM_BOOT_INFORMATION = 32, - SMBIOS_END_OF_TABLE = 127 -}; - -#define SMBIOS_INTERMEDIATE_OFFSET 16 -#define SMBIOS_STRUCT_EOS_BYTES 2 - -struct __packed smbios_entry { - u8 anchor[4]; - u8 checksum; - u8 length; - u8 major_ver; - u8 minor_ver; - u16 max_struct_size; - u8 entry_point_rev; - u8 formatted_area[5]; - u8 intermediate_anchor[5]; - u8 intermediate_checksum; - u16 struct_table_length; - u32 struct_table_address; - u16 struct_count; - u8 bcd_rev; -}; - -/* BIOS characteristics */ -#define BIOS_CHARACTERISTICS_PCI_SUPPORTED (1 << 7) -#define BIOS_CHARACTERISTICS_UPGRADEABLE (1 << 11) -#define BIOS_CHARACTERISTICS_SELECTABLE_BOOT (1 << 16) - -#define BIOS_CHARACTERISTICS_EXT1_ACPI (1 << 0) -#define BIOS_CHARACTERISTICS_EXT2_TARGET (1 << 2) - -struct __packed smbios_type0 { - u8 type; - u8 length; - u16 handle; - u8 vendor; - u8 bios_ver; - u16 bios_start_segment; - u8 bios_release_date; - u8 bios_rom_size; - u64 bios_characteristics; - u8 bios_characteristics_ext1; - u8 bios_characteristics_ext2; - u8 bios_major_release; - u8 bios_minor_release; - u8 ec_major_release; - u8 ec_minor_release; - char eos[SMBIOS_STRUCT_EOS_BYTES]; -}; - -struct __packed smbios_type1 { - u8 type; - u8 length; - u16 handle; - u8 manufacturer; - u8 product_name; - u8 version; - u8 serial_number; - u8 uuid[16]; - u8 wakeup_type; - u8 sku_number; - u8 family; - char eos[SMBIOS_STRUCT_EOS_BYTES]; -}; - -#define SMBIOS_BOARD_FEATURE_HOSTING (1 << 0) -#define SMBIOS_BOARD_MOTHERBOARD 10 - -struct __packed smbios_type2 { - u8 type; - u8 length; - u16 handle; - u8 manufacturer; - u8 product_name; - u8 version; - u8 serial_number; - u8 asset_tag_number; - u8 feature_flags; - u8 chassis_location; - u16 chassis_handle; - u8 board_type; - char eos[SMBIOS_STRUCT_EOS_BYTES]; -}; - -#define SMBIOS_ENCLOSURE_DESKTOP 3 -#define SMBIOS_STATE_SAFE 3 -#define SMBIOS_SECURITY_NONE 3 - -struct __packed smbios_type3 { - u8 type; - u8 length; - u16 handle; - u8 manufacturer; - u8 chassis_type; - u8 version; - u8 serial_number; - u8 asset_tag_number; - u8 bootup_state; - u8 power_supply_state; - u8 thermal_state; - u8 security_status; - u32 oem_defined; - u8 height; - u8 number_of_power_cords; - u8 element_count; - u8 element_record_length; - char eos[SMBIOS_STRUCT_EOS_BYTES]; -}; - -#define SMBIOS_PROCESSOR_TYPE_CENTRAL 3 -#define SMBIOS_PROCESSOR_STATUS_ENABLED 1 -#define SMBIOS_PROCESSOR_UPGRADE_NONE 6 - -struct __packed smbios_type4 { - u8 type; - u8 length; - u16 handle; - u8 socket_designation; - u8 processor_type; - u8 processor_family; - u8 processor_manufacturer; - u32 processor_id[2]; - u8 processor_version; - u8 voltage; - u16 external_clock; - u16 max_speed; - u16 current_speed; - u8 status; - u8 processor_upgrade; - u16 l1_cache_handle; - u16 l2_cache_handle; - u16 l3_cache_handle; - u8 serial_number; - u8 asset_tag; - u8 part_number; - u8 core_count; - u8 core_enabled; - u8 thread_count; - u16 processor_characteristics; - u16 processor_family2; - u16 core_count2; - u16 core_enabled2; - u16 thread_count2; - char eos[SMBIOS_STRUCT_EOS_BYTES]; -}; - -struct __packed smbios_type32 { - u8 type; - u8 length; - u16 handle; - u8 reserved[6]; - u8 boot_status; - u8 eos[SMBIOS_STRUCT_EOS_BYTES]; -}; - -struct __packed smbios_type127 { - u8 type; - u8 length; - u16 handle; - u8 eos[SMBIOS_STRUCT_EOS_BYTES]; -}; - -struct __packed smbios_header { - u8 type; - u8 length; - u16 handle; -}; - -/** - * fill_smbios_header() - Fill the header of an SMBIOS table - * - * This fills the header of an SMBIOS table structure. - * - * @table: start address of the structure - * @type: the type of structure - * @length: the length of the formatted area of the structure - * @handle: the structure's handle, a unique 16-bit number - */ -static inline void fill_smbios_header(void *table, int type, - int length, int handle) -{ - struct smbios_header *header = table; - - header->type = type; - header->length = length - SMBIOS_STRUCT_EOS_BYTES; - header->handle = handle; -} - -/** - * Function prototype to write a specific type of SMBIOS structure - * - * @addr: start address to write the structure - * @handle: the structure's handle, a unique 16-bit number - * @return: size of the structure - */ -typedef int (*smbios_write_type)(u32 *addr, int handle); - -/** - * write_smbios_table() - Write SMBIOS table - * - * This writes SMBIOS table at a given address. - * - * @addr: start address to write SMBIOS table - * @return: end address of SMBIOS table - */ -u32 write_smbios_table(u32 addr); - -#endif /* _SMBIOS_H_ */ diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index e17f0bb..40ea6bf 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -29,7 +29,6 @@ obj-y += relocate.o obj-y += physmem.o obj-$(CONFIG_X86_RAMTEST) += ramtest.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/smbios.c b/arch/x86/lib/smbios.c deleted file mode 100644 index 9f30550..0000000 --- a/arch/x86/lib/smbios.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright (C) 2015, Bin Meng - * - * Adapted from coreboot src/arch/x86/smbios.c - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include - -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(u32 *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); - t->bios_rom_size = (CONFIG_ROM_SIZE / 65536) - 1; - 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 - 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(u32 *current, int handle) -{ - struct smbios_type1 *t = (struct smbios_type1 *)*current; - int len = sizeof(struct smbios_type1); - - 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); - - len = t->length + smbios_string_table_len(t->eos); - *current += len; - - return len; -} - -static int smbios_write_type2(u32 *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(u32 *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 int smbios_write_type4(u32 *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); - 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(u32 *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(u32 *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 -}; - -u32 write_smbios_table(u32 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/arch/x86/lib/tables.c b/arch/x86/lib/tables.c index 9ee6b5e..e62705a 100644 --- a/arch/x86/lib/tables.c +++ b/arch/x86/lib/tables.c @@ -5,9 +5,9 @@ */ #include +#include #include #include -#include #include #include #include diff --git a/include/smbios.h b/include/smbios.h new file mode 100644 index 0000000..623a703 --- /dev/null +++ b/include/smbios.h @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2015, Bin Meng + * + * Adapted from coreboot src/include/smbios.h + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _SMBIOS_H_ +#define _SMBIOS_H_ + +/* SMBIOS spec version implemented */ +#define SMBIOS_MAJOR_VER 3 +#define SMBIOS_MINOR_VER 0 + +/* SMBIOS structure types */ +enum { + SMBIOS_BIOS_INFORMATION = 0, + SMBIOS_SYSTEM_INFORMATION = 1, + SMBIOS_BOARD_INFORMATION = 2, + SMBIOS_SYSTEM_ENCLOSURE = 3, + SMBIOS_PROCESSOR_INFORMATION = 4, + SMBIOS_CACHE_INFORMATION = 7, + SMBIOS_SYSTEM_SLOTS = 9, + SMBIOS_PHYS_MEMORY_ARRAY = 16, + SMBIOS_MEMORY_DEVICE = 17, + SMBIOS_MEMORY_ARRAY_MAPPED_ADDRESS = 19, + SMBIOS_SYSTEM_BOOT_INFORMATION = 32, + SMBIOS_END_OF_TABLE = 127 +}; + +#define SMBIOS_INTERMEDIATE_OFFSET 16 +#define SMBIOS_STRUCT_EOS_BYTES 2 + +struct __packed smbios_entry { + u8 anchor[4]; + u8 checksum; + u8 length; + u8 major_ver; + u8 minor_ver; + u16 max_struct_size; + u8 entry_point_rev; + u8 formatted_area[5]; + u8 intermediate_anchor[5]; + u8 intermediate_checksum; + u16 struct_table_length; + u32 struct_table_address; + u16 struct_count; + u8 bcd_rev; +}; + +/* BIOS characteristics */ +#define BIOS_CHARACTERISTICS_PCI_SUPPORTED (1 << 7) +#define BIOS_CHARACTERISTICS_UPGRADEABLE (1 << 11) +#define BIOS_CHARACTERISTICS_SELECTABLE_BOOT (1 << 16) + +#define BIOS_CHARACTERISTICS_EXT1_ACPI (1 << 0) +#define BIOS_CHARACTERISTICS_EXT2_TARGET (1 << 2) + +struct __packed smbios_type0 { + u8 type; + u8 length; + u16 handle; + u8 vendor; + u8 bios_ver; + u16 bios_start_segment; + u8 bios_release_date; + u8 bios_rom_size; + u64 bios_characteristics; + u8 bios_characteristics_ext1; + u8 bios_characteristics_ext2; + u8 bios_major_release; + u8 bios_minor_release; + u8 ec_major_release; + u8 ec_minor_release; + char eos[SMBIOS_STRUCT_EOS_BYTES]; +}; + +struct __packed smbios_type1 { + u8 type; + u8 length; + u16 handle; + u8 manufacturer; + u8 product_name; + u8 version; + u8 serial_number; + u8 uuid[16]; + u8 wakeup_type; + u8 sku_number; + u8 family; + char eos[SMBIOS_STRUCT_EOS_BYTES]; +}; + +#define SMBIOS_BOARD_FEATURE_HOSTING (1 << 0) +#define SMBIOS_BOARD_MOTHERBOARD 10 + +struct __packed smbios_type2 { + u8 type; + u8 length; + u16 handle; + u8 manufacturer; + u8 product_name; + u8 version; + u8 serial_number; + u8 asset_tag_number; + u8 feature_flags; + u8 chassis_location; + u16 chassis_handle; + u8 board_type; + char eos[SMBIOS_STRUCT_EOS_BYTES]; +}; + +#define SMBIOS_ENCLOSURE_DESKTOP 3 +#define SMBIOS_STATE_SAFE 3 +#define SMBIOS_SECURITY_NONE 3 + +struct __packed smbios_type3 { + u8 type; + u8 length; + u16 handle; + u8 manufacturer; + u8 chassis_type; + u8 version; + u8 serial_number; + u8 asset_tag_number; + u8 bootup_state; + u8 power_supply_state; + u8 thermal_state; + u8 security_status; + u32 oem_defined; + u8 height; + u8 number_of_power_cords; + u8 element_count; + u8 element_record_length; + char eos[SMBIOS_STRUCT_EOS_BYTES]; +}; + +#define SMBIOS_PROCESSOR_TYPE_CENTRAL 3 +#define SMBIOS_PROCESSOR_STATUS_ENABLED 1 +#define SMBIOS_PROCESSOR_UPGRADE_NONE 6 + +struct __packed smbios_type4 { + u8 type; + u8 length; + u16 handle; + u8 socket_designation; + u8 processor_type; + u8 processor_family; + u8 processor_manufacturer; + u32 processor_id[2]; + u8 processor_version; + u8 voltage; + u16 external_clock; + u16 max_speed; + u16 current_speed; + u8 status; + u8 processor_upgrade; + u16 l1_cache_handle; + u16 l2_cache_handle; + u16 l3_cache_handle; + u8 serial_number; + u8 asset_tag; + u8 part_number; + u8 core_count; + u8 core_enabled; + u8 thread_count; + u16 processor_characteristics; + u16 processor_family2; + u16 core_count2; + u16 core_enabled2; + u16 thread_count2; + char eos[SMBIOS_STRUCT_EOS_BYTES]; +}; + +struct __packed smbios_type32 { + u8 type; + u8 length; + u16 handle; + u8 reserved[6]; + u8 boot_status; + u8 eos[SMBIOS_STRUCT_EOS_BYTES]; +}; + +struct __packed smbios_type127 { + u8 type; + u8 length; + u16 handle; + u8 eos[SMBIOS_STRUCT_EOS_BYTES]; +}; + +struct __packed smbios_header { + u8 type; + u8 length; + u16 handle; +}; + +/** + * fill_smbios_header() - Fill the header of an SMBIOS table + * + * This fills the header of an SMBIOS table structure. + * + * @table: start address of the structure + * @type: the type of structure + * @length: the length of the formatted area of the structure + * @handle: the structure's handle, a unique 16-bit number + */ +static inline void fill_smbios_header(void *table, int type, + int length, int handle) +{ + struct smbios_header *header = table; + + header->type = type; + header->length = length - SMBIOS_STRUCT_EOS_BYTES; + header->handle = handle; +} + +/** + * Function prototype to write a specific type of SMBIOS structure + * + * @addr: start address to write the structure + * @handle: the structure's handle, a unique 16-bit number + * @return: size of the structure + */ +typedef int (*smbios_write_type)(u32 *addr, int handle); + +/** + * write_smbios_table() - Write SMBIOS table + * + * This writes SMBIOS table at a given address. + * + * @addr: start address to write SMBIOS table + * @return: end address of SMBIOS table + */ +u32 write_smbios_table(u32 addr); + +#endif /* _SMBIOS_H_ */ diff --git a/lib/Kconfig b/lib/Kconfig index 0e0d8ef..4c098c0 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 + +config GENERATE_SMBIOS_TABLE + bool "Generate an SMBIOS (System Management BIOS) table" + default y + depends on X86 + 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 3842e7d..23e9f1e 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 diff --git a/lib/smbios.c b/lib/smbios.c new file mode 100644 index 0000000..9808ee7 --- /dev/null +++ b/lib/smbios.c @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2015, Bin Meng + * + * Adapted from coreboot src/arch/x86/smbios.c + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +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(u32 *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); + t->bios_rom_size = (CONFIG_ROM_SIZE / 65536) - 1; + 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 + 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(u32 *current, int handle) +{ + struct smbios_type1 *t = (struct smbios_type1 *)*current; + int len = sizeof(struct smbios_type1); + + 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); + + len = t->length + smbios_string_table_len(t->eos); + *current += len; + + return len; +} + +static int smbios_write_type2(u32 *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(u32 *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 int smbios_write_type4(u32 *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); + 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(u32 *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(u32 *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 +}; + +u32 write_smbios_table(u32 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; +} -- cgit v0.10.2 From 488bf12d842e51b8d596f104bc9bd9aa4d0501b6 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 19 Aug 2016 01:23:24 +0200 Subject: efi_loader: Expose efi_install_configuration_table We want to be able to add configuration table entries from our own code as well as from EFI payload code. Export the boot service function internally too, so that we can reuse it. Signed-off-by: Alexander Graf Reviewed-by: Simon Glass diff --git a/include/efi_loader.h b/include/efi_loader.h index 1e4eb46..56b2b47 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -135,6 +135,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; diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 6c8d93b..51961d2 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -37,7 +37,7 @@ 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]; /* * The "gd" pointer lives in a register on ARM and AArch64 that we declare @@ -376,31 +376,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; - 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, @@ -751,7 +755,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, -- cgit v0.10.2 From e824cf3fb5857ef452bb84018da854328d816514 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 19 Aug 2016 01:23:25 +0200 Subject: smbios: Allow compilation on 64bit systems The SMBIOS generation code passes pointers as u32. That causes the compiler to warn on casts to pointers. This patch moves all address pointers to uintptr_t instead. Technically u32 would be enough for the current SMBIOS2 style tables, but we may want to extend the code to SMBIOS3 in the future which is 64bit address capable. Signed-off-by: Alexander Graf Reviewed-by: Bin Meng Reviewed-by: Simon Glass diff --git a/arch/x86/lib/tables.c b/arch/x86/lib/tables.c index e62705a..025b183 100644 --- a/arch/x86/lib/tables.c +++ b/arch/x86/lib/tables.c @@ -12,6 +12,11 @@ #include #include +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/include/smbios.h b/include/smbios.h index 623a703..5962d4c 100644 --- a/include/smbios.h +++ b/include/smbios.h @@ -221,7 +221,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 +231,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/smbios.c b/lib/smbios.c index 9808ee7..8dfd486 100644 --- a/lib/smbios.c +++ b/lib/smbios.c @@ -69,7 +69,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); @@ -98,7 +98,7 @@ 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); @@ -114,7 +114,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 +132,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,7 +152,7 @@ static int smbios_write_type3(u32 *current, int handle) return len; } -static int smbios_write_type4(u32 *current, int handle) +static int smbios_write_type4(uintptr_t *current, int handle) { struct smbios_type4 *t = (struct smbios_type4 *)*current; int len = sizeof(struct smbios_type4); @@ -185,7 +185,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 +198,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 +221,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; -- cgit v0.10.2 From 6f192ddcbd8e13351a8f13365e7c714e7b61a79e Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 19 Aug 2016 01:23:26 +0200 Subject: cpu: Add DMTF id and family fields For SMBIOS tables we need to know the CPU family as well as CPU IDs. This patches allocates some space for them in the cpu device and populates it on x86. Signed-off-by: Alexander Graf Reviewed-by: Simon Glass Reviewed-by: Bin Meng diff --git a/arch/x86/cpu/cpu_x86.c b/arch/x86/cpu/cpu_x86.c index 0941041..39004ee 100644 --- a/arch/x86/cpu/cpu_x86.c +++ b/arch/x86/cpu/cpu_x86.c @@ -15,9 +15,14 @@ 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; } diff --git a/include/cpu.h b/include/cpu.h index bda5315..7d4486b 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 */ -- cgit v0.10.2 From 94eaa79cecf98300974c99d935ff653c9418de21 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 19 Aug 2016 01:23:27 +0200 Subject: cpu: Add get_vendor callback The CPU udevice already has a few callbacks to retreive information about the currently running CPUs. This patch adds a new get_vendor() call that returns the vendor of the main CPUs. Signed-off-by: Alexander Graf Reviewed-by: Simon Glass Reviewed-by: Bin Meng 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 @@ 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 3ba21aa..6977e86 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 39004ee..157f3de 100644 --- a/arch/x86/cpu/cpu_x86.c +++ b/arch/x86/cpu/cpu_x86.c @@ -27,6 +27,18 @@ int cpu_x86_bind(struct udevice *dev) 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) @@ -65,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 b074367..09b5342 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/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_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/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 @@ 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 7d4486b..9542577 100644 --- a/include/cpu.h +++ b/include/cpu.h @@ -73,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) @@ -104,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 -- cgit v0.10.2 From 96476206c54ee9c94e5994d96f52ec9d2063967a Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 19 Aug 2016 01:23:28 +0200 Subject: smbios: Generate type 4 on non-x86 systems The type 4 table generation code is very x86 centric today. Refactor things out into the device model cpu class to allow the tables to get generated for other architectures as well. Signed-off-by: Alexander Graf Reviewed-by: Simon Glass Reviewed-by: Bin Meng diff --git a/include/smbios.h b/include/smbios.h index 5962d4c..3cbc687 100644 --- a/include/smbios.h +++ b/include/smbios.h @@ -139,6 +139,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; diff --git a/lib/smbios.c b/lib/smbios.c index 8dfd486..09a90ca 100644 --- a/lib/smbios.c +++ b/lib/smbios.c @@ -10,7 +10,11 @@ #include #include #include -#include +#ifdef CONFIG_CPU +#include +#include +#include +#endif DECLARE_GLOBAL_DATA_PTR; @@ -152,26 +156,47 @@ static int smbios_write_type3(uintptr_t *current, int handle) 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); - 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; -- cgit v0.10.2 From e663b350f1699312281ddd1439dda6b5fc86598d Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 19 Aug 2016 01:23:29 +0200 Subject: smbios: Expose in efi_loader as table We can pass SMBIOS easily as EFI configuration table to an EFI payload. This patch adds enablement for that case. While at it, we also enable SMBIOS generation for ARM systems, since they support EFI_LOADER. Signed-off-by: Alexander Graf Reviewed-by: Bin Meng Reviewed-by: Simon Glass diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 38c3b41..aa5a01e 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -205,6 +205,9 @@ 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; #endif +#ifdef CONFIG_GENERATE_SMBIOS_TABLE + efi_smbios_register(); +#endif /* Initialize EFI runtime services */ efi_reset_system_init(); 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 @@ 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 56b2b47..1bc3b33 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); diff --git a/include/smbios.h b/include/smbios.h index 3cbc687..d582d4f 100644 --- a/include/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 { diff --git a/lib/Kconfig b/lib/Kconfig index 4c098c0..b16062f 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -164,12 +164,12 @@ config FDT_FIXUP_PARTITIONS variable. menu "System tables" - depends on !EFI && !SYS_COREBOOT + 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 + depends on X86 || EFI_LOADER help The System Management BIOS (SMBIOS) specification addresses how motherboard and system vendors present management information about 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-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_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 +#include +#include +#include + +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 index 09a90ca..237f5f0 100644 --- a/lib/smbios.c +++ b/lib/smbios.c @@ -83,14 +83,20 @@ static int smbios_write_type0(uintptr_t *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; -- cgit v0.10.2 From aba5e9194b98988162e5bd026dbcb6627a53efe5 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 19 Aug 2016 01:23:30 +0200 Subject: efi_loader: Fix efi_install_configuration_table So far we were only installing the FDT table and didn't have space to store any other. Hence nobody realized that our efi table allocation was broken in that it didn't set the indicator for the number of tables plus one. This patch fixes it, allowing code to allocate new efi tables. Signed-off-by: Alexander Graf Reviewed-by: Simon Glass diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 51961d2..17f1927 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -395,7 +395,7 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *table /* 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_SUCCESS; } -- cgit v0.10.2 From 6fb580d7b41069461093296a0f1059cf294a44dd Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 19 Aug 2016 01:23:31 +0200 Subject: smbios: Provide serial number If the system has a valid "serial#" environment variable set (which boards that can find it out programatically set automatically), use that as input for the serial number and UUID fields in the SMBIOS tables. Signed-off-by: Alexander Graf Reviewed-by: Bin Meng Reviewed-by: Simon Glass diff --git a/lib/smbios.c b/lib/smbios.c index 237f5f0..ce1974d 100644 --- a/lib/smbios.c +++ b/lib/smbios.c @@ -112,11 +112,16 @@ 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; -- cgit v0.10.2 From a0b49bc3341f8f19cbf57a56d110ab0fa8f39267 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 25 Sep 2016 15:27:31 -0600 Subject: efi: Use asmlinkage for EFIAPI This is required for x86 and is also correct for ARM (since it is empty). Signed-off-by: Simon Glass Reviewed-by: Bin Meng Signed-off-by: Alexander Graf diff --git a/arch/avr32/include/asm/linkage.h b/arch/avr32/include/asm/linkage.h new file mode 100644 index 0000000..e69de29 diff --git a/arch/m68k/include/asm/linkage.h b/arch/m68k/include/asm/linkage.h new file mode 100644 index 0000000..e69de29 diff --git a/arch/microblaze/include/asm/linkage.h b/arch/microblaze/include/asm/linkage.h new file mode 100644 index 0000000..e69de29 diff --git a/arch/mips/include/asm/linkage.h b/arch/mips/include/asm/linkage.h new file mode 100644 index 0000000..e69de29 diff --git a/arch/nios2/include/asm/linkage.h b/arch/nios2/include/asm/linkage.h new file mode 100644 index 0000000..e69de29 diff --git a/arch/openrisc/include/asm/linkage.h b/arch/openrisc/include/asm/linkage.h new file mode 100644 index 0000000..e69de29 diff --git a/arch/sandbox/include/asm/linkage.h b/arch/sandbox/include/asm/linkage.h new file mode 100644 index 0000000..e69de29 diff --git a/arch/sh/include/asm/linkage.h b/arch/sh/include/asm/linkage.h new file mode 100644 index 0000000..e69de29 diff --git a/arch/sparc/include/asm/linkage.h b/arch/sparc/include/asm/linkage.h new file mode 100644 index 0000000..e69de29 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 #include #include @@ -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; -- cgit v0.10.2 From e275458c2f011a7e66ac01e6558f15f4cf4972f9 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 25 Sep 2016 15:27:32 -0600 Subject: efi: Fix missing EFIAPI specifiers These are missing in some functions. Add them to keep things consistent. Signed-off-by: Simon Glass Reviewed-by: Bin Meng Reviewed-by: Alexander Graf Signed-off-by: Alexander Graf diff --git a/cmd/bootefi.c b/cmd/bootefi.c index aa5a01e..8714666 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include 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 }; diff --git a/include/efi_loader.h b/include/efi_loader.h index 1bc3b33..871499f 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -95,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); diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 17f1927..ac26375 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -160,7 +160,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 */ @@ -169,7 +169,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, 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 @@ 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_net.c b/lib/efi_loader/efi_net.c index 6a8a0d7..3796496 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -198,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) { @@ -210,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) { -- cgit v0.10.2 From 65e4c0b168651285adeab66f32f3a14668f3e4bd Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 25 Sep 2016 15:27:35 -0600 Subject: x86: efi: Add EFI loader support for x86 Add the required pieces to support the EFI loader on x86. Since U-Boot only builds for 32-bit on x86, only a 32-bit EFI application is supported. If a 64-bit kernel must be booted, U-Boot supports this directly using FIT (see doc/uImage.FIT/kernel.its). U-Boot can act as a payload for both 32-bit and 64-bit EFI. Signed-off-by: Simon Glass Reviewed-by: Bin Meng Signed-off-by: Alexander Graf 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 @@ 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/lib/Makefile b/arch/x86/lib/Makefile index 40ea6bf..b9c2922 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -28,6 +28,7 @@ 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-y += string.o ifndef CONFIG_QEMU 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 + * + * 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/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index ac26375..476ef1b 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -39,6 +39,7 @@ static bool efi_is_direct_boot = true; */ 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[2]; * 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; } diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index f73e6d9..f007ca6 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -44,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 +#define R_RELATIVE R_386_RELATIVE +#define R_MASK 0xffULL #else #error Need to add relocation awareness #endif -- cgit v0.10.2 From 3c63db9ca9765c85bbcf2a06f4183cfb0036ea33 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 14 Oct 2016 13:45:30 +0200 Subject: efi_loader: Rename EFI_RUNTIME_{TEXT, DATA} to __efi_runtime{, _data} Compiler attributes are more commonly __foo style tags rather than big upper case eye sores like EFI_RUNTIME_TEXT. Simon Glass felt quite strongly about this, so this patch converts our existing defines over to more eye friendly ones. Signed-off-by: Alexander Graf Reviewed-by: Simon Glass diff --git a/arch/arm/cpu/armv8/fwcall.c b/arch/arm/cpu/armv8/fwcall.c index 64539f9..7dfd270 100644 --- a/arch/arm/cpu/armv8/fwcall.c +++ b/arch/arm/cpu/armv8/fwcall.c @@ -18,7 +18,7 @@ * x0~x7: input arguments * x0~x3: output arguments */ -static void EFI_RUNTIME_TEXT hvc_call(struct pt_regs *args) +static void __efi_runtime hvc_call(struct pt_regs *args) { asm volatile( "ldr x0, %0\n" @@ -52,7 +52,7 @@ static void EFI_RUNTIME_TEXT hvc_call(struct pt_regs *args) * x0~x3: output arguments */ -void EFI_RUNTIME_TEXT smc_call(struct pt_regs *args) +void __efi_runtime smc_call(struct pt_regs *args) { asm volatile( "ldr x0, %0\n" @@ -82,9 +82,9 @@ void EFI_RUNTIME_TEXT smc_call(struct pt_regs *args) * 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; +static const __efi_runtime_data bool use_smc_for_psci = true; -void __noreturn EFI_RUNTIME_TEXT psci_system_reset(void) +void __noreturn __efi_runtime psci_system_reset(void) { struct pt_regs regs; @@ -99,7 +99,7 @@ void __noreturn EFI_RUNTIME_TEXT psci_system_reset(void) ; } -void __noreturn EFI_RUNTIME_TEXT psci_system_off(void) +void __noreturn __efi_runtime psci_system_off(void) { struct pt_regs regs; @@ -121,7 +121,7 @@ void reset_misc(void) } #ifdef CONFIG_EFI_LOADER -void EFI_RUNTIME_TEXT EFIAPI efi_reset_system( +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) diff --git a/include/efi_loader.h b/include/efi_loader.h index 871499f..35b3fe2 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -156,8 +156,8 @@ 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 */ @@ -165,13 +165,13 @@ void efi_add_runtime_mmio(void *mmio_ptr, u64 len); /* Boards may provide the functions below to implement RTS functionality */ -void EFI_RUNTIME_TEXT EFIAPI efi_reset_system( +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_TEXT EFIAPI efi_get_time( +efi_status_t __efi_runtime EFIAPI efi_get_time( struct efi_time *time, struct efi_time_cap *capabilities); void efi_get_time_init(void); @@ -179,8 +179,8 @@ 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 */ diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 476ef1b..1fdddf4 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -37,7 +37,7 @@ 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[2]; +static struct efi_configuration_table __efi_runtime_data efi_conf_table[2]; #ifdef CONFIG_ARM /* @@ -790,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_runtime.c b/lib/efi_loader/efi_runtime.c index f007ca6..dd52755 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -26,9 +26,9 @@ struct efi_runtime_mmio_list { /* This list contains all runtime available mmio regions */ LIST_HEAD(efi_runtime_mmio); -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); +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 @@ -125,7 +125,7 @@ static efi_status_t EFIAPI efi_get_time_boottime( /* Boards may override the helpers below to implement RTS functionality */ -void __weak EFI_RUNTIME_TEXT EFIAPI efi_reset_system( +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) @@ -138,7 +138,7 @@ void __weak efi_reset_system_init(void) { } -efi_status_t __weak EFI_RUNTIME_TEXT EFIAPI efi_get_time( +efi_status_t __weak __efi_runtime EFIAPI efi_get_time( struct efi_time *time, struct efi_time_cap *capabilities) { @@ -346,7 +346,7 @@ void efi_add_runtime_mmio(void *mmio_ptr, u64 len) * 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. */ /* @@ -355,22 +355,22 @@ void efi_add_runtime_mmio(void *mmio_ptr, u64 len) * 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, -- cgit v0.10.2 From 3fb97e267a5e136d8386a7cb1d5b4fe63af518eb Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 18 Oct 2016 15:49:40 +0200 Subject: efi_loader: Revert device_handle to disk after net boot When you boot an efi payload from network, then exit that payload and load another payload from disk afterwords, the disk payload will currently see the network device as its boot path. This breaks grub2 for example which tries to find its modules based on the path it was loaded from. This patch fixes that issue by always reverting to disk paths if we're not in the network boot. That way the data structures after a network boot look the same as before. Signed-off-by: Alexander Graf diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 8714666..c8079c4 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -207,6 +207,8 @@ 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(); -- cgit v0.10.2