xref: /haiku/src/system/boot/platform/u-boot/start.cpp (revision 37fedaf8494b34aad811abcc49e79aa32943f880)
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 "mmu.h"
11 #include "smp.h"
12 #include "uimage.h"
13 #include "keyboard.h"
14 
15 #include <KernelExport.h>
16 #include <boot/platform.h>
17 #include <boot/heap.h>
18 #include <boot/stage2.h>
19 #include <arch/cpu.h>
20 #include <platform_arch.h>
21 #include <platform/openfirmware/openfirmware.h>
22 
23 #include <string.h>
24 
25 extern "C" {
26 #include <fdt.h>
27 #include <libfdt.h>
28 #include <libfdt_env.h>
29 };
30 
31 
32 #define HEAP_SIZE (128 * 1024)
33 
34 
35 typedef struct uboot_gd {
36 	// those are the only few members that we can trust
37 	// others depend on compile-time config
38 	struct board_data *bd;
39 	uint32 flags;
40 	uint32 baudrate;
41 	// those are ARM-only
42 	uint32 have_console;
43 	uint32 reloc_off;
44 	uint32 env_addr;
45 	uint32 env_valid;
46 	uint32 fb_base;
47 } uboot_gd;
48 
49 
50 // GCC defined globals
51 extern void (*__ctor_list)(void);
52 extern void (*__ctor_end)(void);
53 extern uint8 __bss_start;
54 extern uint8 _end;
55 
56 extern "C" int main(stage2_args *args);
57 extern "C" void _start(void);
58 extern "C" int start_raw(int argc, const char **argv);
59 extern "C" void dump_uimage(struct image_header *image);
60 extern "C" void dump_fdt(const void *fdt);
61 
62 // declared in shell.S
63 // those are initialized to NULL but not in the BSS
64 extern struct image_header *gUImage;
65 extern uboot_gd *gUBootGlobalData;
66 extern uint32 gUBootOS;
67 extern void *gFDT;
68 
69 static uint32 sBootOptions;
70 
71 
72 static void
73 clear_bss(void)
74 {
75 	memset(&__bss_start, 0, &_end - &__bss_start);
76 }
77 
78 
79 static void
80 call_ctors(void)
81 {
82 	void (**f)(void);
83 
84 	for (f = &__ctor_list; f < &__ctor_end; f++) {
85 		(**f)();
86 	}
87 }
88 
89 
90 /* needed for libgcc unwind XXX */
91 extern "C" void
92 abort(void)
93 {
94 	panic("abort");
95 }
96 
97 
98 extern "C" void
99 platform_start_kernel(void)
100 {
101 	preloaded_elf32_image *image = static_cast<preloaded_elf32_image *>(
102 		gKernelArgs.kernel_image.Pointer());
103 
104 	addr_t kernelEntry = image->elf_header.e_entry;
105 	addr_t stackTop
106 		= gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size;
107 
108 	if (gFDT) {
109 		// clone the Flattened Device Tree blob
110 		gKernelArgs.platform_args.fdt = kernel_args_malloc(fdt_totalsize(gFDT));
111 		memcpy(gKernelArgs.platform_args.fdt, gFDT, fdt_totalsize(gFDT));
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)
141 		argc++;
142 	gUImage = image;
143 	return start_raw(argc, argv);
144 }
145 
146 
147 extern "C" int
148 start_linux(int argc, int archnum, void *atags)
149 {
150 	return 1;
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 	gFDT = fdt;	//XXX: make a copy?
168 	return start_raw(0, NULL);
169 }
170 
171 
172 extern "C" int
173 start_raw(int argc, const char **argv)
174 {
175 	stage2_args args;
176 
177 	clear_bss();
178 		// call C++ constructors before doing anything else
179 	call_ctors();
180 	args.heap_size = HEAP_SIZE;
181 	args.arguments = NULL;
182 	args.platform.boot_tgz_data = NULL;
183 	args.platform.boot_tgz_size = 0;
184 	args.platform.fdt_data = NULL;
185 	args.platform.fdt_size = 0;
186 
187 	if (argv) {
188 		// skip the kernel name
189 		args.arguments = ++argv;
190 		args.arguments_count = --argc;
191 	}
192 
193 	// if we get passed a uimage, try to find the third blob
194 	// only if we do not have FDT data yet
195 	if (gUImage != NULL
196 		&& !gFDT
197 		&& image_multi_getimg(gUImage, 2,
198 			(uint32*)&args.platform.fdt_data,
199 			&args.platform.fdt_size)) {
200 		// found a blob, assume it is FDT data, when working on a platform
201 		// which does not have an FDT enabled U-Boot
202 		gFDT = args.platform.fdt_data;
203 	}
204 
205 	serial_init(gFDT);
206 	console_init();
207 	// initialize the OpenFirmware wrapper
208 	of_init(NULL);
209 
210 	cpu_init();
211 
212 	if (args.platform.fdt_data) {
213 		dprintf("Found FDT from uimage @ %p, %" B_PRIu32 " bytes\n",
214 			args.platform.fdt_data, args.platform.fdt_size);
215 	} else if (gFDT) {
216 		/* Fixup args so we can pass the gFDT on to the kernel */
217 		args.platform.fdt_data = gFDT;
218 		args.platform.fdt_size = fdt_totalsize(gFDT);
219 	}
220 
221 	// if we get passed an FDT, check /chosen for initrd and bootargs
222 	if (gFDT != NULL) {
223 		int node = fdt_path_offset(gFDT, "/chosen");
224 		const void *prop;
225 		int len;
226 		phys_addr_t initrd_start = 0, initrd_end = 0;
227 
228 		if (node >= 0) {
229 			prop = fdt_getprop(gFDT, node, "linux,initrd-start", &len);
230 			if (prop && len == 4)
231 				initrd_start = fdt32_to_cpu(*(uint32_t *)prop);
232 			prop = fdt_getprop(gFDT, node, "linux,initrd-end", &len);
233 			if (prop && len == 4)
234 				initrd_end = fdt32_to_cpu(*(uint32_t *)prop);
235 			if (initrd_end > initrd_start) {
236 				args.platform.boot_tgz_data = (void *)initrd_start;
237 				args.platform.boot_tgz_size = initrd_end - initrd_start;
238 				dprintf("Found boot tgz from FDT @ %p, %" B_PRIu32 " bytes\n",
239 					args.platform.boot_tgz_data, args.platform.boot_tgz_size);
240 			}
241 			prop = fdt_getprop(gFDT, node, "bootargs", &len);
242 			if (prop) {
243 				dprintf("Found bootargs: %s\n", (const char *)prop);
244 				static const char *sArgs[] = { NULL, NULL };
245 				sArgs[0] = (const char *)prop;
246 				args.arguments = sArgs;
247 				args.arguments_count = 1;
248 			}
249 		}
250 	}
251 
252 	// if we get passed a uimage, try to find the second blob
253 	if (gUImage != NULL
254 		&& image_multi_getimg(gUImage, 1,
255 			(uint32*)&args.platform.boot_tgz_data,
256 			&args.platform.boot_tgz_size)) {
257 		dprintf("Found boot tgz from uimage @ %p, %" B_PRIu32 " bytes\n",
258 			args.platform.boot_tgz_data, args.platform.boot_tgz_size);
259 	}
260 
261 	{ //DEBUG:
262 		int i;
263 		dprintf("argc = %d\n", argc);
264 		for (i = 0; i < argc; i++)
265 			dprintf("argv[%d] @%lx = '%s'\n", i, (uint32)argv[i], argv[i]);
266 		dprintf("os: %d\n", (int)gUBootOS);
267 		dprintf("gd @ %p\n", gUBootGlobalData);
268 		if (gUBootGlobalData)
269 			dprintf("gd->bd @ %p\n", gUBootGlobalData->bd);
270 		//dprintf("fb_base %p\n", (void*)gUBootGlobalData->fb_base);
271 		if (gUImage)
272 			dump_uimage(gUImage);
273 		if (gFDT)
274 			dump_fdt(gFDT);
275 	}
276 
277 	mmu_init();
278 
279 	// wait a bit to give the user the opportunity to press a key
280 //	spin(750000);
281 
282 	// reading the keyboard doesn't seem to work in graphics mode
283 	// (maybe a bochs problem)
284 //	sBootOptions = check_for_boot_keys();
285 	//if (sBootOptions & BOOT_OPTION_DEBUG_OUTPUT)
286 		serial_enable();
287 
288 	main(&args);
289 	return 0;
290 }
291 
292 
293 extern "C" uint32
294 platform_boot_options(void)
295 {
296 	return sBootOptions;
297 }
298