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