]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/boot/efi/util.h
tree-wide: "<n>bit" → "<n>-bit"
[thirdparty/systemd.git] / src / boot / efi / util.h
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
7a3c343c 2#pragma once
0fa2cac4 3
5080a60a 4#include "efi.h"
c2c62035 5#include "log.h"
5080a60a 6#include "proto/file-io.h"
e5bc5f1f
YW
7#include "string-util-fundamental.h"
8
badea0d6
ZJS
9/* This is provided by linker script. */
10extern uint8_t __ImageBase;
11
9148312f
JJ
12static inline void free(void *p) {
13 if (!p)
14 return;
15
16 /* Debugging an invalid free requires trace logging to find the call site or a debugger attached. For
17 * release builds it is not worth the bother to even warn when we cannot even print a call stack. */
18#ifdef EFI_DEBUG
19 assert_se(BS->FreePool(p) == EFI_SUCCESS);
20#else
21 (void) BS->FreePool(p);
22#endif
23}
24
25static inline void freep(void *p) {
26 free(*(void **) p);
27}
28
9148312f
JJ
29#define _cleanup_free_ _cleanup_(freep)
30
31_malloc_ _alloc_(1) _returns_nonnull_ _warn_unused_result_
32static inline void *xmalloc(size_t size) {
33 void *p;
ec232e4a 34 assert_se(BS->AllocatePool(EfiLoaderData, size, &p) == EFI_SUCCESS);
9148312f
JJ
35 return p;
36}
37
38_malloc_ _alloc_(1, 2) _returns_nonnull_ _warn_unused_result_
39static inline void *xmalloc_multiply(size_t size, size_t n) {
40 assert_se(!__builtin_mul_overflow(size, n, &size));
41 return xmalloc(size);
42}
43
44/* Use malloc attribute as this never returns p like userspace realloc. */
45_malloc_ _alloc_(3) _returns_nonnull_ _warn_unused_result_
46static inline void *xrealloc(void *p, size_t old_size, size_t new_size) {
a0e475ce 47 void *t = xmalloc(new_size);
55b5daf9
JJ
48 new_size = MIN(old_size, new_size);
49 if (new_size > 0)
a0e475ce 50 memcpy(t, p, new_size);
9148312f 51 free(p);
a0e475ce 52 return t;
9148312f
JJ
53}
54
0af26643 55#define xnew(type, n) ((type *) xmalloc_multiply(sizeof(type), (n)))
484ddd29 56
09173c91
JJ
57typedef struct {
58 EFI_PHYSICAL_ADDRESS addr;
59 size_t n_pages;
60} Pages;
61
62static inline void cleanup_pages(Pages *p) {
63 if (p->n_pages == 0)
64 return;
65#ifdef EFI_DEBUG
66 assert_se(BS->FreePages(p->addr, p->n_pages) == EFI_SUCCESS);
67#else
68 (void) BS->FreePages(p->addr, p->n_pages);
69#endif
70}
71
72#define _cleanup_pages_ _cleanup_(cleanup_pages)
73
74static inline Pages xmalloc_pages(
75 EFI_ALLOCATE_TYPE type, EFI_MEMORY_TYPE memory_type, size_t n_pages, EFI_PHYSICAL_ADDRESS addr) {
76 assert_se(BS->AllocatePages(type, memory_type, n_pages, &addr) == EFI_SUCCESS);
77 return (Pages) {
78 .addr = addr,
79 .n_pages = n_pages,
80 };
81}
82
e5a1b8f9 83EFI_STATUS parse_boolean(const char *v, bool *b);
4db7e6d7 84
3639d1b0 85EFI_STATUS efivar_set(const EFI_GUID *vendor, const char16_t *name, const char16_t *value, uint32_t flags);
dede50a7
JJ
86EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, const char16_t *name, const void *buf, size_t size, uint32_t flags);
87EFI_STATUS efivar_set_uint_string(const EFI_GUID *vendor, const char16_t *name, size_t i, uint32_t flags);
3639d1b0
JJ
88EFI_STATUS efivar_set_uint32_le(const EFI_GUID *vendor, const char16_t *NAME, uint32_t value, uint32_t flags);
89EFI_STATUS efivar_set_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t value, uint32_t flags);
90void efivar_set_time_usec(const EFI_GUID *vendor, const char16_t *name, uint64_t usec);
0fa2cac4 91
9e406b11 92EFI_STATUS efivar_get(const EFI_GUID *vendor, const char16_t *name, char16_t **ret);
dede50a7
JJ
93EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, const char16_t *name, char **ret, size_t *ret_size);
94EFI_STATUS efivar_get_uint_string(const EFI_GUID *vendor, const char16_t *name, size_t *ret);
3639d1b0
JJ
95EFI_STATUS efivar_get_uint32_le(const EFI_GUID *vendor, const char16_t *name, uint32_t *ret);
96EFI_STATUS efivar_get_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t *ret);
e5a1b8f9 97EFI_STATUS efivar_get_boolean_u8(const EFI_GUID *vendor, const char16_t *name, bool *ret);
0fa2cac4 98
7444e106
JJ
99void convert_efi_path(char16_t *path);
100char16_t *xstr8_to_path(const char *stra);
927ebebe 101void mangle_stub_cmdline(char16_t *cmdline);
0fa2cac4 102
f70f9922 103EFI_STATUS chunked_read(EFI_FILE *file, size_t *size, void *buf);
dede50a7 104EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, size_t off, size_t size, char **content, size_t *content_size);
a42d7cf1 105
85eb489e 106static inline void file_closep(EFI_FILE **handle) {
3aaa95e0
LP
107 if (!*handle)
108 return;
109
12f32748 110 (*handle)->Close(*handle);
3aaa95e0 111}
0e2bc732 112
f386daa0
JJ
113static inline void unload_imagep(EFI_HANDLE *image) {
114 if (*image)
115 (void) BS->UnloadImage(*image);
116}
117
7d2ebb6f
DDM
118/*
119 * Allocated random UUID, intended to be shared across tools that implement
120 * the (ESP)\loader\entries\<vendor>-<revision>.conf convention and the
121 * associated EFI variables.
122 */
123#define LOADER_GUID \
19f08504 124 { 0x4a67b082, 0x0a4c, 0x41cf, { 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f } }
b49dd00f 125
ea592abf
JJ
126/* Note that GUID is evaluated multiple times! */
127#define GUID_FORMAT_STR "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X"
128#define GUID_FORMAT_VAL(g) (g).Data1, (g).Data2, (g).Data3, (g).Data4[0], (g).Data4[1], \
129 (g).Data4[2], (g).Data4[3], (g).Data4[4], (g).Data4[5], (g).Data4[6], (g).Data4[7]
130
dede50a7
JJ
131void print_at(size_t x, size_t y, size_t attr, const char16_t *str);
132void clear_screen(size_t attr);
c6dfe360 133
3d5127c6 134typedef int (*compare_pointer_func_t)(const void *a, const void *b);
dede50a7 135void sort_pointer_array(void **array, size_t n_members, compare_pointer_func_t compare);
80b2f4d9 136
5fa3e628
JJ
137EFI_STATUS get_file_info(EFI_FILE *handle, EFI_FILE_INFO **ret, size_t *ret_size);
138EFI_STATUS readdir(EFI_FILE *handle, EFI_FILE_INFO **buffer, size_t *buffer_size);
c6dfe360 139
e5a1b8f9 140bool is_ascii(const char16_t *f);
c6dfe360 141
3639d1b0 142char16_t **strv_free(char16_t **l);
c6dfe360 143
3639d1b0 144static inline void strv_freep(char16_t ***p) {
c6dfe360
LP
145 strv_free(*p);
146}
147
3639d1b0 148EFI_STATUS open_directory(EFI_FILE *root_dir, const char16_t *path, EFI_FILE **ret);
a0a644be 149
da890466
ZJS
150/* Conversion between EFI_PHYSICAL_ADDRESS and pointers is not obvious. The former is always 64-bit, even on
151 * 32-bit archs. And gcc complains if we cast a pointer to an integer of a different size. Hence let's do the
34938db5 152 * conversion indirectly: first into uintptr_t and then extended to EFI_PHYSICAL_ADDRESS. */
a0a644be 153static inline EFI_PHYSICAL_ADDRESS POINTER_TO_PHYSICAL_ADDRESS(const void *p) {
34938db5 154 return (EFI_PHYSICAL_ADDRESS) (uintptr_t) p;
a0a644be
LP
155}
156
157static inline void *PHYSICAL_ADDRESS_TO_POINTER(EFI_PHYSICAL_ADDRESS addr) {
da890466
ZJS
158 /* On 32-bit systems the address might not be convertible (as pointers are 32-bit but
159 * EFI_PHYSICAL_ADDRESS 64-bit) */
34938db5
JJ
160 assert(addr <= UINTPTR_MAX);
161 return (void *) (uintptr_t) addr;
a0a644be 162}
3a624912 163
db4122d1 164uint64_t get_os_indications_supported(void);
948d085e 165
badea0d6
ZJS
166/* If EFI_DEBUG, print our name and version and also report the address of the image base so a debugger can
167 * be attached. See debug-sd-boot.sh for how this can be done. */
831b6a7f 168void notify_debugger(const char *identity, bool wait);
badea0d6 169
b87d6da4
JJ
170/* On x86 the compiler assumes a different incoming stack alignment than what we get.
171 * This will cause long long variables to be misaligned when building with
172 * '-mlong-double' (for correct struct layouts). Normally, the compiler realigns the
173 * stack itself on entry, but we have to do this ourselves here as the compiler does
174 * not know that this is our entry point. */
175#ifdef __i386__
176# define _realign_stack_ __attribute__((force_align_arg_pointer))
177#else
178# define _realign_stack_
179#endif
180
2afeaf16
JJ
181#define DEFINE_EFI_MAIN_FUNCTION(func, identity, wait_for_debugger) \
182 EFI_SYSTEM_TABLE *ST; \
183 EFI_BOOT_SERVICES *BS; \
184 EFI_RUNTIME_SERVICES *RT; \
b87d6da4 185 _realign_stack_ \
0b482b37 186 EFIAPI EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *system_table); \
2afeaf16
JJ
187 EFIAPI EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *system_table) { \
188 ST = system_table; \
189 BS = system_table->BootServices; \
190 RT = system_table->RuntimeServices; \
48e1b2c2 191 __stack_chk_guard_init(); \
2afeaf16
JJ
192 notify_debugger((identity), (wait_for_debugger)); \
193 EFI_STATUS err = func(image); \
194 log_wait(); \
195 return err; \
31a131bb
JJ
196 }
197
85d2f13b 198#if defined(__i386__) || defined(__x86_64__)
54d9ecc3 199void beep(unsigned beep_count);
85d2f13b 200#else
54d9ecc3 201static inline void beep(unsigned beep_count) {}
85d2f13b 202#endif
f747ca3e
JJ
203
204EFI_STATUS open_volume(EFI_HANDLE device, EFI_FILE **ret_file);
bafc5945 205
50b0b0d3
LP
206static inline bool efi_guid_equal(const EFI_GUID *a, const EFI_GUID *b) {
207 return memcmp(a, b, sizeof(EFI_GUID)) == 0;
208}
a04709c1
LP
209
210void *find_configuration_table(const EFI_GUID *guid);
3e8cb05e
LB
211
212char16_t *get_extra_dir(const EFI_DEVICE_PATH *file_path);