fdt_machdep.c revision 1.48 1 /* $NetBSD: fdt_machdep.c,v 1.48 2018/10/30 16:41:53 skrll Exp $ */
2
3 /*-
4 * Copyright (c) 2015-2017 Jared McNeill <jmcneill (at) invisible.ca>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: fdt_machdep.c,v 1.48 2018/10/30 16:41:53 skrll Exp $");
31
32 #include "opt_machdep.h"
33 #include "opt_bootconfig.h"
34 #include "opt_ddb.h"
35 #include "opt_md.h"
36 #include "opt_arm_debug.h"
37 #include "opt_multiprocessor.h"
38 #include "opt_cpuoptions.h"
39 #include "opt_efi.h"
40
41 #include "ukbd.h"
42 #include "wsdisplay.h"
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/bus.h>
47 #include <sys/atomic.h>
48 #include <sys/cpu.h>
49 #include <sys/device.h>
50 #include <sys/exec.h>
51 #include <sys/kernel.h>
52 #include <sys/kmem.h>
53 #include <sys/ksyms.h>
54 #include <sys/msgbuf.h>
55 #include <sys/proc.h>
56 #include <sys/reboot.h>
57 #include <sys/termios.h>
58 #include <sys/extent.h>
59 #include <sys/bootblock.h>
60 #include <sys/disklabel.h>
61 #include <sys/vnode.h>
62 #include <sys/kauth.h>
63 #include <sys/fcntl.h>
64 #include <sys/md5.h>
65
66 #include <dev/cons.h>
67 #include <uvm/uvm_extern.h>
68
69 #include <sys/conf.h>
70
71 #include <machine/db_machdep.h>
72 #include <ddb/db_sym.h>
73 #include <ddb/db_extern.h>
74
75 #include <machine/bootconfig.h>
76 #include <arm/armreg.h>
77
78 #include <arm/cpufunc.h>
79
80 #include <evbarm/include/autoconf.h>
81 #include <evbarm/fdt/machdep.h>
82 #include <evbarm/fdt/platform.h>
83
84 #include <arm/fdt/arm_fdtvar.h>
85
86 #ifdef EFI_RUNTIME
87 #include <arm/arm/efi_runtime.h>
88 #endif
89
90 #if NUKBD > 0
91 #include <dev/usb/ukbdvar.h>
92 #endif
93 #if NWSDISPLAY > 0
94 #include <dev/wscons/wsdisplayvar.h>
95 #endif
96
97 #ifdef MEMORY_DISK_DYNAMIC
98 #include <dev/md.h>
99 #endif
100
101 #ifndef FDT_MAX_BOOT_STRING
102 #define FDT_MAX_BOOT_STRING 1024
103 #endif
104
105 BootConfig bootconfig;
106 char bootargs[FDT_MAX_BOOT_STRING] = "";
107 char *boot_args = NULL;
108
109 /* filled in before cleaning bss. keep in .data */
110 u_long uboot_args[4] __attribute__((__section__(".data")));
111 const uint8_t *fdt_addr_r __attribute__((__section__(".data")));
112
113 static char fdt_memory_ext_storage[EXTENT_FIXED_STORAGE_SIZE(DRAM_BLOCKS)];
114 static struct extent *fdt_memory_ext;
115
116 static uint64_t initrd_start, initrd_end;
117
118 #include <libfdt.h>
119 #include <dev/fdt/fdtvar.h>
120 #define FDT_BUF_SIZE (512*1024)
121 static uint8_t fdt_data[FDT_BUF_SIZE];
122
123 extern char KERNEL_BASE_phys[];
124 #define KERNEL_BASE_PHYS ((paddr_t)KERNEL_BASE_phys)
125
126 static void fdt_update_stdout_path(void);
127 static void fdt_device_register(device_t, void *);
128 static void fdt_device_register_post_config(device_t, void *);
129 static void fdt_cpu_rootconf(void);
130 static void fdt_reset(void);
131 static void fdt_powerdown(void);
132
133 static dev_type_cnputc(earlyconsputc);
134 static dev_type_cngetc(earlyconsgetc);
135
136 static struct consdev earlycons = {
137 .cn_putc = earlyconsputc,
138 .cn_getc = earlyconsgetc,
139 .cn_pollc = nullcnpollc,
140 };
141
142 static void
143 earlyconsputc(dev_t dev, int c)
144 {
145 uartputc(c);
146 }
147
148 static int
149 earlyconsgetc(dev_t dev)
150 {
151 return 0; /* XXX */
152 }
153
154 #ifdef VERBOSE_INIT_ARM
155 #define VPRINTF(...) printf(__VA_ARGS__)
156 #else
157 #define VPRINTF(...) __nothing
158 #endif
159
160 /*
161 * ARM: Get the first physically contiguous region of memory.
162 * ARM64: Get all of physical memory, including holes.
163 */
164 static void
165 fdt_get_memory(uint64_t *pstart, uint64_t *pend)
166 {
167 const int memory = OF_finddevice("/memory");
168 uint64_t cur_addr, cur_size;
169 int index;
170
171 /* Assume the first entry is the start of memory */
172 if (fdtbus_get_reg64(memory, 0, &cur_addr, &cur_size) != 0)
173 panic("Cannot determine memory size");
174
175 *pstart = cur_addr;
176 *pend = cur_addr + cur_size;
177
178 VPRINTF("FDT /memory [%d] @ 0x%" PRIx64 " size 0x%" PRIx64 "\n",
179 0, *pstart, *pend - *pstart);
180
181 for (index = 1;
182 fdtbus_get_reg64(memory, index, &cur_addr, &cur_size) == 0;
183 index++) {
184 VPRINTF("FDT /memory [%d] @ 0x%" PRIx64 " size 0x%" PRIx64 "\n",
185 index, cur_addr, cur_size);
186
187 #ifdef __aarch64__
188 if (cur_addr + cur_size > *pend)
189 *pend = cur_addr + cur_size;
190 #else
191 /* If subsequent entries follow the previous, append them. */
192 if (*pend == cur_addr)
193 *pend = cur_addr + cur_size;
194 #endif
195 }
196 }
197
198 void
199 fdt_add_reserved_memory_range(uint64_t addr, uint64_t size)
200 {
201 uint64_t start = addr;
202 uint64_t end = addr + size;
203
204 int error = extent_free(fdt_memory_ext, start,
205 end - start, EX_NOWAIT);
206 if (error != 0)
207 printf("MEM ERROR: res %" PRIx64 "-%" PRIx64 " failed: %d\n",
208 start, end, error);
209 else
210 VPRINTF("MEM: res %" PRIx64 "-%" PRIx64 "\n", start, end);
211 }
212
213 /*
214 * Exclude memory ranges from memory config from the device tree
215 */
216 static void
217 fdt_add_reserved_memory(uint64_t min_addr, uint64_t max_addr)
218 {
219 uint64_t lstart = 0, lend = 0;
220 uint64_t addr, size;
221 int index, error;
222
223 const int num = fdt_num_mem_rsv(fdtbus_get_data());
224 for (index = 0; index <= num; index++) {
225 error = fdt_get_mem_rsv(fdtbus_get_data(), index,
226 &addr, &size);
227 if (error != 0)
228 continue;
229 if (lstart <= addr && addr <= lend) {
230 size -= (lend - addr);
231 addr = lend;
232 }
233 if (size == 0)
234 continue;
235 if (addr + size <= min_addr)
236 continue;
237 if (addr >= max_addr)
238 continue;
239 if (addr < min_addr) {
240 size -= (min_addr - addr);
241 addr = min_addr;
242 }
243 if (addr + size > max_addr)
244 size = max_addr - addr;
245 fdt_add_reserved_memory_range(addr, size);
246 lstart = addr;
247 lend = addr + size;
248 }
249 }
250
251 /*
252 * Define usable memory regions.
253 */
254 static void
255 fdt_build_bootconfig(uint64_t mem_start, uint64_t mem_end)
256 {
257 const int memory = OF_finddevice("/memory");
258 BootConfig *bc = &bootconfig;
259 struct extent_region *er;
260 uint64_t addr, size;
261 int index, error;
262
263 fdt_memory_ext = extent_create("FDT Memory", mem_start, mem_end,
264 fdt_memory_ext_storage, sizeof(fdt_memory_ext_storage), EX_EARLY);
265
266 for (index = 0;
267 fdtbus_get_reg64(memory, index, &addr, &size) == 0;
268 index++) {
269 if (addr >= mem_end || size == 0)
270 continue;
271 if (addr + size > mem_end)
272 size = mem_end - addr;
273
274 error = extent_alloc_region(fdt_memory_ext, addr, size,
275 EX_NOWAIT);
276 if (error != 0)
277 printf("MEM ERROR: add %" PRIx64 "-%" PRIx64 " failed: %d\n",
278 addr, addr + size, error);
279 VPRINTF("MEM: add %" PRIx64 "-%" PRIx64 "\n", addr, addr + size);
280 }
281
282 fdt_add_reserved_memory(mem_start, mem_end);
283
284 const uint64_t initrd_size = initrd_end - initrd_start;
285 if (initrd_size > 0)
286 fdt_add_reserved_memory_range(initrd_start, initrd_size);
287
288 const int framebuffer = OF_finddevice("/chosen/framebuffer");
289 if (framebuffer >= 0) {
290 for (index = 0;
291 fdtbus_get_reg64(framebuffer, index, &addr, &size) == 0;
292 index++) {
293 fdt_add_reserved_memory_range(addr, size);
294 }
295 }
296
297 VPRINTF("Usable memory:\n");
298 bc->dramblocks = 0;
299 LIST_FOREACH(er, &fdt_memory_ext->ex_regions, er_link) {
300 VPRINTF(" %lx - %lx\n", er->er_start, er->er_end);
301 bc->dram[bc->dramblocks].address = er->er_start;
302 bc->dram[bc->dramblocks].pages =
303 (er->er_end - er->er_start) / PAGE_SIZE;
304 bc->dramblocks++;
305 }
306 }
307
308 static void
309 fdt_probe_initrd(uint64_t *pstart, uint64_t *pend)
310 {
311 *pstart = *pend = 0;
312
313 #ifdef MEMORY_DISK_DYNAMIC
314 const int chosen = OF_finddevice("/chosen");
315 if (chosen < 0)
316 return;
317
318 int len;
319 const void *start_data = fdtbus_get_prop(chosen,
320 "linux,initrd-start", &len);
321 const void *end_data = fdtbus_get_prop(chosen,
322 "linux,initrd-end", NULL);
323 if (start_data == NULL || end_data == NULL)
324 return;
325
326 switch (len) {
327 case 4:
328 *pstart = be32dec(start_data);
329 *pend = be32dec(end_data);
330 break;
331 case 8:
332 *pstart = be64dec(start_data);
333 *pend = be64dec(end_data);
334 break;
335 default:
336 printf("Unsupported len %d for /chosen/initrd-start\n", len);
337 return;
338 }
339 #endif
340 }
341
342 static void
343 fdt_setup_initrd(void)
344 {
345 #ifdef MEMORY_DISK_DYNAMIC
346 const uint64_t initrd_size = initrd_end - initrd_start;
347 paddr_t startpa = trunc_page(initrd_start);
348 paddr_t endpa = round_page(initrd_end);
349 paddr_t pa;
350 vaddr_t va;
351 void *md_start;
352
353 if (initrd_size == 0)
354 return;
355
356 va = uvm_km_alloc(kernel_map, initrd_size, 0,
357 UVM_KMF_VAONLY | UVM_KMF_NOWAIT);
358 if (va == 0) {
359 printf("Failed to allocate VA for initrd\n");
360 return;
361 }
362
363 md_start = (void *)va;
364
365 for (pa = startpa; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE)
366 pmap_kenter_pa(va, pa, VM_PROT_READ|VM_PROT_WRITE, 0);
367 pmap_update(pmap_kernel());
368
369 md_root_setconf(md_start, initrd_size);
370 #endif
371 }
372
373 #ifdef EFI_RUNTIME
374 static void
375 fdt_map_efi_runtime(const char *prop, bool exec)
376 {
377 int len;
378
379 const int chosen_off = fdt_path_offset(fdt_data, "/chosen");
380 if (chosen_off < 0)
381 return;
382
383 const uint64_t *map = fdt_getprop(fdt_data, chosen_off, prop, &len);
384 if (map == NULL)
385 return;
386
387 while (len >= 24) {
388 const paddr_t pa = be64toh(map[0]);
389 const vaddr_t va = be64toh(map[1]);
390 const uint64_t sz = be64toh(map[2]);
391 arm_efirt_md_map_range(va, pa, sz, exec);
392 map += 3;
393 len -= 24;
394 }
395 }
396 #endif
397
398 u_int initarm(void *arg);
399
400 u_int
401 initarm(void *arg)
402 {
403 const struct arm_platform *plat;
404 uint64_t memory_start, memory_end;
405
406 /* set temporally to work printf()/panic() even before consinit() */
407 cn_tab = &earlycons;
408
409 /* Load FDT */
410 int error = fdt_check_header(fdt_addr_r);
411 if (error == 0) {
412 /* If the DTB is too big, try to pack it in place first. */
413 if (fdt_totalsize(fdt_addr_r) > sizeof(fdt_data))
414 (void)fdt_pack(__UNCONST(fdt_addr_r));
415 error = fdt_open_into(fdt_addr_r, fdt_data, sizeof(fdt_data));
416 if (error != 0)
417 panic("fdt_move failed: %s", fdt_strerror(error));
418 fdtbus_set_data(fdt_data);
419 } else {
420 panic("fdt_check_header failed: %s", fdt_strerror(error));
421 }
422
423 /* Lookup platform specific backend */
424 plat = arm_fdt_platform();
425 if (plat == NULL)
426 panic("Kernel does not support this device");
427
428 /* Early console may be available, announce ourselves. */
429 VPRINTF("FDT<%p>\n", fdt_addr_r);
430
431 const int chosen = OF_finddevice("/chosen");
432 if (chosen >= 0)
433 OF_getprop(chosen, "bootargs", bootargs, sizeof(bootargs));
434 boot_args = bootargs;
435
436 /* Heads up ... Setup the CPU / MMU / TLB functions. */
437 VPRINTF("cpufunc\n");
438 if (set_cpufuncs())
439 panic("cpu not recognized!");
440
441 /*
442 * Memory is still identity/flat mapped this point so using ttbr for
443 * l1pt VA is fine
444 */
445
446 VPRINTF("devmap\n");
447 extern char ARM_BOOTSTRAP_LxPT[];
448 pmap_devmap_bootstrap((vaddr_t)ARM_BOOTSTRAP_LxPT, plat->ap_devmap());
449
450 VPRINTF("bootstrap\n");
451 plat->ap_bootstrap();
452
453 /*
454 * If stdout-path is specified on the command line, override the
455 * value in /chosen/stdout-path before initializing console.
456 */
457 VPRINTF("stdout\n");
458 fdt_update_stdout_path();
459
460 /*
461 * Done making changes to the FDT.
462 */
463 fdt_pack(fdt_data);
464
465 VPRINTF("consinit ");
466 consinit();
467 VPRINTF("ok\n");
468
469 VPRINTF("uboot: args %#lx, %#lx, %#lx, %#lx\n",
470 uboot_args[0], uboot_args[1], uboot_args[2], uboot_args[3]);
471
472 cpu_reset_address = fdt_reset;
473 cpu_powerdown_address = fdt_powerdown;
474 evbarm_device_register = fdt_device_register;
475 evbarm_device_register_post_config = fdt_device_register_post_config;
476 evbarm_cpu_rootconf = fdt_cpu_rootconf;
477
478 /* Talk to the user */
479 printf("NetBSD/evbarm (fdt) booting ...\n");
480
481 #ifdef BOOT_ARGS
482 char mi_bootargs[] = BOOT_ARGS;
483 parse_mi_bootargs(mi_bootargs);
484 #endif
485
486 fdt_get_memory(&memory_start, &memory_end);
487
488 #if !defined(_LP64)
489 /* Cannot map memory above 4GB */
490 if (memory_end >= 0x100000000ULL)
491 memory_end = 0x100000000ULL - PAGE_SIZE;
492
493 #endif
494 uint64_t memory_size = memory_end - memory_start;
495
496 VPRINTF("%s: memory start %" PRIx64 " end %" PRIx64 " (len %"
497 PRIx64 ")\n", __func__, memory_start, memory_end, memory_size);
498
499 /* Parse ramdisk info */
500 fdt_probe_initrd(&initrd_start, &initrd_end);
501
502 /*
503 * Populate bootconfig structure for the benefit of
504 * dodumpsys
505 */
506 VPRINTF("%s: fdt_build_bootconfig\n", __func__);
507 fdt_build_bootconfig(memory_start, memory_end);
508
509 #ifdef EFI_RUNTIME
510 fdt_map_efi_runtime("netbsd,uefi-runtime-code", true);
511 fdt_map_efi_runtime("netbsd,uefi-runtime-data", false);
512 #endif
513
514 /* Perform PT build and VM init */
515 cpu_kernel_vm_init(memory_start, memory_size);
516
517 VPRINTF("bootargs: %s\n", bootargs);
518
519 parse_mi_bootargs(boot_args);
520
521 #define MAX_PHYSMEM 64
522 static struct boot_physmem fdt_physmem[MAX_PHYSMEM];
523 int nfdt_physmem = 0;
524 struct extent_region *er;
525
526 VPRINTF("Memory regions :\n");
527 LIST_FOREACH(er, &fdt_memory_ext->ex_regions, er_link) {
528 VPRINTF(" %lx - %lx\n", er->er_start, er->er_end);
529 struct boot_physmem *bp = &fdt_physmem[nfdt_physmem++];
530
531 KASSERT(nfdt_physmem <= MAX_PHYSMEM);
532
533 bp->bp_start = atop(round_page(er->er_start));
534 bp->bp_pages = atop(trunc_page(er->er_end + 1)) - bp->bp_start;
535 bp->bp_freelist = VM_FREELIST_DEFAULT;
536
537 #ifdef _LP64
538 if (er->er_end > 0x100000000)
539 bp->bp_freelist = VM_FREELIST_HIGHMEM;
540 #endif
541
542 #ifdef PMAP_NEED_ALLOC_POOLPAGE
543 if (atop(memory_size) > bp->bp_pages) {
544 arm_poolpage_vmfreelist = VM_FREELIST_DIRECTMAP;
545 bp->bp_freelist = VM_FREELIST_DIRECTMAP;
546 }
547 #endif
548 }
549
550 u_int sp = initarm_common(KERNEL_VM_BASE, KERNEL_VM_SIZE, fdt_physmem,
551 nfdt_physmem);
552
553 VPRINTF("mpstart\n");
554 if (plat->ap_mpstart)
555 plat->ap_mpstart();
556
557 /*
558 * Now we have APs started the pages used for stacks and L1PT can
559 * be given to uvm
560 */
561 extern char __start__init_memory[], __stop__init_memory[];
562 if (__start__init_memory != __stop__init_memory) {
563 const paddr_t spa = KERN_VTOPHYS((vaddr_t)__start__init_memory);
564 const paddr_t epa = KERN_VTOPHYS((vaddr_t)__stop__init_memory);
565 const paddr_t spg = atop(spa);
566 const paddr_t epg = atop(epa);
567
568 uvm_page_physload(spg, epg, spg, epg, VM_FREELIST_DEFAULT);
569
570 VPRINTF(" start %08lx end %08lx", ptoa(spa), ptoa(epa));
571 }
572
573 return sp;
574 }
575
576 static void
577 fdt_update_stdout_path(void)
578 {
579 char *stdout_path, *ep;
580 int stdout_path_len;
581 char buf[256];
582
583 const int chosen_off = fdt_path_offset(fdt_data, "/chosen");
584 if (chosen_off == -1)
585 return;
586
587 if (get_bootconf_option(boot_args, "stdout-path",
588 BOOTOPT_TYPE_STRING, &stdout_path) == 0)
589 return;
590
591 ep = strchr(stdout_path, ' ');
592 stdout_path_len = ep ? (ep - stdout_path) : strlen(stdout_path);
593 if (stdout_path_len >= sizeof(buf))
594 return;
595
596 strncpy(buf, stdout_path, stdout_path_len);
597 buf[stdout_path_len] = '\0';
598 fdt_setprop(fdt_data, chosen_off, "stdout-path",
599 buf, stdout_path_len + 1);
600 }
601
602 void
603 consinit(void)
604 {
605 static bool initialized = false;
606 const struct arm_platform *plat = arm_fdt_platform();
607 const struct fdt_console *cons = fdtbus_get_console();
608 struct fdt_attach_args faa;
609 u_int uart_freq = 0;
610
611 if (initialized || cons == NULL)
612 return;
613
614 plat->ap_init_attach_args(&faa);
615 faa.faa_phandle = fdtbus_get_stdout_phandle();
616
617 if (plat->ap_uart_freq != NULL)
618 uart_freq = plat->ap_uart_freq();
619
620 cons->consinit(&faa, uart_freq);
621
622 initialized = true;
623 }
624
625 void
626 delay(u_int us)
627 {
628 const struct arm_platform *plat = arm_fdt_platform();
629
630 plat->ap_delay(us);
631 }
632
633 static void
634 fdt_detect_root_device(device_t dev)
635 {
636 struct mbr_sector mbr;
637 uint8_t buf[DEV_BSIZE];
638 uint8_t hash[16];
639 const uint8_t *rhash;
640 char rootarg[32];
641 struct vnode *vp;
642 MD5_CTX md5ctx;
643 int error, len;
644 size_t resid;
645 u_int part;
646
647 const int chosen = OF_finddevice("/chosen");
648 if (chosen < 0)
649 return;
650
651 if (of_hasprop(chosen, "netbsd,mbr") &&
652 of_hasprop(chosen, "netbsd,partition")) {
653
654 /*
655 * The bootloader has passed in a partition index and MD5 hash
656 * of the MBR sector. Read the MBR of this device, calculate the
657 * hash, and compare it with the value passed in.
658 */
659 rhash = fdtbus_get_prop(chosen, "netbsd,mbr", &len);
660 if (rhash == NULL || len != 16)
661 return;
662 of_getprop_uint32(chosen, "netbsd,partition", &part);
663 if (part >= MAXPARTITIONS)
664 return;
665
666 vp = opendisk(dev);
667 if (!vp)
668 return;
669 error = vn_rdwr(UIO_READ, vp, buf, sizeof(buf), 0, UIO_SYSSPACE,
670 0, NOCRED, &resid, NULL);
671 VOP_CLOSE(vp, FREAD, NOCRED);
672 vput(vp);
673
674 if (error != 0)
675 return;
676
677 memcpy(&mbr, buf, sizeof(mbr));
678 MD5Init(&md5ctx);
679 MD5Update(&md5ctx, (void *)&mbr, sizeof(mbr));
680 MD5Final(hash, &md5ctx);
681
682 if (memcmp(rhash, hash, 16) != 0)
683 return;
684
685 snprintf(rootarg, sizeof(rootarg), " root=%s%c", device_xname(dev), part + 'a');
686 strcat(boot_args, rootarg);
687 }
688 }
689
690 static void
691 fdt_device_register(device_t self, void *aux)
692 {
693 const struct arm_platform *plat = arm_fdt_platform();
694
695 if (device_is_a(self, "armfdt"))
696 fdt_setup_initrd();
697
698 if (plat && plat->ap_device_register)
699 plat->ap_device_register(self, aux);
700 }
701
702 static void
703 fdt_device_register_post_config(device_t self, void *aux)
704 {
705 #if NUKBD > 0 && NWSDISPLAY > 0
706 if (device_is_a(self, "wsdisplay")) {
707 struct wsdisplay_softc *sc = device_private(self);
708 if (wsdisplay_isconsole(sc))
709 ukbd_cnattach();
710 }
711 #endif
712 }
713
714 static void
715 fdt_cpu_rootconf(void)
716 {
717 device_t dev;
718 deviter_t di;
719 char *ptr;
720
721 for (dev = deviter_first(&di, 0); dev; dev = deviter_next(&di)) {
722 if (device_class(dev) != DV_DISK)
723 continue;
724
725 if (get_bootconf_option(boot_args, "root", BOOTOPT_TYPE_STRING, &ptr) != 0)
726 break;
727
728 if (device_is_a(dev, "ld") || device_is_a(dev, "sd") || device_is_a(dev, "wd"))
729 fdt_detect_root_device(dev);
730 }
731 deviter_release(&di);
732 }
733
734 static void
735 fdt_reset(void)
736 {
737 const struct arm_platform *plat = arm_fdt_platform();
738
739 fdtbus_power_reset();
740
741 if (plat && plat->ap_reset)
742 plat->ap_reset();
743 }
744
745 static void
746 fdt_powerdown(void)
747 {
748 fdtbus_power_poweroff();
749 }
750