xref: /haiku/src/system/boot/platform/u-boot/start.cpp (revision a085e81e62d7a860f809b4fb7c7bf5654c396985)
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 
22 #include <string.h>
23 
24 extern "C" {
25 #include <fdt.h>
26 #include <libfdt.h>
27 #include <libfdt_env.h>
28 };
29 
30 
31 #define HEAP_SIZE (128 * 1024)
32 
33 
34 typedef struct uboot_gd {
35 	// those are the only few members that we can trust
36 	// others depend on compile-time config
37 	struct board_data *bd;
38 	uint32 flags;
39 	uint32 baudrate;
40 	// those are ARM-only
41 	uint32 have_console;
42 	uint32 reloc_off;
43 	uint32 env_addr;
44 	uint32 env_valid;
45 	uint32 fb_base;
46 } uboot_gd;
47 
48 
49 // GCC defined globals
50 extern void (*__ctor_list)(void);
51 extern void (*__ctor_end)(void);
52 extern uint8 __bss_start;
53 extern uint8 _end;
54 
55 extern "C" int main(stage2_args *args);
56 extern "C" void _start(void);
57 extern "C" int start_raw(int argc, const char **argv);
58 extern "C" void dump_uimage(struct image_header *image);
59 extern "C" void dump_fdt(const void *fdt);
60 
61 // declared in shell.S
62 // those are initialized to NULL but not in the BSS
63 extern struct image_header *gUImage;
64 extern uboot_gd *gUBootGlobalData;
65 extern uint32 gUBootOS;
66 extern void *gFDT;
67 
68 static uint32 sBootOptions;
69 
70 
71 static void
72 clear_bss(void)
73 {
74 	memset(&__bss_start, 0, &_end - &__bss_start);
75 }
76 
77 
78 static void
79 call_ctors(void)
80 {
81 	void (**f)(void);
82 
83 	for (f = &__ctor_list; f < &__ctor_end; f++) {
84 		(**f)();
85 	}
86 }
87 
88 
89 /* needed for libgcc unwind XXX */
90 extern "C" void
91 abort(void)
92 {
93 	panic("abort");
94 }
95 
96 
97 extern "C" void
98 platform_start_kernel(void)
99 {
100 	preloaded_elf32_image *image = static_cast<preloaded_elf32_image *>(
101 		gKernelArgs.kernel_image.Pointer());
102 
103 	addr_t kernelEntry = image->elf_header.e_entry;
104 	addr_t stackTop
105 		= gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size;
106 
107 //	smp_init_other_cpus();
108 	serial_cleanup();
109 	mmu_init_for_kernel();
110 //	smp_boot_other_cpus();
111 
112 	dprintf("kernel entry at %lx\n", kernelEntry);
113 
114 	status_t error = arch_start_kernel(&gKernelArgs, kernelEntry,
115 		stackTop);
116 
117 	panic("kernel returned!\n");
118 }
119 
120 
121 extern "C" void
122 platform_exit(void)
123 {
124 }
125 
126 
127 extern "C" int
128 start_netbsd(struct board_info *bd, struct image_header *image,
129 	const char *consdev, const char *cmdline)
130 {
131 	const char *argv[] = { "haiku", cmdline };
132 	int argc = 1;
133 	if (cmdline)
134 		argc++;
135 	gUImage = image;
136 	return start_raw(argc, argv);
137 }
138 
139 
140 extern "C" int
141 start_linux(int argc, int archnum, void *atags)
142 {
143 	return 1;
144 }
145 
146 
147 extern "C" int
148 start_linux_ppc_old(void */*board_info*/,
149 	void */*initrd_start*/, void */*initrd_end*/,
150 	const char */*cmdline_start*/, const char */*cmdline_end*/)
151 {
152 	return 1;
153 }
154 
155 
156 extern "C" int
157 start_linux_ppc_fdt(void *fdt, long/*UNUSED*/, long/*UNUSED*/,
158 	uint32 epapr_magic, uint32 initial_mem_size)
159 {
160 	gFDT = fdt;	//XXX: make a copy?
161 	return start_raw(0, NULL);
162 }
163 
164 
165 extern "C" int
166 start_raw(int argc, const char **argv)
167 {
168 	stage2_args args;
169 
170 	clear_bss();
171 		// call C++ constructors before doing anything else
172 	call_ctors();
173 	args.heap_size = HEAP_SIZE;
174 	args.arguments = NULL;
175 	args.platform.boot_tgz_data = NULL;
176 	args.platform.boot_tgz_size = 0;
177 	args.platform.fdt_data = NULL;
178 	args.platform.fdt_size = 0;
179 
180 	// if we get passed a uimage, try to find the third blob only if we do not have FDT data yet
181 	if (gUImage != NULL
182 		&& !gFDT
183 		&& image_multi_getimg(gUImage, 2,
184 			(uint32*)&args.platform.fdt_data,
185 			&args.platform.fdt_size)) {
186 		// found a blob, assume it is FDT data, when working on a platform
187 		// which does not have an FDT enabled U-Boot
188 		gFDT = args.platform.fdt_data;
189 	}
190 
191 	serial_init(gFDT);
192 	console_init();
193 	cpu_init();
194 
195 	if (args.platform.fdt_data) {
196 		dprintf("Found FDT from uimage @ %p, %" B_PRIu32 " bytes\n",
197 			args.platform.fdt_data, args.platform.fdt_size);
198 	} else if (gFDT) {
199 		/* Fixup args so we can pass the gFDT on to the kernel */
200 		args.platform.fdt_data = gFDT;
201 		args.platform.fdt_size = fdt_totalsize(gFDT);
202 	}
203 
204 	// if we get passed an FDT, check /chosen for initrd
205 	if (gFDT != NULL) {
206 		int node = fdt_path_offset(gFDT, "/chosen");
207 		const void *prop;
208 		int len;
209 		phys_addr_t initrd_start = 0, initrd_end = 0;
210 
211 		if (node >= 0) {
212 			prop = fdt_getprop(gFDT, node, "linux,initrd-start", &len);
213 			if (prop && len == 4)
214 				initrd_start = fdt32_to_cpu(*(uint32_t *)prop);
215 			prop = fdt_getprop(gFDT, node, "linux,initrd-end", &len);
216 			if (prop && len == 4)
217 				initrd_end = fdt32_to_cpu(*(uint32_t *)prop);
218 			if (initrd_end > initrd_start) {
219 				args.platform.boot_tgz_data = (void *)initrd_start;
220 				args.platform.boot_tgz_size = initrd_end - initrd_start;
221 		dprintf("Found boot tgz from FDT @ %p, %" B_PRIu32 " bytes\n",
222 			args.platform.boot_tgz_data, args.platform.boot_tgz_size);
223 			}
224 		}
225 	}
226 
227 	// if we get passed a uimage, try to find the second blob
228 	if (gUImage != NULL
229 		&& image_multi_getimg(gUImage, 1,
230 			(uint32*)&args.platform.boot_tgz_data,
231 			&args.platform.boot_tgz_size)) {
232 		dprintf("Found boot tgz from uimage @ %p, %" B_PRIu32 " bytes\n",
233 			args.platform.boot_tgz_data, args.platform.boot_tgz_size);
234 	}
235 
236 	{ //DEBUG:
237 		int i;
238 		dprintf("argc = %d\n", argc);
239 		for (i = 0; i < argc; i++)
240 			dprintf("argv[%d] @%lx = '%s'\n", i, (uint32)argv[i], argv[i]);
241 		dprintf("os: %d\n", (int)gUBootOS);
242 		dprintf("gd @ %p\n", gUBootGlobalData);
243 		if (gUBootGlobalData)
244 			dprintf("gd->bd @ %p\n", gUBootGlobalData->bd);
245 		//dprintf("fb_base %p\n", (void*)gUBootGlobalData->fb_base);
246 		if (gUImage)
247 			dump_uimage(gUImage);
248 		if (gFDT)
249 			dump_fdt(gFDT);
250 	}
251 
252 	mmu_init();
253 
254 	// wait a bit to give the user the opportunity to press a key
255 //	spin(750000);
256 
257 	// reading the keyboard doesn't seem to work in graphics mode
258 	// (maybe a bochs problem)
259 //	sBootOptions = check_for_boot_keys();
260 	//if (sBootOptions & BOOT_OPTION_DEBUG_OUTPUT)
261 		serial_enable();
262 
263 	main(&args);
264 	return 0;
265 }
266 
267 
268 extern "C" uint32
269 platform_boot_options(void)
270 {
271 	return sBootOptions;
272 }
273