]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/efi/util.c
boot: Replace UINTN with size_t
[thirdparty/systemd.git] / src / boot / efi / util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <efi.h>
4 #include <efilib.h>
5 #include <inttypes.h>
6
7 #include "ticks.h"
8 #include "util.h"
9
10 EFI_STATUS parse_boolean(const char *v, bool *b) {
11 assert(b);
12
13 if (!v)
14 return EFI_INVALID_PARAMETER;
15
16 if (streq8(v, "1") || streq8(v, "yes") || streq8(v, "y") || streq8(v, "true") || streq8(v, "t") ||
17 streq8(v, "on")) {
18 *b = true;
19 return EFI_SUCCESS;
20 }
21
22 if (streq8(v, "0") || streq8(v, "no") || streq8(v, "n") || streq8(v, "false") || streq8(v, "f") ||
23 streq8(v, "off")) {
24 *b = false;
25 return EFI_SUCCESS;
26 }
27
28 return EFI_INVALID_PARAMETER;
29 }
30
31 EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, const char16_t *name, const void *buf, size_t size, uint32_t flags) {
32 assert(vendor);
33 assert(name);
34 assert(buf || size == 0);
35
36 flags |= EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
37 return RT->SetVariable((char16_t *) name, (EFI_GUID *) vendor, flags, size, (void *) buf);
38 }
39
40 EFI_STATUS efivar_set(const EFI_GUID *vendor, const char16_t *name, const char16_t *value, uint32_t flags) {
41 assert(vendor);
42 assert(name);
43
44 return efivar_set_raw(vendor, name, value, value ? strsize16(value) : 0, flags);
45 }
46
47 EFI_STATUS efivar_set_uint_string(const EFI_GUID *vendor, const char16_t *name, size_t i, uint32_t flags) {
48 assert(vendor);
49 assert(name);
50
51 _cleanup_free_ char16_t *str = xasprintf("%zu", i);
52 return efivar_set(vendor, name, str, flags);
53 }
54
55 EFI_STATUS efivar_set_uint32_le(const EFI_GUID *vendor, const char16_t *name, uint32_t value, uint32_t flags) {
56 uint8_t buf[4];
57
58 assert(vendor);
59 assert(name);
60
61 buf[0] = (uint8_t)(value >> 0U & 0xFF);
62 buf[1] = (uint8_t)(value >> 8U & 0xFF);
63 buf[2] = (uint8_t)(value >> 16U & 0xFF);
64 buf[3] = (uint8_t)(value >> 24U & 0xFF);
65
66 return efivar_set_raw(vendor, name, buf, sizeof(buf), flags);
67 }
68
69 EFI_STATUS efivar_set_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t value, uint32_t flags) {
70 uint8_t buf[8];
71
72 assert(vendor);
73 assert(name);
74
75 buf[0] = (uint8_t)(value >> 0U & 0xFF);
76 buf[1] = (uint8_t)(value >> 8U & 0xFF);
77 buf[2] = (uint8_t)(value >> 16U & 0xFF);
78 buf[3] = (uint8_t)(value >> 24U & 0xFF);
79 buf[4] = (uint8_t)(value >> 32U & 0xFF);
80 buf[5] = (uint8_t)(value >> 40U & 0xFF);
81 buf[6] = (uint8_t)(value >> 48U & 0xFF);
82 buf[7] = (uint8_t)(value >> 56U & 0xFF);
83
84 return efivar_set_raw(vendor, name, buf, sizeof(buf), flags);
85 }
86
87 EFI_STATUS efivar_get(const EFI_GUID *vendor, const char16_t *name, char16_t **ret) {
88 _cleanup_free_ char16_t *buf = NULL;
89 EFI_STATUS err;
90 char16_t *val;
91 size_t size;
92
93 assert(vendor);
94 assert(name);
95
96 err = efivar_get_raw(vendor, name, (char **) &buf, &size);
97 if (err != EFI_SUCCESS)
98 return err;
99
100 /* Make sure there are no incomplete characters in the buffer */
101 if ((size % sizeof(char16_t)) != 0)
102 return EFI_INVALID_PARAMETER;
103
104 if (!ret)
105 return EFI_SUCCESS;
106
107 /* Return buffer directly if it happens to be NUL terminated already */
108 if (size >= sizeof(char16_t) && buf[size / sizeof(char16_t) - 1] == 0) {
109 *ret = TAKE_PTR(buf);
110 return EFI_SUCCESS;
111 }
112
113 /* Make sure a terminating NUL is available at the end */
114 val = xmalloc(size + sizeof(char16_t));
115
116 memcpy(val, buf, size);
117 val[size / sizeof(char16_t) - 1] = 0; /* NUL terminate */
118
119 *ret = val;
120 return EFI_SUCCESS;
121 }
122
123 EFI_STATUS efivar_get_uint_string(const EFI_GUID *vendor, const char16_t *name, size_t *ret) {
124 _cleanup_free_ char16_t *val = NULL;
125 EFI_STATUS err;
126 uint64_t u;
127
128 assert(vendor);
129 assert(name);
130
131 err = efivar_get(vendor, name, &val);
132 if (err != EFI_SUCCESS)
133 return err;
134
135 if (!parse_number16(val, &u, NULL) || u > SIZE_MAX)
136 return EFI_INVALID_PARAMETER;
137
138 if (ret)
139 *ret = u;
140 return EFI_SUCCESS;
141 }
142
143 EFI_STATUS efivar_get_uint32_le(const EFI_GUID *vendor, const char16_t *name, uint32_t *ret) {
144 _cleanup_free_ char *buf = NULL;
145 size_t size;
146 EFI_STATUS err;
147
148 assert(vendor);
149 assert(name);
150
151 err = efivar_get_raw(vendor, name, &buf, &size);
152 if (err != EFI_SUCCESS)
153 return err;
154
155 if (size != sizeof(uint32_t))
156 return EFI_BUFFER_TOO_SMALL;
157
158 if (ret)
159 *ret = (uint32_t) buf[0] << 0U | (uint32_t) buf[1] << 8U | (uint32_t) buf[2] << 16U |
160 (uint32_t) buf[3] << 24U;
161
162 return EFI_SUCCESS;
163 }
164
165 EFI_STATUS efivar_get_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t *ret) {
166 _cleanup_free_ char *buf = NULL;
167 size_t size;
168 EFI_STATUS err;
169
170 assert(vendor);
171 assert(name);
172
173 err = efivar_get_raw(vendor, name, &buf, &size);
174 if (err != EFI_SUCCESS)
175 return err;
176
177 if (size != sizeof(uint64_t))
178 return EFI_BUFFER_TOO_SMALL;
179
180 if (ret)
181 *ret = (uint64_t) buf[0] << 0U | (uint64_t) buf[1] << 8U | (uint64_t) buf[2] << 16U |
182 (uint64_t) buf[3] << 24U | (uint64_t) buf[4] << 32U | (uint64_t) buf[5] << 40U |
183 (uint64_t) buf[6] << 48U | (uint64_t) buf[7] << 56U;
184
185 return EFI_SUCCESS;
186 }
187
188 EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, const char16_t *name, char **ret, size_t *ret_size) {
189 _cleanup_free_ char *buf = NULL;
190 size_t l;
191 EFI_STATUS err;
192
193 assert(vendor);
194 assert(name);
195
196 l = sizeof(char16_t *) * EFI_MAXIMUM_VARIABLE_SIZE;
197 buf = xmalloc(l);
198
199 err = RT->GetVariable((char16_t *) name, (EFI_GUID *) vendor, NULL, &l, buf);
200 if (err != EFI_SUCCESS)
201 return err;
202
203 if (ret)
204 *ret = TAKE_PTR(buf);
205 if (ret_size)
206 *ret_size = l;
207
208 return EFI_SUCCESS;
209 }
210
211 EFI_STATUS efivar_get_boolean_u8(const EFI_GUID *vendor, const char16_t *name, bool *ret) {
212 _cleanup_free_ char *b = NULL;
213 size_t size;
214 EFI_STATUS err;
215
216 assert(vendor);
217 assert(name);
218
219 err = efivar_get_raw(vendor, name, &b, &size);
220 if (err != EFI_SUCCESS)
221 return err;
222
223 if (ret)
224 *ret = *b > 0;
225
226 return EFI_SUCCESS;
227 }
228
229 void efivar_set_time_usec(const EFI_GUID *vendor, const char16_t *name, uint64_t usec) {
230 assert(vendor);
231 assert(name);
232
233 if (usec == 0)
234 usec = time_usec();
235 if (usec == 0)
236 return;
237
238 _cleanup_free_ char16_t *str = xasprintf("%" PRIu64, usec);
239 efivar_set(vendor, name, str, 0);
240 }
241
242 void convert_efi_path(char16_t *path) {
243 assert(path);
244
245 for (size_t i = 0, fixed = 0;; i++) {
246 /* Fix device path node separator. */
247 path[fixed] = (path[i] == '/') ? '\\' : path[i];
248
249 /* Double '\' is not allowed in EFI file paths. */
250 if (fixed > 0 && path[fixed - 1] == '\\' && path[fixed] == '\\')
251 continue;
252
253 if (path[i] == '\0')
254 break;
255
256 fixed++;
257 }
258 }
259
260 char16_t *xstr8_to_path(const char *str8) {
261 assert(str8);
262 char16_t *path = xstr8_to_16(str8);
263 convert_efi_path(path);
264 return path;
265 }
266
267 void mangle_stub_cmdline(char16_t *cmdline) {
268 char16_t *p = cmdline;
269
270 for (; *cmdline != '\0'; cmdline++)
271 /* Convert ASCII control characters to spaces. */
272 if (*cmdline <= 0x1F)
273 *cmdline = ' ';
274
275 /* chomp the trailing whitespaces */
276 while (cmdline != p) {
277 --cmdline;
278
279 if (*cmdline != ' ')
280 break;
281
282 *cmdline = '\0';
283 }
284 }
285
286 EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, size_t off, size_t size, char **ret, size_t *ret_size) {
287 _cleanup_(file_closep) EFI_FILE *handle = NULL;
288 _cleanup_free_ char *buf = NULL;
289 EFI_STATUS err;
290
291 assert(dir);
292 assert(name);
293 assert(ret);
294
295 err = dir->Open(dir, &handle, (char16_t*) name, EFI_FILE_MODE_READ, 0ULL);
296 if (err != EFI_SUCCESS)
297 return err;
298
299 if (size == 0) {
300 _cleanup_free_ EFI_FILE_INFO *info = NULL;
301
302 err = get_file_info_harder(handle, &info, NULL);
303 if (err != EFI_SUCCESS)
304 return err;
305
306 size = info->FileSize;
307 }
308
309 if (off > 0) {
310 err = handle->SetPosition(handle, off);
311 if (err != EFI_SUCCESS)
312 return err;
313 }
314
315 /* Allocate some extra bytes to guarantee the result is NUL-terminated for char and char16_t strings. */
316 size_t extra = size % sizeof(char16_t) + sizeof(char16_t);
317
318 buf = xmalloc(size + extra);
319 if (size > 0) {
320 err = handle->Read(handle, &size, buf);
321 if (err != EFI_SUCCESS)
322 return err;
323 }
324
325 /* Note that handle->Read() changes size to reflect the actually bytes read. */
326 memset(buf + size, 0, extra);
327
328 *ret = TAKE_PTR(buf);
329 if (ret_size)
330 *ret_size = size;
331
332 return err;
333 }
334
335 void print_at(size_t x, size_t y, size_t attr, const char16_t *str) {
336 assert(str);
337 ST->ConOut->SetCursorPosition(ST->ConOut, x, y);
338 ST->ConOut->SetAttribute(ST->ConOut, attr);
339 ST->ConOut->OutputString(ST->ConOut, (char16_t *) str);
340 }
341
342 void clear_screen(size_t attr) {
343 log_wait();
344 ST->ConOut->SetAttribute(ST->ConOut, attr);
345 ST->ConOut->ClearScreen(ST->ConOut);
346 }
347
348 void sort_pointer_array(
349 void **array,
350 size_t n_members,
351 compare_pointer_func_t compare) {
352
353 assert(array || n_members == 0);
354 assert(compare);
355
356 if (n_members <= 1)
357 return;
358
359 for (size_t i = 1; i < n_members; i++) {
360 size_t k;
361 void *entry = array[i];
362
363 for (k = i; k > 0; k--) {
364 if (compare(array[k - 1], entry) <= 0)
365 break;
366
367 array[k] = array[k - 1];
368 }
369
370 array[k] = entry;
371 }
372 }
373
374 EFI_STATUS get_file_info_harder(
375 EFI_FILE *handle,
376 EFI_FILE_INFO **ret,
377 size_t *ret_size) {
378
379 size_t size = offsetof(EFI_FILE_INFO, FileName) + 256;
380 _cleanup_free_ EFI_FILE_INFO *fi = NULL;
381 EFI_STATUS err;
382
383 assert(handle);
384 assert(ret);
385
386 /* A lot like LibFileInfo() but with useful error propagation */
387
388 fi = xmalloc(size);
389 err = handle->GetInfo(handle, MAKE_GUID_PTR(EFI_FILE_INFO), &size, fi);
390 if (err == EFI_BUFFER_TOO_SMALL) {
391 free(fi);
392 fi = xmalloc(size); /* GetInfo tells us the required size, let's use that now */
393 err = handle->GetInfo(handle, MAKE_GUID_PTR(EFI_FILE_INFO), &size, fi);
394 }
395
396 if (err != EFI_SUCCESS)
397 return err;
398
399 *ret = TAKE_PTR(fi);
400
401 if (ret_size)
402 *ret_size = size;
403
404 return EFI_SUCCESS;
405 }
406
407 EFI_STATUS readdir_harder(
408 EFI_FILE *handle,
409 EFI_FILE_INFO **buffer,
410 size_t *buffer_size) {
411
412 EFI_STATUS err;
413 size_t sz;
414
415 assert(handle);
416 assert(buffer);
417 assert(buffer_size);
418
419 /* buffer/buffer_size are both in and output parameters. Should be zero-initialized initially, and
420 * the specified buffer needs to be freed by caller, after final use. */
421
422 if (!*buffer) {
423 /* Some broken firmware violates the EFI spec by still advancing the readdir
424 * position when returning EFI_BUFFER_TOO_SMALL, effectively skipping over any files when
425 * the buffer was too small. Therefore, start with a buffer that should handle FAT32 max
426 * file name length.
427 * As a side effect, most readdir_harder() calls will now be slightly faster. */
428 sz = sizeof(EFI_FILE_INFO) + 256 * sizeof(char16_t);
429 *buffer = xmalloc(sz);
430 *buffer_size = sz;
431 } else
432 sz = *buffer_size;
433
434 err = handle->Read(handle, &sz, *buffer);
435 if (err == EFI_BUFFER_TOO_SMALL) {
436 free(*buffer);
437 *buffer = xmalloc(sz);
438 *buffer_size = sz;
439 err = handle->Read(handle, &sz, *buffer);
440 }
441 if (err != EFI_SUCCESS)
442 return err;
443
444 if (sz == 0) {
445 /* End of directory */
446 free(*buffer);
447 *buffer = NULL;
448 *buffer_size = 0;
449 }
450
451 return EFI_SUCCESS;
452 }
453
454 bool is_ascii(const char16_t *f) {
455 if (!f)
456 return false;
457
458 for (; *f != 0; f++)
459 if (*f > 127)
460 return false;
461
462 return true;
463 }
464
465 char16_t **strv_free(char16_t **v) {
466 if (!v)
467 return NULL;
468
469 for (char16_t **i = v; *i; i++)
470 free(*i);
471
472 free(v);
473 return NULL;
474 }
475
476 EFI_STATUS open_directory(
477 EFI_FILE *root,
478 const char16_t *path,
479 EFI_FILE **ret) {
480
481 _cleanup_(file_closep) EFI_FILE *dir = NULL;
482 _cleanup_free_ EFI_FILE_INFO *file_info = NULL;
483 EFI_STATUS err;
484
485 assert(root);
486
487 /* Opens a file, and then verifies it is actually a directory */
488
489 err = root->Open(root, &dir, (char16_t *) path, EFI_FILE_MODE_READ, 0);
490 if (err != EFI_SUCCESS)
491 return err;
492
493 err = get_file_info_harder(dir, &file_info, NULL);
494 if (err != EFI_SUCCESS)
495 return err;
496 if (!FLAGS_SET(file_info->Attribute, EFI_FILE_DIRECTORY))
497 return EFI_LOAD_ERROR;
498
499 *ret = TAKE_PTR(dir);
500 return EFI_SUCCESS;
501 }
502
503 uint64_t get_os_indications_supported(void) {
504 uint64_t osind;
505 EFI_STATUS err;
506
507 /* Returns the supported OS indications. If we can't acquire it, returns a zeroed out mask, i.e. no
508 * supported features. */
509
510 err = efivar_get_uint64_le(MAKE_GUID_PTR(EFI_GLOBAL_VARIABLE), u"OsIndicationsSupported", &osind);
511 if (err != EFI_SUCCESS)
512 return 0;
513
514 return osind;
515 }
516
517 #ifdef EFI_DEBUG
518 extern uint8_t _text, _data;
519 __attribute__((noinline)) void notify_debugger(const char *identity, volatile bool wait) {
520 printf("%s@%p,%p\n", identity, &_text, &_data);
521 if (wait)
522 printf("Waiting for debugger to attach...\n");
523
524 /* This is a poor programmer's breakpoint to wait until a debugger
525 * has attached to us. Just "set variable wait = 0" or "return" to continue. */
526 while (wait)
527 /* Prefer asm based stalling so that gdb has a source location to present. */
528 #if defined(__i386__) || defined(__x86_64__)
529 asm volatile("pause");
530 #elif defined(__aarch64__)
531 asm volatile("wfi");
532 #else
533 BS->Stall(5000);
534 #endif
535 }
536 #endif
537
538 #ifdef EFI_DEBUG
539 void hexdump(const char16_t *prefix, const void *data, size_t size) {
540 static const char hex[16] = "0123456789abcdef";
541 _cleanup_free_ char16_t *buf = NULL;
542 const uint8_t *d = data;
543
544 assert(prefix);
545 assert(data || size == 0);
546
547 /* Debugging helper — please keep this around, even if not used */
548
549 buf = xnew(char16_t, size*2+1);
550
551 for (size_t i = 0; i < size; i++) {
552 buf[i*2] = hex[d[i] >> 4];
553 buf[i*2+1] = hex[d[i] & 0x0F];
554 }
555
556 buf[size*2] = 0;
557
558 log_error("%ls[%zu]: %ls", prefix, size, buf);
559 }
560 #endif
561
562 #if defined(__i386__) || defined(__x86_64__)
563 static inline uint8_t inb(uint16_t port) {
564 uint8_t value;
565 asm volatile("inb %1, %0" : "=a"(value) : "Nd"(port));
566 return value;
567 }
568
569 static inline void outb(uint16_t port, uint8_t value) {
570 asm volatile("outb %0, %1" : : "a"(value), "Nd"(port));
571 }
572
573 void beep(UINTN beep_count) {
574 enum {
575 PITCH = 500,
576 BEEP_DURATION_USEC = 100 * 1000,
577 WAIT_DURATION_USEC = 400 * 1000,
578
579 PIT_FREQUENCY = 0x1234dd,
580 SPEAKER_CONTROL_PORT = 0x61,
581 SPEAKER_ON_MASK = 0x03,
582 TIMER_PORT_MAGIC = 0xB6,
583 TIMER_CONTROL_PORT = 0x43,
584 TIMER_CONTROL2_PORT = 0x42,
585 };
586
587 /* Set frequency. */
588 uint32_t counter = PIT_FREQUENCY / PITCH;
589 outb(TIMER_CONTROL_PORT, TIMER_PORT_MAGIC);
590 outb(TIMER_CONTROL2_PORT, counter & 0xFF);
591 outb(TIMER_CONTROL2_PORT, (counter >> 8) & 0xFF);
592
593 uint8_t value = inb(SPEAKER_CONTROL_PORT);
594
595 while (beep_count > 0) {
596 /* Turn speaker on. */
597 value |= SPEAKER_ON_MASK;
598 outb(SPEAKER_CONTROL_PORT, value);
599
600 BS->Stall(BEEP_DURATION_USEC);
601
602 /* Turn speaker off. */
603 value &= ~SPEAKER_ON_MASK;
604 outb(SPEAKER_CONTROL_PORT, value);
605
606 beep_count--;
607 if (beep_count > 0)
608 BS->Stall(WAIT_DURATION_USEC);
609 }
610 }
611 #endif
612
613 EFI_STATUS open_volume(EFI_HANDLE device, EFI_FILE **ret_file) {
614 EFI_STATUS err;
615 EFI_FILE *file;
616 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *volume;
617
618 assert(ret_file);
619
620 err = BS->HandleProtocol(device, MAKE_GUID_PTR(EFI_SIMPLE_FILE_SYSTEM_PROTOCOL), (void **) &volume);
621 if (err != EFI_SUCCESS)
622 return err;
623
624 err = volume->OpenVolume(volume, &file);
625 if (err != EFI_SUCCESS)
626 return err;
627
628 *ret_file = file;
629 return EFI_SUCCESS;
630 }
631
632 EFI_STATUS make_file_device_path(EFI_HANDLE device, const char16_t *file, EFI_DEVICE_PATH **ret_dp) {
633 EFI_STATUS err;
634 EFI_DEVICE_PATH *dp;
635
636 assert(file);
637 assert(ret_dp);
638
639 err = BS->HandleProtocol(device, MAKE_GUID_PTR(EFI_DEVICE_PATH_PROTOCOL), (void **) &dp);
640 if (err != EFI_SUCCESS)
641 return err;
642
643 EFI_DEVICE_PATH *end_node = dp;
644 while (!IsDevicePathEnd(end_node))
645 end_node = NextDevicePathNode(end_node);
646
647 size_t file_size = strsize16(file);
648 size_t dp_size = (uint8_t *) end_node - (uint8_t *) dp;
649
650 /* Make a copy that can also hold a file media device path. */
651 *ret_dp = xmalloc(dp_size + file_size + SIZE_OF_FILEPATH_DEVICE_PATH + END_DEVICE_PATH_LENGTH);
652 dp = mempcpy(*ret_dp, dp, dp_size);
653
654 /* Replace end node with file media device path. Use memcpy() in case dp is unaligned (if accessed as
655 * FILEPATH_DEVICE_PATH). */
656 dp->Type = MEDIA_DEVICE_PATH;
657 dp->SubType = MEDIA_FILEPATH_DP;
658 memcpy((uint8_t *) dp + offsetof(FILEPATH_DEVICE_PATH, PathName), file, file_size);
659 SetDevicePathNodeLength(dp, offsetof(FILEPATH_DEVICE_PATH, PathName) + file_size);
660
661 dp = NextDevicePathNode(dp);
662 SetDevicePathEndNode(dp);
663 return EFI_SUCCESS;
664 }
665
666 EFI_STATUS device_path_to_str(const EFI_DEVICE_PATH *dp, char16_t **ret) {
667 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *dp_to_text;
668 EFI_STATUS err;
669 _cleanup_free_ char16_t *str = NULL;
670
671 assert(dp);
672 assert(ret);
673
674 err = BS->LocateProtocol(MAKE_GUID_PTR(EFI_DEVICE_PATH_TO_TEXT_PROTOCOL), NULL, (void **) &dp_to_text);
675 if (err != EFI_SUCCESS) {
676 /* If the device path to text protocol is not available we can still do a best-effort attempt
677 * to convert it ourselves if we are given filepath-only device path. */
678
679 size_t size = 0;
680 for (const EFI_DEVICE_PATH *node = dp; !IsDevicePathEnd(node);
681 node = NextDevicePathNode(node)) {
682
683 if (DevicePathType(node) != MEDIA_DEVICE_PATH ||
684 DevicePathSubType(node) != MEDIA_FILEPATH_DP)
685 return err;
686
687 size_t path_size = DevicePathNodeLength(node);
688 if (path_size <= offsetof(FILEPATH_DEVICE_PATH, PathName) || path_size % sizeof(char16_t))
689 return EFI_INVALID_PARAMETER;
690 path_size -= offsetof(FILEPATH_DEVICE_PATH, PathName);
691
692 _cleanup_free_ char16_t *old = str;
693 str = xmalloc(size + path_size);
694 if (old) {
695 memcpy(str, old, size);
696 str[size / sizeof(char16_t) - 1] = '\\';
697 }
698
699 memcpy(str + (size / sizeof(char16_t)),
700 ((uint8_t *) node) + offsetof(FILEPATH_DEVICE_PATH, PathName),
701 path_size);
702 size += path_size;
703 }
704
705 *ret = TAKE_PTR(str);
706 return EFI_SUCCESS;
707 }
708
709 str = dp_to_text->ConvertDevicePathToText(dp, false, false);
710 if (!str)
711 return EFI_OUT_OF_RESOURCES;
712
713 *ret = TAKE_PTR(str);
714 return EFI_SUCCESS;
715 }
716
717 void *find_configuration_table(const EFI_GUID *guid) {
718 for (size_t i = 0; i < ST->NumberOfTableEntries; i++)
719 if (efi_guid_equal(&ST->ConfigurationTable[i].VendorGuid, guid))
720 return ST->ConfigurationTable[i].VendorTable;
721
722 return NULL;
723 }