xref: /kvm-unit-tests/lib/powerpc/setup.c (revision 0c4e631ecaf30f8065dec5cc589d5894c961e6ee)
1 /*
2  * Initialize machine setup information and I/O.
3  *
4  * After running setup() unit tests may query how many cpus they have
5  * (nr_cpus), how much memory they have (PHYSICAL_END - PHYSICAL_START),
6  * may use dynamic memory allocation (malloc, etc.), printf, and exit.
7  * Finally, argc and argv are also ready to be passed to main().
8  *
9  * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
10  *
11  * This work is licensed under the terms of the GNU LGPL, version 2.
12  */
13 #include <libcflat.h>
14 #include <libfdt/libfdt.h>
15 #include <devicetree.h>
16 #include <alloc.h>
17 #include <asm/setup.h>
18 #include <asm/page.h>
19 
20 extern unsigned long stacktop;
21 extern void io_init(void);
22 extern void setup_args(const char *args);
23 
24 u32 cpus[NR_CPUS] = { [0 ... NR_CPUS-1] = (~0U) };
25 int nr_cpus;
26 
27 struct mem_region mem_regions[NR_MEM_REGIONS];
28 phys_addr_t __physical_start, __physical_end;
29 unsigned __icache_bytes, __dcache_bytes;
30 
31 struct cpu_set_params {
32 	unsigned icache_bytes;
33 	unsigned dcache_bytes;
34 };
35 
36 static void cpu_set(int fdtnode, u32 regval, void *info)
37 {
38 	static bool read_common_info = false;
39 	struct cpu_set_params *params = info;
40 	int cpu = nr_cpus++;
41 
42 	if (cpu >= NR_CPUS) {
43 		printf("Number cpus exceeds maximum supported (%d).\n",
44 			NR_CPUS);
45 		assert(0);
46 	}
47 	cpus[cpu] = regval;
48 
49 	if (!read_common_info) {
50 		const struct fdt_property *prop;
51 		u32 *data;
52 
53 		prop = fdt_get_property(dt_fdt(), fdtnode,
54 					"i-cache-line-size", NULL);
55 		assert(prop != NULL);
56 		data = (u32 *)prop->data;
57 		params->icache_bytes = fdt32_to_cpu(*data);
58 
59 		prop = fdt_get_property(dt_fdt(), fdtnode,
60 					"d-cache-line-size", NULL);
61 		assert(prop != NULL);
62 		data = (u32 *)prop->data;
63 		params->dcache_bytes = fdt32_to_cpu(*data);
64 
65 		read_common_info = true;
66 	}
67 }
68 
69 static void cpu_init(void)
70 {
71 	struct cpu_set_params params;
72 	int ret;
73 
74 	nr_cpus = 0;
75 	ret = dt_for_each_cpu_node(cpu_set, &params);
76 	assert(ret == 0);
77 	__icache_bytes = params.icache_bytes;
78 	__dcache_bytes = params.dcache_bytes;
79 }
80 
81 static void mem_init(phys_addr_t freemem_start)
82 {
83 	struct dt_pbus_reg regs[NR_MEM_REGIONS];
84 	struct mem_region primary, mem = {
85 		.start = (phys_addr_t)-1,
86 	};
87 	int nr_regs, i;
88 
89 	nr_regs = dt_get_memory_params(regs, NR_MEM_REGIONS);
90 	assert(nr_regs > 0);
91 
92 	primary.end = 0;
93 
94 	for (i = 0; i < nr_regs; ++i) {
95 		mem_regions[i].start = regs[i].addr;
96 		mem_regions[i].end = regs[i].addr + regs[i].size;
97 
98 		/*
99 		 * pick the region we're in for our primary region
100 		 */
101 		if (freemem_start >= mem_regions[i].start
102 				&& freemem_start < mem_regions[i].end) {
103 			mem_regions[i].flags |= MR_F_PRIMARY;
104 			primary = mem_regions[i];
105 		}
106 
107 		/*
108 		 * set the lowest and highest addresses found,
109 		 * ignoring potential gaps
110 		 */
111 		if (mem_regions[i].start < mem.start)
112 			mem.start = mem_regions[i].start;
113 		if (mem_regions[i].end > mem.end)
114 			mem.end = mem_regions[i].end;
115 	}
116 	assert(primary.end != 0);
117 //	assert(!(mem.start & ~PHYS_MASK) && !((mem.end - 1) & ~PHYS_MASK));
118 
119 	__physical_start = mem.start;	/* PHYSICAL_START */
120 	__physical_end = mem.end;	/* PHYSICAL_END */
121 
122 	phys_alloc_init(freemem_start, primary.end - freemem_start);
123 	phys_alloc_set_minimum_alignment(__icache_bytes > __dcache_bytes
124 					 ? __icache_bytes : __dcache_bytes);
125 }
126 
127 void setup(const void *fdt)
128 {
129 	const char *bootargs;
130 	u32 fdt_size;
131 	int ret;
132 
133 	/*
134 	 * Move the fdt to just above the stack. The free memory
135 	 * then starts just after the fdt.
136 	 */
137 	fdt_size = fdt_totalsize(fdt);
138 	ret = fdt_move(fdt, &stacktop, fdt_size);
139 	assert(ret == 0);
140 	ret = dt_init(&stacktop);
141 	assert(ret == 0);
142 
143 	cpu_init();
144 	mem_init(PAGE_ALIGN((unsigned long)&stacktop + fdt_size));
145 	io_init();
146 
147 	ret = dt_get_bootargs(&bootargs);
148 	assert(ret == 0);
149 	setup_args(bootargs);
150 }
151