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