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