fdt_machdep.c revision 1.79 1 /* $NetBSD: fdt_machdep.c,v 1.79 2020/11/24 06:36:36 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.79 2020/11/24 06:36:36 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 "genfb.h"
42 #include "ukbd.h"
43 #include "wsdisplay.h"
44
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/bus.h>
48 #include <sys/atomic.h>
49 #include <sys/cpu.h>
50 #include <sys/device.h>
51 #include <sys/endian.h>
52 #include <sys/exec.h>
53 #include <sys/kernel.h>
54 #include <sys/kmem.h>
55 #include <sys/ksyms.h>
56 #include <sys/msgbuf.h>
57 #include <sys/proc.h>
58 #include <sys/reboot.h>
59 #include <sys/termios.h>
60 #include <sys/bootblock.h>
61 #include <sys/disklabel.h>
62 #include <sys/vnode.h>
63 #include <sys/kauth.h>
64 #include <sys/fcntl.h>
65 #include <sys/uuid.h>
66 #include <sys/disk.h>
67 #include <sys/md5.h>
68 #include <sys/pserialize.h>
69 #include <sys/rnd.h>
70 #include <sys/rndsource.h>
71
72 #include <net/if.h>
73 #include <net/if_dl.h>
74
75 #include <dev/cons.h>
76 #include <uvm/uvm_extern.h>
77
78 #include <sys/conf.h>
79
80 #include <machine/db_machdep.h>
81 #include <ddb/db_sym.h>
82 #include <ddb/db_extern.h>
83
84 #include <machine/bootconfig.h>
85 #include <arm/armreg.h>
86
87 #include <arm/cpufunc.h>
88
89 #include <evbarm/include/autoconf.h>
90 #include <evbarm/fdt/machdep.h>
91 #include <evbarm/fdt/platform.h>
92 #include <evbarm/fdt/fdt_memory.h>
93
94 #include <arm/fdt/arm_fdtvar.h>
95 #include <dev/fdt/fdt_private.h>
96
97 #ifdef EFI_RUNTIME
98 #include <arm/arm/efi_runtime.h>
99 #endif
100
101 #if NWSDISPLAY > 0 && NGENFB > 0
102 #include <arm/fdt/arm_simplefb.h>
103 #endif
104
105 #if NUKBD > 0
106 #include <dev/usb/ukbdvar.h>
107 #endif
108 #if NWSDISPLAY > 0
109 #include <dev/wscons/wsdisplayvar.h>
110 #endif
111
112 #ifdef MEMORY_DISK_DYNAMIC
113 #include <dev/md.h>
114 #endif
115
116 #ifndef FDT_MAX_BOOT_STRING
117 #define FDT_MAX_BOOT_STRING 1024
118 #endif
119
120 BootConfig bootconfig;
121 char bootargs[FDT_MAX_BOOT_STRING] = "";
122 char *boot_args = NULL;
123
124 /* filled in before cleaning bss. keep in .data */
125 u_long uboot_args[4] __attribute__((__section__(".data")));
126 const uint8_t *fdt_addr_r __attribute__((__section__(".data")));
127
128 static uint64_t initrd_start, initrd_end;
129 static uint64_t rndseed_start, rndseed_end; /* our on-disk seed */
130 static uint64_t efirng_start, efirng_end; /* firmware's EFI RNG output */
131
132 #include <libfdt.h>
133 #include <dev/fdt/fdtvar.h>
134 #define FDT_BUF_SIZE (512*1024)
135 static uint8_t fdt_data[FDT_BUF_SIZE];
136
137 extern char KERNEL_BASE_phys[];
138 #define KERNEL_BASE_PHYS ((paddr_t)KERNEL_BASE_phys)
139
140 static void fdt_update_stdout_path(void);
141 static void fdt_device_register(device_t, void *);
142 static void fdt_device_register_post_config(device_t, void *);
143 static void fdt_cpu_rootconf(void);
144 static void fdt_reset(void);
145 static void fdt_powerdown(void);
146
147 #if BYTE_ORDER == BIG_ENDIAN
148 static void fdt_update_fb_format(void);
149 #endif
150
151 static void
152 earlyconsputc(dev_t dev, int c)
153 {
154 uartputc(c);
155 }
156
157 static int
158 earlyconsgetc(dev_t dev)
159 {
160 return 0;
161 }
162
163 static struct consdev earlycons = {
164 .cn_putc = earlyconsputc,
165 .cn_getc = earlyconsgetc,
166 .cn_pollc = nullcnpollc,
167 };
168
169 #ifdef VERBOSE_INIT_ARM
170 #define VPRINTF(...) printf(__VA_ARGS__)
171 #else
172 #define VPRINTF(...) __nothing
173 #endif
174
175 /*
176 * Get all of physical memory, including holes.
177 */
178 static void
179 fdt_get_memory(uint64_t *pstart, uint64_t *pend)
180 {
181 const int memory = OF_finddevice("/memory");
182 uint64_t cur_addr, cur_size;
183 int index;
184
185 /* Assume the first entry is the start of memory */
186 if (fdtbus_get_reg64(memory, 0, &cur_addr, &cur_size) != 0)
187 panic("Cannot determine memory size");
188
189 *pstart = cur_addr;
190 *pend = cur_addr + cur_size;
191
192 VPRINTF("FDT /memory [%d] @ 0x%" PRIx64 " size 0x%" PRIx64 "\n",
193 0, *pstart, *pend - *pstart);
194
195 for (index = 1;
196 fdtbus_get_reg64(memory, index, &cur_addr, &cur_size) == 0;
197 index++) {
198 VPRINTF("FDT /memory [%d] @ 0x%" PRIx64 " size 0x%" PRIx64 "\n",
199 index, cur_addr, cur_size);
200
201 if (cur_addr + cur_size > *pend)
202 *pend = cur_addr + cur_size;
203 }
204 }
205
206 void
207 fdt_add_reserved_memory_range(uint64_t addr, uint64_t size)
208 {
209 fdt_memory_remove_range(addr, size);
210 }
211
212 /*
213 * Exclude memory ranges from memory config from the device tree
214 */
215 static void
216 fdt_add_reserved_memory(uint64_t min_addr, uint64_t max_addr)
217 {
218 uint64_t lstart = 0, lend = 0;
219 uint64_t addr, size;
220 int index, error;
221
222 const int num = fdt_num_mem_rsv(fdtbus_get_data());
223 for (index = 0; index <= num; index++) {
224 error = fdt_get_mem_rsv(fdtbus_get_data(), index,
225 &addr, &size);
226 if (error != 0)
227 continue;
228 if (lstart <= addr && addr <= lend) {
229 size -= (lend - addr);
230 addr = lend;
231 }
232 if (size == 0)
233 continue;
234 if (addr + size <= min_addr)
235 continue;
236 if (addr >= max_addr)
237 continue;
238 if (addr < min_addr) {
239 size -= (min_addr - addr);
240 addr = min_addr;
241 }
242 if (addr + size > max_addr)
243 size = max_addr - addr;
244 fdt_add_reserved_memory_range(addr, size);
245 lstart = addr;
246 lend = addr + size;
247 }
248 }
249
250 static void
251 fdt_add_dram_blocks(const struct fdt_memory *m, void *arg)
252 {
253 BootConfig *bc = arg;
254
255 VPRINTF(" %" PRIx64 " - %" PRIx64 "\n", m->start, m->end - 1);
256 bc->dram[bc->dramblocks].address = m->start;
257 bc->dram[bc->dramblocks].pages =
258 (m->end - m->start) / PAGE_SIZE;
259 bc->dramblocks++;
260 }
261
262 #define MAX_PHYSMEM 64
263 static int nfdt_physmem = 0;
264 static struct boot_physmem fdt_physmem[MAX_PHYSMEM];
265
266 static void
267 fdt_add_boot_physmem(const struct fdt_memory *m, void *arg)
268 {
269 const paddr_t saddr = round_page(m->start);
270 const paddr_t eaddr = trunc_page(m->end);
271
272 VPRINTF(" %" PRIx64 " - %" PRIx64, m->start, m->end - 1);
273 if (saddr >= eaddr) {
274 VPRINTF(" skipped\n");
275 return;
276 }
277 VPRINTF("\n");
278
279 struct boot_physmem *bp = &fdt_physmem[nfdt_physmem++];
280
281 KASSERT(nfdt_physmem <= MAX_PHYSMEM);
282
283 bp->bp_start = atop(saddr);
284 bp->bp_pages = atop(eaddr) - bp->bp_start;
285 bp->bp_freelist = VM_FREELIST_DEFAULT;
286
287 #ifdef PMAP_NEED_ALLOC_POOLPAGE
288 const uint64_t memory_size = *(uint64_t *)arg;
289 if (atop(memory_size) > bp->bp_pages) {
290 arm_poolpage_vmfreelist = VM_FREELIST_DIRECTMAP;
291 bp->bp_freelist = VM_FREELIST_DIRECTMAP;
292 }
293 #endif
294 }
295
296 /*
297 * Define usable memory regions.
298 */
299 static void
300 fdt_build_bootconfig(uint64_t mem_start, uint64_t mem_end)
301 {
302 const int memory = OF_finddevice("/memory");
303 BootConfig *bc = &bootconfig;
304 uint64_t addr, size;
305 int index;
306
307 for (index = 0;
308 fdtbus_get_reg64(memory, index, &addr, &size) == 0;
309 index++) {
310 if (addr >= mem_end || size == 0)
311 continue;
312 if (addr + size > mem_end)
313 size = mem_end - addr;
314
315 fdt_memory_add_range(addr, size);
316 }
317
318 fdt_add_reserved_memory(mem_start, mem_end);
319
320 const uint64_t initrd_size =
321 round_page(initrd_end) - trunc_page(initrd_start);
322 if (initrd_size > 0)
323 fdt_memory_remove_range(trunc_page(initrd_start), initrd_size);
324
325 const uint64_t rndseed_size =
326 round_page(rndseed_end) - trunc_page(rndseed_start);
327 if (rndseed_size > 0)
328 fdt_memory_remove_range(trunc_page(rndseed_start),
329 rndseed_size);
330
331 const uint64_t efirng_size =
332 round_page(efirng_end) - trunc_page(efirng_start);
333 if (efirng_size > 0)
334 fdt_memory_remove_range(trunc_page(efirng_start), efirng_size);
335
336 const int framebuffer = OF_finddevice("/chosen/framebuffer");
337 if (framebuffer >= 0) {
338 for (index = 0;
339 fdtbus_get_reg64(framebuffer, index, &addr, &size) == 0;
340 index++) {
341 fdt_add_reserved_memory_range(addr, size);
342 }
343 }
344
345 VPRINTF("Usable memory:\n");
346 bc->dramblocks = 0;
347 fdt_memory_foreach(fdt_add_dram_blocks, bc);
348 }
349
350 static void
351 fdt_probe_range(const char *startname, const char *endname,
352 uint64_t *pstart, uint64_t *pend)
353 {
354 int chosen, len;
355 const void *start_data, *end_data;
356
357 *pstart = *pend = 0;
358
359 chosen = OF_finddevice("/chosen");
360 if (chosen < 0)
361 return;
362
363 start_data = fdtbus_get_prop(chosen, startname, &len);
364 end_data = fdtbus_get_prop(chosen, endname, NULL);
365 if (start_data == NULL || end_data == NULL)
366 return;
367
368 switch (len) {
369 case 4:
370 *pstart = be32dec(start_data);
371 *pend = be32dec(end_data);
372 break;
373 case 8:
374 *pstart = be64dec(start_data);
375 *pend = be64dec(end_data);
376 break;
377 default:
378 printf("Unsupported len %d for /chosen `%s'\n",
379 len, startname);
380 return;
381 }
382 }
383
384 static void *
385 fdt_map_range(uint64_t start, uint64_t end, uint64_t *psize,
386 const char *purpose)
387 {
388 const paddr_t startpa = trunc_page(start);
389 const paddr_t endpa = round_page(end);
390 paddr_t pa;
391 vaddr_t va;
392 void *ptr;
393
394 *psize = end - start;
395 if (*psize == 0)
396 return NULL;
397
398 const vaddr_t voff = start & PAGE_MASK;
399
400 va = uvm_km_alloc(kernel_map, *psize, 0, UVM_KMF_VAONLY|UVM_KMF_NOWAIT);
401 if (va == 0) {
402 printf("Failed to allocate VA for %s\n", purpose);
403 return NULL;
404 }
405 ptr = (void *)(va + voff);
406
407 for (pa = startpa; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE)
408 pmap_kenter_pa(va, pa, VM_PROT_READ|VM_PROT_WRITE, 0);
409 pmap_update(pmap_kernel());
410
411 return ptr;
412 }
413
414 static void
415 fdt_unmap_range(void *ptr, uint64_t size)
416 {
417 const char *start = ptr, *end = start + size;
418 const vaddr_t startva = trunc_page((vaddr_t)(uintptr_t)start);
419 const vaddr_t endva = round_page((vaddr_t)(uintptr_t)end);
420
421 pmap_kremove(startva, endva - startva);
422 pmap_update(pmap_kernel());
423 }
424
425 static void
426 fdt_probe_initrd(uint64_t *pstart, uint64_t *pend)
427 {
428 *pstart = *pend = 0;
429
430 #ifdef MEMORY_DISK_DYNAMIC
431 fdt_probe_range("linux,initrd-start", "linux,initrd-end", pstart, pend);
432 #endif
433 }
434
435 static void
436 fdt_setup_initrd(void)
437 {
438 #ifdef MEMORY_DISK_DYNAMIC
439 void *md_start;
440 uint64_t initrd_size;
441
442 md_start = fdt_map_range(initrd_start, initrd_end, &initrd_size,
443 "initrd");
444 if (md_start == NULL)
445 return;
446 md_root_setconf(md_start, initrd_size);
447 #endif
448 }
449
450 static void
451 fdt_probe_rndseed(uint64_t *pstart, uint64_t *pend)
452 {
453
454 fdt_probe_range("netbsd,rndseed-start", "netbsd,rndseed-end",
455 pstart, pend);
456 }
457
458 static void
459 fdt_setup_rndseed(void)
460 {
461 uint64_t rndseed_size;
462 void *rndseed;
463
464 rndseed = fdt_map_range(rndseed_start, rndseed_end, &rndseed_size,
465 "rndseed");
466 if (rndseed == NULL)
467 return;
468 rnd_seed(rndseed, rndseed_size);
469 fdt_unmap_range(rndseed, rndseed_size);
470 }
471
472 static void
473 fdt_probe_efirng(uint64_t *pstart, uint64_t *pend)
474 {
475
476 fdt_probe_range("netbsd,efirng-start", "netbsd,efirng-end",
477 pstart, pend);
478 }
479
480 static struct krndsource efirng_source;
481
482 static void
483 fdt_setup_efirng(void)
484 {
485 uint64_t efirng_size;
486 void *efirng;
487
488 efirng = fdt_map_range(efirng_start, efirng_end, &efirng_size,
489 "efirng");
490 if (efirng == NULL)
491 return;
492
493 rnd_attach_source(&efirng_source, "efirng", RND_TYPE_RNG,
494 RND_FLAG_DEFAULT);
495 rnd_add_data(&efirng_source, efirng, efirng_size, 0);
496 explicit_memset(efirng, 0, efirng_size);
497 fdt_unmap_range(efirng, efirng_size);
498 }
499
500 #ifdef EFI_RUNTIME
501 static void
502 fdt_map_efi_runtime(const char *prop, enum arm_efirt_mem_type type)
503 {
504 int len;
505
506 const int chosen_off = fdt_path_offset(fdt_data, "/chosen");
507 if (chosen_off < 0)
508 return;
509
510 const uint64_t *map = fdt_getprop(fdt_data, chosen_off, prop, &len);
511 if (map == NULL)
512 return;
513
514 while (len >= 24) {
515 const paddr_t pa = be64toh(map[0]);
516 const vaddr_t va = be64toh(map[1]);
517 const uint64_t sz = be64toh(map[2]);
518 VPRINTF("%s: %s %lx-%lx (%lx-%lx)\n", __func__, prop, pa, pa+sz-1, va, va+sz-1);
519 arm_efirt_md_map_range(va, pa, sz, type);
520 map += 3;
521 len -= 24;
522 }
523 }
524 #endif
525
526 vaddr_t
527 initarm(void *arg)
528 {
529 const struct arm_platform *plat;
530 uint64_t memory_start, memory_end;
531
532 /* set temporally to work printf()/panic() even before consinit() */
533 cn_tab = &earlycons;
534
535 /* Load FDT */
536 int error = fdt_check_header(fdt_addr_r);
537 if (error != 0)
538 panic("fdt_check_header failed: %s", fdt_strerror(error));
539
540 /* If the DTB is too big, try to pack it in place first. */
541 if (fdt_totalsize(fdt_addr_r) > sizeof(fdt_data))
542 (void)fdt_pack(__UNCONST(fdt_addr_r));
543 error = fdt_open_into(fdt_addr_r, fdt_data, sizeof(fdt_data));
544 if (error != 0)
545 panic("fdt_move failed: %s", fdt_strerror(error));
546
547 fdtbus_init(fdt_data);
548
549 /* Lookup platform specific backend */
550 plat = arm_fdt_platform();
551 if (plat == NULL)
552 panic("Kernel does not support this device");
553
554 /* Early console may be available, announce ourselves. */
555 VPRINTF("FDT<%p>\n", fdt_addr_r);
556
557 const int chosen = OF_finddevice("/chosen");
558 if (chosen >= 0)
559 OF_getprop(chosen, "bootargs", bootargs, sizeof(bootargs));
560 boot_args = bootargs;
561
562 /* Heads up ... Setup the CPU / MMU / TLB functions. */
563 VPRINTF("cpufunc\n");
564 if (set_cpufuncs())
565 panic("cpu not recognized!");
566
567 /*
568 * Memory is still identity/flat mapped this point so using ttbr for
569 * l1pt VA is fine
570 */
571
572 VPRINTF("devmap %p\n", plat->ap_devmap());
573 extern char ARM_BOOTSTRAP_LxPT[];
574 pmap_devmap_bootstrap((vaddr_t)ARM_BOOTSTRAP_LxPT, plat->ap_devmap());
575
576 VPRINTF("bootstrap\n");
577 plat->ap_bootstrap();
578
579 /*
580 * If stdout-path is specified on the command line, override the
581 * value in /chosen/stdout-path before initializing console.
582 */
583 VPRINTF("stdout\n");
584 fdt_update_stdout_path();
585
586 #if BYTE_ORDER == BIG_ENDIAN
587 /*
588 * Most boards are configured to little-endian mode in initial, and
589 * switched to big-endian mode after kernel is loaded. In this case,
590 * framebuffer seems byte-swapped to CPU. Override FDT to let
591 * drivers know.
592 */
593 VPRINTF("fb_format\n");
594 fdt_update_fb_format();
595 #endif
596
597 /*
598 * Done making changes to the FDT.
599 */
600 fdt_pack(fdt_data);
601
602 VPRINTF("consinit ");
603 consinit();
604 VPRINTF("ok\n");
605
606 VPRINTF("uboot: args %#lx, %#lx, %#lx, %#lx\n",
607 uboot_args[0], uboot_args[1], uboot_args[2], uboot_args[3]);
608
609 cpu_reset_address = fdt_reset;
610 cpu_powerdown_address = fdt_powerdown;
611 evbarm_device_register = fdt_device_register;
612 evbarm_device_register_post_config = fdt_device_register_post_config;
613 evbarm_cpu_rootconf = fdt_cpu_rootconf;
614
615 /* Talk to the user */
616 printf("NetBSD/evbarm (fdt) booting ...\n");
617
618 #ifdef BOOT_ARGS
619 char mi_bootargs[] = BOOT_ARGS;
620 parse_mi_bootargs(mi_bootargs);
621 #endif
622
623 fdt_get_memory(&memory_start, &memory_end);
624
625 #if !defined(_LP64)
626 /* Cannot map memory above 4GB */
627 if (memory_end >= 0x100000000ULL)
628 memory_end = 0x100000000ULL - PAGE_SIZE;
629
630 #endif
631 uint64_t memory_size = memory_end - memory_start;
632
633 VPRINTF("%s: memory start %" PRIx64 " end %" PRIx64 " (len %"
634 PRIx64 ")\n", __func__, memory_start, memory_end, memory_size);
635
636 /* Parse ramdisk info */
637 fdt_probe_initrd(&initrd_start, &initrd_end);
638
639 /* Parse our on-disk rndseed and the firmware's RNG from EFI */
640 fdt_probe_rndseed(&rndseed_start, &rndseed_end);
641 fdt_probe_efirng(&efirng_start, &efirng_end);
642
643 /*
644 * Populate bootconfig structure for the benefit of
645 * dodumpsys
646 */
647 VPRINTF("%s: fdt_build_bootconfig\n", __func__);
648 fdt_build_bootconfig(memory_start, memory_end);
649
650 #ifdef EFI_RUNTIME
651 fdt_map_efi_runtime("netbsd,uefi-runtime-code", ARM_EFIRT_MEM_CODE);
652 fdt_map_efi_runtime("netbsd,uefi-runtime-data", ARM_EFIRT_MEM_DATA);
653 fdt_map_efi_runtime("netbsd,uefi-runtime-mmio", ARM_EFIRT_MEM_MMIO);
654 #endif
655
656 /* Perform PT build and VM init */
657 cpu_kernel_vm_init(memory_start, memory_size);
658
659 VPRINTF("bootargs: %s\n", bootargs);
660
661 parse_mi_bootargs(boot_args);
662
663 VPRINTF("Memory regions:\n");
664 fdt_memory_foreach(fdt_add_boot_physmem, &memory_size);
665
666 vaddr_t sp = initarm_common(KERNEL_VM_BASE, KERNEL_VM_SIZE, fdt_physmem,
667 nfdt_physmem);
668
669 /*
670 * initarm_common flushes cache if required before AP start
671 */
672 error = 0;
673 if ((boothowto & RB_MD1) == 0) {
674 VPRINTF("mpstart\n");
675 if (plat->ap_mpstart)
676 error = plat->ap_mpstart();
677 }
678
679 if (error)
680 return sp;
681
682 /*
683 * Now we have APs started the pages used for stacks and L1PT can
684 * be given to uvm
685 */
686 extern char const __start__init_memory[];
687 extern char const __stop__init_memory[] __weak;
688
689 if (__start__init_memory != __stop__init_memory) {
690 const paddr_t spa = KERN_VTOPHYS((vaddr_t)__start__init_memory);
691 const paddr_t epa = KERN_VTOPHYS((vaddr_t)__stop__init_memory);
692 const paddr_t spg = atop(spa);
693 const paddr_t epg = atop(epa);
694
695 VPRINTF(" start %08lx end %08lx... "
696 "loading in freelist %d\n", spa, epa, VM_FREELIST_DEFAULT);
697
698 uvm_page_physload(spg, epg, spg, epg, VM_FREELIST_DEFAULT);
699
700 }
701
702 return sp;
703 }
704
705 static void
706 fdt_update_stdout_path(void)
707 {
708 char *stdout_path, *ep;
709 int stdout_path_len;
710 char buf[256];
711
712 const int chosen_off = fdt_path_offset(fdt_data, "/chosen");
713 if (chosen_off == -1)
714 return;
715
716 if (get_bootconf_option(boot_args, "stdout-path",
717 BOOTOPT_TYPE_STRING, &stdout_path) == 0)
718 return;
719
720 ep = strchr(stdout_path, ' ');
721 stdout_path_len = ep ? (ep - stdout_path) : strlen(stdout_path);
722 if (stdout_path_len >= sizeof(buf))
723 return;
724
725 strncpy(buf, stdout_path, stdout_path_len);
726 buf[stdout_path_len] = '\0';
727 fdt_setprop(fdt_data, chosen_off, "stdout-path",
728 buf, stdout_path_len + 1);
729 }
730
731 void
732 consinit(void)
733 {
734 static bool initialized = false;
735 const struct arm_platform *plat = arm_fdt_platform();
736 const struct fdt_console *cons = fdtbus_get_console();
737 struct fdt_attach_args faa;
738 u_int uart_freq = 0;
739
740 if (initialized || cons == NULL)
741 return;
742
743 plat->ap_init_attach_args(&faa);
744 faa.faa_phandle = fdtbus_get_stdout_phandle();
745
746 if (plat->ap_uart_freq != NULL)
747 uart_freq = plat->ap_uart_freq();
748
749 cons->consinit(&faa, uart_freq);
750
751 initialized = true;
752 }
753
754 void
755 cpu_startup_hook(void)
756 {
757
758 fdtbus_intr_init();
759
760 fdt_setup_rndseed();
761 fdt_setup_efirng();
762 }
763
764 void
765 delay(u_int us)
766 {
767 const struct arm_platform *plat = arm_fdt_platform();
768
769 plat->ap_delay(us);
770 }
771
772 static void
773 fdt_detect_root_device(device_t dev)
774 {
775 struct mbr_sector mbr;
776 uint8_t buf[DEV_BSIZE];
777 uint8_t hash[16];
778 const uint8_t *rhash;
779 char rootarg[64];
780 struct vnode *vp;
781 MD5_CTX md5ctx;
782 int error, len;
783 size_t resid;
784 u_int part;
785
786 const int chosen = OF_finddevice("/chosen");
787 if (chosen < 0)
788 return;
789
790 if (of_hasprop(chosen, "netbsd,mbr") &&
791 of_hasprop(chosen, "netbsd,partition")) {
792
793 /*
794 * The bootloader has passed in a partition index and MD5 hash
795 * of the MBR sector. Read the MBR of this device, calculate the
796 * hash, and compare it with the value passed in.
797 */
798 rhash = fdtbus_get_prop(chosen, "netbsd,mbr", &len);
799 if (rhash == NULL || len != 16)
800 return;
801 of_getprop_uint32(chosen, "netbsd,partition", &part);
802 if (part >= MAXPARTITIONS)
803 return;
804
805 vp = opendisk(dev);
806 if (!vp)
807 return;
808 error = vn_rdwr(UIO_READ, vp, buf, sizeof(buf), 0, UIO_SYSSPACE,
809 0, NOCRED, &resid, NULL);
810 VOP_CLOSE(vp, FREAD, NOCRED);
811 vput(vp);
812
813 if (error != 0)
814 return;
815
816 memcpy(&mbr, buf, sizeof(mbr));
817 MD5Init(&md5ctx);
818 MD5Update(&md5ctx, (void *)&mbr, sizeof(mbr));
819 MD5Final(hash, &md5ctx);
820
821 if (memcmp(rhash, hash, 16) != 0)
822 return;
823
824 snprintf(rootarg, sizeof(rootarg), " root=%s%c", device_xname(dev), part + 'a');
825 strcat(boot_args, rootarg);
826 }
827
828 if (of_hasprop(chosen, "netbsd,gpt-guid")) {
829 char guidbuf[UUID_STR_LEN];
830 const struct uuid *guid = fdtbus_get_prop(chosen, "netbsd,gpt-guid", &len);
831 if (guid == NULL || len != 16)
832 return;
833
834 uuid_snprintf(guidbuf, sizeof(guidbuf), guid);
835 snprintf(rootarg, sizeof(rootarg), " root=wedge:%s", guidbuf);
836 strcat(boot_args, rootarg);
837 }
838
839 if (of_hasprop(chosen, "netbsd,gpt-label")) {
840 const char *label = fdtbus_get_string(chosen, "netbsd,gpt-label");
841 if (label == NULL || *label == '\0')
842 return;
843
844 device_t dv = dkwedge_find_by_wname(label);
845 if (dv != NULL)
846 booted_device = dv;
847 }
848
849 if (of_hasprop(chosen, "netbsd,booted-mac-address")) {
850 const uint8_t *macaddr = fdtbus_get_prop(chosen, "netbsd,booted-mac-address", &len);
851 if (macaddr == NULL || len != 6)
852 return;
853 int s = pserialize_read_enter();
854 struct ifnet *ifp;
855 IFNET_READER_FOREACH(ifp) {
856 if (memcmp(macaddr, CLLADDR(ifp->if_sadl), len) == 0) {
857 device_t dv = device_find_by_xname(ifp->if_xname);
858 if (dv != NULL)
859 booted_device = dv;
860 break;
861 }
862 }
863 pserialize_read_exit(s);
864 }
865 }
866
867 static void
868 fdt_device_register(device_t self, void *aux)
869 {
870 const struct arm_platform *plat = arm_fdt_platform();
871
872 if (device_is_a(self, "armfdt")) {
873 fdt_setup_initrd();
874
875 #if NWSDISPLAY > 0 && NGENFB > 0
876 /*
877 * Setup framebuffer console, if present.
878 */
879 arm_simplefb_preattach();
880 #endif
881 }
882
883 #if NWSDISPLAY > 0 && NGENFB > 0
884 if (device_is_a(self, "genfb")) {
885 prop_dictionary_t dict = device_properties(self);
886 prop_dictionary_set_uint64(dict,
887 "simplefb-physaddr", arm_simplefb_physaddr());
888 }
889 #endif
890
891 if (plat && plat->ap_device_register)
892 plat->ap_device_register(self, aux);
893 }
894
895 static void
896 fdt_device_register_post_config(device_t self, void *aux)
897 {
898 #if NUKBD > 0 && NWSDISPLAY > 0
899 if (device_is_a(self, "wsdisplay")) {
900 struct wsdisplay_softc *sc = device_private(self);
901 if (wsdisplay_isconsole(sc))
902 ukbd_cnattach();
903 }
904 #endif
905 }
906
907 static void
908 fdt_cpu_rootconf(void)
909 {
910 device_t dev;
911 deviter_t di;
912 char *ptr;
913
914 for (dev = deviter_first(&di, 0); dev; dev = deviter_next(&di)) {
915 if (device_class(dev) != DV_DISK)
916 continue;
917
918 if (get_bootconf_option(boot_args, "root", BOOTOPT_TYPE_STRING, &ptr) != 0)
919 break;
920
921 if (device_is_a(dev, "ld") || device_is_a(dev, "sd") || device_is_a(dev, "wd"))
922 fdt_detect_root_device(dev);
923 }
924 deviter_release(&di);
925 }
926
927 static void
928 fdt_reset(void)
929 {
930 const struct arm_platform *plat = arm_fdt_platform();
931
932 fdtbus_power_reset();
933
934 if (plat && plat->ap_reset)
935 plat->ap_reset();
936 }
937
938 static void
939 fdt_powerdown(void)
940 {
941 fdtbus_power_poweroff();
942 }
943
944 #if BYTE_ORDER == BIG_ENDIAN
945 static void
946 fdt_update_fb_format(void)
947 {
948 int off, len;
949 const char *format, *replace;
950
951 off = fdt_path_offset(fdt_data, "/chosen");
952 if (off < 0)
953 return;
954
955 for (;;) {
956 off = fdt_node_offset_by_compatible(fdt_data, off,
957 "simple-framebuffer");
958 if (off < 0)
959 return;
960
961 format = fdt_getprop(fdt_data, off, "format", &len);
962 if (format == NULL)
963 continue;
964
965 replace = NULL;
966 if (strcmp(format, "a8b8g8r8") == 0)
967 replace = "r8g8b8a8";
968 else if (strcmp(format, "x8r8g8b8") == 0)
969 replace = "b8g8r8x8";
970 if (replace != NULL)
971 fdt_setprop(fdt_data, off, "format", replace,
972 strlen(replace) + 1);
973 }
974 }
975 #endif
976