diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Kconfig | 21 | ||||
-rw-r--r-- | lib/Makefile | 3 | ||||
-rw-r--r-- | lib/efi_selftest/Makefile | 1 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_el.c | 46 | ||||
-rw-r--r-- | lib/initcall.c | 102 | ||||
-rw-r--r-- | lib/smbios.c | 2 | ||||
-rw-r--r-- | lib/time.c | 9 | ||||
-rw-r--r-- | lib/uthread.c | 165 | ||||
-rw-r--r-- | lib/uuid.c | 9 |
9 files changed, 248 insertions, 110 deletions
diff --git a/lib/Kconfig b/lib/Kconfig index ac34ec45bb1..b2aecd8a49e 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -1258,6 +1258,27 @@ config PHANDLE_CHECK_SEQ enable this config option to distinguish them using phandles in fdtdec_get_alias_seq() function. +config UTHREAD + bool "Enable thread support" + depends on HAVE_INITJMP + help + Implement a simple form of cooperative multi-tasking based on + context-switching via initjmp(), setjmp() and longjmp(). The + uthread_ interface enables the main thread of execution to create + one or more secondary threads and schedule them until they all have + returned. At any point a thread may suspend its execution and + schedule another thread, which allows for the efficient multiplexing + of leghthy operations. + +config UTHREAD_STACK_SIZE + int "Default uthread stack size" + depends on UTHREAD + default 32768 + help + The default stack size for uthreads. Each uthread has its own stack. + When the stack_sz argument to uthread_create() is zero then this + value is used. + endmenu source "lib/fwu_updates/Kconfig" diff --git a/lib/Makefile b/lib/Makefile index 24876bc2622..18ae0cd87bf 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -43,7 +43,6 @@ endif obj-$(CONFIG_SMBIOS_PARSER) += smbios-parser.o obj-$(CONFIG_IMAGE_SPARSE) += image-sparse.o -obj-y += initcall.o obj-y += ldiv.o obj-$(CONFIG_XXHASH) += xxhash.o obj-y += net_utils.o @@ -160,6 +159,8 @@ obj-$(CONFIG_LIB_ELF) += elf.o obj-$(CONFIG_$(PHASE_)SEMIHOSTING) += semihosting.o +obj-$(CONFIG_UTHREAD) += uthread.o + # # Build a fast OID lookup registry from include/linux/oid_registry.h # diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 17fbfad116f..d78bf7d6191 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -51,6 +51,7 @@ efi_selftest_variables_runtime.o \ efi_selftest_watchdog.o obj-$(CONFIG_EFI_ECPT) += efi_selftest_ecpt.o +obj-$(CONFIG_ARM64) += efi_selftest_el.o obj-$(CONFIG_NETDEVICES) += efi_selftest_snp.o obj-$(CONFIG_EFI_HTTP_PROTOCOL) += efi_selftest_http.o obj-$(CONFIG_EFI_HTTP_PROTOCOL) += efi_selftest_ipconfig.o diff --git a/lib/efi_selftest/efi_selftest_el.c b/lib/efi_selftest/efi_selftest_el.c new file mode 100644 index 00000000000..f9941caf22d --- /dev/null +++ b/lib/efi_selftest/efi_selftest_el.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Check current exception level on ARMv8. + */ +#include <efi_loader.h> +#include <efi_selftest.h> + +/** + * current_exception_level() + * + * Return: current exception level, 0 - 3 + */ +static unsigned int current_exception_level(void) +{ + unsigned long el; + + asm volatile ( + "MRS %0, CurrentEL" + : "=r" (el) : : ); + + return (el >> 2) & 0x3; +} + +/** + * execute() - execute test + * + * Check that the exception level is not EL3. + */ +static int execute(void) +{ + unsigned int el = current_exception_level(); + + efi_st_printf("Exception level EL%u\n", el); + if (el != 1 && el != 2) { + efi_st_error("EL1 or EL2 expected"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(el) = { + .name = "exception level", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .execute = execute, +}; diff --git a/lib/initcall.c b/lib/initcall.c deleted file mode 100644 index 2686b9aed5c..00000000000 --- a/lib/initcall.c +++ /dev/null @@ -1,102 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 2013 The Chromium OS Authors. - */ - -#include <efi.h> -#include <initcall.h> -#include <log.h> -#include <relocate.h> -#include <asm/global_data.h> - -DECLARE_GLOBAL_DATA_PTR; - -static ulong calc_reloc_ofs(void) -{ -#ifdef CONFIG_EFI_APP - return (ulong)image_base; -#endif - /* - * Sandbox is relocated by the OS, so symbols always appear at - * the relocated address. - */ - if (IS_ENABLED(CONFIG_SANDBOX) || (gd->flags & GD_FLG_RELOC)) - return gd->reloc_off; - - return 0; -} - -/** - * initcall_is_event() - Get the event number for an initcall - * - * func: Function pointer to check - * Return: Event number, if this is an event, else 0 - */ -static int initcall_is_event(init_fnc_t func) -{ - ulong val = (ulong)func; - - if ((val & INITCALL_IS_EVENT) == INITCALL_IS_EVENT) - return val & INITCALL_EVENT_TYPE; - - return 0; -} - -/* - * To enable debugging. add #define DEBUG at the top of the including file. - * - * To find a symbol, use grep on u-boot.map - */ -int initcall_run_list(const init_fnc_t init_sequence[]) -{ - ulong reloc_ofs; - const init_fnc_t *ptr; - enum event_t type; - init_fnc_t func; - int ret = 0; - - for (ptr = init_sequence; func = *ptr, func; ptr++) { - reloc_ofs = calc_reloc_ofs(); - type = initcall_is_event(func); - - if (type) { - if (!CONFIG_IS_ENABLED(EVENT)) - continue; - debug("initcall: event %d/%s\n", type, - event_type_name(type)); - } else if (reloc_ofs) { - debug("initcall: %p (relocated to %p)\n", - (char *)func - reloc_ofs, (char *)func); - } else { - debug("initcall: %p\n", (char *)func - reloc_ofs); - } - - ret = type ? event_notify_null(type) : func(); - if (ret) - break; - } - - if (ret) { - if (CONFIG_IS_ENABLED(EVENT)) { - char buf[60]; - - /* don't worry about buf size as we are dying here */ - if (type) { - sprintf(buf, "event %d/%s", type, - event_type_name(type)); - } else { - sprintf(buf, "call %p", - (char *)func - reloc_ofs); - } - - printf("initcall failed at %s (err=%dE)\n", buf, ret); - } else { - printf("initcall failed at call %p (err=%d)\n", - (char *)func - reloc_ofs, ret); - } - - return ret; - } - - return 0; -} diff --git a/lib/smbios.c b/lib/smbios.c index 7c9701a57f9..b8c2846277a 100644 --- a/lib/smbios.c +++ b/lib/smbios.c @@ -950,7 +950,7 @@ ulong write_smbios_table(ulong addr) ctx.subnode_name = NULL; if (method->subnode_name) { ctx.subnode_name = method->subnode_name; - if (IS_ENABLED(CONFIG_OF_CONTROL)) + if (ofnode_valid(parent_node)) ctx.node = ofnode_find_subnode(parent_node, method->subnode_name); } diff --git a/lib/time.c b/lib/time.c index d88edafb196..0e9b079f9cf 100644 --- a/lib/time.c +++ b/lib/time.c @@ -17,6 +17,7 @@ #include <asm/global_data.h> #include <asm/io.h> #include <linux/delay.h> +#include <uthread.h> #ifndef CFG_WD_PERIOD # define CFG_WD_PERIOD (10 * 1000 * 1000) /* 10 seconds default */ @@ -197,7 +198,13 @@ void udelay(unsigned long usec) do { schedule(); kv = usec > CFG_WD_PERIOD ? CFG_WD_PERIOD : usec; - __udelay(kv); + if (CONFIG_IS_ENABLED(UTHREAD)) { + ulong t0 = timer_get_us(); + while (timer_get_us() - t0 < kv) + uthread_schedule(); + } else { + __udelay(kv); + } usec -= kv; } while(usec); } diff --git a/lib/uthread.c b/lib/uthread.c new file mode 100644 index 00000000000..062fca7d209 --- /dev/null +++ b/lib/uthread.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 Ahmad Fatoum, Pengutronix + * Copyright (C) 2025 Linaro Limited + * + * An implementation of cooperative multi-tasking inspired from barebox threads + * https://github.com/barebox/barebox/blob/master/common/bthread.c + */ + +#include <compiler.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <malloc.h> +#include <setjmp.h> +#include <stdint.h> +#include <uthread.h> + +static struct uthread main_thread = { + .list = LIST_HEAD_INIT(main_thread.list), +}; + +static struct uthread *current = &main_thread; + +/** + * uthread_trampoline() - Call the current thread's entry point then resume the + * main thread. + * + * This is a helper function which is used as the @func argument to the + * initjmp() function, and ultimately invoked via setjmp(). It does not return + * but instead longjmp()'s back to the main thread. + */ +static void __noreturn uthread_trampoline(void) +{ + struct uthread *curr = current; + + curr->fn(curr->arg); + curr->done = true; + current = &main_thread; + longjmp(current->ctx, 1); + /* Not reached */ + while (true) + ; +} + +/** + * uthread_free() - Free memory used by a uthread object. + */ +static void uthread_free(struct uthread *uthread) +{ + if (!uthread) + return; + free(uthread->stack); + free(uthread); +} + +int uthread_create(struct uthread *uthr, void (*fn)(void *), void *arg, + size_t stack_sz, unsigned int grp_id) +{ + bool user_allocated = false; + + if (!stack_sz) + stack_sz = CONFIG_UTHREAD_STACK_SIZE; + + if (uthr) { + user_allocated = true; + } else { + uthr = calloc(1, sizeof(*uthr)); + if (!uthr) + return -1; + } + + uthr->stack = memalign(16, stack_sz); + if (!uthr->stack) + goto err; + + uthr->fn = fn; + uthr->arg = arg; + uthr->grp_id = grp_id; + + list_add_tail(&uthr->list, ¤t->list); + + initjmp(uthr->ctx, uthread_trampoline, uthr->stack, stack_sz); + + return 0; +err: + if (!user_allocated) + free(uthr); + return -1; +} + +/** + * uthread_resume() - switch execution to a given thread + * + * @uthread: the thread object that should be resumed + */ +static void uthread_resume(struct uthread *uthread) +{ + if (!setjmp(current->ctx)) { + current = uthread; + longjmp(uthread->ctx, 1); + } +} + +bool uthread_schedule(void) +{ + struct uthread *next; + struct uthread *tmp; + + list_for_each_entry_safe(next, tmp, ¤t->list, list) { + if (!next->done) { + uthread_resume(next); + return true; + } + /* Found a 'done' thread, free its resources */ + list_del(&next->list); + uthread_free(next); + } + return false; +} + +unsigned int uthread_grp_new_id(void) +{ + static unsigned int id; + + return ++id; +} + +bool uthread_grp_done(unsigned int grp_id) +{ + struct uthread *next; + + list_for_each_entry(next, &main_thread.list, list) { + if (next->grp_id == grp_id && !next->done) + return false; + } + + return true; +} + +int uthread_mutex_lock(struct uthread_mutex *mutex) +{ + while (mutex->state == UTHREAD_MUTEX_LOCKED) + uthread_schedule(); + + mutex->state = UTHREAD_MUTEX_LOCKED; + return 0; +} + +int uthread_mutex_trylock(struct uthread_mutex *mutex) +{ + if (mutex->state == UTHREAD_MUTEX_UNLOCKED) { + mutex->state = UTHREAD_MUTEX_LOCKED; + return 0; + } + + return -EBUSY; +} + +int uthread_mutex_unlock(struct uthread_mutex *mutex) +{ + mutex->state = UTHREAD_MUTEX_UNLOCKED; + + return 0; +} diff --git a/lib/uuid.c b/lib/uuid.c index 75658778044..6abbcf27b1f 100644 --- a/lib/uuid.c +++ b/lib/uuid.c @@ -67,8 +67,11 @@ static const struct { efi_guid_t guid; } list_guid[] = { #ifndef USE_HOSTCC +#if defined(CONFIG_PARTITION_TYPE_GUID) || defined(CONFIG_CMD_EFIDEBUG) || \ + defined(CONFIG_EFI) + {"EFI System Partition", PARTITION_SYSTEM_GUID}, +#endif #ifdef CONFIG_PARTITION_TYPE_GUID - {"system", PARTITION_SYSTEM_GUID}, {"mbr", LEGACY_MBR_PARTITION_GUID}, {"msft", PARTITION_MSFT_RESERVED_GUID}, {"data", PARTITION_BASIC_DATA_GUID}, @@ -182,10 +185,6 @@ static const struct { { "TCG2", EFI_TCG2_PROTOCOL_GUID, - }, - { - "System Partition", - PARTITION_SYSTEM_GUID }, { "Firmware Management", |