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