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