]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/efi/util.h
db48f7add54533ba45baff89c3151efa46aaa34a
[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_freepool_ _cleanup_free_
45 #define _cleanup_free_ _cleanup_(freep)
46
47 _malloc_ _alloc_(1) _returns_nonnull_ _warn_unused_result_
48 static inline void *xmalloc(size_t size) {
49 void *p;
50 assert_se(BS->AllocatePool(EfiBootServicesData, size, &p) == EFI_SUCCESS);
51 return p;
52 }
53
54 _malloc_ _alloc_(1, 2) _returns_nonnull_ _warn_unused_result_
55 static inline void *xmalloc_multiply(size_t size, size_t n) {
56 assert_se(!__builtin_mul_overflow(size, n, &size));
57 return xmalloc(size);
58 }
59
60 /* Use malloc attribute as this never returns p like userspace realloc. */
61 _malloc_ _alloc_(3) _returns_nonnull_ _warn_unused_result_
62 static inline void *xrealloc(void *p, size_t old_size, size_t new_size) {
63 void *r = xmalloc(new_size);
64 efi_memcpy(r, p, MIN(old_size, new_size));
65 free(p);
66 return r;
67 }
68
69 #define xpool_print(fmt, ...) ((char16_t *) ASSERT_SE_PTR(PoolPrint((fmt), ##__VA_ARGS__)))
70 #define xnew(type, n) ((type *) xmalloc_multiply(sizeof(type), (n)))
71
72 EFI_STATUS parse_boolean(const CHAR8 *v, BOOLEAN *b);
73
74 EFI_STATUS efivar_set(const EFI_GUID *vendor, const char16_t *name, const char16_t *value, uint32_t flags);
75 EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, const char16_t *name, const void *buf, UINTN size, uint32_t flags);
76 EFI_STATUS efivar_set_uint_string(const EFI_GUID *vendor, const char16_t *name, UINTN i, uint32_t flags);
77 EFI_STATUS efivar_set_uint32_le(const EFI_GUID *vendor, const char16_t *NAME, uint32_t value, uint32_t flags);
78 EFI_STATUS efivar_set_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t value, uint32_t flags);
79 void efivar_set_time_usec(const EFI_GUID *vendor, const char16_t *name, uint64_t usec);
80
81 EFI_STATUS efivar_get(const EFI_GUID *vendor, const char16_t *name, char16_t **value);
82 EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, const char16_t *name, CHAR8 **buffer, UINTN *size);
83 EFI_STATUS efivar_get_uint_string(const EFI_GUID *vendor, const char16_t *name, UINTN *i);
84 EFI_STATUS efivar_get_uint32_le(const EFI_GUID *vendor, const char16_t *name, uint32_t *ret);
85 EFI_STATUS efivar_get_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t *ret);
86 EFI_STATUS efivar_get_boolean_u8(const EFI_GUID *vendor, const char16_t *name, BOOLEAN *ret);
87
88 char16_t *xstra_to_path(const CHAR8 *stra);
89 char16_t *xstra_to_str(const CHAR8 *stra);
90
91 EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, UINTN off, UINTN size, CHAR8 **content, UINTN *content_size);
92
93 static inline void file_closep(EFI_FILE **handle) {
94 if (!*handle)
95 return;
96
97 (*handle)->Close(*handle);
98 }
99
100 static inline void unload_imagep(EFI_HANDLE *image) {
101 if (*image)
102 (void) BS->UnloadImage(*image);
103 }
104
105 /*
106 * Allocated random UUID, intended to be shared across tools that implement
107 * the (ESP)\loader\entries\<vendor>-<revision>.conf convention and the
108 * associated EFI variables.
109 */
110 #define LOADER_GUID \
111 &(const EFI_GUID) { 0x4a67b082, 0x0a4c, 0x41cf, { 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f } }
112 #define EFI_GLOBAL_GUID &(const EFI_GUID) EFI_GLOBAL_VARIABLE
113
114 void log_error_stall(const char16_t *fmt, ...);
115 EFI_STATUS log_oom(void);
116
117 /* This works just like log_error_errno() from userspace, but requires you
118 * to provide err a second time if you want to use %r in the message! */
119 #define log_error_status_stall(err, fmt, ...) \
120 ({ \
121 log_error_stall(fmt, ##__VA_ARGS__); \
122 err; \
123 })
124
125 void print_at(UINTN x, UINTN y, UINTN attr, const char16_t *str);
126 void clear_screen(UINTN attr);
127
128 typedef int (*compare_pointer_func_t)(const void *a, const void *b);
129 void sort_pointer_array(void **array, UINTN n_members, compare_pointer_func_t compare);
130
131 EFI_STATUS get_file_info_harder(EFI_FILE *handle, EFI_FILE_INFO **ret, UINTN *ret_size);
132
133 EFI_STATUS readdir_harder(EFI_FILE *handle, EFI_FILE_INFO **buffer, UINTN *buffer_size);
134
135 BOOLEAN is_ascii(const char16_t *f);
136
137 char16_t **strv_free(char16_t **l);
138
139 static inline void strv_freep(char16_t ***p) {
140 strv_free(*p);
141 }
142
143 EFI_STATUS open_directory(EFI_FILE *root_dir, const char16_t *path, EFI_FILE **ret);
144
145 /* Conversion between EFI_PHYSICAL_ADDRESS and pointers is not obvious. The former is always 64bit, even on
146 * 32bit archs. And gcc complains if we cast a pointer to an integer of a different size. Hence let's do the
147 * conversion indirectly: first into UINTN (which is defined by UEFI to have the same size as a pointer), and
148 * then extended to EFI_PHYSICAL_ADDRESS. */
149 static inline EFI_PHYSICAL_ADDRESS POINTER_TO_PHYSICAL_ADDRESS(const void *p) {
150 return (EFI_PHYSICAL_ADDRESS) (UINTN) p;
151 }
152
153 static inline void *PHYSICAL_ADDRESS_TO_POINTER(EFI_PHYSICAL_ADDRESS addr) {
154 #if __SIZEOF_POINTER__ == 4
155 /* On 32bit systems the address might not be convertible (as pointers are 32bit but
156 * EFI_PHYSICAL_ADDRESS 64bit) */
157 assert(addr <= UINT32_MAX);
158 #elif __SIZEOF_POINTER__ != 8
159 #error "Unexpected pointer size"
160 #endif
161
162 return (void*) (UINTN) addr;
163 }
164
165 uint64_t get_os_indications_supported(void);
166
167 #ifdef EFI_DEBUG
168 void debug_break(void);
169 extern uint8_t _text, _data;
170 /* Report the relocated position of text and data sections so that a debugger
171 * can attach to us. See debug-sd-boot.sh for how this can be done. */
172 # define debug_hook(identity) Print(identity L"@0x%lx,0x%lx\n", POINTER_TO_PHYSICAL_ADDRESS(&_text), POINTER_TO_PHYSICAL_ADDRESS(&_data))
173 #else
174 # define debug_hook(identity)
175 #endif
176
177 #if defined(__i386__) || defined(__x86_64__)
178 void beep(UINTN beep_count);
179 #else
180 static inline void beep(UINTN beep_count) {}
181 #endif
182
183 EFI_STATUS open_volume(EFI_HANDLE device, EFI_FILE **ret_file);
184 EFI_STATUS make_file_device_path(EFI_HANDLE device, const char16_t *file, EFI_DEVICE_PATH **ret_dp);