1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
8 #include "string-util-fundamental.h"
10 #define UINTN_MAX (~(UINTN)0)
11 #define INTN_MAX ((INTN)(UINTN_MAX>>1))
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
20 #elif __SIZEOF_POINTER__ == 8
24 # error "Unexpected pointer size"
27 static inline void free(void *p
) {
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. */
34 assert_se(BS
->FreePool(p
) == EFI_SUCCESS
);
36 (void) BS
->FreePool(p
);
40 static inline void freep(void *p
) {
44 #define _cleanup_free_ _cleanup_(freep)
46 _malloc_
_alloc_(1) _returns_nonnull_ _warn_unused_result_
47 static inline void *xmalloc(size_t size
) {
49 assert_se(BS
->AllocatePool(EfiBootServicesData
, size
, &p
) == EFI_SUCCESS
);
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
));
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
);
65 memcpy(r
, p
, new_size
);
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)))
74 EFI_PHYSICAL_ADDRESS addr
;
78 static inline void cleanup_pages(Pages
*p
) {
82 assert_se(BS
->FreePages(p
->addr
, p
->n_pages
) == EFI_SUCCESS
);
84 (void) BS
->FreePages(p
->addr
, p
->n_pages
);
88 #define _cleanup_pages_ _cleanup_(cleanup_pages)
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
);
99 EFI_STATUS
parse_boolean(const char *v
, bool *b
);
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
);
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
);
115 char16_t
*xstra_to_path(const char *stra
);
116 char16_t
*xstra_to_str(const char *stra
);
118 EFI_STATUS
file_read(EFI_FILE
*dir
, const char16_t
*name
, UINTN off
, UINTN size
, char **content
, UINTN
*content_size
);
120 static inline void file_closep(EFI_FILE
**handle
) {
124 (*handle
)->Close(*handle
);
127 static inline void unload_imagep(EFI_HANDLE
*image
) {
129 (void) BS
->UnloadImage(*image
);
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.
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
141 void log_error_stall(const char16_t
*fmt
, ...);
142 EFI_STATUS
log_oom(void);
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, ...) \
148 log_error_stall(fmt, ##__VA_ARGS__); \
152 void print_at(UINTN x
, UINTN y
, UINTN attr
, const char16_t
*str
);
153 void clear_screen(UINTN attr
);
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
);
158 EFI_STATUS
get_file_info_harder(EFI_FILE
*handle
, EFI_FILE_INFO
**ret
, UINTN
*ret_size
);
160 EFI_STATUS
readdir_harder(EFI_FILE
*handle
, EFI_FILE_INFO
**buffer
, UINTN
*buffer_size
);
162 bool is_ascii(const char16_t
*f
);
164 char16_t
**strv_free(char16_t
**l
);
166 static inline void strv_freep(char16_t
***p
) {
170 EFI_STATUS
open_directory(EFI_FILE
*root_dir
, const char16_t
*path
, EFI_FILE
**ret
);
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
;
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
;
186 uint64_t get_os_indications_supported(void);
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))
195 # define debug_hook(identity)
199 void hexdump(const char16_t
*prefix
, const void *data
, UINTN size
);
202 #if defined(__i386__) || defined(__x86_64__)
203 void beep(UINTN beep_count
);
205 static inline void beep(UINTN beep_count
) {}
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
);
212 #if defined(__i386__) || defined(__x86_64__)
213 bool in_hypervisor(void);
215 static inline bool in_hypervisor(void) {