]>
Commit | Line | Data |
---|---|---|
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. */ |
10 | extern uint8_t __ImageBase; | |
11 | ||
9148312f JJ |
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 | ||
9148312f JJ |
29 | #define _cleanup_free_ _cleanup_(freep) |
30 | ||
31 | _malloc_ _alloc_(1) _returns_nonnull_ _warn_unused_result_ | |
32 | static 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_ | |
39 | static 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_ | |
46 | static 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 |
57 | typedef struct { |
58 | EFI_PHYSICAL_ADDRESS addr; | |
59 | size_t n_pages; | |
60 | } Pages; | |
61 | ||
62 | static 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 | ||
74 | static 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 | 83 | EFI_STATUS parse_boolean(const char *v, bool *b); |
4db7e6d7 | 84 | |
3639d1b0 | 85 | EFI_STATUS efivar_set(const EFI_GUID *vendor, const char16_t *name, const char16_t *value, uint32_t flags); |
dede50a7 JJ |
86 | EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, const char16_t *name, const void *buf, size_t size, uint32_t flags); |
87 | EFI_STATUS efivar_set_uint_string(const EFI_GUID *vendor, const char16_t *name, size_t i, uint32_t flags); | |
3639d1b0 JJ |
88 | EFI_STATUS efivar_set_uint32_le(const EFI_GUID *vendor, const char16_t *NAME, uint32_t value, uint32_t flags); |
89 | EFI_STATUS efivar_set_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t value, uint32_t flags); | |
90 | void efivar_set_time_usec(const EFI_GUID *vendor, const char16_t *name, uint64_t usec); | |
0fa2cac4 | 91 | |
9e406b11 | 92 | EFI_STATUS efivar_get(const EFI_GUID *vendor, const char16_t *name, char16_t **ret); |
dede50a7 JJ |
93 | EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, const char16_t *name, char **ret, size_t *ret_size); |
94 | EFI_STATUS efivar_get_uint_string(const EFI_GUID *vendor, const char16_t *name, size_t *ret); | |
3639d1b0 JJ |
95 | EFI_STATUS efivar_get_uint32_le(const EFI_GUID *vendor, const char16_t *name, uint32_t *ret); |
96 | EFI_STATUS efivar_get_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t *ret); | |
e5a1b8f9 | 97 | EFI_STATUS efivar_get_boolean_u8(const EFI_GUID *vendor, const char16_t *name, bool *ret); |
0fa2cac4 | 98 | |
7444e106 JJ |
99 | void convert_efi_path(char16_t *path); |
100 | char16_t *xstr8_to_path(const char *stra); | |
927ebebe | 101 | void mangle_stub_cmdline(char16_t *cmdline); |
0fa2cac4 | 102 | |
f70f9922 | 103 | EFI_STATUS chunked_read(EFI_FILE *file, size_t *size, void *buf); |
dede50a7 | 104 | EFI_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 | 106 | static 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 |
113 | static 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 |
131 | void print_at(size_t x, size_t y, size_t attr, const char16_t *str); |
132 | void clear_screen(size_t attr); | |
c6dfe360 | 133 | |
3d5127c6 | 134 | typedef int (*compare_pointer_func_t)(const void *a, const void *b); |
dede50a7 | 135 | void sort_pointer_array(void **array, size_t n_members, compare_pointer_func_t compare); |
80b2f4d9 | 136 | |
5fa3e628 JJ |
137 | EFI_STATUS get_file_info(EFI_FILE *handle, EFI_FILE_INFO **ret, size_t *ret_size); |
138 | EFI_STATUS readdir(EFI_FILE *handle, EFI_FILE_INFO **buffer, size_t *buffer_size); | |
c6dfe360 | 139 | |
e5a1b8f9 | 140 | bool is_ascii(const char16_t *f); |
c6dfe360 | 141 | |
3639d1b0 | 142 | char16_t **strv_free(char16_t **l); |
c6dfe360 | 143 | |
3639d1b0 | 144 | static inline void strv_freep(char16_t ***p) { |
c6dfe360 LP |
145 | strv_free(*p); |
146 | } | |
147 | ||
3639d1b0 | 148 | EFI_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 | 153 | static inline EFI_PHYSICAL_ADDRESS POINTER_TO_PHYSICAL_ADDRESS(const void *p) { |
34938db5 | 154 | return (EFI_PHYSICAL_ADDRESS) (uintptr_t) p; |
a0a644be LP |
155 | } |
156 | ||
157 | static 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 | 164 | uint64_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 | 168 | void 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 | 199 | void beep(unsigned beep_count); |
85d2f13b | 200 | #else |
54d9ecc3 | 201 | static inline void beep(unsigned beep_count) {} |
85d2f13b | 202 | #endif |
f747ca3e JJ |
203 | |
204 | EFI_STATUS open_volume(EFI_HANDLE device, EFI_FILE **ret_file); | |
bafc5945 | 205 | |
50b0b0d3 LP |
206 | static 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 | |
210 | void *find_configuration_table(const EFI_GUID *guid); | |
3e8cb05e LB |
211 | |
212 | char16_t *get_extra_dir(const EFI_DEVICE_PATH *file_path); |