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