1 /* $OpenBSD: efiboot.c,v 1.11 2024/06/23 13:11:51 kettenis Exp $ */
2
3 /*
4 * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
5 * Copyright (c) 2016 Mark Kettenis
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 #include <sys/param.h>
21 #include <sys/queue.h>
22 #include <sys/stat.h>
23 #include <dev/cons.h>
24 #include <sys/disklabel.h>
25
26 #include <efi.h>
27 #include <efiapi.h>
28 #include <efiprot.h>
29 #include <eficonsctl.h>
30
31 #include <dev/biovar.h>
32 #include <dev/softraidvar.h>
33
34 #include <lib/libkern/libkern.h>
35 #include <lib/libsa/softraid.h>
36 #include <stand/boot/cmd.h>
37
38 #include "libsa.h"
39 #include "disk.h"
40 #include "softraid_riscv64.h"
41
42 #include "efidev.h"
43 #include "efiboot.h"
44 #include "efidt.h"
45 #include "fdt.h"
46
47 EFI_SYSTEM_TABLE *ST;
48 EFI_BOOT_SERVICES *BS;
49 EFI_RUNTIME_SERVICES *RS;
50 EFI_HANDLE IH, efi_bootdp;
51 void *fdt_sys = NULL;
52 void *fdt_override = NULL;
53 size_t fdt_override_size;
54
55 EFI_PHYSICAL_ADDRESS heap;
56 UINTN heapsiz = 1 * 1024 * 1024;
57 EFI_MEMORY_DESCRIPTOR *mmap;
58 UINTN mmap_key;
59 UINTN mmap_ndesc;
60 UINTN mmap_descsiz;
61 UINT32 mmap_version;
62
63 static EFI_GUID imgp_guid = LOADED_IMAGE_PROTOCOL;
64 static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL;
65 static EFI_GUID devp_guid = DEVICE_PATH_PROTOCOL;
66 static EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
67 static EFI_GUID fdt_guid = FDT_TABLE_GUID;
68 static EFI_GUID dt_fixup_guid = EFI_DT_FIXUP_PROTOCOL_GUID;
69
70 #define efi_guidcmp(_a, _b) memcmp((_a), (_b), sizeof(EFI_GUID))
71
72 int efi_device_path_depth(EFI_DEVICE_PATH *dp, int);
73 int efi_device_path_ncmp(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *, int);
74 static void efi_heap_init(void);
75 static void efi_memprobe_internal(void);
76 static void efi_timer_init(void);
77 static void efi_timer_cleanup(void);
78 static EFI_STATUS efi_memprobe_find(UINTN, UINTN, EFI_PHYSICAL_ADDRESS *);
79 void *efi_fdt(void);
80 int fdt_load_override(char *);
81
82 EFI_STATUS
efi_main(EFI_HANDLE image,EFI_SYSTEM_TABLE * systab)83 efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
84 {
85 extern char *progname;
86 EFI_LOADED_IMAGE *imgp;
87 EFI_DEVICE_PATH *dp = NULL;
88 EFI_STATUS status;
89 int i;
90
91 ST = systab;
92 BS = ST->BootServices;
93 RS = ST->RuntimeServices;
94 IH = image;
95
96 /* disable reset by watchdog after 5 minutes */
97 BS->SetWatchdogTimer(0, 0, 0, NULL);
98
99 status = BS->HandleProtocol(image, &imgp_guid, (void **)&imgp);
100 if (status == EFI_SUCCESS)
101 status = BS->HandleProtocol(imgp->DeviceHandle, &devp_guid,
102 (void **)&dp);
103 if (status == EFI_SUCCESS)
104 efi_bootdp = dp;
105
106 for (i = 0; i < ST->NumberOfTableEntries; i++) {
107 if (efi_guidcmp(&fdt_guid,
108 &ST->ConfigurationTable[i].VendorGuid) == 0)
109 fdt_sys = ST->ConfigurationTable[i].VendorTable;
110 }
111 fdt_init(fdt_sys);
112
113 progname = "BOOTRISCV64";
114
115 boot(0);
116
117 return (EFI_SUCCESS);
118 }
119
120 static SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
121 static SIMPLE_INPUT_INTERFACE *conin;
122
123 /*
124 * The device majors for these don't match the ones used by the
125 * kernel. That's fine. They're just used as an index into the cdevs
126 * array and never passed on to the kernel.
127 */
128 static dev_t serial = makedev(0, 0);
129 static dev_t framebuffer = makedev(1, 0);
130
131 static char framebuffer_path[128];
132
133 void
efi_cons_probe(struct consdev * cn)134 efi_cons_probe(struct consdev *cn)
135 {
136 cn->cn_pri = CN_MIDPRI;
137 cn->cn_dev = serial;
138 }
139
140 void
efi_cons_init(struct consdev * cp)141 efi_cons_init(struct consdev *cp)
142 {
143 conin = ST->ConIn;
144 conout = ST->ConOut;
145 }
146
147 int
efi_cons_getc(dev_t dev)148 efi_cons_getc(dev_t dev)
149 {
150 EFI_INPUT_KEY key;
151 EFI_STATUS status;
152 #if 0
153 UINTN dummy;
154 #endif
155 static int lastchar = 0;
156
157 if (lastchar) {
158 int r = lastchar;
159 if ((dev & 0x80) == 0)
160 lastchar = 0;
161 return (r);
162 }
163
164 status = conin->ReadKeyStroke(conin, &key);
165 while (status == EFI_NOT_READY || key.UnicodeChar == 0) {
166 if (dev & 0x80)
167 return (0);
168 /*
169 * XXX The implementation of WaitForEvent() in U-boot
170 * is broken and neverreturns.
171 */
172 #if 0
173 BS->WaitForEvent(1, &conin->WaitForKey, &dummy);
174 #endif
175 status = conin->ReadKeyStroke(conin, &key);
176 }
177
178 if (dev & 0x80)
179 lastchar = key.UnicodeChar;
180
181 return (key.UnicodeChar);
182 }
183
184 void
efi_cons_putc(dev_t dev,int c)185 efi_cons_putc(dev_t dev, int c)
186 {
187 CHAR16 buf[2];
188
189 if (c == '\n')
190 efi_cons_putc(dev, '\r');
191
192 buf[0] = c;
193 buf[1] = 0;
194
195 conout->OutputString(conout, buf);
196 }
197
198 void
efi_fb_probe(struct consdev * cn)199 efi_fb_probe(struct consdev *cn)
200 {
201 cn->cn_pri = CN_LOWPRI;
202 cn->cn_dev = framebuffer;
203 }
204
205 void
efi_fb_init(struct consdev * cn)206 efi_fb_init(struct consdev *cn)
207 {
208 conin = ST->ConIn;
209 conout = ST->ConOut;
210 }
211
212 int
efi_fb_getc(dev_t dev)213 efi_fb_getc(dev_t dev)
214 {
215 return efi_cons_getc(dev);
216 }
217
218 void
efi_fb_putc(dev_t dev,int c)219 efi_fb_putc(dev_t dev, int c)
220 {
221 efi_cons_putc(dev, c);
222 }
223
224 static void
efi_heap_init(void)225 efi_heap_init(void)
226 {
227 EFI_STATUS status;
228
229 status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
230 EFI_SIZE_TO_PAGES(heapsiz), &heap);
231 if (status != EFI_SUCCESS)
232 panic("BS->AllocatePages()");
233 }
234
235 struct disklist_lh disklist;
236 struct diskinfo *bootdev_dip;
237
238 void
efi_diskprobe(void)239 efi_diskprobe(void)
240 {
241 int i, bootdev = 0, depth = -1;
242 UINTN sz;
243 EFI_STATUS status;
244 EFI_HANDLE *handles = NULL;
245 EFI_BLOCK_IO *blkio;
246 EFI_BLOCK_IO_MEDIA *media;
247 struct diskinfo *di;
248 EFI_DEVICE_PATH *dp;
249
250 TAILQ_INIT(&disklist);
251
252 sz = 0;
253 status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, 0);
254 if (status == EFI_BUFFER_TOO_SMALL) {
255 handles = alloc(sz);
256 status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz,
257 handles);
258 }
259 if (handles == NULL || EFI_ERROR(status))
260 return;
261
262 if (efi_bootdp != NULL)
263 depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH);
264
265 /*
266 * U-Boot incorrectly represents devices with a single
267 * MEDIA_DEVICE_PATH component. In that case include that
268 * component into the matching, otherwise we'll blindly select
269 * the first device.
270 */
271 if (depth == 0)
272 depth = 1;
273
274 for (i = 0; i < sz / sizeof(EFI_HANDLE); i++) {
275 status = BS->HandleProtocol(handles[i], &blkio_guid,
276 (void **)&blkio);
277 if (EFI_ERROR(status))
278 panic("BS->HandleProtocol() returns %d", status);
279
280 media = blkio->Media;
281 if (media->LogicalPartition || !media->MediaPresent)
282 continue;
283 di = alloc(sizeof(struct diskinfo));
284 efid_init(di, blkio);
285
286 if (efi_bootdp == NULL || depth == -1 || bootdev != 0)
287 goto next;
288 status = BS->HandleProtocol(handles[i], &devp_guid,
289 (void **)&dp);
290 if (EFI_ERROR(status))
291 goto next;
292 if (efi_device_path_ncmp(efi_bootdp, dp, depth) == 0) {
293 TAILQ_INSERT_HEAD(&disklist, di, list);
294 bootdev_dip = di;
295 bootdev = 1;
296 continue;
297 }
298 next:
299 TAILQ_INSERT_TAIL(&disklist, di, list);
300 }
301
302 free(handles, sz);
303
304 /* Print available disks and probe for softraid. */
305 i = 0;
306 printf("disks:");
307 TAILQ_FOREACH(di, &disklist, list) {
308 printf(" sd%d%s", i, di == bootdev_dip ? "*" : "");
309 i++;
310 }
311 srprobe();
312 printf("\n");
313 }
314
315 /*
316 * Determine the number of nodes up to, but not including, the first
317 * node of the specified type.
318 */
319 int
efi_device_path_depth(EFI_DEVICE_PATH * dp,int dptype)320 efi_device_path_depth(EFI_DEVICE_PATH *dp, int dptype)
321 {
322 int i;
323
324 for (i = 0; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp), i++) {
325 if (DevicePathType(dp) == dptype)
326 return (i);
327 }
328
329 return (i);
330 }
331
332 int
efi_device_path_ncmp(EFI_DEVICE_PATH * dpa,EFI_DEVICE_PATH * dpb,int deptn)333 efi_device_path_ncmp(EFI_DEVICE_PATH *dpa, EFI_DEVICE_PATH *dpb, int deptn)
334 {
335 int i, cmp;
336
337 for (i = 0; i < deptn; i++) {
338 if (IsDevicePathEnd(dpa) || IsDevicePathEnd(dpb))
339 return ((IsDevicePathEnd(dpa) && IsDevicePathEnd(dpb))
340 ? 0 : (IsDevicePathEnd(dpa))? -1 : 1);
341 cmp = DevicePathNodeLength(dpa) - DevicePathNodeLength(dpb);
342 if (cmp)
343 return (cmp);
344 cmp = memcmp(dpa, dpb, DevicePathNodeLength(dpa));
345 if (cmp)
346 return (cmp);
347 dpa = NextDevicePathNode(dpa);
348 dpb = NextDevicePathNode(dpb);
349 }
350
351 return (0);
352 }
353
354 void
efi_framebuffer(void)355 efi_framebuffer(void)
356 {
357 EFI_GRAPHICS_OUTPUT *gop;
358 EFI_STATUS status;
359 void *node, *child;
360 uint32_t acells, scells;
361 uint64_t base, size;
362 uint32_t reg[4];
363 uint32_t width, height, stride;
364 char *format;
365 char *prop;
366
367 /*
368 * Don't create a "simple-framebuffer" node if we already have
369 * one. Besides "/chosen", we also check under "/" since that
370 * is where the Raspberry Pi firmware puts it.
371 */
372 node = fdt_find_node("/chosen");
373 for (child = fdt_child_node(node); child;
374 child = fdt_next_node(child)) {
375 if (!fdt_node_is_compatible(child, "simple-framebuffer"))
376 continue;
377 if (!fdt_node_property(child, "status", &prop) ||
378 strcmp(prop, "okay") == 0) {
379 strlcpy(framebuffer_path, "/chosen/",
380 sizeof(framebuffer_path));
381 strlcat(framebuffer_path, fdt_node_name(child),
382 sizeof(framebuffer_path));
383 return;
384 }
385 }
386 node = fdt_find_node("/");
387 for (child = fdt_child_node(node); child;
388 child = fdt_next_node(child)) {
389 if (!fdt_node_is_compatible(child, "simple-framebuffer"))
390 continue;
391 if (!fdt_node_property(child, "status", &prop) ||
392 strcmp(prop, "okay") == 0) {
393 strlcpy(framebuffer_path, "/",
394 sizeof(framebuffer_path));
395 strlcat(framebuffer_path, fdt_node_name(child),
396 sizeof(framebuffer_path));
397 return;
398 }
399 }
400
401 status = BS->LocateProtocol(&gop_guid, NULL, (void **)&gop);
402 if (status != EFI_SUCCESS)
403 return;
404
405 /* Paranoia! */
406 if (gop == NULL || gop->Mode == NULL || gop->Mode->Info == NULL)
407 return;
408
409 /* We only support 32-bit pixel modes for now. */
410 switch (gop->Mode->Info->PixelFormat) {
411 case PixelRedGreenBlueReserved8BitPerColor:
412 format = "x8b8g8r8";
413 break;
414 case PixelBlueGreenRedReserved8BitPerColor:
415 format = "x8r8g8b8";
416 break;
417 default:
418 return;
419 }
420
421 base = gop->Mode->FrameBufferBase;
422 size = gop->Mode->FrameBufferSize;
423 width = htobe32(gop->Mode->Info->HorizontalResolution);
424 height = htobe32(gop->Mode->Info->VerticalResolution);
425 stride = htobe32(gop->Mode->Info->PixelsPerScanLine * 4);
426
427 node = fdt_find_node("/");
428 if (fdt_node_property_int(node, "#address-cells", &acells) != 1)
429 acells = 1;
430 if (fdt_node_property_int(node, "#size-cells", &scells) != 1)
431 scells = 1;
432 if (acells > 2 || scells > 2)
433 return;
434 if (acells >= 1)
435 reg[0] = htobe32(base);
436 if (acells == 2) {
437 reg[1] = reg[0];
438 reg[0] = htobe32(base >> 32);
439 }
440 if (scells >= 1)
441 reg[acells] = htobe32(size);
442 if (scells == 2) {
443 reg[acells + 1] = reg[acells];
444 reg[acells] = htobe32(size >> 32);
445 }
446
447 node = fdt_find_node("/chosen");
448 fdt_node_add_node(node, "framebuffer", &child);
449 fdt_node_add_property(child, "status", "okay", strlen("okay") + 1);
450 fdt_node_add_property(child, "format", format, strlen(format) + 1);
451 fdt_node_add_property(child, "stride", &stride, 4);
452 fdt_node_add_property(child, "height", &height, 4);
453 fdt_node_add_property(child, "width", &width, 4);
454 fdt_node_add_property(child, "reg", reg, (acells + scells) * 4);
455 fdt_node_add_property(child, "compatible",
456 "simple-framebuffer", strlen("simple-framebuffer") + 1);
457
458 strlcpy(framebuffer_path, "/chosen/framebuffer",
459 sizeof(framebuffer_path));
460 }
461
462 void
efi_console(void)463 efi_console(void)
464 {
465 void *node;
466
467 if (cn_tab->cn_dev != framebuffer)
468 return;
469
470 if (strlen(framebuffer_path) == 0)
471 return;
472
473 /* Point stdout-path at the framebuffer node. */
474 node = fdt_find_node("/chosen");
475 fdt_node_add_property(node, "stdout-path",
476 framebuffer_path, strlen(framebuffer_path) + 1);
477 }
478
479 uint64_t dma_constraint[2] = { 0, -1 };
480
481 void
efi_dma_constraint(void)482 efi_dma_constraint(void)
483 {
484 void *node;
485
486 /* StarFive JH71x0 has peripherals that only support 32-bit DMA. */
487 node = fdt_find_node("/");
488 if (fdt_node_is_compatible(node, "starfive,jh7100") ||
489 fdt_node_is_compatible(node, "starfive,jh7110"))
490 dma_constraint[1] = htobe64(0xffffffff);
491
492 /* Pass DMA constraint. */
493 node = fdt_find_node("/chosen");
494 fdt_node_add_property(node, "openbsd,dma-constraint",
495 dma_constraint, sizeof(dma_constraint));
496 }
497
498 char *bootmac = NULL;
499
500 void *
efi_makebootargs(char * bootargs,int howto)501 efi_makebootargs(char *bootargs, int howto)
502 {
503 struct sr_boot_volume *bv;
504 u_char bootduid[8];
505 u_char zero[8] = { 0 };
506 uint64_t uefi_system_table = htobe64((uintptr_t)ST);
507 uint32_t boothowto = htobe32(howto);
508 int32_t hartid;
509 EFI_PHYSICAL_ADDRESS addr;
510 void *node, *fdt;
511 size_t len;
512
513 fdt = efi_fdt();
514 if (fdt == NULL)
515 return NULL;
516
517 if (!fdt_get_size(fdt))
518 return NULL;
519
520 len = roundup(fdt_get_size(fdt) + PAGE_SIZE, PAGE_SIZE);
521 if (BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
522 EFI_SIZE_TO_PAGES(len), &addr) == EFI_SUCCESS) {
523 memcpy((void *)addr, fdt, fdt_get_size(fdt));
524 ((struct fdt_head *)addr)->fh_size = htobe32(len);
525 fdt = (void *)addr;
526 }
527
528 if (!fdt_init(fdt))
529 return NULL;
530
531 /* Create common nodes which might not exist when using mach dtb */
532 node = fdt_find_node("/aliases");
533 if (node == NULL)
534 fdt_node_add_node(fdt_find_node("/"), "aliases", &node);
535 node = fdt_find_node("/chosen");
536 if (node == NULL)
537 fdt_node_add_node(fdt_find_node("/"), "chosen", &node);
538
539 node = fdt_find_node("/chosen");
540 hartid = efi_get_boot_hart_id();
541 if (hartid >= 0) {
542 hartid = htobe32(hartid);
543 fdt_node_add_property(node, "boot-hartid", &hartid, 4);
544 }
545
546 len = strlen(bootargs) + 1;
547 fdt_node_add_property(node, "bootargs", bootargs, len);
548 fdt_node_add_property(node, "openbsd,boothowto",
549 &boothowto, sizeof(boothowto));
550
551 /* Pass DUID of the boot disk. */
552 if (bootdev_dip) {
553 memcpy(&bootduid, bootdev_dip->disklabel.d_uid,
554 sizeof(bootduid));
555 if (memcmp(bootduid, zero, sizeof(bootduid)) != 0) {
556 fdt_node_add_property(node, "openbsd,bootduid",
557 bootduid, sizeof(bootduid));
558 }
559
560 if (bootdev_dip->sr_vol != NULL) {
561 bv = bootdev_dip->sr_vol;
562 fdt_node_add_property(node, "openbsd,sr-bootuuid",
563 &bv->sbv_uuid, sizeof(bv->sbv_uuid));
564 if (bv->sbv_maskkey != NULL)
565 fdt_node_add_property(node,
566 "openbsd,sr-bootkey", bv->sbv_maskkey,
567 SR_CRYPTO_MAXKEYBYTES);
568 }
569 }
570
571 sr_clear_keys();
572
573 /* Pass netboot interface address. */
574 if (bootmac)
575 fdt_node_add_property(node, "openbsd,bootmac", bootmac, 6);
576
577 /* Pass EFI system table. */
578 fdt_node_add_property(node, "openbsd,uefi-system-table",
579 &uefi_system_table, sizeof(uefi_system_table));
580
581 /* Placeholders for EFI memory map. */
582 fdt_node_add_property(node, "openbsd,uefi-mmap-start", zero, 8);
583 fdt_node_add_property(node, "openbsd,uefi-mmap-size", zero, 4);
584 fdt_node_add_property(node, "openbsd,uefi-mmap-desc-size", zero, 4);
585 fdt_node_add_property(node, "openbsd,uefi-mmap-desc-ver", zero, 4);
586
587 efi_framebuffer();
588 efi_console();
589 efi_dma_constraint();
590
591 fdt_finalize();
592
593 return fdt;
594 }
595
596 void
efi_updatefdt(void)597 efi_updatefdt(void)
598 {
599 uint64_t uefi_mmap_start = htobe64((uintptr_t)mmap);
600 uint32_t uefi_mmap_size = htobe32(mmap_ndesc * mmap_descsiz);
601 uint32_t uefi_mmap_desc_size = htobe32(mmap_descsiz);
602 uint32_t uefi_mmap_desc_ver = htobe32(mmap_version);
603 void *node;
604
605 node = fdt_find_node("/chosen");
606 if (!node)
607 return;
608
609 /* Pass EFI memory map. */
610 fdt_node_set_property(node, "openbsd,uefi-mmap-start",
611 &uefi_mmap_start, sizeof(uefi_mmap_start));
612 fdt_node_set_property(node, "openbsd,uefi-mmap-size",
613 &uefi_mmap_size, sizeof(uefi_mmap_size));
614 fdt_node_set_property(node, "openbsd,uefi-mmap-desc-size",
615 &uefi_mmap_desc_size, sizeof(uefi_mmap_desc_size));
616 fdt_node_set_property(node, "openbsd,uefi-mmap-desc-ver",
617 &uefi_mmap_desc_ver, sizeof(uefi_mmap_desc_ver));
618
619 fdt_finalize();
620 }
621
622 u_long efi_loadaddr;
623
624 void
machdep(void)625 machdep(void)
626 {
627 EFI_PHYSICAL_ADDRESS addr;
628
629 cninit();
630 efi_heap_init();
631
632 /*
633 * The kernel expects to be loaded into a block of memory aligned
634 * on a 2MB boundary. We allocate a block of 64MB of memory, which
635 * gives us plenty of room for growth.
636 */
637 if (efi_memprobe_find(EFI_SIZE_TO_PAGES(64 * 1024 * 1024),
638 0x200000, &addr) != EFI_SUCCESS)
639 printf("Can't allocate memory\n");
640 efi_loadaddr = addr;
641
642 efi_timer_init();
643 efi_diskprobe();
644 efi_pxeprobe();
645 }
646
647 void
efi_cleanup(void)648 efi_cleanup(void)
649 {
650 int retry;
651 EFI_STATUS status;
652
653 efi_timer_cleanup();
654
655 /* retry once in case of failure */
656 for (retry = 1; retry >= 0; retry--) {
657 efi_memprobe_internal(); /* sync the current map */
658 efi_updatefdt();
659 status = BS->ExitBootServices(IH, mmap_key);
660 if (status == EFI_SUCCESS)
661 break;
662 if (retry == 0)
663 panic("ExitBootServices failed (%d)", status);
664 }
665 }
666
667 void
_rtt(void)668 _rtt(void)
669 {
670 #ifdef EFI_DEBUG
671 printf("Hit any key to reboot\n");
672 efi_cons_getc(0);
673 #endif
674 RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
675 for (;;)
676 continue;
677 }
678
679 /*
680 * U-Boot only implements the GetTime() Runtime Service if it has been
681 * configured with CONFIG_DM_RTC. Most board configurations don't
682 * include that option, so we can't use it to implement our boot
683 * prompt timeout. Instead we use timer events to simulate a clock
684 * that ticks ever second.
685 */
686
687 EFI_EVENT timer;
688 int ticks;
689
690 static VOID
efi_timer(EFI_EVENT event,VOID * context)691 efi_timer(EFI_EVENT event, VOID *context)
692 {
693 ticks++;
694 }
695
696 static void
efi_timer_init(void)697 efi_timer_init(void)
698 {
699 EFI_STATUS status;
700
701 status = BS->CreateEvent(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
702 efi_timer, NULL, &timer);
703 if (status == EFI_SUCCESS)
704 status = BS->SetTimer(timer, TimerPeriodic, 10000000);
705 if (EFI_ERROR(status))
706 printf("Can't create timer\n");
707 }
708
709 static void
efi_timer_cleanup(void)710 efi_timer_cleanup(void)
711 {
712 BS->CloseEvent(timer);
713 }
714
715 time_t
getsecs(void)716 getsecs(void)
717 {
718 return ticks;
719 }
720
721 /*
722 * Various device-related bits.
723 */
724
725 void
devboot(dev_t dev,char * p)726 devboot(dev_t dev, char *p)
727 {
728 struct sr_boot_volume *bv;
729 struct sr_boot_chunk *bc;
730 struct diskinfo *dip;
731 int sd_boot_vol = 0;
732 int sr_boot_vol = -1;
733 int part_type = FS_UNUSED;
734
735 if (bootdev_dip == NULL) {
736 strlcpy(p, "tftp0a", 7);
737 return;
738 }
739
740 TAILQ_FOREACH(dip, &disklist, list) {
741 if (bootdev_dip == dip)
742 break;
743 sd_boot_vol++;
744 }
745
746 /*
747 * Determine the partition type for the 'a' partition of the
748 * boot device.
749 */
750 if ((bootdev_dip->flags & DISKINFO_FLAG_GOODLABEL) != 0)
751 part_type = bootdev_dip->disklabel.d_partitions[0].p_fstype;
752
753 /*
754 * See if we booted from a disk that is a member of a bootable
755 * softraid volume.
756 */
757 SLIST_FOREACH(bv, &sr_volumes, sbv_link) {
758 SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link)
759 if (bc->sbc_diskinfo == bootdev_dip)
760 sr_boot_vol = bv->sbv_unit;
761 if (sr_boot_vol != -1)
762 break;
763 }
764
765 if (sr_boot_vol != -1 && part_type != FS_BSDFFS) {
766 strlcpy(p, "sr0a", 5);
767 p[2] = '0' + sr_boot_vol;
768 return;
769 }
770
771 strlcpy(p, "sd0a", 5);
772 p[2] = '0' + sd_boot_vol;
773 }
774
775 const char cdevs[][4] = { "com", "fb" };
776 const int ncdevs = nitems(cdevs);
777
778 int
cnspeed(dev_t dev,int sp)779 cnspeed(dev_t dev, int sp)
780 {
781 return 115200;
782 }
783
784 char ttyname_buf[8];
785
786 char *
ttyname(int fd)787 ttyname(int fd)
788 {
789 snprintf(ttyname_buf, sizeof ttyname_buf, "%s%d",
790 cdevs[major(cn_tab->cn_dev)], minor(cn_tab->cn_dev));
791
792 return ttyname_buf;
793 }
794
795 dev_t
ttydev(char * name)796 ttydev(char *name)
797 {
798 int i, unit = -1;
799 char *no = name + strlen(name) - 1;
800
801 while (no >= name && *no >= '0' && *no <= '9')
802 unit = (unit < 0 ? 0 : (unit * 10)) + *no-- - '0';
803 if (no < name || unit < 0)
804 return NODEV;
805 for (i = 0; i < ncdevs; i++)
806 if (strncmp(name, cdevs[i], no - name + 1) == 0)
807 return makedev(i, unit);
808 return NODEV;
809 }
810
811 #define MAXDEVNAME 16
812
813 /*
814 * Parse a device spec.
815 *
816 * [A-Za-z]*[0-9]*[A-Za-z]:file
817 * dev uint part
818 */
819 int
devparse(const char * fname,int * dev,int * unit,int * part,const char ** file)820 devparse(const char *fname, int *dev, int *unit, int *part, const char **file)
821 {
822 const char *s;
823
824 *unit = 0; /* default to wd0a */
825 *part = 0;
826 *dev = 0;
827
828 s = strchr(fname, ':');
829 if (s != NULL) {
830 int devlen;
831 int i, u, p = 0;
832 struct devsw *dp;
833 char devname[MAXDEVNAME];
834
835 devlen = s - fname;
836 if (devlen > MAXDEVNAME)
837 return (EINVAL);
838
839 /* extract device name */
840 for (i = 0; isalpha(fname[i]) && (i < devlen); i++)
841 devname[i] = fname[i];
842 devname[i] = 0;
843
844 if (!isdigit(fname[i]))
845 return (EUNIT);
846
847 /* device number */
848 for (u = 0; isdigit(fname[i]) && (i < devlen); i++)
849 u = u * 10 + (fname[i] - '0');
850
851 if (!isalpha(fname[i]))
852 return (EPART);
853
854 /* partition number */
855 if (i < devlen)
856 p = fname[i++] - 'a';
857
858 if (i != devlen)
859 return (ENXIO);
860
861 /* check device name */
862 for (dp = devsw, i = 0; i < ndevs; dp++, i++) {
863 if (dp->dv_name && !strcmp(devname, dp->dv_name))
864 break;
865 }
866
867 if (i >= ndevs)
868 return (ENXIO);
869
870 *unit = u;
871 *part = p;
872 *dev = i;
873 fname = ++s;
874 }
875
876 *file = fname;
877
878 return (0);
879 }
880
881 int
devopen(struct open_file * f,const char * fname,char ** file)882 devopen(struct open_file *f, const char *fname, char **file)
883 {
884 struct devsw *dp;
885 int dev, unit, part, error;
886
887 error = devparse(fname, &dev, &unit, &part, (const char **)file);
888 if (error)
889 return (error);
890
891 dp = &devsw[dev];
892 f->f_dev = dp;
893
894 if (strcmp("tftp", dp->dv_name) != 0) {
895 /*
896 * Clear bootmac, to signal that we loaded this file from a
897 * non-network device.
898 */
899 bootmac = NULL;
900 }
901
902 return (*dp->dv_open)(f, unit, part);
903 }
904
905 static void
efi_memprobe_internal(void)906 efi_memprobe_internal(void)
907 {
908 EFI_STATUS status;
909 UINTN mapkey, mmsiz, siz;
910 UINT32 mmver;
911 EFI_MEMORY_DESCRIPTOR *mm;
912 int n;
913
914 free(mmap, mmap_ndesc * mmap_descsiz);
915
916 siz = 0;
917 status = BS->GetMemoryMap(&siz, NULL, &mapkey, &mmsiz, &mmver);
918 if (status != EFI_BUFFER_TOO_SMALL)
919 panic("cannot get the size of memory map");
920 mm = alloc(siz);
921 status = BS->GetMemoryMap(&siz, mm, &mapkey, &mmsiz, &mmver);
922 if (status != EFI_SUCCESS)
923 panic("cannot get the memory map");
924 n = siz / mmsiz;
925 mmap = mm;
926 mmap_key = mapkey;
927 mmap_ndesc = n;
928 mmap_descsiz = mmsiz;
929 mmap_version = mmver;
930 }
931
932 /*
933 * 64-bit ARMs can have a much wider memory mapping, as in somewhere
934 * after the 32-bit region. To cope with our alignment requirement,
935 * use the memory table to find a place where we can fit.
936 */
937 static EFI_STATUS
efi_memprobe_find(UINTN pages,UINTN align,EFI_PHYSICAL_ADDRESS * addr)938 efi_memprobe_find(UINTN pages, UINTN align, EFI_PHYSICAL_ADDRESS *addr)
939 {
940 EFI_MEMORY_DESCRIPTOR *mm;
941 int i, j;
942
943 if (align < EFI_PAGE_SIZE)
944 return EFI_INVALID_PARAMETER;
945
946 efi_memprobe_internal(); /* sync the current map */
947
948 for (i = 0, mm = mmap; i < mmap_ndesc;
949 i++, mm = NextMemoryDescriptor(mm, mmap_descsiz)) {
950 if (mm->Type != EfiConventionalMemory)
951 continue;
952
953 if (mm->NumberOfPages < pages)
954 continue;
955
956 for (j = 0; j < mm->NumberOfPages; j++) {
957 EFI_PHYSICAL_ADDRESS paddr;
958
959 if (mm->NumberOfPages - j < pages)
960 break;
961
962 paddr = mm->PhysicalStart + (j * EFI_PAGE_SIZE);
963 if (paddr & (align - 1))
964 continue;
965
966 if (BS->AllocatePages(AllocateAddress, EfiLoaderData,
967 pages, &paddr) == EFI_SUCCESS) {
968 *addr = paddr;
969 return EFI_SUCCESS;
970 }
971 }
972 }
973 return EFI_OUT_OF_RESOURCES;
974 }
975
976 void *
efi_fdt(void)977 efi_fdt(void)
978 {
979 /* 'mach dtb' has precedence */
980 if (fdt_override != NULL)
981 return fdt_override;
982
983 return fdt_sys;
984 }
985
986 int
fdt_load_override(char * file)987 fdt_load_override(char *file)
988 {
989 EFI_DT_FIXUP_PROTOCOL *dt_fixup;
990 EFI_PHYSICAL_ADDRESS addr;
991 char path[MAXPATHLEN];
992 EFI_STATUS status;
993 struct stat sb;
994 size_t dt_size;
995 UINTN sz;
996 int fd;
997
998 if (file == NULL && fdt_override) {
999 BS->FreePages((uint64_t)fdt_override,
1000 EFI_SIZE_TO_PAGES(fdt_override_size));
1001 fdt_override = NULL;
1002 fdt_init(fdt_sys);
1003 return 0;
1004 }
1005
1006 snprintf(path, sizeof(path), "%s:%s", cmd.bootdev, file);
1007
1008 fd = open(path, O_RDONLY);
1009 if (fd < 0 || fstat(fd, &sb) == -1) {
1010 printf("cannot open %s\n", path);
1011 return 0;
1012 }
1013 dt_size = sb.st_size;
1014 retry:
1015 if (efi_memprobe_find(EFI_SIZE_TO_PAGES(dt_size),
1016 PAGE_SIZE, &addr) != EFI_SUCCESS) {
1017 printf("cannot allocate memory for %s\n", path);
1018 return 0;
1019 }
1020 if (read(fd, (void *)addr, sb.st_size) != sb.st_size) {
1021 printf("cannot read from %s\n", path);
1022 return 0;
1023 }
1024
1025 status = BS->LocateProtocol(&dt_fixup_guid, NULL, (void **)&dt_fixup);
1026 if (status == EFI_SUCCESS) {
1027 sz = dt_size;
1028 status = dt_fixup->Fixup(dt_fixup, (void *)addr, &sz,
1029 EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY);
1030 if (status == EFI_BUFFER_TOO_SMALL) {
1031 BS->FreePages(addr, EFI_SIZE_TO_PAGES(dt_size));
1032 lseek(fd, 0, SEEK_SET);
1033 dt_size = sz;
1034 goto retry;
1035 }
1036 if (status != EFI_SUCCESS)
1037 panic("DT fixup failed: 0x%lx", status);
1038 }
1039
1040 if (!fdt_init((void *)addr)) {
1041 printf("invalid device tree\n");
1042 BS->FreePages(addr, EFI_SIZE_TO_PAGES(dt_size));
1043 return 0;
1044 }
1045
1046 if (fdt_override) {
1047 BS->FreePages((uint64_t)fdt_override,
1048 EFI_SIZE_TO_PAGES(fdt_override_size));
1049 fdt_override = NULL;
1050 }
1051
1052 fdt_override = (void *)addr;
1053 fdt_override_size = dt_size;
1054 return 0;
1055 }
1056
1057 /*
1058 * Commands
1059 */
1060
1061 int Xdtb_efi(void);
1062 int Xexit_efi(void);
1063 int Xpoweroff_efi(void);
1064
1065 const struct cmd_table cmd_machine[] = {
1066 { "dtb", CMDT_CMD, Xdtb_efi },
1067 { "exit", CMDT_CMD, Xexit_efi },
1068 { "poweroff", CMDT_CMD, Xpoweroff_efi },
1069 { NULL, 0 }
1070 };
1071
1072 int
Xdtb_efi(void)1073 Xdtb_efi(void)
1074 {
1075 if (cmd.argc == 1) {
1076 fdt_load_override(NULL);
1077 return (0);
1078 }
1079
1080 if (cmd.argc != 2) {
1081 printf("dtb file\n");
1082 return (0);
1083 }
1084
1085 return fdt_load_override(cmd.argv[1]);
1086 }
1087
1088 int
Xexit_efi(void)1089 Xexit_efi(void)
1090 {
1091 BS->Exit(IH, 0, 0, NULL);
1092 for (;;)
1093 continue;
1094 return (0);
1095 }
1096
1097 int
Xpoweroff_efi(void)1098 Xpoweroff_efi(void)
1099 {
1100 RS->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL);
1101 return (0);
1102 }
1103