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