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 84 clear_bss(void) 85 { 86 memset(&__bss_start, 0, &__bss_end - &__bss_start); 87 } 88 89 90 static 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 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 134 platform_exit(void) 135 { 136 } 137 138 139 extern "C" int 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 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 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 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 177 start_raw(int argc, const char **argv) 178 { 179 return start_gen(argc, argv); 180 } 181 182 183 extern "C" int 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 356 platform_boot_options(void) 357 { 358 return sBootOptions; 359 } 360