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
clear_bss(void)84 clear_bss(void)
85 {
86 memset(&__bss_start, 0, &__bss_end - &__bss_start);
87 }
88
89
90 static void
call_ctors(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
platform_start_kernel(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
platform_exit(void)134 platform_exit(void)
135 {
136 }
137
138
139 extern "C" int
start_netbsd(struct board_info * bd,struct image_header * image,const char * consdev,const char * cmdline)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
start_linux(int argc,int archnum,void * atags)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
start_linux_ppc_old(void *,void *,void *,const char *,const char *)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
start_linux_ppc_fdt(void * fdt,long,long,uint32 epapr_magic,uint32 initial_mem_size)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
start_raw(int argc,const char ** argv)177 start_raw(int argc, const char **argv)
178 {
179 return start_gen(argc, argv);
180 }
181
182
183 extern "C" int
start_gen(int argc,const char ** argv,struct image_header * uimage,void * fdt)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
platform_boot_options(void)356 platform_boot_options(void)
357 {
358 return sBootOptions;
359 }
360