xref: /haiku/src/system/boot/platform/u-boot/start.cpp (revision 6288f7b4537703bfaa43bf8f8fa0c58e4c8dd82b)
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 	// TODO: Ensure cmdline is mapped into memory by MMU before usage.
141 	if (cmdline && *cmdline)
142 		argc++;
143 	gUImage = image;
144 	return start_raw(argc, argv);
145 }
146 
147 
148 extern "C" int
149 start_linux(int argc, int archnum, void *atags)
150 {
151 	return 1;
152 }
153 
154 
155 extern "C" int
156 start_linux_ppc_old(void */*board_info*/,
157 	void */*initrd_start*/, void */*initrd_end*/,
158 	const char */*cmdline_start*/, const char */*cmdline_end*/)
159 {
160 	return 1;
161 }
162 
163 
164 extern "C" int
165 start_linux_ppc_fdt(void *fdt, long/*UNUSED*/, long/*UNUSED*/,
166 	uint32 epapr_magic, uint32 initial_mem_size)
167 {
168 	gFDT = fdt;	//XXX: make a copy?
169 	return start_raw(0, NULL);
170 }
171 
172 
173 extern "C" int
174 start_raw(int argc, const char **argv)
175 {
176 	stage2_args args;
177 
178 	clear_bss();
179 		// call C++ constructors before doing anything else
180 	call_ctors();
181 	args.heap_size = HEAP_SIZE;
182 	args.arguments = NULL;
183 	args.platform.boot_tgz_data = NULL;
184 	args.platform.boot_tgz_size = 0;
185 	args.platform.fdt_data = NULL;
186 	args.platform.fdt_size = 0;
187 
188 	if (argv) {
189 		// skip the kernel name
190 		args.arguments = ++argv;
191 		args.arguments_count = --argc;
192 	}
193 
194 	// if we get passed a uimage, try to find the third blob
195 	// only if we do not have FDT data yet
196 	if (gUImage != NULL
197 		&& !gFDT
198 		&& image_multi_getimg(gUImage, 2,
199 			(uint32*)&args.platform.fdt_data,
200 			&args.platform.fdt_size)) {
201 		// found a blob, assume it is FDT data, when working on a platform
202 		// which does not have an FDT enabled U-Boot
203 		gFDT = args.platform.fdt_data;
204 	}
205 
206 	serial_init(gFDT);
207 	console_init();
208 	// initialize the OpenFirmware wrapper
209 	of_init(NULL);
210 
211 	cpu_init();
212 
213 	if (args.platform.fdt_data) {
214 		dprintf("Found FDT from uimage @ %p, %" B_PRIu32 " bytes\n",
215 			args.platform.fdt_data, args.platform.fdt_size);
216 	} else if (gFDT) {
217 		/* Fixup args so we can pass the gFDT on to the kernel */
218 		args.platform.fdt_data = gFDT;
219 		args.platform.fdt_size = fdt_totalsize(gFDT);
220 	}
221 
222 	// if we get passed an FDT, check /chosen for initrd and bootargs
223 	if (gFDT != NULL) {
224 		int node = fdt_path_offset(gFDT, "/chosen");
225 		const void *prop;
226 		int len;
227 		phys_addr_t initrd_start = 0, initrd_end = 0;
228 
229 		if (node >= 0) {
230 			prop = fdt_getprop(gFDT, node, "linux,initrd-start", &len);
231 			if (prop && len == 4)
232 				initrd_start = fdt32_to_cpu(*(uint32_t *)prop);
233 			prop = fdt_getprop(gFDT, node, "linux,initrd-end", &len);
234 			if (prop && len == 4)
235 				initrd_end = fdt32_to_cpu(*(uint32_t *)prop);
236 			if (initrd_end > initrd_start) {
237 				args.platform.boot_tgz_data = (void *)initrd_start;
238 				args.platform.boot_tgz_size = initrd_end - initrd_start;
239 				dprintf("Found boot tgz from FDT @ %p, %" B_PRIu32 " bytes\n",
240 					args.platform.boot_tgz_data, args.platform.boot_tgz_size);
241 			}
242 			prop = fdt_getprop(gFDT, node, "bootargs", &len);
243 			if (prop) {
244 				dprintf("Found bootargs: %s\n", (const char *)prop);
245 				static const char *sArgs[] = { NULL, NULL };
246 				sArgs[0] = (const char *)prop;
247 				args.arguments = sArgs;
248 				args.arguments_count = 1;
249 			}
250 		}
251 	}
252 
253 	// if we get passed a uimage, try to find the second blob
254 	if (gUImage != NULL
255 		&& image_multi_getimg(gUImage, 1,
256 			(uint32*)&args.platform.boot_tgz_data,
257 			&args.platform.boot_tgz_size)) {
258 		dprintf("Found boot tgz from uimage @ %p, %" B_PRIu32 " bytes\n",
259 			args.platform.boot_tgz_data, args.platform.boot_tgz_size);
260 	}
261 
262 	{ //DEBUG:
263 		int i;
264 		dprintf("argc = %d\n", argc);
265 		for (i = 0; i < argc; i++)
266 			dprintf("argv[%d] @%lx = '%s'\n", i, (uint32)argv[i], argv[i]);
267 		dprintf("os: %d\n", (int)gUBootOS);
268 		dprintf("gd @ %p\n", gUBootGlobalData);
269 		if (gUBootGlobalData)
270 			dprintf("gd->bd @ %p\n", gUBootGlobalData->bd);
271 		//dprintf("fb_base %p\n", (void*)gUBootGlobalData->fb_base);
272 		if (gUImage)
273 			dump_uimage(gUImage);
274 		if (gFDT)
275 			dump_fdt(gFDT);
276 	}
277 
278 	mmu_init();
279 
280 	// wait a bit to give the user the opportunity to press a key
281 //	spin(750000);
282 
283 	// reading the keyboard doesn't seem to work in graphics mode
284 	// (maybe a bochs problem)
285 //	sBootOptions = check_for_boot_keys();
286 	//if (sBootOptions & BOOT_OPTION_DEBUG_OUTPUT)
287 		serial_enable();
288 
289 	main(&args);
290 	return 0;
291 }
292 
293 
294 extern "C" uint32
295 platform_boot_options(void)
296 {
297 	return sBootOptions;
298 }
299