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