]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/boot/efi/util.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / boot / efi / util.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
0fa2cac4
KS
2/*
3 * This program is free software; you can redistribute it and/or modify it
4 * under the terms of the GNU Lesser General Public License as published by
5 * the Free Software Foundation; either version 2.1 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org>
14 * Copyright (C) 2012 Harald Hoyer <harald@redhat.com>
15 */
16
17#include <efi.h>
18#include <efilib.h>
19
20#include "util.h"
21
22/*
23 * Allocated random UUID, intended to be shared across tools that implement
24 * the (ESP)\loader\entries\<vendor>-<revision>.conf convention and the
25 * associated EFI variables.
26 */
27static const EFI_GUID loader_guid = { 0x4a67b082, 0x0a4c, 0x41cf, {0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f} };
28
29#ifdef __x86_64__
30UINT64 ticks_read(VOID) {
31 UINT64 a, d;
32 __asm__ volatile ("rdtsc" : "=a" (a), "=d" (d));
33 return (d << 32) | a;
34}
8403daa2 35#elif defined(__i386__)
0fa2cac4
KS
36UINT64 ticks_read(VOID) {
37 UINT64 val;
38 __asm__ volatile ("rdtsc" : "=A" (val));
39 return val;
40}
0d8d3689
KK
41#else
42UINT64 ticks_read(VOID) {
43 UINT64 val = 1;
44 return val;
45}
0fa2cac4
KS
46#endif
47
48/* count TSC ticks during a millisecond delay */
49UINT64 ticks_freq(VOID) {
50 UINT64 ticks_start, ticks_end;
51
52 ticks_start = ticks_read();
53 uefi_call_wrapper(BS->Stall, 1, 1000);
54 ticks_end = ticks_read();
55
56 return (ticks_end - ticks_start) * 1000;
57}
58
59UINT64 time_usec(VOID) {
60 UINT64 ticks;
61 static UINT64 freq;
62
63 ticks = ticks_read();
64 if (ticks == 0)
65 return 0;
66
67 if (freq == 0) {
68 freq = ticks_freq();
69 if (freq == 0)
70 return 0;
71 }
72
73 return 1000 * 1000 * ticks / freq;
74}
75
4db7e6d7
KS
76EFI_STATUS parse_boolean(CHAR8 *v, BOOLEAN *b) {
77 if (strcmpa(v, (CHAR8 *)"1") == 0 ||
78 strcmpa(v, (CHAR8 *)"yes") == 0 ||
79 strcmpa(v, (CHAR8 *)"y") == 0 ||
80 strcmpa(v, (CHAR8 *)"true") == 0) {
81 *b = TRUE;
82 return EFI_SUCCESS;
83 }
84
85 if (strcmpa(v, (CHAR8 *)"0") == 0 ||
86 strcmpa(v, (CHAR8 *)"no") == 0 ||
87 strcmpa(v, (CHAR8 *)"n") == 0 ||
88 strcmpa(v, (CHAR8 *)"false") == 0) {
89 *b = FALSE;
90 return EFI_SUCCESS;
91 }
92
93 return EFI_INVALID_PARAMETER;
94}
95
0fa2cac4
KS
96EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, CHAR16 *name, CHAR8 *buf, UINTN size, BOOLEAN persistent) {
97 UINT32 flags;
98
99 flags = EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
100 if (persistent)
101 flags |= EFI_VARIABLE_NON_VOLATILE;
102
103 return uefi_call_wrapper(RT->SetVariable, 5, name, (EFI_GUID *)vendor, flags, size, buf);
104}
105
106EFI_STATUS efivar_set(CHAR16 *name, CHAR16 *value, BOOLEAN persistent) {
107 return efivar_set_raw(&loader_guid, name, (CHAR8 *)value, value ? (StrLen(value)+1) * sizeof(CHAR16) : 0, persistent);
108}
109
110EFI_STATUS efivar_set_int(CHAR16 *name, UINTN i, BOOLEAN persistent) {
111 CHAR16 str[32];
112
113 SPrint(str, 32, L"%d", i);
114 return efivar_set(name, str, persistent);
115}
116
117EFI_STATUS efivar_get(CHAR16 *name, CHAR16 **value) {
118 CHAR8 *buf;
119 CHAR16 *val;
120 UINTN size;
121 EFI_STATUS err;
122
123 err = efivar_get_raw(&loader_guid, name, &buf, &size);
124 if (EFI_ERROR(err))
125 return err;
126
127 val = StrDuplicate((CHAR16 *)buf);
128 if (!val) {
129 FreePool(buf);
130 return EFI_OUT_OF_RESOURCES;
131 }
132
133 *value = val;
134 return EFI_SUCCESS;
135}
136
137EFI_STATUS efivar_get_int(CHAR16 *name, UINTN *i) {
138 CHAR16 *val;
139 EFI_STATUS err;
140
141 err = efivar_get(name, &val);
142 if (!EFI_ERROR(err)) {
143 *i = Atoi(val);
144 FreePool(val);
145 }
146 return err;
147}
148
149EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, CHAR16 *name, CHAR8 **buffer, UINTN *size) {
150 CHAR8 *buf;
151 UINTN l;
152 EFI_STATUS err;
153
154 l = sizeof(CHAR16 *) * EFI_MAXIMUM_VARIABLE_SIZE;
155 buf = AllocatePool(l);
156 if (!buf)
157 return EFI_OUT_OF_RESOURCES;
158
159 err = uefi_call_wrapper(RT->GetVariable, 5, name, (EFI_GUID *)vendor, NULL, &l, buf);
160 if (!EFI_ERROR(err)) {
161 *buffer = buf;
162 if (size)
163 *size = l;
164 } else
165 FreePool(buf);
166 return err;
167
168}
169
170VOID efivar_set_time_usec(CHAR16 *name, UINT64 usec) {
171 CHAR16 str[32];
172
173 if (usec == 0)
174 usec = time_usec();
175 if (usec == 0)
176 return;
177
178 SPrint(str, 32, L"%ld", usec);
179 efivar_set(name, str, FALSE);
180}
181
182static INTN utf8_to_16(CHAR8 *stra, CHAR16 *c) {
183 CHAR16 unichar;
184 UINTN len;
185 UINTN i;
186
187 if (stra[0] < 0x80)
188 len = 1;
189 else if ((stra[0] & 0xe0) == 0xc0)
190 len = 2;
191 else if ((stra[0] & 0xf0) == 0xe0)
192 len = 3;
193 else if ((stra[0] & 0xf8) == 0xf0)
194 len = 4;
195 else if ((stra[0] & 0xfc) == 0xf8)
196 len = 5;
197 else if ((stra[0] & 0xfe) == 0xfc)
198 len = 6;
199 else
200 return -1;
201
202 switch (len) {
203 case 1:
204 unichar = stra[0];
205 break;
206 case 2:
207 unichar = stra[0] & 0x1f;
208 break;
209 case 3:
210 unichar = stra[0] & 0x0f;
211 break;
212 case 4:
213 unichar = stra[0] & 0x07;
214 break;
215 case 5:
216 unichar = stra[0] & 0x03;
217 break;
218 case 6:
219 unichar = stra[0] & 0x01;
220 break;
221 }
222
223 for (i = 1; i < len; i++) {
224 if ((stra[i] & 0xc0) != 0x80)
225 return -1;
226 unichar <<= 6;
227 unichar |= stra[i] & 0x3f;
228 }
229
230 *c = unichar;
231 return len;
232}
233
234CHAR16 *stra_to_str(CHAR8 *stra) {
235 UINTN strlen;
236 UINTN len;
237 UINTN i;
238 CHAR16 *str;
239
240 len = strlena(stra);
241 str = AllocatePool((len + 1) * sizeof(CHAR16));
242
243 strlen = 0;
244 i = 0;
245 while (i < len) {
246 INTN utf8len;
247
248 utf8len = utf8_to_16(stra + i, str + strlen);
249 if (utf8len <= 0) {
250 /* invalid utf8 sequence, skip the garbage */
251 i++;
252 continue;
253 }
254
255 strlen++;
256 i += utf8len;
257 }
258 str[strlen] = '\0';
259 return str;
260}
261
262CHAR16 *stra_to_path(CHAR8 *stra) {
263 CHAR16 *str;
264 UINTN strlen;
265 UINTN len;
266 UINTN i;
267
268 len = strlena(stra);
269 str = AllocatePool((len + 2) * sizeof(CHAR16));
270
271 str[0] = '\\';
272 strlen = 1;
273 i = 0;
274 while (i < len) {
275 INTN utf8len;
276
277 utf8len = utf8_to_16(stra + i, str + strlen);
278 if (utf8len <= 0) {
279 /* invalid utf8 sequence, skip the garbage */
280 i++;
281 continue;
282 }
283
284 if (str[strlen] == '/')
285 str[strlen] = '\\';
286 if (str[strlen] == '\\' && str[strlen-1] == '\\') {
287 /* skip double slashes */
288 i += utf8len;
289 continue;
290 }
291
292 strlen++;
293 i += utf8len;
294 }
295 str[strlen] = '\0';
296 return str;
297}
298
299CHAR8 *strchra(CHAR8 *s, CHAR8 c) {
300 do {
301 if (*s == c)
302 return s;
303 } while (*s++);
304 return NULL;
305}
306
307INTN file_read(EFI_FILE_HANDLE dir, CHAR16 *name, UINTN off, UINTN size, CHAR8 **content) {
308 EFI_FILE_HANDLE handle;
309 CHAR8 *buf;
310 UINTN buflen;
311 EFI_STATUS err;
312 UINTN len;
313
314 err = uefi_call_wrapper(dir->Open, 5, dir, &handle, name, EFI_FILE_MODE_READ, 0ULL);
315 if (EFI_ERROR(err))
316 return err;
317
318 if (size == 0) {
319 EFI_FILE_INFO *info;
320
321 info = LibFileInfo(handle);
322 buflen = info->FileSize+1;
323 FreePool(info);
324 } else
325 buflen = size;
326
327 if (off > 0) {
328 err = uefi_call_wrapper(handle->SetPosition, 2, handle, off);
329 if (EFI_ERROR(err))
330 return err;
331 }
332
333 buf = AllocatePool(buflen);
334 err = uefi_call_wrapper(handle->Read, 3, handle, &buflen, buf);
335 if (!EFI_ERROR(err)) {
336 buf[buflen] = '\0';
337 *content = buf;
338 len = buflen;
339 } else {
340 len = err;
341 FreePool(buf);
342 }
343
344 uefi_call_wrapper(handle->Close, 1, handle);
345 return len;
346}