summaryrefslogtreecommitdiffstats
path: root/src/boot/efi/util.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/boot/efi/util.h')
-rw-r--r--src/boot/efi/util.h213
1 files changed, 213 insertions, 0 deletions
diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h
new file mode 100644
index 0000000..0306e32
--- /dev/null
+++ b/src/boot/efi/util.h
@@ -0,0 +1,213 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include "efi.h"
+#include "log.h"
+#include "proto/file-io.h"
+#include "string-util-fundamental.h"
+
+/* This is provided by the linker. */
+extern uint8_t __executable_start[];
+
+static inline void free(void *p) {
+ if (!p)
+ return;
+
+ /* Debugging an invalid free requires trace logging to find the call site or a debugger attached. For
+ * release builds it is not worth the bother to even warn when we cannot even print a call stack. */
+#ifdef EFI_DEBUG
+ assert_se(BS->FreePool(p) == EFI_SUCCESS);
+#else
+ (void) BS->FreePool(p);
+#endif
+}
+
+static inline void freep(void *p) {
+ free(*(void **) p);
+}
+
+#define _cleanup_free_ _cleanup_(freep)
+
+_malloc_ _alloc_(1) _returns_nonnull_ _warn_unused_result_
+void *xmalloc(size_t size);
+
+_malloc_ _alloc_(1, 2) _returns_nonnull_ _warn_unused_result_
+static inline void *xmalloc_multiply(size_t n, size_t size) {
+ assert_se(!__builtin_mul_overflow(size, n, &size));
+ return xmalloc(size);
+}
+
+/* Use malloc attribute as this never returns p like userspace realloc. */
+_malloc_ _alloc_(3) _returns_nonnull_ _warn_unused_result_
+static inline void *xrealloc(void *p, size_t old_size, size_t new_size) {
+ void *t = xmalloc(new_size);
+ new_size = MIN(old_size, new_size);
+ if (new_size > 0)
+ memcpy(t, p, new_size);
+ free(p);
+ return t;
+}
+
+_malloc_ _alloc_(2) _returns_nonnull_ _warn_unused_result_
+static inline void* xmemdup(const void *p, size_t l) {
+ return memcpy(xmalloc(l), p, l);
+}
+
+#define xnew(type, n) ((type *) xmalloc_multiply((n), sizeof(type)))
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS addr;
+ size_t n_pages;
+} Pages;
+
+static inline void cleanup_pages(Pages *p) {
+ if (p->n_pages == 0)
+ return;
+#ifdef EFI_DEBUG
+ assert_se(BS->FreePages(p->addr, p->n_pages) == EFI_SUCCESS);
+#else
+ (void) BS->FreePages(p->addr, p->n_pages);
+#endif
+}
+
+#define _cleanup_pages_ _cleanup_(cleanup_pages)
+
+static inline Pages xmalloc_pages(
+ EFI_ALLOCATE_TYPE type, EFI_MEMORY_TYPE memory_type, size_t n_pages, EFI_PHYSICAL_ADDRESS addr) {
+ assert_se(BS->AllocatePages(type, memory_type, n_pages, &addr) == EFI_SUCCESS);
+ return (Pages) {
+ .addr = addr,
+ .n_pages = n_pages,
+ };
+}
+
+EFI_STATUS efivar_set(const EFI_GUID *vendor, const char16_t *name, const char16_t *value, uint32_t flags);
+EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, const char16_t *name, const void *buf, size_t size, uint32_t flags);
+EFI_STATUS efivar_set_uint_string(const EFI_GUID *vendor, const char16_t *name, size_t i, uint32_t flags);
+EFI_STATUS efivar_set_uint32_le(const EFI_GUID *vendor, const char16_t *NAME, uint32_t value, uint32_t flags);
+EFI_STATUS efivar_set_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t value, uint32_t flags);
+void efivar_set_time_usec(const EFI_GUID *vendor, const char16_t *name, uint64_t usec);
+
+EFI_STATUS efivar_unset(const EFI_GUID *vendor, const char16_t *name, uint32_t flags);
+
+EFI_STATUS efivar_get(const EFI_GUID *vendor, const char16_t *name, char16_t **ret);
+EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, const char16_t *name, char **ret, size_t *ret_size);
+EFI_STATUS efivar_get_uint_string(const EFI_GUID *vendor, const char16_t *name, size_t *ret);
+EFI_STATUS efivar_get_uint32_le(const EFI_GUID *vendor, const char16_t *name, uint32_t *ret);
+EFI_STATUS efivar_get_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t *ret);
+EFI_STATUS efivar_get_boolean_u8(const EFI_GUID *vendor, const char16_t *name, bool *ret);
+
+void convert_efi_path(char16_t *path);
+char16_t *xstr8_to_path(const char *stra);
+char16_t *mangle_stub_cmdline(char16_t *cmdline);
+
+EFI_STATUS chunked_read(EFI_FILE *file, size_t *size, void *buf);
+EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, size_t off, size_t size, char **content, size_t *content_size);
+
+static inline void file_closep(EFI_FILE **handle) {
+ if (!*handle)
+ return;
+
+ (*handle)->Close(*handle);
+}
+
+static inline void unload_imagep(EFI_HANDLE *image) {
+ if (*image)
+ (void) BS->UnloadImage(*image);
+}
+
+/*
+ * Allocated random UUID, intended to be shared across tools that implement
+ * the (ESP)\loader\entries\<vendor>-<revision>.conf convention and the
+ * associated EFI variables.
+ */
+#define LOADER_GUID \
+ { 0x4a67b082, 0x0a4c, 0x41cf, { 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f } }
+
+/* Note that GUID is evaluated multiple times! */
+#define GUID_FORMAT_STR "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X"
+#define GUID_FORMAT_VAL(g) (g).Data1, (g).Data2, (g).Data3, (g).Data4[0], (g).Data4[1], \
+ (g).Data4[2], (g).Data4[3], (g).Data4[4], (g).Data4[5], (g).Data4[6], (g).Data4[7]
+
+void print_at(size_t x, size_t y, size_t attr, const char16_t *str);
+void clear_screen(size_t attr);
+
+typedef int (*compare_pointer_func_t)(const void *a, const void *b);
+void sort_pointer_array(void **array, size_t n_members, compare_pointer_func_t compare);
+
+EFI_STATUS get_file_info(EFI_FILE *handle, EFI_FILE_INFO **ret, size_t *ret_size);
+EFI_STATUS readdir(EFI_FILE *handle, EFI_FILE_INFO **buffer, size_t *buffer_size);
+
+bool is_ascii(const char16_t *f);
+
+char16_t **strv_free(char16_t **l);
+
+static inline void strv_freep(char16_t ***p) {
+ strv_free(*p);
+}
+
+EFI_STATUS open_directory(EFI_FILE *root_dir, const char16_t *path, EFI_FILE **ret);
+
+/* Conversion between EFI_PHYSICAL_ADDRESS and pointers is not obvious. The former is always 64-bit, even on
+ * 32-bit archs. And gcc complains if we cast a pointer to an integer of a different size. Hence let's do the
+ * conversion indirectly: first into uintptr_t and then extended to EFI_PHYSICAL_ADDRESS. */
+static inline EFI_PHYSICAL_ADDRESS POINTER_TO_PHYSICAL_ADDRESS(const void *p) {
+ return (EFI_PHYSICAL_ADDRESS) (uintptr_t) p;
+}
+
+static inline void *PHYSICAL_ADDRESS_TO_POINTER(EFI_PHYSICAL_ADDRESS addr) {
+ /* On 32-bit systems the address might not be convertible (as pointers are 32-bit but
+ * EFI_PHYSICAL_ADDRESS 64-bit) */
+ assert(addr <= UINTPTR_MAX);
+ return (void *) (uintptr_t) addr;
+}
+
+uint64_t get_os_indications_supported(void);
+
+/* If EFI_DEBUG, print our name and version and also report the address of the image base so a debugger can
+ * be attached. See debug-sd-boot.sh for how this can be done. */
+void notify_debugger(const char *identity, bool wait);
+
+/* On x86 the compiler assumes a different incoming stack alignment than what we get.
+ * This will cause long long variables to be misaligned when building with
+ * '-mlong-double' (for correct struct layouts). Normally, the compiler realigns the
+ * stack itself on entry, but we have to do this ourselves here as the compiler does
+ * not know that this is our entry point. */
+#ifdef __i386__
+# define _realign_stack_ __attribute__((force_align_arg_pointer))
+#else
+# define _realign_stack_
+#endif
+
+#define DEFINE_EFI_MAIN_FUNCTION(func, identity, wait_for_debugger) \
+ EFI_SYSTEM_TABLE *ST; \
+ EFI_BOOT_SERVICES *BS; \
+ EFI_RUNTIME_SERVICES *RT; \
+ _realign_stack_ \
+ EFIAPI EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *system_table); \
+ EFIAPI EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *system_table) { \
+ ST = system_table; \
+ BS = system_table->BootServices; \
+ RT = system_table->RuntimeServices; \
+ __stack_chk_guard_init(); \
+ notify_debugger((identity), (wait_for_debugger)); \
+ EFI_STATUS err = func(image); \
+ log_wait(); \
+ return err; \
+ }
+
+#if defined(__i386__) || defined(__x86_64__)
+void beep(unsigned beep_count);
+#else
+static inline void beep(unsigned beep_count) {}
+#endif
+
+EFI_STATUS open_volume(EFI_HANDLE device, EFI_FILE **ret_file);
+
+static inline bool efi_guid_equal(const EFI_GUID *a, const EFI_GUID *b) {
+ return memcmp(a, b, sizeof(EFI_GUID)) == 0;
+}
+
+void *find_configuration_table(const EFI_GUID *guid);
+
+char16_t *get_extra_dir(const EFI_DEVICE_PATH *file_path);