xref: /haiku/src/system/boot/platform/u-boot/start.cpp (revision 81ec973846ea4816c53ed8901822e43c8b06878d)
1 /*
2  * Copyright 2003-2010, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "serial.h"
8 #include "console.h"
9 #include "cpu.h"
10 #include "mmu.h"
11 #include "smp.h"
12 #include "uimage.h"
13 #include "keyboard.h"
14 
15 #include <KernelExport.h>
16 #include <boot/platform.h>
17 #include <boot/heap.h>
18 #include <boot/stage2.h>
19 #include <arch/cpu.h>
20 #include <platform_arch.h>
21 #include <platform/openfirmware/openfirmware.h>
22 #include <board_config.h>
23 
24 #include <string.h>
25 
26 extern "C" {
27 #include <fdt.h>
28 #include <libfdt.h>
29 #include <libfdt_env.h>
30 };
31 
32 
33 #define HEAP_SIZE (128 * 1024)
34 
35 
36 typedef struct uboot_gd {
37 	// those are the only few members that we can trust
38 	// others depend on compile-time config
39 	struct board_data *bd;
40 	uint32 flags;
41 	uint32 baudrate;
42 	// those are ARM-only
43 	uint32 have_console;
44 	uint32 reloc_off;
45 	uint32 env_addr;
46 	uint32 env_valid;
47 	uint32 fb_base;
48 } uboot_gd;
49 
50 
51 // GCC defined globals
52 extern void (*__ctor_list)(void);
53 extern void (*__ctor_end)(void);
54 extern uint8 __bss_start, __bss_end;
55 extern uint8 _end;
56 
57 extern "C" int main(stage2_args *args);
58 extern "C" void _start(void);
59 extern "C" int start_gen(int argc, const char **argv,
60 	struct image_header *uimage=NULL, void *fdt=NULL);
61 extern "C" void dump_uimage(struct image_header *image);
62 extern "C" void dump_fdt(const void *fdt);
63 
64 // declared in shell.S
65 // those are initialized to NULL but not in the BSS
66 extern uboot_gd *gUBootGlobalData;
67 extern uint32 gUBootOS;
68 
69 struct image_header *gUImage;
70 void *gFDT;
71 
72 static uint32 sBootOptions;
73 
74 
75 static void
76 clear_bss(void)
77 {
78 	memset(&__bss_start, 0, &__bss_end - &__bss_start);
79 }
80 
81 
82 static void
83 call_ctors(void)
84 {
85 	void (**f)(void);
86 
87 	for (f = &__ctor_list; f < &__ctor_end; f++) {
88 		(**f)();
89 	}
90 }
91 
92 
93 extern "C" void
94 platform_start_kernel(void)
95 {
96 	preloaded_elf32_image *image = static_cast<preloaded_elf32_image *>(
97 		gKernelArgs.kernel_image.Pointer());
98 
99 	addr_t kernelEntry = image->elf_header.e_entry;
100 	addr_t stackTop
101 		= gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size;
102 
103 	// clone the Flattened Device Tree blob into the kernel args if we've got it
104 	if (gFDT) {
105 		size_t fdtSize = fdt_totalsize(gFDT);
106 		gKernelArgs.platform_args.fdt = kernel_args_malloc(fdtSize);
107 		memcpy(gKernelArgs.platform_args.fdt, gFDT, fdtSize);
108 	}
109 
110 //	smp_init_other_cpus();
111 	serial_cleanup();
112 	mmu_init_for_kernel();
113 //	smp_boot_other_cpus();
114 
115 	dprintf("kernel entry at %lx\n", kernelEntry);
116 
117 	status_t error = arch_start_kernel(&gKernelArgs, kernelEntry,
118 		stackTop);
119 
120 	panic("kernel returned %lx!\n", error);
121 }
122 
123 
124 extern "C" void
125 platform_exit(void)
126 {
127 }
128 
129 
130 extern "C" int
131 start_netbsd(struct board_info *bd, struct image_header *image,
132 	const char *consdev, const char *cmdline)
133 {
134 	const char *argv[] = { "haiku", cmdline };
135 	int argc = 1;
136 	if (cmdline && *cmdline)
137 		argc++;
138 	return start_gen(argc, argv, image);
139 }
140 
141 
142 extern "C" int
143 start_linux(int argc, int archnum, void *atags)
144 {
145 	// newer U-Boot pass the FDT in atags
146 	return start_gen(0, NULL, NULL, atags);
147 }
148 
149 
150 extern "C" int
151 start_linux_ppc_old(void */*board_info*/,
152 	void */*initrd_start*/, void */*initrd_end*/,
153 	const char */*cmdline_start*/, const char */*cmdline_end*/)
154 {
155 	return 1;
156 }
157 
158 
159 extern "C" int
160 start_linux_ppc_fdt(void *fdt, long/*UNUSED*/, long/*UNUSED*/,
161 	uint32 epapr_magic, uint32 initial_mem_size)
162 {
163 	return start_gen(0, NULL, NULL, fdt);
164 }
165 
166 
167 extern "C" int
168 start_raw(int argc, const char **argv)
169 {
170 	return start_gen(argc, argv);
171 }
172 
173 
174 extern "C" int
175 start_gen(int argc, const char **argv, struct image_header *uimage, void *fdt)
176 {
177 	stage2_args args;
178 
179 	clear_bss();
180 		// call C++ constructors before doing anything else
181 	call_ctors();
182 	args.heap_size = HEAP_SIZE;
183 	args.arguments = NULL;
184 	args.arguments_count = 0;
185 	args.platform.boot_tgz_data = NULL;
186 	args.platform.boot_tgz_size = 0;
187 	args.platform.fdt_data = NULL;
188 	args.platform.fdt_size = 0;
189 
190 	gUImage = uimage;
191 	gFDT = fdt;	//XXX: make a copy?
192 		// TODO: check for atags instead and convert them
193 
194 	if (argv) {
195 		// skip the kernel name
196 		++argv;
197 		--argc;
198 	}
199 	// TODO: Ensure cmdline is mapped into memory by MMU before usage.
200 
201 	// if we get passed a uimage, try to find the third blob
202 	// only if we do not have FDT data yet
203 	if (gUImage != NULL
204 		&& !gFDT
205 		&& image_multi_getimg(gUImage, 2,
206 			(uint32*)&args.platform.fdt_data,
207 			&args.platform.fdt_size)) {
208 		// found a blob, assume it is FDT data, when working on a platform
209 		// which does not have an FDT enabled U-Boot
210 		gFDT = args.platform.fdt_data;
211 	}
212 
213 	serial_init(gFDT);
214 	console_init();
215 	// initialize the OpenFirmware wrapper
216 	of_init(NULL);
217 
218 	cpu_init();
219 
220 	// if we get passed an FDT, check /chosen for initrd and bootargs
221 	if (gFDT != NULL) {
222 		int node = fdt_path_offset(gFDT, "/chosen");
223 		const void *prop;
224 		int len;
225 		phys_addr_t initrd_start = 0, initrd_end = 0;
226 
227 		if (node >= 0) {
228 			prop = fdt_getprop(gFDT, node, "linux,initrd-start", &len);
229 			if (prop && len == 4)
230 				initrd_start = fdt32_to_cpu(*(uint32_t *)prop);
231 			prop = fdt_getprop(gFDT, node, "linux,initrd-end", &len);
232 			if (prop && len == 4)
233 				initrd_end = fdt32_to_cpu(*(uint32_t *)prop);
234 			if (initrd_end > initrd_start) {
235 				args.platform.boot_tgz_data = (void *)initrd_start;
236 				args.platform.boot_tgz_size = initrd_end - initrd_start;
237 				dprintf("Found boot tgz from FDT @ %p, %" B_PRIu32 " bytes\n",
238 					args.platform.boot_tgz_data, args.platform.boot_tgz_size);
239 			}
240 			// we check for bootargs after remapping the FDT
241 		}
242 	}
243 
244 	// if we get passed a uimage, try to find the second blob
245 	if (gUImage != NULL
246 		&& image_multi_getimg(gUImage, 1,
247 			(uint32*)&args.platform.boot_tgz_data,
248 			&args.platform.boot_tgz_size)) {
249 		dprintf("Found boot tgz from uimage @ %p, %" B_PRIu32 " bytes\n",
250 			args.platform.boot_tgz_data, args.platform.boot_tgz_size);
251 	}
252 
253 	{ //DEBUG:
254 		int i;
255 		dprintf("argc = %d\n", argc);
256 		for (i = 0; i < argc; i++)
257 			dprintf("argv[%d] @%lx = '%s'\n", i, (uint32)argv[i], argv[i]);
258 		dprintf("os: %d\n", (int)gUBootOS);
259 		dprintf("gd @ %p\n", gUBootGlobalData);
260 		if (gUBootGlobalData)
261 			dprintf("gd->bd @ %p\n", gUBootGlobalData->bd);
262 		//dprintf("fb_base %p\n", (void*)gUBootGlobalData->fb_base);
263 		if (gUImage)
264 			dump_uimage(gUImage);
265 		if (gFDT)
266 			dump_fdt(gFDT);
267 	}
268 
269 	if (args.platform.boot_tgz_size > 0) {
270 		insert_physical_allocated_range((addr_t)args.platform.boot_tgz_data,
271 			args.platform.boot_tgz_size);
272 	}
273 
274 	// save the size of the FDT so we can map it easily after mmu_init
275 	size_t fdtSize = gFDT ? fdt_totalsize(gFDT) : 0;
276 
277 	mmu_init();
278 
279 	// Handle our tarFS post-mmu
280 	if (args.platform.boot_tgz_size > 0) {
281 		args.platform.boot_tgz_data = (void*)mmu_map_physical_memory((addr_t)
282 			args.platform.boot_tgz_data, args.platform.boot_tgz_size,
283 			kDefaultPageFlags);
284 	}
285 	// .. and our FDT
286 	if (gFDT != NULL)
287 		gFDT = (void*)mmu_map_physical_memory((addr_t)gFDT, fdtSize, kDefaultPageFlags);
288 
289 	// if we get passed an FDT, check /chosen for bootargs now
290 	// to avoid having to copy them.
291 	if (gFDT != NULL) {
292 		int node = fdt_path_offset(gFDT, "/chosen");
293 		const void *prop;
294 		int len;
295 
296 		if (node >= 0) {
297 			prop = fdt_getprop(gFDT, node, "bootargs", &len);
298 			if (prop) {
299 				dprintf("Found bootargs: %s\n", (const char *)prop);
300 				static const char *sArgs[] = { NULL, NULL };
301 				sArgs[0] = (const char *)prop;
302 				// override main() args
303 				args.arguments = sArgs;
304 				args.arguments_count = 1;
305 			}
306 		}
307 		dprintf("args.arguments_count = %d\n", args.arguments_count);
308 		for (int i = 0; i < args.arguments_count; i++)
309 			dprintf("args.arguments[%d] @%lx = '%s'\n", i,
310 				(uint32)args.arguments[i], args.arguments[i]);
311 	}
312 
313 	// wait a bit to give the user the opportunity to press a key
314 //	spin(750000);
315 
316 	// reading the keyboard doesn't seem to work in graphics mode
317 	// (maybe a bochs problem)
318 //	sBootOptions = check_for_boot_keys();
319 	//if (sBootOptions & BOOT_OPTION_DEBUG_OUTPUT)
320 		serial_enable();
321 
322 	main(&args);
323 	return 0;
324 }
325 
326 
327 extern "C" uint32
328 platform_boot_options(void)
329 {
330 	return sBootOptions;
331 }
332