]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/boot/efi/util.h
boot: implement kernel EFI RNG seed protocol with proper hashing
[thirdparty/systemd.git] / src / boot / efi / util.h
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
7a3c343c 2#pragma once
0fa2cac4
KS
3
4#include <efi.h>
5#include <efilib.h>
11f9a32d 6#include <stddef.h>
0fa2cac4 7
e5bc5f1f
YW
8#include "string-util-fundamental.h"
9
88657f75
LP
10#define UINTN_MAX (~(UINTN)0)
11#define INTN_MAX ((INTN)(UINTN_MAX>>1))
88657f75 12
0be72218
JD
13#ifdef __OPTIMIZE__
14#ifndef __has_attribute
15#define __has_attribute(x) 0
16#endif
17#if __has_attribute(__error__)
18__attribute__((noreturn)) extern void __assert_cl_failure__(void) __attribute__((__error__("compile-time assertion failed")));
19#else
20__attribute__((noreturn)) extern void __assert_cl_failure__(void);
21#endif
22/* assert_cl generates a later-stage compile-time assertion when constant folding occurs. */
23#define assert_cl(condition) if (!(condition)) __assert_cl_failure__()
24#else
25#define assert_cl(condition) assert(condition)
26#endif
27
ec4106af
JJ
28/* gnu-efi format specifiers for integers are fixed to either 64bit with 'l' and 32bit without a size prefix.
29 * We rely on %u/%d/%x to format regular ints, so ensure the size is what we expect. At the same time, we also
30 * need specifiers for (U)INTN which are native (pointer) sized. */
db4122d1 31assert_cc(sizeof(int) == sizeof(uint32_t));
ec4106af
JJ
32#if __SIZEOF_POINTER__ == 4
33# define PRIuN L"u"
34# define PRIiN L"d"
35#elif __SIZEOF_POINTER__ == 8
36# define PRIuN L"lu"
37# define PRIiN L"ld"
38#else
39# error "Unexpected pointer size"
40#endif
41
9148312f
JJ
42static inline void free(void *p) {
43 if (!p)
44 return;
45
46 /* Debugging an invalid free requires trace logging to find the call site or a debugger attached. For
47 * release builds it is not worth the bother to even warn when we cannot even print a call stack. */
48#ifdef EFI_DEBUG
49 assert_se(BS->FreePool(p) == EFI_SUCCESS);
50#else
51 (void) BS->FreePool(p);
52#endif
53}
54
55static inline void freep(void *p) {
56 free(*(void **) p);
57}
58
9148312f
JJ
59#define _cleanup_free_ _cleanup_(freep)
60
0be72218
JD
61static __always_inline void erase_obj(void *p) {
62 size_t l;
63 assert_cl(p != NULL);
64 l = __builtin_object_size(p, 0);
65 assert_cl(l != (size_t) -1);
66 explicit_bzero_safe(p, l);
67}
68
69#define _cleanup_erase_ _cleanup_(erase_obj)
70
9148312f
JJ
71_malloc_ _alloc_(1) _returns_nonnull_ _warn_unused_result_
72static inline void *xmalloc(size_t size) {
73 void *p;
74 assert_se(BS->AllocatePool(EfiBootServicesData, size, &p) == EFI_SUCCESS);
75 return p;
76}
77
78_malloc_ _alloc_(1, 2) _returns_nonnull_ _warn_unused_result_
79static inline void *xmalloc_multiply(size_t size, size_t n) {
80 assert_se(!__builtin_mul_overflow(size, n, &size));
81 return xmalloc(size);
82}
83
84/* Use malloc attribute as this never returns p like userspace realloc. */
85_malloc_ _alloc_(3) _returns_nonnull_ _warn_unused_result_
86static inline void *xrealloc(void *p, size_t old_size, size_t new_size) {
87 void *r = xmalloc(new_size);
55b5daf9
JJ
88 new_size = MIN(old_size, new_size);
89 if (new_size > 0)
90 memcpy(r, p, new_size);
9148312f
JJ
91 free(p);
92 return r;
93}
94
3639d1b0 95#define xpool_print(fmt, ...) ((char16_t *) ASSERT_SE_PTR(PoolPrint((fmt), ##__VA_ARGS__)))
0af26643 96#define xnew(type, n) ((type *) xmalloc_multiply(sizeof(type), (n)))
484ddd29 97
09173c91
JJ
98typedef struct {
99 EFI_PHYSICAL_ADDRESS addr;
100 size_t n_pages;
101} Pages;
102
103static inline void cleanup_pages(Pages *p) {
104 if (p->n_pages == 0)
105 return;
106#ifdef EFI_DEBUG
107 assert_se(BS->FreePages(p->addr, p->n_pages) == EFI_SUCCESS);
108#else
109 (void) BS->FreePages(p->addr, p->n_pages);
110#endif
111}
112
113#define _cleanup_pages_ _cleanup_(cleanup_pages)
114
115static inline Pages xmalloc_pages(
116 EFI_ALLOCATE_TYPE type, EFI_MEMORY_TYPE memory_type, size_t n_pages, EFI_PHYSICAL_ADDRESS addr) {
117 assert_se(BS->AllocatePages(type, memory_type, n_pages, &addr) == EFI_SUCCESS);
118 return (Pages) {
119 .addr = addr,
120 .n_pages = n_pages,
121 };
122}
123
e5a1b8f9 124EFI_STATUS parse_boolean(const char *v, bool *b);
4db7e6d7 125
3639d1b0
JJ
126EFI_STATUS efivar_set(const EFI_GUID *vendor, const char16_t *name, const char16_t *value, uint32_t flags);
127EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, const char16_t *name, const void *buf, UINTN size, uint32_t flags);
128EFI_STATUS efivar_set_uint_string(const EFI_GUID *vendor, const char16_t *name, UINTN i, uint32_t flags);
129EFI_STATUS efivar_set_uint32_le(const EFI_GUID *vendor, const char16_t *NAME, uint32_t value, uint32_t flags);
130EFI_STATUS efivar_set_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t value, uint32_t flags);
131void efivar_set_time_usec(const EFI_GUID *vendor, const char16_t *name, uint64_t usec);
0fa2cac4 132
3639d1b0 133EFI_STATUS efivar_get(const EFI_GUID *vendor, const char16_t *name, char16_t **value);
07d0fde4 134EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, const char16_t *name, char **buffer, UINTN *size);
3639d1b0
JJ
135EFI_STATUS efivar_get_uint_string(const EFI_GUID *vendor, const char16_t *name, UINTN *i);
136EFI_STATUS efivar_get_uint32_le(const EFI_GUID *vendor, const char16_t *name, uint32_t *ret);
137EFI_STATUS efivar_get_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t *ret);
e5a1b8f9 138EFI_STATUS efivar_get_boolean_u8(const EFI_GUID *vendor, const char16_t *name, bool *ret);
0fa2cac4 139
07d0fde4
JJ
140char16_t *xstra_to_path(const char *stra);
141char16_t *xstra_to_str(const char *stra);
0fa2cac4 142
07d0fde4 143EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, UINTN off, UINTN size, char **content, UINTN *content_size);
a42d7cf1 144
85eb489e 145static inline void file_closep(EFI_FILE **handle) {
3aaa95e0
LP
146 if (!*handle)
147 return;
148
12f32748 149 (*handle)->Close(*handle);
3aaa95e0 150}
0e2bc732 151
f386daa0
JJ
152static inline void unload_imagep(EFI_HANDLE *image) {
153 if (*image)
154 (void) BS->UnloadImage(*image);
155}
156
7d2ebb6f
DDM
157/*
158 * Allocated random UUID, intended to be shared across tools that implement
159 * the (ESP)\loader\entries\<vendor>-<revision>.conf convention and the
160 * associated EFI variables.
161 */
162#define LOADER_GUID \
163 &(const EFI_GUID) { 0x4a67b082, 0x0a4c, 0x41cf, { 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f } }
164#define EFI_GLOBAL_GUID &(const EFI_GUID) EFI_GLOBAL_VARIABLE
b49dd00f 165
3639d1b0 166void log_error_stall(const char16_t *fmt, ...);
b19fa812 167EFI_STATUS log_oom(void);
8aba0eec
JJ
168
169/* This works just like log_error_errno() from userspace, but requires you
170 * to provide err a second time if you want to use %r in the message! */
171#define log_error_status_stall(err, fmt, ...) \
172 ({ \
173 log_error_stall(fmt, ##__VA_ARGS__); \
174 err; \
175 })
43ee1fe0 176
3639d1b0 177void print_at(UINTN x, UINTN y, UINTN attr, const char16_t *str);
70cd15e9 178void clear_screen(UINTN attr);
c6dfe360 179
3d5127c6 180typedef int (*compare_pointer_func_t)(const void *a, const void *b);
70cd15e9 181void sort_pointer_array(void **array, UINTN n_members, compare_pointer_func_t compare);
80b2f4d9 182
85eb489e 183EFI_STATUS get_file_info_harder(EFI_FILE *handle, EFI_FILE_INFO **ret, UINTN *ret_size);
c6dfe360 184
85eb489e 185EFI_STATUS readdir_harder(EFI_FILE *handle, EFI_FILE_INFO **buffer, UINTN *buffer_size);
c6dfe360 186
e5a1b8f9 187bool is_ascii(const char16_t *f);
c6dfe360 188
3639d1b0 189char16_t **strv_free(char16_t **l);
c6dfe360 190
3639d1b0 191static inline void strv_freep(char16_t ***p) {
c6dfe360
LP
192 strv_free(*p);
193}
194
3639d1b0 195EFI_STATUS open_directory(EFI_FILE *root_dir, const char16_t *path, EFI_FILE **ret);
a0a644be
LP
196
197/* Conversion between EFI_PHYSICAL_ADDRESS and pointers is not obvious. The former is always 64bit, even on
198 * 32bit archs. And gcc complains if we cast a pointer to an integer of a different size. Hence let's do the
34938db5 199 * conversion indirectly: first into uintptr_t and then extended to EFI_PHYSICAL_ADDRESS. */
a0a644be 200static inline EFI_PHYSICAL_ADDRESS POINTER_TO_PHYSICAL_ADDRESS(const void *p) {
34938db5 201 return (EFI_PHYSICAL_ADDRESS) (uintptr_t) p;
a0a644be
LP
202}
203
204static inline void *PHYSICAL_ADDRESS_TO_POINTER(EFI_PHYSICAL_ADDRESS addr) {
a0a644be
LP
205 /* On 32bit systems the address might not be convertible (as pointers are 32bit but
206 * EFI_PHYSICAL_ADDRESS 64bit) */
34938db5
JJ
207 assert(addr <= UINTPTR_MAX);
208 return (void *) (uintptr_t) addr;
a0a644be 209}
3a624912 210
db4122d1 211uint64_t get_os_indications_supported(void);
948d085e
JJ
212
213#ifdef EFI_DEBUG
214void debug_break(void);
db4122d1 215extern uint8_t _text, _data;
948d085e
JJ
216/* Report the relocated position of text and data sections so that a debugger
217 * can attach to us. See debug-sd-boot.sh for how this can be done. */
ec4106af 218# define debug_hook(identity) Print(identity L"@0x%lx,0x%lx\n", POINTER_TO_PHYSICAL_ADDRESS(&_text), POINTER_TO_PHYSICAL_ADDRESS(&_data))
948d085e
JJ
219#else
220# define debug_hook(identity)
221#endif
85d2f13b 222
257bc3ef
LP
223#ifdef EFI_DEBUG
224void hexdump(const char16_t *prefix, const void *data, UINTN size);
225#endif
226
85d2f13b 227#if defined(__i386__) || defined(__x86_64__)
cc25bedb 228void beep(UINTN beep_count);
85d2f13b 229#else
cc25bedb 230static inline void beep(UINTN beep_count) {}
85d2f13b 231#endif
f747ca3e
JJ
232
233EFI_STATUS open_volume(EFI_HANDLE device, EFI_FILE **ret_file);
79a2b916 234EFI_STATUS make_file_device_path(EFI_HANDLE device, const char16_t *file, EFI_DEVICE_PATH **ret_dp);
3b3eb196 235EFI_STATUS device_path_to_str(const EFI_DEVICE_PATH *dp, char16_t **ret);
bafc5945
JJ
236
237#if defined(__i386__) || defined(__x86_64__)
238bool in_hypervisor(void);
239#else
240static inline bool in_hypervisor(void) {
241 return false;
242}
243#endif