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