]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/efi/util.c
tty-ask-password: Split out password sending
[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 #elif defined(__i386__)
37 UINT64 ticks_read(VOID) {
38 UINT64 val;
39 __asm__ volatile ("rdtsc" : "=A" (val));
40 return val;
41 }
42 #else
43 UINT64 ticks_read(VOID) {
44 UINT64 val = 1;
45 return val;
46 }
47 #endif
48
49 /* count TSC ticks during a millisecond delay */
50 UINT64 ticks_freq(VOID) {
51 UINT64 ticks_start, ticks_end;
52
53 ticks_start = ticks_read();
54 uefi_call_wrapper(BS->Stall, 1, 1000);
55 ticks_end = ticks_read();
56
57 return (ticks_end - ticks_start) * 1000;
58 }
59
60 UINT64 time_usec(VOID) {
61 UINT64 ticks;
62 static UINT64 freq;
63
64 ticks = ticks_read();
65 if (ticks == 0)
66 return 0;
67
68 if (freq == 0) {
69 freq = ticks_freq();
70 if (freq == 0)
71 return 0;
72 }
73
74 return 1000 * 1000 * ticks / freq;
75 }
76
77 EFI_STATUS parse_boolean(CHAR8 *v, BOOLEAN *b) {
78 if (strcmpa(v, (CHAR8 *)"1") == 0 ||
79 strcmpa(v, (CHAR8 *)"yes") == 0 ||
80 strcmpa(v, (CHAR8 *)"y") == 0 ||
81 strcmpa(v, (CHAR8 *)"true") == 0) {
82 *b = TRUE;
83 return EFI_SUCCESS;
84 }
85
86 if (strcmpa(v, (CHAR8 *)"0") == 0 ||
87 strcmpa(v, (CHAR8 *)"no") == 0 ||
88 strcmpa(v, (CHAR8 *)"n") == 0 ||
89 strcmpa(v, (CHAR8 *)"false") == 0) {
90 *b = FALSE;
91 return EFI_SUCCESS;
92 }
93
94 return EFI_INVALID_PARAMETER;
95 }
96
97 EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, CHAR16 *name, CHAR8 *buf, UINTN size, BOOLEAN persistent) {
98 UINT32 flags;
99
100 flags = EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
101 if (persistent)
102 flags |= EFI_VARIABLE_NON_VOLATILE;
103
104 return uefi_call_wrapper(RT->SetVariable, 5, name, (EFI_GUID *)vendor, flags, size, buf);
105 }
106
107 EFI_STATUS efivar_set(CHAR16 *name, CHAR16 *value, BOOLEAN persistent) {
108 return efivar_set_raw(&loader_guid, name, (CHAR8 *)value, value ? (StrLen(value)+1) * sizeof(CHAR16) : 0, persistent);
109 }
110
111 EFI_STATUS efivar_set_int(CHAR16 *name, UINTN i, BOOLEAN persistent) {
112 CHAR16 str[32];
113
114 SPrint(str, 32, L"%d", i);
115 return efivar_set(name, str, persistent);
116 }
117
118 EFI_STATUS efivar_get(CHAR16 *name, CHAR16 **value) {
119 CHAR8 *buf;
120 CHAR16 *val;
121 UINTN size;
122 EFI_STATUS err;
123
124 err = efivar_get_raw(&loader_guid, name, &buf, &size);
125 if (EFI_ERROR(err))
126 return err;
127
128 val = StrDuplicate((CHAR16 *)buf);
129 if (!val) {
130 FreePool(buf);
131 return EFI_OUT_OF_RESOURCES;
132 }
133
134 *value = val;
135 return EFI_SUCCESS;
136 }
137
138 EFI_STATUS efivar_get_int(CHAR16 *name, UINTN *i) {
139 CHAR16 *val;
140 EFI_STATUS err;
141
142 err = efivar_get(name, &val);
143 if (!EFI_ERROR(err)) {
144 *i = Atoi(val);
145 FreePool(val);
146 }
147 return err;
148 }
149
150 EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, CHAR16 *name, CHAR8 **buffer, UINTN *size) {
151 CHAR8 *buf;
152 UINTN l;
153 EFI_STATUS err;
154
155 l = sizeof(CHAR16 *) * EFI_MAXIMUM_VARIABLE_SIZE;
156 buf = AllocatePool(l);
157 if (!buf)
158 return EFI_OUT_OF_RESOURCES;
159
160 err = uefi_call_wrapper(RT->GetVariable, 5, name, (EFI_GUID *)vendor, NULL, &l, buf);
161 if (!EFI_ERROR(err)) {
162 *buffer = buf;
163 if (size)
164 *size = l;
165 } else
166 FreePool(buf);
167 return err;
168
169 }
170
171 VOID efivar_set_time_usec(CHAR16 *name, UINT64 usec) {
172 CHAR16 str[32];
173
174 if (usec == 0)
175 usec = time_usec();
176 if (usec == 0)
177 return;
178
179 SPrint(str, 32, L"%ld", usec);
180 efivar_set(name, str, FALSE);
181 }
182
183 static INTN utf8_to_16(CHAR8 *stra, CHAR16 *c) {
184 CHAR16 unichar;
185 UINTN len;
186 UINTN i;
187
188 if (stra[0] < 0x80)
189 len = 1;
190 else if ((stra[0] & 0xe0) == 0xc0)
191 len = 2;
192 else if ((stra[0] & 0xf0) == 0xe0)
193 len = 3;
194 else if ((stra[0] & 0xf8) == 0xf0)
195 len = 4;
196 else if ((stra[0] & 0xfc) == 0xf8)
197 len = 5;
198 else if ((stra[0] & 0xfe) == 0xfc)
199 len = 6;
200 else
201 return -1;
202
203 switch (len) {
204 case 1:
205 unichar = stra[0];
206 break;
207 case 2:
208 unichar = stra[0] & 0x1f;
209 break;
210 case 3:
211 unichar = stra[0] & 0x0f;
212 break;
213 case 4:
214 unichar = stra[0] & 0x07;
215 break;
216 case 5:
217 unichar = stra[0] & 0x03;
218 break;
219 case 6:
220 unichar = stra[0] & 0x01;
221 break;
222 }
223
224 for (i = 1; i < len; i++) {
225 if ((stra[i] & 0xc0) != 0x80)
226 return -1;
227 unichar <<= 6;
228 unichar |= stra[i] & 0x3f;
229 }
230
231 *c = unichar;
232 return len;
233 }
234
235 CHAR16 *stra_to_str(CHAR8 *stra) {
236 UINTN strlen;
237 UINTN len;
238 UINTN i;
239 CHAR16 *str;
240
241 len = strlena(stra);
242 str = AllocatePool((len + 1) * sizeof(CHAR16));
243
244 strlen = 0;
245 i = 0;
246 while (i < len) {
247 INTN utf8len;
248
249 utf8len = utf8_to_16(stra + i, str + strlen);
250 if (utf8len <= 0) {
251 /* invalid utf8 sequence, skip the garbage */
252 i++;
253 continue;
254 }
255
256 strlen++;
257 i += utf8len;
258 }
259 str[strlen] = '\0';
260 return str;
261 }
262
263 CHAR16 *stra_to_path(CHAR8 *stra) {
264 CHAR16 *str;
265 UINTN strlen;
266 UINTN len;
267 UINTN i;
268
269 len = strlena(stra);
270 str = AllocatePool((len + 2) * sizeof(CHAR16));
271
272 str[0] = '\\';
273 strlen = 1;
274 i = 0;
275 while (i < len) {
276 INTN utf8len;
277
278 utf8len = utf8_to_16(stra + i, str + strlen);
279 if (utf8len <= 0) {
280 /* invalid utf8 sequence, skip the garbage */
281 i++;
282 continue;
283 }
284
285 if (str[strlen] == '/')
286 str[strlen] = '\\';
287 if (str[strlen] == '\\' && str[strlen-1] == '\\') {
288 /* skip double slashes */
289 i += utf8len;
290 continue;
291 }
292
293 strlen++;
294 i += utf8len;
295 }
296 str[strlen] = '\0';
297 return str;
298 }
299
300 CHAR8 *strchra(CHAR8 *s, CHAR8 c) {
301 do {
302 if (*s == c)
303 return s;
304 } while (*s++);
305 return NULL;
306 }
307
308 INTN file_read(EFI_FILE_HANDLE dir, CHAR16 *name, UINTN off, UINTN size, CHAR8 **content) {
309 EFI_FILE_HANDLE handle;
310 CHAR8 *buf;
311 UINTN buflen;
312 EFI_STATUS err;
313 UINTN len;
314
315 err = uefi_call_wrapper(dir->Open, 5, dir, &handle, name, EFI_FILE_MODE_READ, 0ULL);
316 if (EFI_ERROR(err))
317 return err;
318
319 if (size == 0) {
320 EFI_FILE_INFO *info;
321
322 info = LibFileInfo(handle);
323 buflen = info->FileSize+1;
324 FreePool(info);
325 } else
326 buflen = size;
327
328 if (off > 0) {
329 err = uefi_call_wrapper(handle->SetPosition, 2, handle, off);
330 if (EFI_ERROR(err))
331 return err;
332 }
333
334 buf = AllocatePool(buflen);
335 err = uefi_call_wrapper(handle->Read, 3, handle, &buflen, buf);
336 if (!EFI_ERROR(err)) {
337 buf[buflen] = '\0';
338 *content = buf;
339 len = buflen;
340 } else {
341 len = err;
342 FreePool(buf);
343 }
344
345 uefi_call_wrapper(handle->Close, 1, handle);
346 return len;
347 }