Annotation of src/sys/arch/evbarm/fdt/fdt_machdep.c, Revision 1.9
1.9 ! chs 1: /* $NetBSD: fdt_machdep.c,v 1.8 2017/07/05 01:08:45 jmcneill Exp $ */
1.1 jmcneill 2:
3: /*-
4: * Copyright (c) 2015-2017 Jared McNeill <jmcneill@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>
1.9 ! chs 30: __KERNEL_RCSID(0, "$NetBSD: fdt_machdep.c,v 1.8 2017/07/05 01:08:45 jmcneill Exp $");
1.1 jmcneill 31:
32: #include "opt_machdep.h"
33: #include "opt_ddb.h"
34: #include "opt_md.h"
35: #include "opt_arm_debug.h"
36: #include "opt_multiprocessor.h"
37: #include "opt_cpuoptions.h"
38:
39: #include <sys/param.h>
40: #include <sys/systm.h>
41: #include <sys/bus.h>
42: #include <sys/atomic.h>
43: #include <sys/cpu.h>
44: #include <sys/device.h>
45: #include <sys/exec.h>
46: #include <sys/kernel.h>
47: #include <sys/kmem.h>
48: #include <sys/ksyms.h>
49: #include <sys/msgbuf.h>
50: #include <sys/proc.h>
51: #include <sys/reboot.h>
52: #include <sys/termios.h>
1.8 jmcneill 53: #include <sys/extent.h>
1.1 jmcneill 54:
55: #include <uvm/uvm_extern.h>
56:
57: #include <sys/conf.h>
58:
59: #include <machine/db_machdep.h>
60: #include <ddb/db_sym.h>
61: #include <ddb/db_extern.h>
62:
63: #include <machine/bootconfig.h>
64: #include <arm/armreg.h>
65: #include <arm/undefined.h>
66:
67: #include <arm/arm32/machdep.h>
68:
69: #include <evbarm/include/autoconf.h>
70: #include <evbarm/fdt/platform.h>
71:
72: #include <arm/fdt/arm_fdtvar.h>
73:
1.8 jmcneill 74: #ifdef MEMORY_DISK_DYNAMIC
75: #include <dev/md.h>
76: #endif
77:
1.1 jmcneill 78: #ifndef FDT_MAX_BOOT_STRING
79: #define FDT_MAX_BOOT_STRING 1024
80: #endif
81:
82: BootConfig bootconfig;
83: char bootargs[FDT_MAX_BOOT_STRING] = "";
84: char *boot_args = NULL;
85: u_int uboot_args[4] = { 0 }; /* filled in by xxx_start.S (not in bss) */
86:
1.8 jmcneill 87: static char fdt_memory_ext_storage[EXTENT_FIXED_STORAGE_SIZE(DRAM_BLOCKS)];
88: static struct extent *fdt_memory_ext;
89:
90: static uint64_t initrd_start, initrd_end;
91:
1.1 jmcneill 92: #include <libfdt.h>
93: #include <dev/fdt/fdtvar.h>
94: #define FDT_BUF_SIZE (128*1024)
95: static uint8_t fdt_data[FDT_BUF_SIZE];
96:
97: extern char KERNEL_BASE_phys[];
98: #define KERNEL_BASE_PHYS ((paddr_t)KERNEL_BASE_phys)
99:
1.5 jmcneill 100: static void fdt_update_stdout_path(void);
1.1 jmcneill 101: static void fdt_device_register(device_t, void *);
102: static void fdt_reset(void);
103: static void fdt_powerdown(void);
104:
105: #ifdef PMAP_NEED_ALLOC_POOLPAGE
106: static struct boot_physmem bp_lowgig = {
107: .bp_pages = (KERNEL_VM_BASE - KERNEL_BASE) / NBPG,
108: .bp_freelist = VM_FREELIST_ISADMA,
109: .bp_flags = 0
110: };
111: #endif
112:
113: #ifdef VERBOSE_INIT_ARM
114: static void
115: fdt_putchar(char c)
116: {
117: const struct arm_platform *plat = arm_fdt_platform();
1.2 jmcneill 118: if (plat && plat->early_putchar)
1.1 jmcneill 119: plat->early_putchar(c);
120: }
121:
122: static void
123: fdt_putstr(const char *s)
124: {
125: for (const char *p = s; *p; p++)
126: fdt_putchar(*p);
127: }
128:
129: static void
130: fdt_printn(u_int n, int base)
131: {
132: char *p, buf[(sizeof(u_int) * NBBY / 3) + 1 + 2 /* ALT + SIGN */];
133:
134: p = buf;
135: do {
136: *p++ = hexdigits[n % base];
137: } while (n /= base);
138:
139: do {
140: fdt_putchar(*--p);
141: } while (p > buf);
142: }
143: #define DPRINTF(...) printf(__VA_ARGS__)
144: #define DPRINT(x) fdt_putstr(x)
145: #define DPRINTN(x,b) fdt_printn((x), (b))
146: #else
147: #define DPRINTF(...)
148: #define DPRINT(x)
149: #define DPRINTN(x,b)
150: #endif
151:
1.7 jmcneill 152: /*
153: * Get the first physically contiguous region of memory.
154: */
155: static void
156: fdt_get_memory(uint64_t *paddr, uint64_t *psize)
157: {
158: const int memory = OF_finddevice("/memory");
159: uint64_t cur_addr, cur_size;
160: int index;
161:
162: /* Assume the first entry is the start of memory */
163: if (fdtbus_get_reg64(memory, 0, paddr, psize) != 0)
164: panic("Cannot determine memory size");
165:
166: DPRINTF("FDT /memory [%d] @ 0x%" PRIx64 " size 0x%" PRIx64 "\n",
167: 0, *paddr, *psize);
168:
169: /* If subsequent entries follow the previous one, append them. */
170: for (index = 1;
171: fdtbus_get_reg64(memory, index, &cur_addr, &cur_size) == 0;
172: index++) {
173: DPRINTF("FDT /memory [%d] @ 0x%" PRIx64 " size 0x%" PRIx64 "\n",
174: index, cur_addr, cur_size);
175: if (*paddr + *psize == cur_addr)
176: *psize += cur_size;
177: }
178: }
179:
1.8 jmcneill 180: static void
181: fdt_add_reserved_memory_range(uint64_t addr, uint64_t size)
182: {
183: int error;
184:
185: error = extent_free(fdt_memory_ext, addr, size, EX_NOWAIT);
186: if (error != 0)
187: printf("MEM ERROR: add %llx-%llx failed: %d\n",
188: addr, size, error);
189: DPRINTF("MEM: res %llx-%llx: %d\n", addr, size);
190: }
191:
192: /*
193: * Exclude memory ranges from memory config from a /reserved-memory/ child
194: */
195: static void
196: fdt_add_reserved_memory(int phandle, uint64_t max_addr)
197: {
198: uint64_t addr, size;
199: int index;
200:
201: for (index = 0;
202: fdtbus_get_reg64(phandle, index, &addr, &size) == 0;
203: index++) {
204: if (addr >= max_addr)
205: continue;
206: if (addr + size > max_addr)
207: size = max_addr - addr;
208: fdt_add_reserved_memory_range(addr, size);
209: }
210: }
211:
212: /*
213: * Define usable memory regions.
214: */
215: static void
216: fdt_build_bootconfig(uint64_t mem_addr, uint64_t mem_size)
217: {
218: const int memory = OF_finddevice("/memory");
219: const uint64_t max_addr = mem_addr + mem_size;
220: BootConfig *bc = &bootconfig;
221: struct extent_region *er;
222: uint64_t addr, size;
223: int index, child, error;
224:
225: fdt_memory_ext = extent_create("FDT Memory", mem_addr, max_addr,
226: fdt_memory_ext_storage, sizeof(fdt_memory_ext_storage), 0);
227:
228: for (index = 0;
229: fdtbus_get_reg64(memory, index, &addr, &size) == 0;
230: index++) {
231: if (addr >= max_addr)
232: continue;
233: if (addr + size > max_addr)
234: size = max_addr - addr;
235:
236: error = extent_alloc_region(fdt_memory_ext, addr, size,
237: EX_NOWAIT);
238: if (error != 0)
239: printf("MEM ERROR: add %llx-%llx failed: %d\n",
240: addr, size, error);
241: DPRINTF("MEM: add %llx-%llx\n", addr, size);
242: }
243:
244: const int reserved = OF_finddevice("/reserved-memory");
245: if (reserved > 0)
246: for (child = OF_child(reserved); child; child = OF_peer(child))
247: fdt_add_reserved_memory(child, max_addr);
248:
249: const uint64_t initrd_size = initrd_end - initrd_start;
250: if (initrd_size > 0)
251: fdt_add_reserved_memory_range(initrd_start, initrd_size);
252:
253: DPRINTF("Usable memory:\n");
254: bc->dramblocks = 0;
255: LIST_FOREACH(er, &fdt_memory_ext->ex_regions, er_link) {
256: DPRINTF(" %lx - %lx\n", er->er_start, er->er_end);
257: bc->dram[bc->dramblocks].address = er->er_start;
258: bc->dram[bc->dramblocks].pages =
259: (er->er_end - er->er_start) / PAGE_SIZE;
260: bc->dramblocks++;
261: }
262: }
263:
264: static void
265: fdt_probe_initrd(uint64_t *pstart, uint64_t *pend)
266: {
267: *pstart = *pend = 0;
268:
269: #ifdef MEMORY_DISK_DYNAMIC
270: const int chosen = OF_finddevice("/chosen");
271: if (chosen < 0)
272: return;
273:
274: int len;
275: const void *start_data = fdtbus_get_prop(chosen,
276: "linux,initrd-start", &len);
277: const void *end_data = fdtbus_get_prop(chosen,
278: "linux,initrd-end", NULL);
279: if (start_data == NULL || end_data == NULL)
280: return;
281:
282: switch (len) {
283: case 4:
284: *pstart = be32dec(start_data);
285: *pend = be32dec(end_data);
286: break;
287: case 8:
288: *pstart = be64dec(start_data);
289: *pend = be64dec(end_data);
290: break;
291: default:
292: printf("Unsupported len %d for /chosen/initrd-start\n", len);
293: return;
294: }
295: #endif
296: }
297:
298: static void
299: fdt_setup_initrd(void)
300: {
301: #ifdef MEMORY_DISK_DYNAMIC
302: const uint64_t initrd_size = initrd_end - initrd_start;
303: paddr_t startpa = trunc_page(initrd_start);
304: paddr_t endpa = round_page(initrd_end);
305: paddr_t pa;
306: vaddr_t va;
307: void *md_start;
308:
309: if (initrd_size == 0)
310: return;
311:
312: va = uvm_km_alloc(kernel_map, initrd_size, 0,
313: UVM_KMF_VAONLY | UVM_KMF_NOWAIT);
314: if (va == 0) {
315: printf("Failed to allocate VA for initrd\n");
316: return;
317: }
318:
319: md_start = (void *)va;
320:
321: for (pa = startpa; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE)
322: pmap_kenter_pa(va, pa, VM_PROT_READ|VM_PROT_WRITE, 0);
323: pmap_update(pmap_kernel());
324:
325: md_root_setconf(md_start, initrd_size);
326: #endif
327: }
328:
1.1 jmcneill 329: u_int
330: initarm(void *arg)
331: {
332: const struct arm_platform *plat;
333: uint64_t memory_addr, memory_size;
334: psize_t ram_size = 0;
335:
336: /* Load FDT */
337: const uint8_t *fdt_addr_r = (const uint8_t *)uboot_args[2];
338: int error = fdt_check_header(fdt_addr_r);
339: if (error == 0) {
340: error = fdt_move(fdt_addr_r, fdt_data, sizeof(fdt_data));
341: if (error != 0)
342: panic("fdt_move failed: %s", fdt_strerror(error));
343: fdtbus_set_data(fdt_data);
344: } else {
345: panic("fdt_check_header failed: %s", fdt_strerror(error));
346: }
347:
348: /* Lookup platform specific backend */
349: plat = arm_fdt_platform();
350: if (plat == NULL)
351: panic("Kernel does not support this device");
352:
353: /* Early console may be available, announce ourselves. */
1.2 jmcneill 354: DPRINT("FDT<");
355: DPRINTN((uintptr_t)fdt_addr_r, 16);
356: DPRINT(">");
1.1 jmcneill 357:
1.6 jmcneill 358: const int chosen = OF_finddevice("/chosen");
359: if (chosen >= 0)
360: OF_getprop(chosen, "bootargs", bootargs, sizeof(bootargs));
361: boot_args = bootargs;
362:
1.1 jmcneill 363: DPRINT(" devmap");
364: pmap_devmap_register(plat->devmap());
365:
366: DPRINT(" bootstrap");
367: plat->bootstrap();
368:
369: /* Heads up ... Setup the CPU / MMU / TLB functions. */
370: DPRINT(" cpufunc");
371: if (set_cpufuncs())
372: panic("cpu not recognized!");
373:
1.5 jmcneill 374: /*
375: * If stdout-path is specified on the command line, override the
376: * value in /chosen/stdout-path before initializing console.
377: */
378: fdt_update_stdout_path();
379:
1.1 jmcneill 380: DPRINT(" consinit");
381: consinit();
382:
383: DPRINTF(" ok\n");
384:
385: DPRINTF("uboot: args %#x, %#x, %#x, %#x\n",
386: uboot_args[0], uboot_args[1], uboot_args[2], uboot_args[3]);
387:
388: cpu_reset_address = fdt_reset;
389: cpu_powerdown_address = fdt_powerdown;
390: evbarm_device_register = fdt_device_register;
391:
392: /* Talk to the user */
393: DPRINTF("\nNetBSD/evbarm (fdt) booting ...\n");
394:
395: #ifdef BOOT_ARGS
396: char mi_bootargs[] = BOOT_ARGS;
397: parse_mi_bootargs(mi_bootargs);
398: #endif
399:
400: DPRINTF("KERNEL_BASE=0x%x, "
401: "KERNEL_VM_BASE=0x%x, "
402: "KERNEL_VM_BASE - KERNEL_BASE=0x%x, "
403: "KERNEL_BASE_VOFFSET=0x%x\n",
404: KERNEL_BASE,
405: KERNEL_VM_BASE,
406: KERNEL_VM_BASE - KERNEL_BASE,
407: KERNEL_BASE_VOFFSET);
408:
1.7 jmcneill 409: fdt_get_memory(&memory_addr, &memory_size);
1.1 jmcneill 410:
411: #if !defined(_LP64)
412: /* Cannot map memory above 4GB */
1.9 ! chs 413: if (memory_addr + memory_size >= 0x100000000)
! 414: memory_size = 0x100000000 - memory_addr - PAGE_SIZE;
1.1 jmcneill 415: #endif
416:
417: ram_size = (bus_size_t)memory_size;
418:
419: #ifdef __HAVE_MM_MD_DIRECT_MAPPED_PHYS
420: const bool mapallmem_p = true;
421: #ifndef PMAP_NEED_ALLOC_POOLPAGE
422: if (ram_size > KERNEL_VM_BASE - KERNEL_BASE) {
423: DPRINTF("%s: dropping RAM size from %luMB to %uMB\n",
424: __func__, (unsigned long) (ram_size >> 20),
425: (KERNEL_VM_BASE - KERNEL_BASE) >> 20);
426: ram_size = KERNEL_VM_BASE - KERNEL_BASE;
427: }
428: #endif
429: #else
430: const bool mapallmem_p = false;
431: #endif
432:
1.8 jmcneill 433: /* Parse ramdisk info */
434: fdt_probe_initrd(&initrd_start, &initrd_end);
435:
436: /* Populate bootconfig structure for the benefit of pmap.c. */
437: fdt_build_bootconfig(memory_addr, memory_size);
1.1 jmcneill 438:
439: arm32_bootmem_init(bootconfig.dram[0].address, ram_size,
440: KERNEL_BASE_PHYS);
441: arm32_kernel_vm_init(KERNEL_VM_BASE, ARM_VECTORS_HIGH, 0,
442: plat->devmap(), mapallmem_p);
443:
444: DPRINTF("bootargs: %s\n", bootargs);
445:
446: parse_mi_bootargs(boot_args);
447:
448: #ifdef PMAP_NEED_ALLOC_POOLPAGE
449: bp_lowgig.bp_start = memory_addr / NBPG;
450: if (atop(ram_size) > bp_lowgig.bp_pages) {
451: arm_poolpage_vmfreelist = bp_lowgig.bp_freelist;
452: return initarm_common(KERNEL_VM_BASE, KERNEL_VM_SIZE,
453: &bp_lowgig, 1);
454: }
455: #endif
456:
457: return initarm_common(KERNEL_VM_BASE, KERNEL_VM_SIZE, NULL, 0);
458: }
459:
1.5 jmcneill 460: static void
461: fdt_update_stdout_path(void)
462: {
463: char *stdout_path, *ep;
464: int stdout_path_len;
465: char buf[256];
466:
467: const int chosen_off = fdt_path_offset(fdt_data, "/chosen");
468: if (chosen_off == -1)
469: return;
470:
471: if (get_bootconf_option(boot_args, "stdout-path",
472: BOOTOPT_TYPE_STRING, &stdout_path) == 0)
473: return;
474:
475: ep = strchr(stdout_path, ' ');
476: stdout_path_len = ep ? (ep - stdout_path) : strlen(stdout_path);
477: if (stdout_path_len >= sizeof(buf))
478: return;
479:
480: strncpy(buf, stdout_path, stdout_path_len);
481: buf[stdout_path_len] = '\0';
482: fdt_setprop(fdt_data, chosen_off, "stdout-path",
483: buf, stdout_path_len + 1);
484: }
485:
1.1 jmcneill 486: void
487: consinit(void)
488: {
489: static bool initialized = false;
490: const struct arm_platform *plat = arm_fdt_platform();
491: const struct fdt_console *cons = fdtbus_get_console();
492: struct fdt_attach_args faa;
1.4 jmcneill 493: u_int uart_freq = 0;
1.1 jmcneill 494:
495: if (initialized || cons == NULL)
496: return;
497:
498: plat->init_attach_args(&faa);
499: faa.faa_phandle = fdtbus_get_stdout_phandle();
500:
1.4 jmcneill 501: if (plat->uart_freq != NULL)
502: uart_freq = plat->uart_freq();
503:
504: cons->consinit(&faa, uart_freq);
1.1 jmcneill 505:
506: initialized = true;
507: }
508:
1.3 jmcneill 509: void
510: delay(u_int us)
511: {
512: const struct arm_platform *plat = arm_fdt_platform();
513:
514: plat->delay(us);
515: }
516:
1.1 jmcneill 517: static void
518: fdt_device_register(device_t self, void *aux)
519: {
520: const struct arm_platform *plat = arm_fdt_platform();
521:
1.8 jmcneill 522: if (device_is_a(self, "armfdt"))
523: fdt_setup_initrd();
524:
1.1 jmcneill 525: if (plat && plat->device_register)
526: plat->device_register(self, aux);
527: }
528:
529: static void
530: fdt_reset(void)
531: {
532: const struct arm_platform *plat = arm_fdt_platform();
533:
534: fdtbus_power_reset();
535:
536: if (plat && plat->reset)
537: plat->reset();
538: }
539:
540: static void
541: fdt_powerdown(void)
542: {
543: fdtbus_power_poweroff();
544: }
CVSweb <webmaster@jp.NetBSD.org>