master
c 247 lines 5.64 KB
Raw
1 /*
2 * SPDX-License-Identifier: GPL-2.0-or-later
3 *
4 * uefi vars device - helper functions for ucs2 strings and tracing
5 */
6 #include "qemu/osdep.h"
7 #include "system/dma.h"
8
9 #include "hw/uefi/var-service.h"
10
11 #include "trace.h"
12
13 /* ------------------------------------------------------------------ */
14
15 /*
16 * string helper functions.
17 *
18 * Most of the time uefi ucs2 strings are NULL-terminated, except
19 * sometimes when they are not (for example in variable policies).
20 */
21
22 gboolean uefi_str_is_valid(const uint16_t *str, size_t bytes,
23 gboolean must_be_null_terminated)
24 {
25 size_t chars = bytes / 2;
26 size_t pos = 0;
27
28 if ((bytes % 2) != 0) {
29 return false;
30 }
31
32 for (;;) {
33 if (pos == chars) {
34 if (must_be_null_terminated) {
35 return false;
36 } else {
37 return true;
38 }
39 }
40 switch (str[pos]) {
41 case 0:
42 /* end of string */
43 return true;
44 case 0xd800 ... 0xdfff:
45 /* reject surrogates */
46 return false;
47 default:
48 /* char is good, check next */
49 break;
50 }
51 pos++;
52 }
53 }
54
55 size_t uefi_strlen(const uint16_t *str, size_t bytes)
56 {
57 size_t chars = bytes / 2;
58 size_t pos = 0;
59
60 for (;;) {
61 if (pos == chars) {
62 return pos;
63 }
64 if (str[pos] == 0) {
65 return pos;
66 }
67 pos++;
68 }
69 }
70
71 gboolean uefi_str_equal_ex(const uint16_t *a, size_t a_bytes,
72 const uint16_t *b, size_t b_bytes,
73 gboolean wildcards_in_a)
74 {
75 size_t a_chars = a_bytes / 2;
76 size_t b_chars = b_bytes / 2;
77 size_t pos = 0;
78
79 for (;;) {
80 if (pos == a_chars && pos == b_chars) {
81 return true;
82 }
83 if (pos == a_chars && b[pos] == 0) {
84 return true;
85 }
86 if (pos == b_chars && a[pos] == 0) {
87 return true;
88 }
89 if (pos == a_chars || pos == b_chars) {
90 return false;
91 }
92 if (a[pos] == 0 && b[pos] == 0) {
93 return true;
94 }
95
96 if (wildcards_in_a && a[pos] == '#') {
97 if (!isxdigit(b[pos])) {
98 return false;
99 }
100 } else {
101 if (a[pos] != b[pos]) {
102 return false;
103 }
104 }
105 pos++;
106 }
107 }
108
109 gboolean uefi_str_equal(const uint16_t *a, size_t a_bytes,
110 const uint16_t *b, size_t b_bytes)
111 {
112 return uefi_str_equal_ex(a, a_bytes, b, b_bytes, false);
113 }
114
115 char *uefi_ucs2_to_ascii(const uint16_t *ucs2, uint64_t ucs2_bytes)
116 {
117 char *str = g_malloc0(ucs2_bytes / 2 + 1);
118 int i;
119
120 for (i = 0; i * 2 < ucs2_bytes; i++) {
121 if (ucs2[i] == 0) {
122 break;
123 }
124 if (ucs2[i] < 128) {
125 str[i] = ucs2[i];
126 } else {
127 str[i] = '?';
128 }
129 }
130 str[i] = 0;
131 return str;
132 }
133
134 /* ------------------------------------------------------------------ */
135 /* time helper functions */
136
137 int uefi_time_compare(efi_time *a, efi_time *b)
138 {
139 if (a->year < b->year) {
140 return -1;
141 }
142 if (a->year > b->year) {
143 return 1;
144 }
145
146 if (a->month < b->month) {
147 return -1;
148 }
149 if (a->month > b->month) {
150 return 1;
151 }
152
153 if (a->day < b->day) {
154 return -1;
155 }
156 if (a->day > b->day) {
157 return 1;
158 }
159
160 if (a->hour < b->hour) {
161 return -1;
162 }
163 if (a->hour > b->hour) {
164 return 1;
165 }
166
167 if (a->minute < b->minute) {
168 return -1;
169 }
170 if (a->minute > b->minute) {
171 return 1;
172 }
173
174 if (a->second < b->second) {
175 return -1;
176 }
177 if (a->second > b->second) {
178 return 1;
179 }
180
181 if (a->nanosecond < b->nanosecond) {
182 return -1;
183 }
184 if (a->nanosecond > b->nanosecond) {
185 return 1;
186 }
187
188 return 0;
189 }
190
191 /* ------------------------------------------------------------------ */
192 /* tracing helper functions */
193
194 void uefi_trace_variable(const char *action, QemuUUID guid,
195 const uint16_t *name, uint64_t name_size)
196 {
197 QemuUUID be = qemu_uuid_bswap(guid);
198 char *str_uuid = qemu_uuid_unparse_strdup(&be);
199 char *str_name = uefi_ucs2_to_ascii(name, name_size);
200
201 trace_uefi_variable(action, str_name, name_size, str_uuid);
202
203 g_free(str_name);
204 g_free(str_uuid);
205 }
206
207 void uefi_trace_status(const char *action, efi_status status)
208 {
209 switch (status) {
210 case EFI_SUCCESS:
211 trace_uefi_status(action, "success");
212 break;
213 case EFI_INVALID_PARAMETER:
214 trace_uefi_status(action, "invalid parameter");
215 break;
216 case EFI_UNSUPPORTED:
217 trace_uefi_status(action, "unsupported");
218 break;
219 case EFI_BAD_BUFFER_SIZE:
220 trace_uefi_status(action, "bad buffer size");
221 break;
222 case EFI_BUFFER_TOO_SMALL:
223 trace_uefi_status(action, "buffer too small");
224 break;
225 case EFI_WRITE_PROTECTED:
226 trace_uefi_status(action, "write protected");
227 break;
228 case EFI_OUT_OF_RESOURCES:
229 trace_uefi_status(action, "out of resources");
230 break;
231 case EFI_NOT_FOUND:
232 trace_uefi_status(action, "not found");
233 break;
234 case EFI_ACCESS_DENIED:
235 trace_uefi_status(action, "access denied");
236 break;
237 case EFI_ALREADY_STARTED:
238 trace_uefi_status(action, "already started");
239 break;
240 case EFI_SECURITY_VIOLATION:
241 trace_uefi_status(action, "security violation");
242 break;
243 default:
244 trace_uefi_status(action, "unknown error");
245 break;
246 }
247 }