xref: /kvm-unit-tests/lib/arm/setup.c (revision d9729025989690ae4e02c6b84eac881849dd186a)
15e61cba0SAndrew Jones /*
25e61cba0SAndrew Jones  * Initialize machine setup information and I/O.
35e61cba0SAndrew Jones  *
45e61cba0SAndrew Jones  * After running setup() unit tests may query how many cpus they have
55e61cba0SAndrew Jones  * (nr_cpus), how much memory they have (PHYS_END - PHYS_OFFSET), may
65e61cba0SAndrew Jones  * use dynamic memory allocation (malloc, etc.), printf, and exit.
75e61cba0SAndrew Jones  * Finally, argc and argv are also ready to be passed to main().
85e61cba0SAndrew Jones  *
95e61cba0SAndrew Jones  * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com>
105e61cba0SAndrew Jones  *
115e61cba0SAndrew Jones  * This work is licensed under the terms of the GNU LGPL, version 2.
125e61cba0SAndrew Jones  */
138cca5668SAndrew Jones #include <libcflat.h>
148cca5668SAndrew Jones #include <libfdt/libfdt.h>
158cca5668SAndrew Jones #include <devicetree.h>
168cca5668SAndrew Jones #include <alloc.h>
17f6d10793SAndrew Jones #include <asm/thread_info.h>
188cca5668SAndrew Jones #include <asm/setup.h>
198cca5668SAndrew Jones #include <asm/page.h>
208cca5668SAndrew Jones #include <asm/mmu.h>
2168ea0e0bSAndrew Jones #include <asm/smp.h>
225e61cba0SAndrew Jones 
235e61cba0SAndrew Jones extern unsigned long stacktop;
245e61cba0SAndrew Jones extern void io_init(void);
25809ebcb3SAndrew Jones extern void setup_args_progname(const char *args);
265e61cba0SAndrew Jones 
278d83d5e7SAndrew Jones u32 cpus[NR_CPUS] = { [0 ... NR_CPUS-1] = (~0U) };
285e61cba0SAndrew Jones int nr_cpus;
295e61cba0SAndrew Jones 
3062de081aSAndrew Jones struct mem_region mem_regions[NR_MEM_REGIONS];
315e61cba0SAndrew Jones phys_addr_t __phys_offset, __phys_end;
325e61cba0SAndrew Jones 
33*d9729025SAndrew Jones int mpidr_to_cpu(uint64_t mpidr)
34*d9729025SAndrew Jones {
35*d9729025SAndrew Jones 	int i;
36*d9729025SAndrew Jones 
37*d9729025SAndrew Jones 	for (i = 0; i < nr_cpus; ++i)
38*d9729025SAndrew Jones 		if (cpus[i] == (mpidr & MPIDR_HWID_BITMASK))
39*d9729025SAndrew Jones 			return i;
40*d9729025SAndrew Jones 	return -1;
41*d9729025SAndrew Jones }
42*d9729025SAndrew Jones 
435e61cba0SAndrew Jones static void cpu_set(int fdtnode __unused, u32 regval, void *info __unused)
445e61cba0SAndrew Jones {
4568ea0e0bSAndrew Jones 	int cpu = nr_cpus++;
4662de081aSAndrew Jones 
4762de081aSAndrew Jones 	if (cpu >= NR_CPUS) {
4862de081aSAndrew Jones 		printf("Number cpus exceeds maximum supported (%d).\n",
4962de081aSAndrew Jones 			NR_CPUS);
5062de081aSAndrew Jones 		assert(0);
5162de081aSAndrew Jones 	}
5268ea0e0bSAndrew Jones 	cpus[cpu] = regval;
5368ea0e0bSAndrew Jones 	set_cpu_present(cpu, true);
545e61cba0SAndrew Jones }
555e61cba0SAndrew Jones 
565e61cba0SAndrew Jones static void cpu_init(void)
575e61cba0SAndrew Jones {
5818ab6cadSAndrew Jones 	int ret;
5918ab6cadSAndrew Jones 
605e61cba0SAndrew Jones 	nr_cpus = 0;
6118ab6cadSAndrew Jones 	ret = dt_for_each_cpu_node(cpu_set, NULL);
6218ab6cadSAndrew Jones 	assert(ret == 0);
6368ea0e0bSAndrew Jones 	set_cpu_online(0, true);
645e61cba0SAndrew Jones }
655e61cba0SAndrew Jones 
665e61cba0SAndrew Jones static void mem_init(phys_addr_t freemem_start)
675e61cba0SAndrew Jones {
6862de081aSAndrew Jones 	struct dt_pbus_reg regs[NR_MEM_REGIONS];
6962de081aSAndrew Jones 	struct mem_region primary, mem = {
7062de081aSAndrew Jones 		.start = (phys_addr_t)-1,
7162de081aSAndrew Jones 	};
7262de081aSAndrew Jones 	int nr_regs, i;
735e61cba0SAndrew Jones 
7462de081aSAndrew Jones 	nr_regs = dt_get_memory_params(regs, NR_MEM_REGIONS);
7562de081aSAndrew Jones 	assert(nr_regs > 0);
765e61cba0SAndrew Jones 
7762de081aSAndrew Jones 	primary.end = 0;
785e61cba0SAndrew Jones 
7962de081aSAndrew Jones 	for (i = 0; i < nr_regs; ++i) {
8062de081aSAndrew Jones 		mem_regions[i].start = regs[i].addr;
8162de081aSAndrew Jones 		mem_regions[i].end = regs[i].addr + regs[i].size;
825e61cba0SAndrew Jones 
8362de081aSAndrew Jones 		/*
8462de081aSAndrew Jones 		 * pick the region we're in for our primary region
8562de081aSAndrew Jones 		 */
8662de081aSAndrew Jones 		if (freemem_start >= mem_regions[i].start
8762de081aSAndrew Jones 				&& freemem_start < mem_regions[i].end) {
8862de081aSAndrew Jones 			mem_regions[i].flags |= MR_F_PRIMARY;
8962de081aSAndrew Jones 			primary = mem_regions[i];
9062de081aSAndrew Jones 		}
915e61cba0SAndrew Jones 
9262de081aSAndrew Jones 		/*
9362de081aSAndrew Jones 		 * set the lowest and highest addresses found,
9462de081aSAndrew Jones 		 * ignoring potential gaps
9562de081aSAndrew Jones 		 */
9662de081aSAndrew Jones 		if (mem_regions[i].start < mem.start)
9762de081aSAndrew Jones 			mem.start = mem_regions[i].start;
9862de081aSAndrew Jones 		if (mem_regions[i].end > mem.end)
9962de081aSAndrew Jones 			mem.end = mem_regions[i].end;
10062de081aSAndrew Jones 	}
10162de081aSAndrew Jones 	assert(primary.end != 0);
10262de081aSAndrew Jones 	assert(!(mem.start & ~PHYS_MASK) && !((mem.end - 1) & ~PHYS_MASK));
10362de081aSAndrew Jones 
10462de081aSAndrew Jones 	__phys_offset = mem.start;	/* PHYS_OFFSET */
10562de081aSAndrew Jones 	__phys_end = mem.end;		/* PHYS_END */
10662de081aSAndrew Jones 
10762de081aSAndrew Jones 	phys_alloc_init(freemem_start, primary.end - freemem_start);
1085e61cba0SAndrew Jones 	phys_alloc_set_minimum_alignment(SMP_CACHE_BYTES);
109153d1936SAndrew Jones 
110153d1936SAndrew Jones 	mmu_enable_idmap();
1115e61cba0SAndrew Jones }
1125e61cba0SAndrew Jones 
113dd4af6b1SAndrew Jones void setup(const void *fdt)
1145e61cba0SAndrew Jones {
1155e61cba0SAndrew Jones 	const char *bootargs;
1165e61cba0SAndrew Jones 	u32 fdt_size;
11718ab6cadSAndrew Jones 	int ret;
1185e61cba0SAndrew Jones 
1195e61cba0SAndrew Jones 	/*
1205e61cba0SAndrew Jones 	 * Move the fdt to just above the stack. The free memory
1215e61cba0SAndrew Jones 	 * then starts just after the fdt.
1225e61cba0SAndrew Jones 	 */
1235e61cba0SAndrew Jones 	fdt_size = fdt_totalsize(fdt);
12418ab6cadSAndrew Jones 	ret = fdt_move(fdt, &stacktop, fdt_size);
12518ab6cadSAndrew Jones 	assert(ret == 0);
12618ab6cadSAndrew Jones 	ret = dt_init(&stacktop);
12718ab6cadSAndrew Jones 	assert(ret == 0);
1285e61cba0SAndrew Jones 
1295e61cba0SAndrew Jones 	mem_init(PAGE_ALIGN((unsigned long)&stacktop + fdt_size));
1305e61cba0SAndrew Jones 	io_init();
1315e61cba0SAndrew Jones 	cpu_init();
1325e61cba0SAndrew Jones 
133f6d10793SAndrew Jones 	thread_info_init(current_thread_info(), 0);
134f6d10793SAndrew Jones 
13518ab6cadSAndrew Jones 	ret = dt_get_bootargs(&bootargs);
13618ab6cadSAndrew Jones 	assert(ret == 0);
137809ebcb3SAndrew Jones 	setup_args_progname(bootargs);
1385e61cba0SAndrew Jones }
139