xref: /kvm-unit-tests/lib/riscv/setup.c (revision 2479ae507a7e89903c067d89b476bb27e48875fe)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Initialize machine setup information and I/O.
4  *
5  * Copyright (C) 2023, Ventana Micro Systems Inc., Andrew Jones <ajones@ventanamicro.com>
6  */
7 #include <libcflat.h>
8 #include <alloc.h>
9 #include <alloc_phys.h>
10 #include <argv.h>
11 #include <cpumask.h>
12 #include <devicetree.h>
13 #include <on-cpus.h>
14 #include <asm/csr.h>
15 #include <asm/page.h>
16 #include <asm/processor.h>
17 #include <asm/setup.h>
18 
19 char *initrd;
20 u32 initrd_size;
21 
22 struct thread_info cpus[NR_CPUS];
23 int nr_cpus;
24 
25 int hartid_to_cpu(unsigned long hartid)
26 {
27 	int cpu;
28 
29 	for_each_present_cpu(cpu)
30 		if (cpus[cpu].hartid == hartid)
31 			return cpu;
32 	return -1;
33 }
34 
35 static void cpu_set_fdt(int fdtnode __unused, u64 regval, void *info __unused)
36 {
37 	int cpu = nr_cpus++;
38 
39 	assert_msg(cpu < NR_CPUS, "Number cpus exceeds maximum supported (%d).", NR_CPUS);
40 
41 	cpus[cpu].cpu = cpu;
42 	cpus[cpu].hartid = regval;
43 	set_cpu_present(cpu, true);
44 }
45 
46 static void cpu_init_acpi(void)
47 {
48 	assert_msg(false, "ACPI not available");
49 }
50 
51 static void cpu_init(void)
52 {
53 	int ret;
54 
55 	nr_cpus = 0;
56 	if (dt_available()) {
57 		ret = dt_for_each_cpu_node(cpu_set_fdt, NULL);
58 		assert(ret == 0);
59 	} else {
60 		cpu_init_acpi();
61 	}
62 
63 	set_cpu_online(hartid_to_cpu(csr_read(CSR_SSCRATCH)), true);
64 	cpu0_calls_idle = true;
65 }
66 
67 static void mem_init(phys_addr_t freemem_start)
68 {
69 	//TODO - for now just assume we've got some memory available
70 	phys_alloc_init(freemem_start, 16 * SZ_1M);
71 }
72 
73 static void banner(void)
74 {
75 	puts("\n");
76 	puts("##########################################################################\n");
77 	puts("#    kvm-unit-tests\n");
78 	puts("##########################################################################\n");
79 	puts("\n");
80 }
81 
82 void setup(const void *fdt, phys_addr_t freemem_start)
83 {
84 	void *freemem;
85 	const char *bootargs, *tmp;
86 	u32 fdt_size;
87 	int ret;
88 
89 	assert(sizeof(long) == 8 || freemem_start < (3ul << 30));
90 	freemem = (void *)(unsigned long)freemem_start;
91 
92 	/* Move the FDT to the base of free memory */
93 	fdt_size = fdt_totalsize(fdt);
94 	ret = fdt_move(fdt, freemem, fdt_size);
95 	assert(ret == 0);
96 	ret = dt_init(freemem);
97 	assert(ret == 0);
98 	freemem += fdt_size;
99 
100 	/* Move the initrd to the top of the FDT */
101 	ret = dt_get_initrd(&tmp, &initrd_size);
102 	assert(ret == 0 || ret == -FDT_ERR_NOTFOUND);
103 	if (ret == 0) {
104 		initrd = freemem;
105 		memmove(initrd, tmp, initrd_size);
106 		freemem += initrd_size;
107 	}
108 
109 	mem_init(PAGE_ALIGN((unsigned long)freemem));
110 	cpu_init();
111 	thread_info_init();
112 	io_init();
113 
114 	ret = dt_get_bootargs(&bootargs);
115 	assert(ret == 0 || ret == -FDT_ERR_NOTFOUND);
116 	setup_args_progname(bootargs);
117 
118 	if (initrd) {
119 		/* environ is currently the only file in the initrd */
120 		char *env = malloc(initrd_size);
121 		memcpy(env, initrd, initrd_size);
122 		setup_env(env, initrd_size);
123 	}
124 
125 	banner();
126 }
127