1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 #pragma once
3 
4 #include <efi.h>
5 #include <efilib.h>
6 
7 #include "string-util-fundamental.h"
8 
9 #define offsetof(type, member) __builtin_offsetof(type, member)
10 
11 #define UINTN_MAX (~(UINTN)0)
12 #define INTN_MAX ((INTN)(UINTN_MAX>>1))
13 #ifndef UINT32_MAX
14 #define UINT32_MAX ((UINT32) -1)
15 #endif
16 #ifndef UINT64_MAX
17 #define UINT64_MAX ((UINT64) -1)
18 #endif
19 
20 /* gnu-efi format specifiers for integers are fixed to either 64bit with 'l' and 32bit without a size prefix.
21  * We rely on %u/%d/%x to format regular ints, so ensure the size is what we expect. At the same time, we also
22  * need specifiers for (U)INTN which are native (pointer) sized. */
23 assert_cc(sizeof(int) == sizeof(UINT32));
24 #if __SIZEOF_POINTER__ == 4
25 #  define PRIuN L"u"
26 #  define PRIiN L"d"
27 #elif __SIZEOF_POINTER__ == 8
28 #  define PRIuN L"lu"
29 #  define PRIiN L"ld"
30 #else
31 #  error "Unexpected pointer size"
32 #endif
33 
34 #define xnew_alloc(type, n, alloc)                                           \
35         ({                                                                   \
36                 UINTN _alloc_size;                                           \
37                 assert_se(!__builtin_mul_overflow(sizeof(type), (n), &_alloc_size)); \
38                 (type *) alloc(_alloc_size);                                 \
39         })
40 
41 #define xallocate_pool(size) ASSERT_SE_PTR(AllocatePool(size))
42 #define xallocate_zero_pool(size) ASSERT_SE_PTR(AllocateZeroPool(size))
43 #define xreallocate_pool(p, old_size, new_size) ASSERT_SE_PTR(ReallocatePool((p), (old_size), (new_size)))
44 #define xpool_print(fmt, ...) ((CHAR16 *) ASSERT_SE_PTR(PoolPrint((fmt), ##__VA_ARGS__)))
45 #define xstrdup(str) ((CHAR16 *) ASSERT_SE_PTR(StrDuplicate(str)))
46 #define xnew(type, n) xnew_alloc(type, (n), xallocate_pool)
47 #define xnew0(type, n) xnew_alloc(type, (n), xallocate_zero_pool)
48 
49 EFI_STATUS parse_boolean(const CHAR8 *v, BOOLEAN *b);
50 
51 EFI_STATUS efivar_set(const EFI_GUID *vendor, const CHAR16 *name, const CHAR16 *value, UINT32 flags);
52 EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, const CHAR16 *name, const void *buf, UINTN size, UINT32 flags);
53 EFI_STATUS efivar_set_uint_string(const EFI_GUID *vendor, const CHAR16 *name, UINTN i, UINT32 flags);
54 EFI_STATUS efivar_set_uint32_le(const EFI_GUID *vendor, const CHAR16 *NAME, UINT32 value, UINT32 flags);
55 EFI_STATUS efivar_set_uint64_le(const EFI_GUID *vendor, const CHAR16 *name, UINT64 value, UINT32 flags);
56 void efivar_set_time_usec(const EFI_GUID *vendor, const CHAR16 *name, UINT64 usec);
57 
58 EFI_STATUS efivar_get(const EFI_GUID *vendor, const CHAR16 *name, CHAR16 **value);
59 EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, const CHAR16 *name, CHAR8 **buffer, UINTN *size);
60 EFI_STATUS efivar_get_uint_string(const EFI_GUID *vendor, const CHAR16 *name, UINTN *i);
61 EFI_STATUS efivar_get_uint32_le(const EFI_GUID *vendor, const CHAR16 *name, UINT32 *ret);
62 EFI_STATUS efivar_get_uint64_le(const EFI_GUID *vendor, const CHAR16 *name, UINT64 *ret);
63 EFI_STATUS efivar_get_boolean_u8(const EFI_GUID *vendor, const CHAR16 *name, BOOLEAN *ret);
64 
65 CHAR8 *strchra(const CHAR8 *s, CHAR8 c);
66 CHAR16 *xstra_to_path(const CHAR8 *stra);
67 CHAR16 *xstra_to_str(const CHAR8 *stra);
68 
69 EFI_STATUS file_read(EFI_FILE *dir, const CHAR16 *name, UINTN off, UINTN size, CHAR8 **content, UINTN *content_size);
70 
free_poolp(void * p)71 static inline void free_poolp(void *p) {
72         void *q = *(void**) p;
73 
74         if (!q)
75                 return;
76 
77         (void) BS->FreePool(q);
78 }
79 
80 #define _cleanup_freepool_ _cleanup_(free_poolp)
81 
file_closep(EFI_FILE ** handle)82 static inline void file_closep(EFI_FILE **handle) {
83         if (!*handle)
84                 return;
85 
86         (*handle)->Close(*handle);
87 }
88 
89 /*
90  * Allocated random UUID, intended to be shared across tools that implement
91  * the (ESP)\loader\entries\<vendor>-<revision>.conf convention and the
92  * associated EFI variables.
93  */
94 #define LOADER_GUID \
95         &(const EFI_GUID) { 0x4a67b082, 0x0a4c, 0x41cf, { 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f } }
96 #define EFI_GLOBAL_GUID &(const EFI_GUID) EFI_GLOBAL_VARIABLE
97 
98 void log_error_stall(const CHAR16 *fmt, ...);
99 EFI_STATUS log_oom(void);
100 
101 /* This works just like log_error_errno() from userspace, but requires you
102  * to provide err a second time if you want to use %r in the message! */
103 #define log_error_status_stall(err, fmt, ...) \
104         ({ \
105                 log_error_stall(fmt, ##__VA_ARGS__); \
106                 err; \
107         })
108 
109 void print_at(UINTN x, UINTN y, UINTN attr, const CHAR16 *str);
110 void clear_screen(UINTN attr);
111 
112 typedef INTN (*compare_pointer_func_t)(const void *a, const void *b);
113 void sort_pointer_array(void **array, UINTN n_members, compare_pointer_func_t compare);
114 
115 EFI_STATUS get_file_info_harder(EFI_FILE *handle, EFI_FILE_INFO **ret, UINTN *ret_size);
116 
117 EFI_STATUS readdir_harder(EFI_FILE *handle, EFI_FILE_INFO **buffer, UINTN *buffer_size);
118 
119 UINTN strnlena(const CHAR8 *p, UINTN maxlen);
120 CHAR8 *xstrndup8(const CHAR8 *p, UINTN sz);
121 INTN strncasecmpa(const CHAR8 *a, const CHAR8 *b, UINTN maxlen);
strncaseeqa(const CHAR8 * a,const CHAR8 * b,UINTN maxlen)122 static inline BOOLEAN strncaseeqa(const CHAR8 *a, const CHAR8 *b, UINTN maxlen) {
123         return strncasecmpa(a, b, maxlen) == 0;
124 }
125 
126 BOOLEAN is_ascii(const CHAR16 *f);
127 
128 CHAR16 **strv_free(CHAR16 **l);
129 
strv_freep(CHAR16 *** p)130 static inline void strv_freep(CHAR16 ***p) {
131         strv_free(*p);
132 }
133 
134 EFI_STATUS open_directory(EFI_FILE *root_dir, const CHAR16 *path, EFI_FILE **ret);
135 
136 /* Conversion between EFI_PHYSICAL_ADDRESS and pointers is not obvious. The former is always 64bit, even on
137  * 32bit archs. And gcc complains if we cast a pointer to an integer of a different size. Hence let's do the
138  * conversion indirectly: first into UINTN (which is defined by UEFI to have the same size as a pointer), and
139  * then extended to EFI_PHYSICAL_ADDRESS. */
POINTER_TO_PHYSICAL_ADDRESS(const void * p)140 static inline EFI_PHYSICAL_ADDRESS POINTER_TO_PHYSICAL_ADDRESS(const void *p) {
141         return (EFI_PHYSICAL_ADDRESS) (UINTN) p;
142 }
143 
PHYSICAL_ADDRESS_TO_POINTER(EFI_PHYSICAL_ADDRESS addr)144 static inline void *PHYSICAL_ADDRESS_TO_POINTER(EFI_PHYSICAL_ADDRESS addr) {
145 #if __SIZEOF_POINTER__ == 4
146         /* On 32bit systems the address might not be convertible (as pointers are 32bit but
147          * EFI_PHYSICAL_ADDRESS 64bit) */
148         assert(addr <= UINT32_MAX);
149 #elif __SIZEOF_POINTER__ != 8
150         #error "Unexpected pointer size"
151 #endif
152 
153         return (void*) (UINTN) addr;
154 }
155 
156 UINT64 get_os_indications_supported(void);
157 
158 #ifdef EFI_DEBUG
159 void debug_break(void);
160 extern UINT8 _text, _data;
161 /* Report the relocated position of text and data sections so that a debugger
162  * can attach to us. See debug-sd-boot.sh for how this can be done. */
163 #  define debug_hook(identity) Print(identity L"@0x%lx,0x%lx\n", POINTER_TO_PHYSICAL_ADDRESS(&_text), POINTER_TO_PHYSICAL_ADDRESS(&_data))
164 #else
165 #  define debug_hook(identity)
166 #endif
167 
168 #if defined(__i386__) || defined(__x86_64__)
169 void beep(UINTN beep_count);
170 #else
beep(UINTN beep_count)171 static inline void beep(UINTN beep_count) {}
172 #endif
173