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> 9*6895ce6dSAndrew Jones #include <alloc_page.h> 1022f287f4SAndrew Jones #include <alloc_phys.h> 1122f287f4SAndrew Jones #include <argv.h> 1222f287f4SAndrew Jones #include <cpumask.h> 1322f287f4SAndrew Jones #include <devicetree.h> 14*6895ce6dSAndrew Jones #include <memregions.h> 159c92b28eSAndrew Jones #include <on-cpus.h> 1622f287f4SAndrew Jones #include <asm/csr.h> 1722f287f4SAndrew Jones #include <asm/page.h> 18386561f8SAndrew Jones #include <asm/processor.h> 19bd744d46SAndrew Jones #include <asm/setup.h> 20bd744d46SAndrew Jones 21*6895ce6dSAndrew Jones #define VA_BASE ((phys_addr_t)3 * SZ_1G) 22*6895ce6dSAndrew Jones 23*6895ce6dSAndrew Jones #define MAX_DT_MEM_REGIONS 16 24*6895ce6dSAndrew Jones #define NR_MEM_REGIONS (MAX_DT_MEM_REGIONS + 16) 25*6895ce6dSAndrew Jones 2622f287f4SAndrew Jones char *initrd; 2722f287f4SAndrew Jones u32 initrd_size; 2822f287f4SAndrew Jones 29386561f8SAndrew Jones struct thread_info cpus[NR_CPUS]; 3022f287f4SAndrew Jones int nr_cpus; 3122f287f4SAndrew Jones 32*6895ce6dSAndrew Jones static struct mem_region riscv_mem_regions[NR_MEM_REGIONS + 1]; 33*6895ce6dSAndrew Jones 3422f287f4SAndrew Jones int hartid_to_cpu(unsigned long hartid) 3522f287f4SAndrew Jones { 3622f287f4SAndrew Jones int cpu; 3722f287f4SAndrew Jones 3822f287f4SAndrew Jones for_each_present_cpu(cpu) 39386561f8SAndrew Jones if (cpus[cpu].hartid == hartid) 4022f287f4SAndrew Jones return cpu; 4122f287f4SAndrew Jones return -1; 4222f287f4SAndrew Jones } 4322f287f4SAndrew Jones 4422f287f4SAndrew Jones static void cpu_set_fdt(int fdtnode __unused, u64 regval, void *info __unused) 4522f287f4SAndrew Jones { 4622f287f4SAndrew Jones int cpu = nr_cpus++; 4722f287f4SAndrew Jones 4822f287f4SAndrew Jones assert_msg(cpu < NR_CPUS, "Number cpus exceeds maximum supported (%d).", NR_CPUS); 4922f287f4SAndrew Jones 50386561f8SAndrew Jones cpus[cpu].cpu = cpu; 51386561f8SAndrew Jones cpus[cpu].hartid = regval; 5222f287f4SAndrew Jones set_cpu_present(cpu, true); 5322f287f4SAndrew Jones } 5422f287f4SAndrew Jones 5522f287f4SAndrew Jones static void cpu_init_acpi(void) 5622f287f4SAndrew Jones { 5722f287f4SAndrew Jones assert_msg(false, "ACPI not available"); 5822f287f4SAndrew Jones } 5922f287f4SAndrew Jones 6022f287f4SAndrew Jones static void cpu_init(void) 6122f287f4SAndrew Jones { 6222f287f4SAndrew Jones int ret; 6322f287f4SAndrew Jones 6422f287f4SAndrew Jones nr_cpus = 0; 6522f287f4SAndrew Jones if (dt_available()) { 6622f287f4SAndrew Jones ret = dt_for_each_cpu_node(cpu_set_fdt, NULL); 6722f287f4SAndrew Jones assert(ret == 0); 6822f287f4SAndrew Jones } else { 6922f287f4SAndrew Jones cpu_init_acpi(); 7022f287f4SAndrew Jones } 7122f287f4SAndrew Jones 7222f287f4SAndrew Jones set_cpu_online(hartid_to_cpu(csr_read(CSR_SSCRATCH)), true); 739c92b28eSAndrew Jones cpu0_calls_idle = true; 7422f287f4SAndrew Jones } 7522f287f4SAndrew Jones 76*6895ce6dSAndrew Jones extern unsigned long _etext; 77*6895ce6dSAndrew Jones 7822f287f4SAndrew Jones static void mem_init(phys_addr_t freemem_start) 7922f287f4SAndrew Jones { 80*6895ce6dSAndrew Jones struct mem_region *freemem, *code, *data; 81*6895ce6dSAndrew Jones phys_addr_t freemem_end, base, top; 82*6895ce6dSAndrew Jones 83*6895ce6dSAndrew Jones memregions_init(riscv_mem_regions, NR_MEM_REGIONS); 84*6895ce6dSAndrew Jones memregions_add_dt_regions(MAX_DT_MEM_REGIONS); 85*6895ce6dSAndrew Jones 86*6895ce6dSAndrew Jones /* Split the region with the code into two regions; code and data */ 87*6895ce6dSAndrew Jones memregions_split((unsigned long)&_etext, &code, &data); 88*6895ce6dSAndrew Jones assert(code); 89*6895ce6dSAndrew Jones code->flags |= MR_F_CODE; 90*6895ce6dSAndrew Jones 91*6895ce6dSAndrew Jones freemem = memregions_find(freemem_start); 92*6895ce6dSAndrew Jones assert(freemem && !(freemem->flags & (MR_F_IO | MR_F_CODE))); 93*6895ce6dSAndrew Jones 94*6895ce6dSAndrew Jones freemem_end = freemem->end & PAGE_MASK; 95*6895ce6dSAndrew Jones 96*6895ce6dSAndrew Jones /* 97*6895ce6dSAndrew Jones * The assert below is mostly checking that the free memory doesn't 98*6895ce6dSAndrew Jones * start in the 3G-4G range, which is reserved for virtual addresses, 99*6895ce6dSAndrew Jones * but it also confirms that there is some free memory (the amount 100*6895ce6dSAndrew Jones * is arbitrarily selected, but should be sufficient for a unit test) 101*6895ce6dSAndrew Jones * 102*6895ce6dSAndrew Jones * TODO: Allow the VA range to shrink and move. 103*6895ce6dSAndrew Jones */ 104*6895ce6dSAndrew Jones if (freemem_end > VA_BASE) 105*6895ce6dSAndrew Jones freemem_end = VA_BASE; 106*6895ce6dSAndrew Jones assert(freemem_end - freemem_start >= SZ_1M * 16); 107*6895ce6dSAndrew Jones 108*6895ce6dSAndrew Jones /* 109*6895ce6dSAndrew Jones * TODO: Remove the need for this phys allocator dance, since, as we 110*6895ce6dSAndrew Jones * can see with the assert, we could have gone straight to the page 111*6895ce6dSAndrew Jones * allocator. 112*6895ce6dSAndrew Jones */ 113*6895ce6dSAndrew Jones phys_alloc_init(freemem_start, freemem_end - freemem_start); 114*6895ce6dSAndrew Jones phys_alloc_set_minimum_alignment(PAGE_SIZE); 115*6895ce6dSAndrew Jones phys_alloc_get_unused(&base, &top); 116*6895ce6dSAndrew Jones assert(base == freemem_start && top == freemem_end); 117*6895ce6dSAndrew Jones 118*6895ce6dSAndrew Jones page_alloc_init_area(0, freemem_start >> PAGE_SHIFT, freemem_end >> PAGE_SHIFT); 119*6895ce6dSAndrew Jones page_alloc_ops_enable(); 12022f287f4SAndrew Jones } 12122f287f4SAndrew Jones 12222f287f4SAndrew Jones static void banner(void) 12322f287f4SAndrew Jones { 12422f287f4SAndrew Jones puts("\n"); 12522f287f4SAndrew Jones puts("##########################################################################\n"); 12622f287f4SAndrew Jones puts("# kvm-unit-tests\n"); 12722f287f4SAndrew Jones puts("##########################################################################\n"); 12822f287f4SAndrew Jones puts("\n"); 12922f287f4SAndrew Jones } 13022f287f4SAndrew Jones 131bd744d46SAndrew Jones void setup(const void *fdt, phys_addr_t freemem_start) 132bd744d46SAndrew Jones { 13322f287f4SAndrew Jones void *freemem; 13422f287f4SAndrew Jones const char *bootargs, *tmp; 13522f287f4SAndrew Jones u32 fdt_size; 13622f287f4SAndrew Jones int ret; 13722f287f4SAndrew Jones 138*6895ce6dSAndrew Jones assert(sizeof(long) == 8 || freemem_start < VA_BASE); 13922f287f4SAndrew Jones freemem = (void *)(unsigned long)freemem_start; 14022f287f4SAndrew Jones 14122f287f4SAndrew Jones /* Move the FDT to the base of free memory */ 14222f287f4SAndrew Jones fdt_size = fdt_totalsize(fdt); 14322f287f4SAndrew Jones ret = fdt_move(fdt, freemem, fdt_size); 14422f287f4SAndrew Jones assert(ret == 0); 14522f287f4SAndrew Jones ret = dt_init(freemem); 14622f287f4SAndrew Jones assert(ret == 0); 14722f287f4SAndrew Jones freemem += fdt_size; 14822f287f4SAndrew Jones 14922f287f4SAndrew Jones /* Move the initrd to the top of the FDT */ 15022f287f4SAndrew Jones ret = dt_get_initrd(&tmp, &initrd_size); 15122f287f4SAndrew Jones assert(ret == 0 || ret == -FDT_ERR_NOTFOUND); 15222f287f4SAndrew Jones if (ret == 0) { 15322f287f4SAndrew Jones initrd = freemem; 15422f287f4SAndrew Jones memmove(initrd, tmp, initrd_size); 15522f287f4SAndrew Jones freemem += initrd_size; 15622f287f4SAndrew Jones } 15722f287f4SAndrew Jones 15822f287f4SAndrew Jones mem_init(PAGE_ALIGN((unsigned long)freemem)); 15922f287f4SAndrew Jones cpu_init(); 160386561f8SAndrew Jones thread_info_init(); 16122f287f4SAndrew Jones io_init(); 16222f287f4SAndrew Jones 16322f287f4SAndrew Jones ret = dt_get_bootargs(&bootargs); 16422f287f4SAndrew Jones assert(ret == 0 || ret == -FDT_ERR_NOTFOUND); 16522f287f4SAndrew Jones setup_args_progname(bootargs); 16622f287f4SAndrew Jones 16722f287f4SAndrew Jones if (initrd) { 16822f287f4SAndrew Jones /* environ is currently the only file in the initrd */ 16922f287f4SAndrew Jones char *env = malloc(initrd_size); 17022f287f4SAndrew Jones memcpy(env, initrd, initrd_size); 17122f287f4SAndrew Jones setup_env(env, initrd_size); 17222f287f4SAndrew Jones } 17322f287f4SAndrew Jones 17422f287f4SAndrew Jones banner(); 175bd744d46SAndrew Jones } 176