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> 23bd744d46SAndrew Jones 246895ce6dSAndrew Jones #define VA_BASE ((phys_addr_t)3 * SZ_1G) 2523100d97SAndrew Jones #if __riscv_xlen == 64 2623100d97SAndrew Jones #define VA_TOP ((phys_addr_t)4 * SZ_1G) 2723100d97SAndrew Jones #else 2823100d97SAndrew Jones #define VA_TOP ((phys_addr_t)0) 2923100d97SAndrew Jones #endif 306895ce6dSAndrew Jones 316895ce6dSAndrew Jones #define MAX_DT_MEM_REGIONS 16 326895ce6dSAndrew Jones #define NR_MEM_REGIONS (MAX_DT_MEM_REGIONS + 16) 336895ce6dSAndrew Jones 34*31b4ef45SAndrew Jones extern unsigned long _etext; 35*31b4ef45SAndrew Jones 3622f287f4SAndrew Jones char *initrd; 3722f287f4SAndrew Jones u32 initrd_size; 3822f287f4SAndrew Jones 39386561f8SAndrew Jones struct thread_info cpus[NR_CPUS]; 4022f287f4SAndrew Jones int nr_cpus; 4122f287f4SAndrew Jones 426895ce6dSAndrew Jones static struct mem_region riscv_mem_regions[NR_MEM_REGIONS + 1]; 436895ce6dSAndrew Jones 4422f287f4SAndrew Jones int hartid_to_cpu(unsigned long hartid) 4522f287f4SAndrew Jones { 4622f287f4SAndrew Jones int cpu; 4722f287f4SAndrew Jones 4822f287f4SAndrew Jones for_each_present_cpu(cpu) 49386561f8SAndrew Jones if (cpus[cpu].hartid == hartid) 5022f287f4SAndrew Jones return cpu; 5122f287f4SAndrew Jones return -1; 5222f287f4SAndrew Jones } 5322f287f4SAndrew Jones 5422f287f4SAndrew Jones static void cpu_set_fdt(int fdtnode __unused, u64 regval, void *info __unused) 5522f287f4SAndrew Jones { 5622f287f4SAndrew Jones int cpu = nr_cpus++; 5722f287f4SAndrew Jones 5822f287f4SAndrew Jones assert_msg(cpu < NR_CPUS, "Number cpus exceeds maximum supported (%d).", NR_CPUS); 5922f287f4SAndrew Jones 60386561f8SAndrew Jones cpus[cpu].cpu = cpu; 61386561f8SAndrew Jones cpus[cpu].hartid = regval; 6222f287f4SAndrew Jones set_cpu_present(cpu, true); 6322f287f4SAndrew Jones } 6422f287f4SAndrew Jones 6522f287f4SAndrew Jones static void cpu_init_acpi(void) 6622f287f4SAndrew Jones { 6722f287f4SAndrew Jones assert_msg(false, "ACPI not available"); 6822f287f4SAndrew Jones } 6922f287f4SAndrew Jones 7022f287f4SAndrew Jones static void cpu_init(void) 7122f287f4SAndrew Jones { 7222f287f4SAndrew Jones int ret; 7322f287f4SAndrew Jones 7422f287f4SAndrew Jones nr_cpus = 0; 7522f287f4SAndrew Jones if (dt_available()) { 7622f287f4SAndrew Jones ret = dt_for_each_cpu_node(cpu_set_fdt, NULL); 7722f287f4SAndrew Jones assert(ret == 0); 7822f287f4SAndrew Jones } else { 7922f287f4SAndrew Jones cpu_init_acpi(); 8022f287f4SAndrew Jones } 8122f287f4SAndrew Jones 8222f287f4SAndrew Jones set_cpu_online(hartid_to_cpu(csr_read(CSR_SSCRATCH)), true); 839c92b28eSAndrew Jones cpu0_calls_idle = true; 8422f287f4SAndrew Jones } 8522f287f4SAndrew Jones 86*31b4ef45SAndrew Jones static void mem_allocator_init(phys_addr_t freemem_start, phys_addr_t freemem_end) 8722f287f4SAndrew Jones { 88*31b4ef45SAndrew Jones phys_addr_t base, top; 896895ce6dSAndrew Jones 90*31b4ef45SAndrew Jones freemem_start = PAGE_ALIGN(freemem_start); 91*31b4ef45SAndrew Jones freemem_end &= PAGE_MASK; 926895ce6dSAndrew Jones 936895ce6dSAndrew Jones /* 946895ce6dSAndrew Jones * The assert below is mostly checking that the free memory doesn't 956895ce6dSAndrew Jones * start in the 3G-4G range, which is reserved for virtual addresses, 966895ce6dSAndrew Jones * but it also confirms that there is some free memory (the amount 976895ce6dSAndrew Jones * is arbitrarily selected, but should be sufficient for a unit test) 986895ce6dSAndrew Jones * 996895ce6dSAndrew Jones * TODO: Allow the VA range to shrink and move. 1006895ce6dSAndrew Jones */ 1016895ce6dSAndrew Jones if (freemem_end > VA_BASE) 1026895ce6dSAndrew Jones freemem_end = VA_BASE; 1036895ce6dSAndrew Jones assert(freemem_end - freemem_start >= SZ_1M * 16); 1046895ce6dSAndrew Jones 10523100d97SAndrew Jones init_alloc_vpage(__va(VA_TOP)); 10623100d97SAndrew Jones 1076895ce6dSAndrew Jones /* 1086895ce6dSAndrew Jones * TODO: Remove the need for this phys allocator dance, since, as we 1096895ce6dSAndrew Jones * can see with the assert, we could have gone straight to the page 1106895ce6dSAndrew Jones * allocator. 1116895ce6dSAndrew Jones */ 1126895ce6dSAndrew Jones phys_alloc_init(freemem_start, freemem_end - freemem_start); 1136895ce6dSAndrew Jones phys_alloc_set_minimum_alignment(PAGE_SIZE); 1146895ce6dSAndrew Jones phys_alloc_get_unused(&base, &top); 1156895ce6dSAndrew Jones assert(base == freemem_start && top == freemem_end); 1166895ce6dSAndrew Jones 1176895ce6dSAndrew Jones page_alloc_init_area(0, freemem_start >> PAGE_SHIFT, freemem_end >> PAGE_SHIFT); 1186895ce6dSAndrew Jones page_alloc_ops_enable(); 11922f287f4SAndrew Jones } 12022f287f4SAndrew Jones 121*31b4ef45SAndrew Jones static void mem_init(phys_addr_t freemem_start) 122*31b4ef45SAndrew Jones { 123*31b4ef45SAndrew Jones struct mem_region *freemem, *code, *data; 124*31b4ef45SAndrew Jones 125*31b4ef45SAndrew Jones memregions_init(riscv_mem_regions, NR_MEM_REGIONS); 126*31b4ef45SAndrew Jones memregions_add_dt_regions(MAX_DT_MEM_REGIONS); 127*31b4ef45SAndrew Jones 128*31b4ef45SAndrew Jones /* Split the region with the code into two regions; code and data */ 129*31b4ef45SAndrew Jones memregions_split((unsigned long)&_etext, &code, &data); 130*31b4ef45SAndrew Jones assert(code); 131*31b4ef45SAndrew Jones code->flags |= MR_F_CODE; 132*31b4ef45SAndrew Jones 133*31b4ef45SAndrew Jones freemem = memregions_find(freemem_start); 134*31b4ef45SAndrew Jones assert(freemem && !(freemem->flags & (MR_F_IO | MR_F_CODE))); 135*31b4ef45SAndrew Jones 136*31b4ef45SAndrew Jones mem_allocator_init(freemem_start, freemem->end); 137*31b4ef45SAndrew Jones } 138*31b4ef45SAndrew Jones 139*31b4ef45SAndrew Jones static void freemem_push_fdt(void **freemem, const void *fdt) 140*31b4ef45SAndrew Jones { 141*31b4ef45SAndrew Jones u32 fdt_size; 142*31b4ef45SAndrew Jones int ret; 143*31b4ef45SAndrew Jones 144*31b4ef45SAndrew Jones fdt_size = fdt_totalsize(fdt); 145*31b4ef45SAndrew Jones ret = fdt_move(fdt, *freemem, fdt_size); 146*31b4ef45SAndrew Jones assert(ret == 0); 147*31b4ef45SAndrew Jones ret = dt_init(*freemem); 148*31b4ef45SAndrew Jones assert(ret == 0); 149*31b4ef45SAndrew Jones *freemem += fdt_size; 150*31b4ef45SAndrew Jones } 151*31b4ef45SAndrew Jones 152*31b4ef45SAndrew Jones static void freemem_push_dt_initrd(void **freemem) 153*31b4ef45SAndrew Jones { 154*31b4ef45SAndrew Jones const char *tmp; 155*31b4ef45SAndrew Jones int ret; 156*31b4ef45SAndrew Jones 157*31b4ef45SAndrew Jones ret = dt_get_initrd(&tmp, &initrd_size); 158*31b4ef45SAndrew Jones assert(ret == 0 || ret == -FDT_ERR_NOTFOUND); 159*31b4ef45SAndrew Jones if (ret == 0) { 160*31b4ef45SAndrew Jones initrd = *freemem; 161*31b4ef45SAndrew Jones memmove(initrd, tmp, initrd_size); 162*31b4ef45SAndrew Jones *freemem += initrd_size; 163*31b4ef45SAndrew Jones } 164*31b4ef45SAndrew Jones } 165*31b4ef45SAndrew Jones 166*31b4ef45SAndrew Jones static void initrd_setup(void) 167*31b4ef45SAndrew Jones { 168*31b4ef45SAndrew Jones char *env; 169*31b4ef45SAndrew Jones 170*31b4ef45SAndrew Jones if (!initrd) 171*31b4ef45SAndrew Jones return; 172*31b4ef45SAndrew Jones 173*31b4ef45SAndrew Jones /* environ is currently the only file in the initrd */ 174*31b4ef45SAndrew Jones env = malloc(initrd_size); 175*31b4ef45SAndrew Jones memcpy(env, initrd, initrd_size); 176*31b4ef45SAndrew Jones setup_env(env, initrd_size); 177*31b4ef45SAndrew Jones } 178*31b4ef45SAndrew Jones 17922f287f4SAndrew Jones static void banner(void) 18022f287f4SAndrew Jones { 18122f287f4SAndrew Jones puts("\n"); 18222f287f4SAndrew Jones puts("##########################################################################\n"); 18322f287f4SAndrew Jones puts("# kvm-unit-tests\n"); 18422f287f4SAndrew Jones puts("##########################################################################\n"); 18522f287f4SAndrew Jones puts("\n"); 18622f287f4SAndrew Jones } 18722f287f4SAndrew Jones 188bd744d46SAndrew Jones void setup(const void *fdt, phys_addr_t freemem_start) 189bd744d46SAndrew Jones { 19022f287f4SAndrew Jones void *freemem; 191*31b4ef45SAndrew Jones const char *bootargs; 19222f287f4SAndrew Jones int ret; 19322f287f4SAndrew Jones 1946895ce6dSAndrew Jones assert(sizeof(long) == 8 || freemem_start < VA_BASE); 19523100d97SAndrew Jones freemem = __va(freemem_start); 19622f287f4SAndrew Jones 197*31b4ef45SAndrew Jones freemem_push_fdt(&freemem, fdt); 198*31b4ef45SAndrew Jones freemem_push_dt_initrd(&freemem); 19922f287f4SAndrew Jones 20023100d97SAndrew Jones mem_init(PAGE_ALIGN(__pa(freemem))); 20122f287f4SAndrew Jones cpu_init(); 202386561f8SAndrew Jones thread_info_init(); 20322f287f4SAndrew Jones io_init(); 20422f287f4SAndrew Jones 20522f287f4SAndrew Jones ret = dt_get_bootargs(&bootargs); 20622f287f4SAndrew Jones assert(ret == 0 || ret == -FDT_ERR_NOTFOUND); 20722f287f4SAndrew Jones setup_args_progname(bootargs); 20822f287f4SAndrew Jones 209*31b4ef45SAndrew Jones initrd_setup(); 21022f287f4SAndrew Jones 21123100d97SAndrew Jones if (!(auxinfo.flags & AUXINFO_MMU_OFF)) 21223100d97SAndrew Jones setup_vm(); 213ad435a71SAndrew Jones 21422f287f4SAndrew Jones banner(); 215bd744d46SAndrew Jones } 216