]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
7a3c343c | 2 | #pragma once |
0fa2cac4 KS |
3 | |
4 | #include <efi.h> | |
5 | #include <efilib.h> | |
11f9a32d | 6 | #include <stddef.h> |
0fa2cac4 | 7 | |
e5bc5f1f YW |
8 | #include "string-util-fundamental.h" |
9 | ||
88657f75 LP |
10 | #define UINTN_MAX (~(UINTN)0) |
11 | #define INTN_MAX ((INTN)(UINTN_MAX>>1)) | |
88657f75 | 12 | |
0be72218 JD |
13 | #ifdef __OPTIMIZE__ |
14 | #ifndef __has_attribute | |
15 | #define __has_attribute(x) 0 | |
16 | #endif | |
17 | #if __has_attribute(__error__) | |
18 | __attribute__((noreturn)) extern void __assert_cl_failure__(void) __attribute__((__error__("compile-time assertion failed"))); | |
19 | #else | |
20 | __attribute__((noreturn)) extern void __assert_cl_failure__(void); | |
21 | #endif | |
22 | /* assert_cl generates a later-stage compile-time assertion when constant folding occurs. */ | |
23 | #define assert_cl(condition) if (!(condition)) __assert_cl_failure__() | |
24 | #else | |
25 | #define assert_cl(condition) assert(condition) | |
26 | #endif | |
27 | ||
ec4106af JJ |
28 | /* gnu-efi format specifiers for integers are fixed to either 64bit with 'l' and 32bit without a size prefix. |
29 | * We rely on %u/%d/%x to format regular ints, so ensure the size is what we expect. At the same time, we also | |
30 | * need specifiers for (U)INTN which are native (pointer) sized. */ | |
db4122d1 | 31 | assert_cc(sizeof(int) == sizeof(uint32_t)); |
ec4106af JJ |
32 | #if __SIZEOF_POINTER__ == 4 |
33 | # define PRIuN L"u" | |
34 | # define PRIiN L"d" | |
35 | #elif __SIZEOF_POINTER__ == 8 | |
36 | # define PRIuN L"lu" | |
37 | # define PRIiN L"ld" | |
38 | #else | |
39 | # error "Unexpected pointer size" | |
40 | #endif | |
41 | ||
9148312f JJ |
42 | static inline void free(void *p) { |
43 | if (!p) | |
44 | return; | |
45 | ||
46 | /* Debugging an invalid free requires trace logging to find the call site or a debugger attached. For | |
47 | * release builds it is not worth the bother to even warn when we cannot even print a call stack. */ | |
48 | #ifdef EFI_DEBUG | |
49 | assert_se(BS->FreePool(p) == EFI_SUCCESS); | |
50 | #else | |
51 | (void) BS->FreePool(p); | |
52 | #endif | |
53 | } | |
54 | ||
55 | static inline void freep(void *p) { | |
56 | free(*(void **) p); | |
57 | } | |
58 | ||
9148312f JJ |
59 | #define _cleanup_free_ _cleanup_(freep) |
60 | ||
0be72218 JD |
61 | static __always_inline void erase_obj(void *p) { |
62 | size_t l; | |
63 | assert_cl(p != NULL); | |
64 | l = __builtin_object_size(p, 0); | |
65 | assert_cl(l != (size_t) -1); | |
66 | explicit_bzero_safe(p, l); | |
67 | } | |
68 | ||
69 | #define _cleanup_erase_ _cleanup_(erase_obj) | |
70 | ||
9148312f JJ |
71 | _malloc_ _alloc_(1) _returns_nonnull_ _warn_unused_result_ |
72 | static inline void *xmalloc(size_t size) { | |
73 | void *p; | |
74 | assert_se(BS->AllocatePool(EfiBootServicesData, size, &p) == EFI_SUCCESS); | |
75 | return p; | |
76 | } | |
77 | ||
78 | _malloc_ _alloc_(1, 2) _returns_nonnull_ _warn_unused_result_ | |
79 | static inline void *xmalloc_multiply(size_t size, size_t n) { | |
80 | assert_se(!__builtin_mul_overflow(size, n, &size)); | |
81 | return xmalloc(size); | |
82 | } | |
83 | ||
84 | /* Use malloc attribute as this never returns p like userspace realloc. */ | |
85 | _malloc_ _alloc_(3) _returns_nonnull_ _warn_unused_result_ | |
86 | static inline void *xrealloc(void *p, size_t old_size, size_t new_size) { | |
87 | void *r = xmalloc(new_size); | |
55b5daf9 JJ |
88 | new_size = MIN(old_size, new_size); |
89 | if (new_size > 0) | |
90 | memcpy(r, p, new_size); | |
9148312f JJ |
91 | free(p); |
92 | return r; | |
93 | } | |
94 | ||
3639d1b0 | 95 | #define xpool_print(fmt, ...) ((char16_t *) ASSERT_SE_PTR(PoolPrint((fmt), ##__VA_ARGS__))) |
0af26643 | 96 | #define xnew(type, n) ((type *) xmalloc_multiply(sizeof(type), (n))) |
484ddd29 | 97 | |
09173c91 JJ |
98 | typedef struct { |
99 | EFI_PHYSICAL_ADDRESS addr; | |
100 | size_t n_pages; | |
101 | } Pages; | |
102 | ||
103 | static inline void cleanup_pages(Pages *p) { | |
104 | if (p->n_pages == 0) | |
105 | return; | |
106 | #ifdef EFI_DEBUG | |
107 | assert_se(BS->FreePages(p->addr, p->n_pages) == EFI_SUCCESS); | |
108 | #else | |
109 | (void) BS->FreePages(p->addr, p->n_pages); | |
110 | #endif | |
111 | } | |
112 | ||
113 | #define _cleanup_pages_ _cleanup_(cleanup_pages) | |
114 | ||
115 | static inline Pages xmalloc_pages( | |
116 | EFI_ALLOCATE_TYPE type, EFI_MEMORY_TYPE memory_type, size_t n_pages, EFI_PHYSICAL_ADDRESS addr) { | |
117 | assert_se(BS->AllocatePages(type, memory_type, n_pages, &addr) == EFI_SUCCESS); | |
118 | return (Pages) { | |
119 | .addr = addr, | |
120 | .n_pages = n_pages, | |
121 | }; | |
122 | } | |
123 | ||
e5a1b8f9 | 124 | EFI_STATUS parse_boolean(const char *v, bool *b); |
4db7e6d7 | 125 | |
3639d1b0 JJ |
126 | EFI_STATUS efivar_set(const EFI_GUID *vendor, const char16_t *name, const char16_t *value, uint32_t flags); |
127 | EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, const char16_t *name, const void *buf, UINTN size, uint32_t flags); | |
128 | EFI_STATUS efivar_set_uint_string(const EFI_GUID *vendor, const char16_t *name, UINTN i, uint32_t flags); | |
129 | EFI_STATUS efivar_set_uint32_le(const EFI_GUID *vendor, const char16_t *NAME, uint32_t value, uint32_t flags); | |
130 | EFI_STATUS efivar_set_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t value, uint32_t flags); | |
131 | void efivar_set_time_usec(const EFI_GUID *vendor, const char16_t *name, uint64_t usec); | |
0fa2cac4 | 132 | |
3639d1b0 | 133 | EFI_STATUS efivar_get(const EFI_GUID *vendor, const char16_t *name, char16_t **value); |
07d0fde4 | 134 | EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, const char16_t *name, char **buffer, UINTN *size); |
3639d1b0 JJ |
135 | EFI_STATUS efivar_get_uint_string(const EFI_GUID *vendor, const char16_t *name, UINTN *i); |
136 | EFI_STATUS efivar_get_uint32_le(const EFI_GUID *vendor, const char16_t *name, uint32_t *ret); | |
137 | EFI_STATUS efivar_get_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t *ret); | |
e5a1b8f9 | 138 | EFI_STATUS efivar_get_boolean_u8(const EFI_GUID *vendor, const char16_t *name, bool *ret); |
0fa2cac4 | 139 | |
07d0fde4 JJ |
140 | char16_t *xstra_to_path(const char *stra); |
141 | char16_t *xstra_to_str(const char *stra); | |
0fa2cac4 | 142 | |
07d0fde4 | 143 | EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, UINTN off, UINTN size, char **content, UINTN *content_size); |
a42d7cf1 | 144 | |
85eb489e | 145 | static inline void file_closep(EFI_FILE **handle) { |
3aaa95e0 LP |
146 | if (!*handle) |
147 | return; | |
148 | ||
12f32748 | 149 | (*handle)->Close(*handle); |
3aaa95e0 | 150 | } |
0e2bc732 | 151 | |
f386daa0 JJ |
152 | static inline void unload_imagep(EFI_HANDLE *image) { |
153 | if (*image) | |
154 | (void) BS->UnloadImage(*image); | |
155 | } | |
156 | ||
7d2ebb6f DDM |
157 | /* |
158 | * Allocated random UUID, intended to be shared across tools that implement | |
159 | * the (ESP)\loader\entries\<vendor>-<revision>.conf convention and the | |
160 | * associated EFI variables. | |
161 | */ | |
162 | #define LOADER_GUID \ | |
163 | &(const EFI_GUID) { 0x4a67b082, 0x0a4c, 0x41cf, { 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f } } | |
164 | #define EFI_GLOBAL_GUID &(const EFI_GUID) EFI_GLOBAL_VARIABLE | |
b49dd00f | 165 | |
3639d1b0 | 166 | void log_error_stall(const char16_t *fmt, ...); |
b19fa812 | 167 | EFI_STATUS log_oom(void); |
8aba0eec JJ |
168 | |
169 | /* This works just like log_error_errno() from userspace, but requires you | |
170 | * to provide err a second time if you want to use %r in the message! */ | |
171 | #define log_error_status_stall(err, fmt, ...) \ | |
172 | ({ \ | |
173 | log_error_stall(fmt, ##__VA_ARGS__); \ | |
174 | err; \ | |
175 | }) | |
43ee1fe0 | 176 | |
3639d1b0 | 177 | void print_at(UINTN x, UINTN y, UINTN attr, const char16_t *str); |
70cd15e9 | 178 | void clear_screen(UINTN attr); |
c6dfe360 | 179 | |
3d5127c6 | 180 | typedef int (*compare_pointer_func_t)(const void *a, const void *b); |
70cd15e9 | 181 | void sort_pointer_array(void **array, UINTN n_members, compare_pointer_func_t compare); |
80b2f4d9 | 182 | |
85eb489e | 183 | EFI_STATUS get_file_info_harder(EFI_FILE *handle, EFI_FILE_INFO **ret, UINTN *ret_size); |
c6dfe360 | 184 | |
85eb489e | 185 | EFI_STATUS readdir_harder(EFI_FILE *handle, EFI_FILE_INFO **buffer, UINTN *buffer_size); |
c6dfe360 | 186 | |
e5a1b8f9 | 187 | bool is_ascii(const char16_t *f); |
c6dfe360 | 188 | |
3639d1b0 | 189 | char16_t **strv_free(char16_t **l); |
c6dfe360 | 190 | |
3639d1b0 | 191 | static inline void strv_freep(char16_t ***p) { |
c6dfe360 LP |
192 | strv_free(*p); |
193 | } | |
194 | ||
3639d1b0 | 195 | EFI_STATUS open_directory(EFI_FILE *root_dir, const char16_t *path, EFI_FILE **ret); |
a0a644be LP |
196 | |
197 | /* Conversion between EFI_PHYSICAL_ADDRESS and pointers is not obvious. The former is always 64bit, even on | |
198 | * 32bit archs. And gcc complains if we cast a pointer to an integer of a different size. Hence let's do the | |
34938db5 | 199 | * conversion indirectly: first into uintptr_t and then extended to EFI_PHYSICAL_ADDRESS. */ |
a0a644be | 200 | static inline EFI_PHYSICAL_ADDRESS POINTER_TO_PHYSICAL_ADDRESS(const void *p) { |
34938db5 | 201 | return (EFI_PHYSICAL_ADDRESS) (uintptr_t) p; |
a0a644be LP |
202 | } |
203 | ||
204 | static inline void *PHYSICAL_ADDRESS_TO_POINTER(EFI_PHYSICAL_ADDRESS addr) { | |
a0a644be LP |
205 | /* On 32bit systems the address might not be convertible (as pointers are 32bit but |
206 | * EFI_PHYSICAL_ADDRESS 64bit) */ | |
34938db5 JJ |
207 | assert(addr <= UINTPTR_MAX); |
208 | return (void *) (uintptr_t) addr; | |
a0a644be | 209 | } |
3a624912 | 210 | |
db4122d1 | 211 | uint64_t get_os_indications_supported(void); |
948d085e JJ |
212 | |
213 | #ifdef EFI_DEBUG | |
214 | void debug_break(void); | |
db4122d1 | 215 | extern uint8_t _text, _data; |
948d085e JJ |
216 | /* Report the relocated position of text and data sections so that a debugger |
217 | * can attach to us. See debug-sd-boot.sh for how this can be done. */ | |
ec4106af | 218 | # define debug_hook(identity) Print(identity L"@0x%lx,0x%lx\n", POINTER_TO_PHYSICAL_ADDRESS(&_text), POINTER_TO_PHYSICAL_ADDRESS(&_data)) |
948d085e JJ |
219 | #else |
220 | # define debug_hook(identity) | |
221 | #endif | |
85d2f13b | 222 | |
257bc3ef LP |
223 | #ifdef EFI_DEBUG |
224 | void hexdump(const char16_t *prefix, const void *data, UINTN size); | |
225 | #endif | |
226 | ||
85d2f13b | 227 | #if defined(__i386__) || defined(__x86_64__) |
cc25bedb | 228 | void beep(UINTN beep_count); |
85d2f13b | 229 | #else |
cc25bedb | 230 | static inline void beep(UINTN beep_count) {} |
85d2f13b | 231 | #endif |
f747ca3e JJ |
232 | |
233 | EFI_STATUS open_volume(EFI_HANDLE device, EFI_FILE **ret_file); | |
79a2b916 | 234 | EFI_STATUS make_file_device_path(EFI_HANDLE device, const char16_t *file, EFI_DEVICE_PATH **ret_dp); |
3b3eb196 | 235 | EFI_STATUS device_path_to_str(const EFI_DEVICE_PATH *dp, char16_t **ret); |
bafc5945 JJ |
236 | |
237 | #if defined(__i386__) || defined(__x86_64__) | |
238 | bool in_hypervisor(void); | |
239 | #else | |
240 | static inline bool in_hypervisor(void) { | |
241 | return false; | |
242 | } | |
243 | #endif |