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