]>
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 | ||
9148312f JJ |
9 | static inline void free(void *p) { |
10 | if (!p) | |
11 | return; | |
12 | ||
13 | /* Debugging an invalid free requires trace logging to find the call site or a debugger attached. For | |
14 | * release builds it is not worth the bother to even warn when we cannot even print a call stack. */ | |
15 | #ifdef EFI_DEBUG | |
16 | assert_se(BS->FreePool(p) == EFI_SUCCESS); | |
17 | #else | |
18 | (void) BS->FreePool(p); | |
19 | #endif | |
20 | } | |
21 | ||
22 | static inline void freep(void *p) { | |
23 | free(*(void **) p); | |
24 | } | |
25 | ||
9148312f JJ |
26 | #define _cleanup_free_ _cleanup_(freep) |
27 | ||
28 | _malloc_ _alloc_(1) _returns_nonnull_ _warn_unused_result_ | |
29 | static inline void *xmalloc(size_t size) { | |
30 | void *p; | |
31 | assert_se(BS->AllocatePool(EfiBootServicesData, size, &p) == EFI_SUCCESS); | |
32 | return p; | |
33 | } | |
34 | ||
35 | _malloc_ _alloc_(1, 2) _returns_nonnull_ _warn_unused_result_ | |
36 | static inline void *xmalloc_multiply(size_t size, size_t n) { | |
37 | assert_se(!__builtin_mul_overflow(size, n, &size)); | |
38 | return xmalloc(size); | |
39 | } | |
40 | ||
41 | /* Use malloc attribute as this never returns p like userspace realloc. */ | |
42 | _malloc_ _alloc_(3) _returns_nonnull_ _warn_unused_result_ | |
43 | static inline void *xrealloc(void *p, size_t old_size, size_t new_size) { | |
a0e475ce | 44 | void *t = xmalloc(new_size); |
55b5daf9 JJ |
45 | new_size = MIN(old_size, new_size); |
46 | if (new_size > 0) | |
a0e475ce | 47 | memcpy(t, p, new_size); |
9148312f | 48 | free(p); |
a0e475ce | 49 | return t; |
9148312f JJ |
50 | } |
51 | ||
0af26643 | 52 | #define xnew(type, n) ((type *) xmalloc_multiply(sizeof(type), (n))) |
484ddd29 | 53 | |
09173c91 JJ |
54 | typedef struct { |
55 | EFI_PHYSICAL_ADDRESS addr; | |
56 | size_t n_pages; | |
57 | } Pages; | |
58 | ||
59 | static inline void cleanup_pages(Pages *p) { | |
60 | if (p->n_pages == 0) | |
61 | return; | |
62 | #ifdef EFI_DEBUG | |
63 | assert_se(BS->FreePages(p->addr, p->n_pages) == EFI_SUCCESS); | |
64 | #else | |
65 | (void) BS->FreePages(p->addr, p->n_pages); | |
66 | #endif | |
67 | } | |
68 | ||
69 | #define _cleanup_pages_ _cleanup_(cleanup_pages) | |
70 | ||
71 | static inline Pages xmalloc_pages( | |
72 | EFI_ALLOCATE_TYPE type, EFI_MEMORY_TYPE memory_type, size_t n_pages, EFI_PHYSICAL_ADDRESS addr) { | |
73 | assert_se(BS->AllocatePages(type, memory_type, n_pages, &addr) == EFI_SUCCESS); | |
74 | return (Pages) { | |
75 | .addr = addr, | |
76 | .n_pages = n_pages, | |
77 | }; | |
78 | } | |
79 | ||
e5a1b8f9 | 80 | EFI_STATUS parse_boolean(const char *v, bool *b); |
4db7e6d7 | 81 | |
3639d1b0 | 82 | EFI_STATUS efivar_set(const EFI_GUID *vendor, const char16_t *name, const char16_t *value, uint32_t flags); |
dede50a7 JJ |
83 | EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, const char16_t *name, const void *buf, size_t size, uint32_t flags); |
84 | EFI_STATUS efivar_set_uint_string(const EFI_GUID *vendor, const char16_t *name, size_t i, uint32_t flags); | |
3639d1b0 JJ |
85 | EFI_STATUS efivar_set_uint32_le(const EFI_GUID *vendor, const char16_t *NAME, uint32_t value, uint32_t flags); |
86 | EFI_STATUS efivar_set_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t value, uint32_t flags); | |
87 | void efivar_set_time_usec(const EFI_GUID *vendor, const char16_t *name, uint64_t usec); | |
0fa2cac4 | 88 | |
9e406b11 | 89 | EFI_STATUS efivar_get(const EFI_GUID *vendor, const char16_t *name, char16_t **ret); |
dede50a7 JJ |
90 | EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, const char16_t *name, char **ret, size_t *ret_size); |
91 | EFI_STATUS efivar_get_uint_string(const EFI_GUID *vendor, const char16_t *name, size_t *ret); | |
3639d1b0 JJ |
92 | EFI_STATUS efivar_get_uint32_le(const EFI_GUID *vendor, const char16_t *name, uint32_t *ret); |
93 | EFI_STATUS efivar_get_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t *ret); | |
e5a1b8f9 | 94 | EFI_STATUS efivar_get_boolean_u8(const EFI_GUID *vendor, const char16_t *name, bool *ret); |
0fa2cac4 | 95 | |
7444e106 JJ |
96 | void convert_efi_path(char16_t *path); |
97 | char16_t *xstr8_to_path(const char *stra); | |
927ebebe | 98 | void mangle_stub_cmdline(char16_t *cmdline); |
0fa2cac4 | 99 | |
dede50a7 | 100 | EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, size_t off, size_t size, char **content, size_t *content_size); |
a42d7cf1 | 101 | |
85eb489e | 102 | static inline void file_closep(EFI_FILE **handle) { |
3aaa95e0 LP |
103 | if (!*handle) |
104 | return; | |
105 | ||
12f32748 | 106 | (*handle)->Close(*handle); |
3aaa95e0 | 107 | } |
0e2bc732 | 108 | |
f386daa0 JJ |
109 | static inline void unload_imagep(EFI_HANDLE *image) { |
110 | if (*image) | |
111 | (void) BS->UnloadImage(*image); | |
112 | } | |
113 | ||
7d2ebb6f DDM |
114 | /* |
115 | * Allocated random UUID, intended to be shared across tools that implement | |
116 | * the (ESP)\loader\entries\<vendor>-<revision>.conf convention and the | |
117 | * associated EFI variables. | |
118 | */ | |
119 | #define LOADER_GUID \ | |
19f08504 | 120 | { 0x4a67b082, 0x0a4c, 0x41cf, { 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f } } |
b49dd00f | 121 | |
ea592abf JJ |
122 | /* Note that GUID is evaluated multiple times! */ |
123 | #define GUID_FORMAT_STR "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" | |
124 | #define GUID_FORMAT_VAL(g) (g).Data1, (g).Data2, (g).Data3, (g).Data4[0], (g).Data4[1], \ | |
125 | (g).Data4[2], (g).Data4[3], (g).Data4[4], (g).Data4[5], (g).Data4[6], (g).Data4[7] | |
126 | ||
dede50a7 JJ |
127 | void print_at(size_t x, size_t y, size_t attr, const char16_t *str); |
128 | void clear_screen(size_t attr); | |
c6dfe360 | 129 | |
3d5127c6 | 130 | typedef int (*compare_pointer_func_t)(const void *a, const void *b); |
dede50a7 | 131 | void sort_pointer_array(void **array, size_t n_members, compare_pointer_func_t compare); |
80b2f4d9 | 132 | |
5fa3e628 JJ |
133 | EFI_STATUS get_file_info(EFI_FILE *handle, EFI_FILE_INFO **ret, size_t *ret_size); |
134 | EFI_STATUS readdir(EFI_FILE *handle, EFI_FILE_INFO **buffer, size_t *buffer_size); | |
c6dfe360 | 135 | |
e5a1b8f9 | 136 | bool is_ascii(const char16_t *f); |
c6dfe360 | 137 | |
3639d1b0 | 138 | char16_t **strv_free(char16_t **l); |
c6dfe360 | 139 | |
3639d1b0 | 140 | static inline void strv_freep(char16_t ***p) { |
c6dfe360 LP |
141 | strv_free(*p); |
142 | } | |
143 | ||
3639d1b0 | 144 | EFI_STATUS open_directory(EFI_FILE *root_dir, const char16_t *path, EFI_FILE **ret); |
a0a644be LP |
145 | |
146 | /* Conversion between EFI_PHYSICAL_ADDRESS and pointers is not obvious. The former is always 64bit, even on | |
147 | * 32bit archs. And gcc complains if we cast a pointer to an integer of a different size. Hence let's do the | |
34938db5 | 148 | * conversion indirectly: first into uintptr_t and then extended to EFI_PHYSICAL_ADDRESS. */ |
a0a644be | 149 | static inline EFI_PHYSICAL_ADDRESS POINTER_TO_PHYSICAL_ADDRESS(const void *p) { |
34938db5 | 150 | return (EFI_PHYSICAL_ADDRESS) (uintptr_t) p; |
a0a644be LP |
151 | } |
152 | ||
153 | static inline void *PHYSICAL_ADDRESS_TO_POINTER(EFI_PHYSICAL_ADDRESS addr) { | |
a0a644be LP |
154 | /* On 32bit systems the address might not be convertible (as pointers are 32bit but |
155 | * EFI_PHYSICAL_ADDRESS 64bit) */ | |
34938db5 JJ |
156 | assert(addr <= UINTPTR_MAX); |
157 | return (void *) (uintptr_t) addr; | |
a0a644be | 158 | } |
3a624912 | 159 | |
db4122d1 | 160 | uint64_t get_os_indications_supported(void); |
948d085e JJ |
161 | |
162 | #ifdef EFI_DEBUG | |
948d085e JJ |
163 | /* Report the relocated position of text and data sections so that a debugger |
164 | * can attach to us. See debug-sd-boot.sh for how this can be done. */ | |
831b6a7f JJ |
165 | void notify_debugger(const char *identity, bool wait); |
166 | void hexdump(const char16_t *prefix, const void *data, size_t size); | |
948d085e | 167 | #else |
831b6a7f | 168 | # define notify_debugger(i, w) |
257bc3ef LP |
169 | #endif |
170 | ||
31a131bb | 171 | #define DEFINE_EFI_MAIN_FUNCTION(func, identity, wait_for_debugger) \ |
1d278ad7 JJ |
172 | EFI_SYSTEM_TABLE *ST; \ |
173 | EFI_BOOT_SERVICES *BS; \ | |
174 | EFI_RUNTIME_SERVICES *RT; \ | |
31a131bb | 175 | EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *system_table) { \ |
1d278ad7 JJ |
176 | ST = system_table; \ |
177 | BS = system_table->BootServices; \ | |
178 | RT = system_table->RuntimeServices; \ | |
31a131bb JJ |
179 | notify_debugger((identity), (wait_for_debugger)); \ |
180 | EFI_STATUS err = func(image); \ | |
181 | log_wait(); \ | |
182 | return err; \ | |
183 | } | |
184 | ||
85d2f13b | 185 | #if defined(__i386__) || defined(__x86_64__) |
54d9ecc3 | 186 | void beep(unsigned beep_count); |
85d2f13b | 187 | #else |
54d9ecc3 | 188 | static inline void beep(unsigned beep_count) {} |
85d2f13b | 189 | #endif |
f747ca3e JJ |
190 | |
191 | EFI_STATUS open_volume(EFI_HANDLE device, EFI_FILE **ret_file); | |
bafc5945 | 192 | |
50b0b0d3 LP |
193 | static inline bool efi_guid_equal(const EFI_GUID *a, const EFI_GUID *b) { |
194 | return memcmp(a, b, sizeof(EFI_GUID)) == 0; | |
195 | } | |
a04709c1 LP |
196 | |
197 | void *find_configuration_table(const EFI_GUID *guid); |