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