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