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