1bd744d46SAndrew Jones // SPDX-License-Identifier: GPL-2.0-only 2bd744d46SAndrew Jones /* 3bd744d46SAndrew Jones * Initialize machine setup information and I/O. 4bd744d46SAndrew Jones * 5bd744d46SAndrew Jones * Copyright (C) 2023, Ventana Micro Systems Inc., Andrew Jones <ajones@ventanamicro.com> 6bd744d46SAndrew Jones */ 7bd744d46SAndrew Jones #include <libcflat.h> 822f287f4SAndrew Jones #include <alloc.h> 96895ce6dSAndrew Jones #include <alloc_page.h> 1022f287f4SAndrew Jones #include <alloc_phys.h> 1122f287f4SAndrew Jones #include <argv.h> 1223100d97SAndrew Jones #include <auxinfo.h> 1322f287f4SAndrew Jones #include <cpumask.h> 1422f287f4SAndrew Jones #include <devicetree.h> 156895ce6dSAndrew Jones #include <memregions.h> 169c92b28eSAndrew Jones #include <on-cpus.h> 1723100d97SAndrew Jones #include <vmalloc.h> 1822f287f4SAndrew Jones #include <asm/csr.h> 19ad435a71SAndrew Jones #include <asm/mmu.h> 2022f287f4SAndrew Jones #include <asm/page.h> 21386561f8SAndrew Jones #include <asm/processor.h> 22bd744d46SAndrew Jones #include <asm/setup.h> 2393bcbb09SJames Raphael Tiovalen #include <asm/timer.h> 24bd744d46SAndrew Jones 256895ce6dSAndrew Jones #define VA_BASE ((phys_addr_t)3 * SZ_1G) 2623100d97SAndrew Jones #if __riscv_xlen == 64 2723100d97SAndrew Jones #define VA_TOP ((phys_addr_t)4 * SZ_1G) 2823100d97SAndrew Jones #else 2923100d97SAndrew Jones #define VA_TOP ((phys_addr_t)0) 3023100d97SAndrew Jones #endif 316895ce6dSAndrew Jones 326895ce6dSAndrew Jones #define MAX_DT_MEM_REGIONS 16 336895ce6dSAndrew Jones #define NR_MEM_REGIONS (MAX_DT_MEM_REGIONS + 16) 346895ce6dSAndrew Jones 3531b4ef45SAndrew Jones extern unsigned long _etext; 3631b4ef45SAndrew Jones 3722f287f4SAndrew Jones char *initrd; 3822f287f4SAndrew Jones u32 initrd_size; 3922f287f4SAndrew Jones 40386561f8SAndrew Jones struct thread_info cpus[NR_CPUS]; 4122f287f4SAndrew Jones int nr_cpus; 4293bcbb09SJames Raphael Tiovalen uint64_t timebase_frequency; 4322f287f4SAndrew Jones 446895ce6dSAndrew Jones static struct mem_region riscv_mem_regions[NR_MEM_REGIONS + 1]; 456895ce6dSAndrew Jones 4622f287f4SAndrew Jones int hartid_to_cpu(unsigned long hartid) 4722f287f4SAndrew Jones { 4822f287f4SAndrew Jones int cpu; 4922f287f4SAndrew Jones 5022f287f4SAndrew Jones for_each_present_cpu(cpu) 51386561f8SAndrew Jones if (cpus[cpu].hartid == hartid) 5222f287f4SAndrew Jones return cpu; 5322f287f4SAndrew Jones return -1; 5422f287f4SAndrew Jones } 5522f287f4SAndrew Jones 5622f287f4SAndrew Jones static void cpu_set_fdt(int fdtnode __unused, u64 regval, void *info __unused) 5722f287f4SAndrew Jones { 5822f287f4SAndrew Jones int cpu = nr_cpus++; 5922f287f4SAndrew Jones 6022f287f4SAndrew Jones assert_msg(cpu < NR_CPUS, "Number cpus exceeds maximum supported (%d).", NR_CPUS); 6122f287f4SAndrew Jones 62386561f8SAndrew Jones cpus[cpu].cpu = cpu; 63386561f8SAndrew Jones cpus[cpu].hartid = regval; 6422f287f4SAndrew Jones set_cpu_present(cpu, true); 6522f287f4SAndrew Jones } 6622f287f4SAndrew Jones 6722f287f4SAndrew Jones static void cpu_init_acpi(void) 6822f287f4SAndrew Jones { 6922f287f4SAndrew Jones assert_msg(false, "ACPI not available"); 7022f287f4SAndrew Jones } 7122f287f4SAndrew Jones 7222f287f4SAndrew Jones static void cpu_init(void) 7322f287f4SAndrew Jones { 7422f287f4SAndrew Jones int ret; 7522f287f4SAndrew Jones 7622f287f4SAndrew Jones nr_cpus = 0; 7722f287f4SAndrew Jones if (dt_available()) { 7822f287f4SAndrew Jones ret = dt_for_each_cpu_node(cpu_set_fdt, NULL); 7922f287f4SAndrew Jones assert(ret == 0); 8022f287f4SAndrew Jones } else { 8122f287f4SAndrew Jones cpu_init_acpi(); 8222f287f4SAndrew Jones } 8322f287f4SAndrew Jones 8422f287f4SAndrew Jones set_cpu_online(hartid_to_cpu(csr_read(CSR_SSCRATCH)), true); 859c92b28eSAndrew Jones cpu0_calls_idle = true; 8622f287f4SAndrew Jones } 8722f287f4SAndrew Jones 883d83840dSAndrew Jones static void mem_allocator_init(struct mem_region *freemem, phys_addr_t freemem_start) 8922f287f4SAndrew Jones { 903d83840dSAndrew Jones phys_addr_t freemem_end = freemem->end; 9131b4ef45SAndrew Jones phys_addr_t base, top; 926895ce6dSAndrew Jones 9331b4ef45SAndrew Jones freemem_start = PAGE_ALIGN(freemem_start); 9488f594c8SAndrew Jones freemem_end &= PHYS_PAGE_MASK; 956895ce6dSAndrew Jones 966895ce6dSAndrew Jones /* 976895ce6dSAndrew Jones * The assert below is mostly checking that the free memory doesn't 986895ce6dSAndrew Jones * start in the 3G-4G range, which is reserved for virtual addresses, 996895ce6dSAndrew Jones * but it also confirms that there is some free memory (the amount 1006895ce6dSAndrew Jones * is arbitrarily selected, but should be sufficient for a unit test) 1016895ce6dSAndrew Jones * 1026895ce6dSAndrew Jones * TODO: Allow the VA range to shrink and move. 1036895ce6dSAndrew Jones */ 1043d83840dSAndrew Jones if (freemem_end > VA_BASE) { 1053d83840dSAndrew Jones struct mem_region *curr, *rest; 1066895ce6dSAndrew Jones freemem_end = VA_BASE; 1073d83840dSAndrew Jones memregions_split(VA_BASE, &curr, &rest); 1083d83840dSAndrew Jones assert(curr == freemem); 1093d83840dSAndrew Jones if (rest) 1103d83840dSAndrew Jones rest->flags = MR_F_UNUSED; 1113d83840dSAndrew Jones } 1126895ce6dSAndrew Jones assert(freemem_end - freemem_start >= SZ_1M * 16); 1136895ce6dSAndrew Jones 11423100d97SAndrew Jones init_alloc_vpage(__va(VA_TOP)); 11523100d97SAndrew Jones 1166895ce6dSAndrew Jones /* 1176895ce6dSAndrew Jones * TODO: Remove the need for this phys allocator dance, since, as we 1186895ce6dSAndrew Jones * can see with the assert, we could have gone straight to the page 1196895ce6dSAndrew Jones * allocator. 1206895ce6dSAndrew Jones */ 1216895ce6dSAndrew Jones phys_alloc_init(freemem_start, freemem_end - freemem_start); 1226895ce6dSAndrew Jones phys_alloc_set_minimum_alignment(PAGE_SIZE); 1236895ce6dSAndrew Jones phys_alloc_get_unused(&base, &top); 1246895ce6dSAndrew Jones assert(base == freemem_start && top == freemem_end); 1256895ce6dSAndrew Jones 1266895ce6dSAndrew Jones page_alloc_init_area(0, freemem_start >> PAGE_SHIFT, freemem_end >> PAGE_SHIFT); 1276895ce6dSAndrew Jones page_alloc_ops_enable(); 12822f287f4SAndrew Jones } 12922f287f4SAndrew Jones 13031b4ef45SAndrew Jones static void mem_init(phys_addr_t freemem_start) 13131b4ef45SAndrew Jones { 13231b4ef45SAndrew Jones struct mem_region *freemem, *code, *data; 13331b4ef45SAndrew Jones 13431b4ef45SAndrew Jones memregions_init(riscv_mem_regions, NR_MEM_REGIONS); 13531b4ef45SAndrew Jones memregions_add_dt_regions(MAX_DT_MEM_REGIONS); 13631b4ef45SAndrew Jones 13731b4ef45SAndrew Jones /* Split the region with the code into two regions; code and data */ 13831b4ef45SAndrew Jones memregions_split((unsigned long)&_etext, &code, &data); 13931b4ef45SAndrew Jones assert(code); 14031b4ef45SAndrew Jones code->flags |= MR_F_CODE; 14131b4ef45SAndrew Jones 14231b4ef45SAndrew Jones freemem = memregions_find(freemem_start); 14331b4ef45SAndrew Jones assert(freemem && !(freemem->flags & (MR_F_IO | MR_F_CODE))); 14431b4ef45SAndrew Jones 1453d83840dSAndrew Jones mem_allocator_init(freemem, freemem_start); 14631b4ef45SAndrew Jones } 14731b4ef45SAndrew Jones 14831b4ef45SAndrew Jones static void freemem_push_fdt(void **freemem, const void *fdt) 14931b4ef45SAndrew Jones { 15031b4ef45SAndrew Jones u32 fdt_size; 15131b4ef45SAndrew Jones int ret; 15231b4ef45SAndrew Jones 15331b4ef45SAndrew Jones fdt_size = fdt_totalsize(fdt); 15431b4ef45SAndrew Jones ret = fdt_move(fdt, *freemem, fdt_size); 15531b4ef45SAndrew Jones assert(ret == 0); 15631b4ef45SAndrew Jones ret = dt_init(*freemem); 15731b4ef45SAndrew Jones assert(ret == 0); 15831b4ef45SAndrew Jones *freemem += fdt_size; 15931b4ef45SAndrew Jones } 16031b4ef45SAndrew Jones 16131b4ef45SAndrew Jones static void freemem_push_dt_initrd(void **freemem) 16231b4ef45SAndrew Jones { 16331b4ef45SAndrew Jones const char *tmp; 16431b4ef45SAndrew Jones int ret; 16531b4ef45SAndrew Jones 16631b4ef45SAndrew Jones ret = dt_get_initrd(&tmp, &initrd_size); 16731b4ef45SAndrew Jones assert(ret == 0 || ret == -FDT_ERR_NOTFOUND); 16831b4ef45SAndrew Jones if (ret == 0) { 16931b4ef45SAndrew Jones initrd = *freemem; 17031b4ef45SAndrew Jones memmove(initrd, tmp, initrd_size); 17131b4ef45SAndrew Jones *freemem += initrd_size; 17231b4ef45SAndrew Jones } 17331b4ef45SAndrew Jones } 17431b4ef45SAndrew Jones 17531b4ef45SAndrew Jones static void initrd_setup(void) 17631b4ef45SAndrew Jones { 17731b4ef45SAndrew Jones char *env; 17831b4ef45SAndrew Jones 17931b4ef45SAndrew Jones if (!initrd) 18031b4ef45SAndrew Jones return; 18131b4ef45SAndrew Jones 18231b4ef45SAndrew Jones /* environ is currently the only file in the initrd */ 18331b4ef45SAndrew Jones env = malloc(initrd_size); 18431b4ef45SAndrew Jones memcpy(env, initrd, initrd_size); 18531b4ef45SAndrew Jones setup_env(env, initrd_size); 18631b4ef45SAndrew Jones } 18731b4ef45SAndrew Jones 18822f287f4SAndrew Jones static void banner(void) 18922f287f4SAndrew Jones { 19022f287f4SAndrew Jones puts("\n"); 19122f287f4SAndrew Jones puts("##########################################################################\n"); 19222f287f4SAndrew Jones puts("# kvm-unit-tests\n"); 19322f287f4SAndrew Jones puts("##########################################################################\n"); 19422f287f4SAndrew Jones puts("\n"); 19522f287f4SAndrew Jones } 19622f287f4SAndrew Jones 197bd744d46SAndrew Jones void setup(const void *fdt, phys_addr_t freemem_start) 198bd744d46SAndrew Jones { 19922f287f4SAndrew Jones void *freemem; 20031b4ef45SAndrew Jones const char *bootargs; 20122f287f4SAndrew Jones int ret; 20222f287f4SAndrew Jones 20374492717SAndrew Jones assert(freemem_start < VA_BASE); 20423100d97SAndrew Jones freemem = __va(freemem_start); 20522f287f4SAndrew Jones 20631b4ef45SAndrew Jones freemem_push_fdt(&freemem, fdt); 20731b4ef45SAndrew Jones freemem_push_dt_initrd(&freemem); 20822f287f4SAndrew Jones 20923100d97SAndrew Jones mem_init(PAGE_ALIGN(__pa(freemem))); 21022f287f4SAndrew Jones cpu_init(); 21193bcbb09SJames Raphael Tiovalen timer_get_frequency(); 212386561f8SAndrew Jones thread_info_init(); 213*94ca1aafSAndrew Jones local_hart_init(); 21422f287f4SAndrew Jones io_init(); 21522f287f4SAndrew Jones 21622f287f4SAndrew Jones ret = dt_get_bootargs(&bootargs); 21722f287f4SAndrew Jones assert(ret == 0 || ret == -FDT_ERR_NOTFOUND); 21822f287f4SAndrew Jones setup_args_progname(bootargs); 21922f287f4SAndrew Jones 22031b4ef45SAndrew Jones initrd_setup(); 22122f287f4SAndrew Jones 22223100d97SAndrew Jones if (!(auxinfo.flags & AUXINFO_MMU_OFF)) 22323100d97SAndrew Jones setup_vm(); 224ad435a71SAndrew Jones 22522f287f4SAndrew Jones banner(); 226bd744d46SAndrew Jones } 2279f34c810SAndrew Jones 2289f34c810SAndrew Jones #ifdef CONFIG_EFI 2299f34c810SAndrew Jones #include <efi.h> 2309f34c810SAndrew Jones 2319f34c810SAndrew Jones extern unsigned long exception_vectors; 2329f34c810SAndrew Jones extern unsigned long boot_hartid; 2339f34c810SAndrew Jones 2349f34c810SAndrew Jones static efi_status_t efi_mem_init(efi_bootinfo_t *efi_bootinfo) 2359f34c810SAndrew Jones { 2369f34c810SAndrew Jones struct mem_region *freemem_mr = NULL, *code, *data; 2379f34c810SAndrew Jones void *freemem; 2389f34c810SAndrew Jones 2399f34c810SAndrew Jones memregions_init(riscv_mem_regions, NR_MEM_REGIONS); 2409f34c810SAndrew Jones 2419f34c810SAndrew Jones memregions_efi_init(&efi_bootinfo->mem_map, &freemem_mr); 2429f34c810SAndrew Jones if (!freemem_mr) 2439f34c810SAndrew Jones return EFI_OUT_OF_RESOURCES; 2449f34c810SAndrew Jones 2459f34c810SAndrew Jones memregions_split((unsigned long)&_etext, &code, &data); 2469f34c810SAndrew Jones assert(code && (code->flags & MR_F_CODE)); 2479f34c810SAndrew Jones if (data) 2489f34c810SAndrew Jones data->flags &= ~MR_F_CODE; 2499f34c810SAndrew Jones 2509f34c810SAndrew Jones for (struct mem_region *m = mem_regions; m->end; ++m) 2519f34c810SAndrew Jones assert(m == code || !(m->flags & MR_F_CODE)); 2529f34c810SAndrew Jones 2539f34c810SAndrew Jones freemem = (void *)PAGE_ALIGN(freemem_mr->start); 2549f34c810SAndrew Jones 2559f34c810SAndrew Jones if (efi_bootinfo->fdt) 2569f34c810SAndrew Jones freemem_push_fdt(&freemem, efi_bootinfo->fdt); 2579f34c810SAndrew Jones 2589f34c810SAndrew Jones mmu_disable(); 2593d83840dSAndrew Jones mem_allocator_init(freemem_mr, (unsigned long)freemem); 2609f34c810SAndrew Jones 2619f34c810SAndrew Jones return EFI_SUCCESS; 2629f34c810SAndrew Jones } 2639f34c810SAndrew Jones 2649f34c810SAndrew Jones efi_status_t setup_efi(efi_bootinfo_t *efi_bootinfo) 2659f34c810SAndrew Jones { 2669f34c810SAndrew Jones efi_status_t status; 2679f34c810SAndrew Jones 2689f34c810SAndrew Jones csr_write(CSR_STVEC, (unsigned long)&exception_vectors); 2699f34c810SAndrew Jones csr_write(CSR_SSCRATCH, boot_hartid); 2709f34c810SAndrew Jones 2719f34c810SAndrew Jones status = efi_mem_init(efi_bootinfo); 2729f34c810SAndrew Jones if (status != EFI_SUCCESS) { 2739f34c810SAndrew Jones printf("Failed to initialize memory\n"); 2749f34c810SAndrew Jones return status; 2759f34c810SAndrew Jones } 2769f34c810SAndrew Jones 2779f34c810SAndrew Jones cpu_init(); 27893bcbb09SJames Raphael Tiovalen timer_get_frequency(); 2799f34c810SAndrew Jones thread_info_init(); 280*94ca1aafSAndrew Jones local_hart_init(); 2819f34c810SAndrew Jones io_init(); 2829f34c810SAndrew Jones initrd_setup(); 2839f34c810SAndrew Jones 2849f34c810SAndrew Jones if (!(auxinfo.flags & AUXINFO_MMU_OFF)) 2859f34c810SAndrew Jones setup_vm(); 2869f34c810SAndrew Jones 2879f34c810SAndrew Jones banner(); 2889f34c810SAndrew Jones 2899f34c810SAndrew Jones return EFI_SUCCESS; 2909f34c810SAndrew Jones } 2919f34c810SAndrew Jones #endif /* CONFIG_EFI */ 292