Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/arch/evbarm/fdt/fdt_machdep.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/arch/evbarm/fdt/fdt_machdep.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.7 retrieving revision 1.107 diff -u -p -r1.7 -r1.107 --- src/sys/arch/evbarm/fdt/fdt_machdep.c 2017/06/11 20:25:07 1.7 +++ src/sys/arch/evbarm/fdt/fdt_machdep.c 2024/01/19 09:09:04 1.107 @@ -1,4 +1,4 @@ -/* $NetBSD: fdt_machdep.c,v 1.7 2017/06/11 20:25:07 jmcneill Exp $ */ +/* $NetBSD: fdt_machdep.c,v 1.107 2024/01/19 09:09:04 skrll Exp $ */ /*- * Copyright (c) 2015-2017 Jared McNeill @@ -27,33 +27,53 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: fdt_machdep.c,v 1.7 2017/06/11 20:25:07 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: fdt_machdep.c,v 1.107 2024/01/19 09:09:04 skrll Exp $"); -#include "opt_machdep.h" -#include "opt_ddb.h" -#include "opt_md.h" #include "opt_arm_debug.h" -#include "opt_multiprocessor.h" +#include "opt_bootconfig.h" #include "opt_cpuoptions.h" +#include "opt_ddb.h" +#include "opt_efi.h" +#include "opt_machdep.h" +#include "opt_multiprocessor.h" + +#include "genfb.h" +#include "ukbd.h" +#include "wsdisplay.h" #include -#include -#include +#include + #include +#include +#include +#include #include #include +#include +#include +#include #include +#include +#include #include #include #include +#include #include #include +#include #include +#include #include +#include +#include -#include +#include +#include -#include +#include +#include #include #include @@ -61,274 +81,351 @@ __KERNEL_RCSID(0, "$NetBSD: fdt_machdep. #include #include -#include -#include +#include #include +#include #include #include -#ifndef FDT_MAX_BOOT_STRING -#define FDT_MAX_BOOT_STRING 1024 +#include +#include +#include +#include + +#ifdef EFI_RUNTIME +#include +#endif + +#if NWSDISPLAY > 0 && NGENFB > 0 +#include +#endif + +#if NUKBD > 0 +#include +#endif +#if NWSDISPLAY > 0 +#include #endif BootConfig bootconfig; -char bootargs[FDT_MAX_BOOT_STRING] = ""; char *boot_args = NULL; -u_int uboot_args[4] = { 0 }; /* filled in by xxx_start.S (not in bss) */ + +/* filled in before cleaning bss. keep in .data */ +u_long uboot_args[4] __attribute__((__section__(".data"))); +const uint8_t *fdt_addr_r __attribute__((__section__(".data"))); #include #include -#define FDT_BUF_SIZE (128*1024) +#define FDT_BUF_SIZE (512*1024) static uint8_t fdt_data[FDT_BUF_SIZE]; extern char KERNEL_BASE_phys[]; #define KERNEL_BASE_PHYS ((paddr_t)KERNEL_BASE_phys) -static void fdt_update_stdout_path(void); static void fdt_device_register(device_t, void *); +static void fdt_device_register_post_config(device_t, void *); static void fdt_reset(void); static void fdt_powerdown(void); -#ifdef PMAP_NEED_ALLOC_POOLPAGE -static struct boot_physmem bp_lowgig = { - .bp_pages = (KERNEL_VM_BASE - KERNEL_BASE) / NBPG, - .bp_freelist = VM_FREELIST_ISADMA, - .bp_flags = 0 -}; +#if BYTE_ORDER == BIG_ENDIAN +static void fdt_update_fb_format(void); #endif -#ifdef VERBOSE_INIT_ARM static void -fdt_putchar(char c) +earlyconsputc(dev_t dev, int c) +{ + uartputc(c); +} + +static int +earlyconsgetc(dev_t dev) { - const struct arm_platform *plat = arm_fdt_platform(); - if (plat && plat->early_putchar) - plat->early_putchar(c); + return -1; } +static struct consdev earlycons = { + .cn_putc = earlyconsputc, + .cn_getc = earlyconsgetc, + .cn_pollc = nullcnpollc, +}; + +#ifdef VERBOSE_INIT_ARM +#define VPRINTF(...) printf(__VA_ARGS__) +#else +#define VPRINTF(...) __nothing +#endif + static void -fdt_putstr(const char *s) +fdt_add_dram_blocks(const struct fdt_memory *m, void *arg) { - for (const char *p = s; *p; p++) - fdt_putchar(*p); + BootConfig *bc = arg; + + VPRINTF(" %" PRIx64 " - %" PRIx64 "\n", m->start, m->end - 1); + bc->dram[bc->dramblocks].address = m->start; + bc->dram[bc->dramblocks].pages = + (m->end - m->start) / PAGE_SIZE; + bc->dramblocks++; } +static int nfdt_physmem = 0; +static struct boot_physmem fdt_physmem[FDT_MEMORY_RANGES]; + static void -fdt_printn(u_int n, int base) +fdt_add_boot_physmem(const struct fdt_memory *m, void *arg) { - char *p, buf[(sizeof(u_int) * NBBY / 3) + 1 + 2 /* ALT + SIGN */]; + const paddr_t saddr = round_page(m->start); + const paddr_t eaddr = trunc_page(m->end); - p = buf; - do { - *p++ = hexdigits[n % base]; - } while (n /= base); - - do { - fdt_putchar(*--p); - } while (p > buf); -} -#define DPRINTF(...) printf(__VA_ARGS__) -#define DPRINT(x) fdt_putstr(x) -#define DPRINTN(x,b) fdt_printn((x), (b)) -#else -#define DPRINTF(...) -#define DPRINT(x) -#define DPRINTN(x,b) + VPRINTF(" %" PRIx64 " - %" PRIx64, m->start, m->end - 1); + if (saddr >= eaddr) { + VPRINTF(" skipped\n"); + return; + } + VPRINTF("\n"); + + struct boot_physmem *bp = &fdt_physmem[nfdt_physmem++]; + + KASSERT(nfdt_physmem <= FDT_MEMORY_RANGES); + + bp->bp_start = atop(saddr); + bp->bp_pages = atop(eaddr) - bp->bp_start; + bp->bp_freelist = VM_FREELIST_DEFAULT; + +#ifdef PMAP_NEED_ALLOC_POOLPAGE + const uint64_t memory_size = *(uint64_t *)arg; + if (atop(memory_size) > bp->bp_pages) { + arm_poolpage_vmfreelist = VM_FREELIST_DIRECTMAP; + bp->bp_freelist = VM_FREELIST_DIRECTMAP; + } #endif +} + + +static void +fdt_print_memory(const struct fdt_memory *m, void *arg) +{ + + VPRINTF("FDT /memory @ 0x%" PRIx64 " size 0x%" PRIx64 "\n", + m->start, m->end - m->start); +} + /* - * Get the first physically contiguous region of memory. + * Define usable memory regions. */ static void -fdt_get_memory(uint64_t *paddr, uint64_t *psize) +fdt_build_bootconfig(uint64_t mem_start, uint64_t mem_end) { - const int memory = OF_finddevice("/memory"); - uint64_t cur_addr, cur_size; + BootConfig *bc = &bootconfig; + + uint64_t addr, size; int index; - /* Assume the first entry is the start of memory */ - if (fdtbus_get_reg64(memory, 0, paddr, psize) != 0) - panic("Cannot determine memory size"); - - DPRINTF("FDT /memory [%d] @ 0x%" PRIx64 " size 0x%" PRIx64 "\n", - 0, *paddr, *psize); - - /* If subsequent entries follow the previous one, append them. */ - for (index = 1; - fdtbus_get_reg64(memory, index, &cur_addr, &cur_size) == 0; - index++) { - DPRINTF("FDT /memory [%d] @ 0x%" PRIx64 " size 0x%" PRIx64 "\n", - index, cur_addr, cur_size); - if (*paddr + *psize == cur_addr) - *psize += cur_size; + /* Reserve pages for ramdisk, rndseed, and firmware's RNG */ + fdt_reserve_initrd(); + fdt_reserve_rndseed(); + fdt_reserve_efirng(); + + const int framebuffer = OF_finddevice("/chosen/framebuffer"); + if (framebuffer >= 0) { + for (index = 0; + fdtbus_get_reg64(framebuffer, index, &addr, &size) == 0; + index++) { + fdt_memory_remove_range(addr, size); + } } + + VPRINTF("Usable memory:\n"); + bc->dramblocks = 0; + fdt_memory_foreach(fdt_add_dram_blocks, bc); } -u_int + +vaddr_t initarm(void *arg) { - const struct arm_platform *plat; - uint64_t memory_addr, memory_size; - psize_t ram_size = 0; + const struct fdt_platform *plat; + uint64_t memory_start, memory_end; + + /* set temporally to work printf()/panic() even before consinit() */ + cn_tab = &earlycons; /* Load FDT */ - const uint8_t *fdt_addr_r = (const uint8_t *)uboot_args[2]; int error = fdt_check_header(fdt_addr_r); - if (error == 0) { - error = fdt_move(fdt_addr_r, fdt_data, sizeof(fdt_data)); - if (error != 0) - panic("fdt_move failed: %s", fdt_strerror(error)); - fdtbus_set_data(fdt_data); - } else { + if (error != 0) panic("fdt_check_header failed: %s", fdt_strerror(error)); - } + + /* If the DTB is too big, try to pack it in place first. */ + if (fdt_totalsize(fdt_addr_r) > sizeof(fdt_data)) + (void)fdt_pack(__UNCONST(fdt_addr_r)); + + error = fdt_open_into(fdt_addr_r, fdt_data, sizeof(fdt_data)); + if (error != 0) + panic("fdt_move failed: %s", fdt_strerror(error)); + + fdtbus_init(fdt_data); /* Lookup platform specific backend */ - plat = arm_fdt_platform(); + plat = fdt_platform_find(); if (plat == NULL) panic("Kernel does not support this device"); /* Early console may be available, announce ourselves. */ - DPRINT("FDT<"); - DPRINTN((uintptr_t)fdt_addr_r, 16); - DPRINT(">"); - - const int chosen = OF_finddevice("/chosen"); - if (chosen >= 0) - OF_getprop(chosen, "bootargs", bootargs, sizeof(bootargs)); - boot_args = bootargs; - - DPRINT(" devmap"); - pmap_devmap_register(plat->devmap()); + VPRINTF("FDT<%p>\n", fdt_addr_r); - DPRINT(" bootstrap"); - plat->bootstrap(); + boot_args = fdt_get_bootargs(); /* Heads up ... Setup the CPU / MMU / TLB functions. */ - DPRINT(" cpufunc"); + VPRINTF("cpufunc\n"); if (set_cpufuncs()) panic("cpu not recognized!"); /* + * Memory is still identity/flat mapped this point so using ttbr for + * l1pt VA is fine + */ + + VPRINTF("devmap %p\n", plat->fp_devmap()); + extern char ARM_BOOTSTRAP_LxPT[]; + pmap_devmap_bootstrap((vaddr_t)ARM_BOOTSTRAP_LxPT, plat->fp_devmap()); + + VPRINTF("bootstrap\n"); + plat->fp_bootstrap(); + + /* * If stdout-path is specified on the command line, override the * value in /chosen/stdout-path before initializing console. */ - fdt_update_stdout_path(); + VPRINTF("stdout\n"); + fdt_update_stdout_path(fdt_data, boot_args); - DPRINT(" consinit"); - consinit(); +#if BYTE_ORDER == BIG_ENDIAN + /* + * Most boards are configured to little-endian mode initially, and + * switched to big-endian mode after kernel is loaded. In this case, + * framebuffer seems byte-swapped to CPU. Override FDT to let + * drivers know. + */ + VPRINTF("fb_format\n"); + fdt_update_fb_format(); +#endif - DPRINTF(" ok\n"); + /* + * Done making changes to the FDT. + */ + fdt_pack(fdt_data); + + VPRINTF("consinit "); + consinit(); + VPRINTF("ok\n"); - DPRINTF("uboot: args %#x, %#x, %#x, %#x\n", + VPRINTF("uboot: args %#lx, %#lx, %#lx, %#lx\n", uboot_args[0], uboot_args[1], uboot_args[2], uboot_args[3]); cpu_reset_address = fdt_reset; cpu_powerdown_address = fdt_powerdown; evbarm_device_register = fdt_device_register; + evbarm_device_register_post_config = fdt_device_register_post_config; + evbarm_cpu_rootconf = fdt_cpu_rootconf; /* Talk to the user */ - DPRINTF("\nNetBSD/evbarm (fdt) booting ...\n"); + printf("NetBSD/evbarm (fdt) booting ...\n"); #ifdef BOOT_ARGS char mi_bootargs[] = BOOT_ARGS; parse_mi_bootargs(mi_bootargs); #endif - DPRINTF("KERNEL_BASE=0x%x, " - "KERNEL_VM_BASE=0x%x, " - "KERNEL_VM_BASE - KERNEL_BASE=0x%x, " - "KERNEL_BASE_VOFFSET=0x%x\n", - KERNEL_BASE, - KERNEL_VM_BASE, - KERNEL_VM_BASE - KERNEL_BASE, - KERNEL_BASE_VOFFSET); + fdt_memory_get(&memory_start, &memory_end); - fdt_get_memory(&memory_addr, &memory_size); + fdt_memory_foreach(fdt_print_memory, NULL); #if !defined(_LP64) - /* Cannot map memory above 4GB */ - if (memory_addr + memory_size > 0x100000000) - memory_size = 0x100000000 - memory_addr; -#endif - - ram_size = (bus_size_t)memory_size; - -#ifdef __HAVE_MM_MD_DIRECT_MAPPED_PHYS - const bool mapallmem_p = true; -#ifndef PMAP_NEED_ALLOC_POOLPAGE - if (ram_size > KERNEL_VM_BASE - KERNEL_BASE) { - DPRINTF("%s: dropping RAM size from %luMB to %uMB\n", - __func__, (unsigned long) (ram_size >> 20), - (KERNEL_VM_BASE - KERNEL_BASE) >> 20); - ram_size = KERNEL_VM_BASE - KERNEL_BASE; + /* Cannot map memory above 4GB (remove last page as well) */ + const uint64_t memory_limit = 0x100000000ULL - PAGE_SIZE; + if (memory_end > memory_limit) { + fdt_memory_remove_range(memory_limit , memory_end); + memory_end = memory_limit; } #endif -#else - const bool mapallmem_p = false; -#endif + uint64_t memory_size = memory_end - memory_start; - /* Fake bootconfig structure for the benefit of pmap.c. */ - bootconfig.dramblocks = 1; - bootconfig.dram[0].address = (bus_addr_t)memory_addr; - bootconfig.dram[0].pages = ram_size / PAGE_SIZE; + VPRINTF("%s: memory start %" PRIx64 " end %" PRIx64 " (len %" + PRIx64 ")\n", __func__, memory_start, memory_end, memory_size); - arm32_bootmem_init(bootconfig.dram[0].address, ram_size, - KERNEL_BASE_PHYS); - arm32_kernel_vm_init(KERNEL_VM_BASE, ARM_VECTORS_HIGH, 0, - plat->devmap(), mapallmem_p); + /* Parse ramdisk info */ + fdt_probe_initrd(); - DPRINTF("bootargs: %s\n", bootargs); + /* Parse our on-disk rndseed and the firmware's RNG from EFI */ + fdt_probe_rndseed(); + fdt_probe_efirng(); + + fdt_memory_remove_reserved(memory_start, memory_end); + + /* + * Populate bootconfig structure for the benefit of dodumpsys + */ + VPRINTF("%s: fdt_build_bootconfig\n", __func__); + fdt_build_bootconfig(memory_start, memory_end); + + /* Perform PT build and VM init */ + cpu_kernel_vm_init(memory_start, memory_size); + + VPRINTF("bootargs: %s\n", boot_args); parse_mi_bootargs(boot_args); -#ifdef PMAP_NEED_ALLOC_POOLPAGE - bp_lowgig.bp_start = memory_addr / NBPG; - if (atop(ram_size) > bp_lowgig.bp_pages) { - arm_poolpage_vmfreelist = bp_lowgig.bp_freelist; - return initarm_common(KERNEL_VM_BASE, KERNEL_VM_SIZE, - &bp_lowgig, 1); - } -#endif + VPRINTF("Memory regions:\n"); - return initarm_common(KERNEL_VM_BASE, KERNEL_VM_SIZE, NULL, 0); + /* Populate fdt_physmem / nfdt_physmem for initarm_common */ + fdt_memory_foreach(fdt_add_boot_physmem, &memory_size); -} + vaddr_t sp = initarm_common(KERNEL_VM_BASE, KERNEL_VM_SIZE, fdt_physmem, + nfdt_physmem); -static void -fdt_update_stdout_path(void) -{ - char *stdout_path, *ep; - int stdout_path_len; - char buf[256]; + /* + * initarm_common flushes cache if required before AP start + */ + error = 0; + if ((boothowto & RB_MD1) == 0) { + VPRINTF("mpstart\n"); + if (plat->fp_mpstart) + error = plat->fp_mpstart(); + } - const int chosen_off = fdt_path_offset(fdt_data, "/chosen"); - if (chosen_off == -1) - return; + if (error) + return sp; - if (get_bootconf_option(boot_args, "stdout-path", - BOOTOPT_TYPE_STRING, &stdout_path) == 0) - return; + /* + * Now we have APs started the pages used for stacks and L1PT can + * be given to uvm + */ + extern char const __start__init_memory[]; + extern char const __stop__init_memory[] __weak; - ep = strchr(stdout_path, ' '); - stdout_path_len = ep ? (ep - stdout_path) : strlen(stdout_path); - if (stdout_path_len >= sizeof(buf)) - return; + if (&__start__init_memory[0] != &__stop__init_memory[0]) { + const paddr_t spa = KERN_VTOPHYS((vaddr_t)__start__init_memory); + const paddr_t epa = KERN_VTOPHYS((vaddr_t)__stop__init_memory); + const paddr_t spg = atop(spa); + const paddr_t epg = atop(epa); - strncpy(buf, stdout_path, stdout_path_len); - buf[stdout_path_len] = '\0'; - fdt_setprop(fdt_data, chosen_off, "stdout-path", - buf, stdout_path_len + 1); + VPRINTF(" start %08lx end %08lx... " + "loading in freelist %d\n", spa, epa, VM_FREELIST_DEFAULT); + + uvm_page_physload(spg, epg, spg, epg, VM_FREELIST_DEFAULT); + } + + return sp; } void consinit(void) { static bool initialized = false; - const struct arm_platform *plat = arm_fdt_platform(); + const struct fdt_platform *plat = fdt_platform_find(); const struct fdt_console *cons = fdtbus_get_console(); struct fdt_attach_args faa; u_int uart_freq = 0; @@ -336,11 +433,11 @@ consinit(void) if (initialized || cons == NULL) return; - plat->init_attach_args(&faa); + plat->fp_init_attach_args(&faa); faa.faa_phandle = fdtbus_get_stdout_phandle(); - if (plat->uart_freq != NULL) - uart_freq = plat->uart_freq(); + if (plat->fp_uart_freq != NULL) + uart_freq = plat->fp_uart_freq(); cons->consinit(&faa, uart_freq); @@ -348,31 +445,76 @@ consinit(void) } void -delay(u_int us) +cpu_startup_hook(void) { - const struct arm_platform *plat = arm_fdt_platform(); +#ifdef EFI_RUNTIME + fdt_map_efi_runtime("netbsd,uefi-runtime-code", ARM_EFIRT_MEM_CODE); + fdt_map_efi_runtime("netbsd,uefi-runtime-data", ARM_EFIRT_MEM_DATA); + fdt_map_efi_runtime("netbsd,uefi-runtime-mmio", ARM_EFIRT_MEM_MMIO); +#endif - plat->delay(us); + fdtbus_intr_init(); + + fdt_setup_rndseed(); + fdt_setup_efirng(); } +void +delay(u_int us) +{ + const struct fdt_platform *plat = fdt_platform_find(); + + plat->fp_delay(us); +} static void fdt_device_register(device_t self, void *aux) { - const struct arm_platform *plat = arm_fdt_platform(); + const struct fdt_platform *plat = fdt_platform_find(); + + if (device_is_a(self, "armfdt")) { + fdt_setup_initrd(); + +#if NWSDISPLAY > 0 && NGENFB > 0 + /* + * Setup framebuffer console, if present. + */ + arm_simplefb_preattach(); +#endif + } - if (plat && plat->device_register) - plat->device_register(self, aux); +#if NWSDISPLAY > 0 && NGENFB > 0 + if (device_is_a(self, "genfb")) { + prop_dictionary_t dict = device_properties(self); + prop_dictionary_set_uint64(dict, + "simplefb-physaddr", arm_simplefb_physaddr()); + } +#endif + + if (plat && plat->fp_device_register) + plat->fp_device_register(self, aux); +} + +static void +fdt_device_register_post_config(device_t self, void *aux) +{ +#if NUKBD > 0 && NWSDISPLAY > 0 + if (device_is_a(self, "wsdisplay")) { + struct wsdisplay_softc *sc = device_private(self); + if (wsdisplay_isconsole(sc)) + ukbd_cnattach(); + } +#endif } static void fdt_reset(void) { - const struct arm_platform *plat = arm_fdt_platform(); + const struct fdt_platform *plat = fdt_platform_find(); fdtbus_power_reset(); - if (plat && plat->reset) - plat->reset(); + if (plat && plat->fp_reset) + plat->fp_reset(); } static void @@ -380,3 +522,36 @@ fdt_powerdown(void) { fdtbus_power_poweroff(); } + +#if BYTE_ORDER == BIG_ENDIAN +static void +fdt_update_fb_format(void) +{ + int off, len; + const char *format, *replace; + + off = fdt_path_offset(fdt_data, "/chosen"); + if (off < 0) + return; + + for (;;) { + off = fdt_node_offset_by_compatible(fdt_data, off, + "simple-framebuffer"); + if (off < 0) + return; + + format = fdt_getprop(fdt_data, off, "format", &len); + if (format == NULL) + continue; + + replace = NULL; + if (strcmp(format, "a8b8g8r8") == 0) + replace = "r8g8b8a8"; + else if (strcmp(format, "x8r8g8b8") == 0) + replace = "b8g8r8x8"; + if (replace != NULL) + fdt_setprop(fdt_data, off, "format", replace, + strlen(replace) + 1); + } +} +#endif