1 /* 2 * Copyright 2003-2010, Axel Dörfler, axeld@pinc-software.de. 3 * Copyright 2011, Alexander von Gluck, kallisti5@unixzen.com 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 #include <string.h> 9 10 #include <OS.h> 11 12 #include <boot/platform.h> 13 #include <boot/stage2.h> 14 #include <boot/heap.h> 15 #include <platform/openfirmware/openfirmware.h> 16 #include <platform_arch.h> 17 18 #include "console.h" 19 #include "machine.h" 20 #include "real_time_clock.h" 21 22 23 #define HEAP_SIZE 65536 24 25 26 extern "C" void _start(uint32 _unused1, uint32 _unused2, 27 void *openFirmwareEntry); 28 extern "C" void start(void *openFirmwareEntry); 29 30 // XCOFF "entry-point" is actually a pointer to the real code 31 extern "C" void *_coff_start; 32 void *_coff_start = (void *)&_start; 33 34 // GCC defined globals 35 extern void (*__ctor_list)(void); 36 extern void (*__ctor_end)(void); 37 extern uint8 __bss_start; 38 extern uint8 _end; 39 40 uint32 gMachine; 41 static uint32 sBootOptions; 42 43 44 static void 45 call_ctors(void) 46 { 47 void (**f)(void); 48 49 for (f = &__ctor_list; f < &__ctor_end; f++) { 50 (**f)(); 51 } 52 } 53 54 55 static void 56 clear_bss(void) 57 { 58 memset(&__bss_start, 0, &_end - &__bss_start); 59 } 60 61 62 static void 63 determine_machine(void) 64 { 65 gMachine = MACHINE_UNKNOWN; 66 67 int root = of_finddevice("/"); 68 char buffer[64]; 69 int length; 70 71 // TODO : Probe other OpenFirmware platforms and set gMachine as needed 72 73 if ((length = of_getprop(root, "device_type", buffer, sizeof(buffer) - 1)) 74 != OF_FAILED) { 75 buffer[length] = '\0'; 76 if (!strcasecmp("chrp", buffer)) 77 gMachine = MACHINE_CHRP; 78 else if (!strcasecmp("bootrom", buffer)) 79 gMachine = MACHINE_MAC; 80 } else 81 gMachine = MACHINE_MAC; 82 83 if ((length = of_getprop(root, "model", buffer, sizeof(buffer) - 1)) 84 != OF_FAILED) { 85 buffer[length] = '\0'; 86 if (!strcasecmp("pegasos", buffer)) 87 gMachine |= MACHINE_PEGASOS; 88 } 89 90 if ((length = of_getprop(root, "name", buffer, sizeof(buffer) - 1)) 91 != OF_FAILED) { 92 buffer[length] = '\0'; 93 if (!strcasecmp("openbiosteam,openbios", buffer)) 94 gMachine |= MACHINE_QEMU; 95 } 96 } 97 98 99 extern "C" void 100 platform_start_kernel(void) 101 { 102 preloaded_elf32_image* image = static_cast<preloaded_elf32_image*>( 103 gKernelArgs.kernel_image.Pointer()); 104 105 addr_t kernelEntry = image->elf_header.e_entry; 106 addr_t stackTop = gKernelArgs.cpu_kstack[0].start 107 + gKernelArgs.cpu_kstack[0].size; 108 109 printf("kernel entry at %p\n", (void*)kernelEntry); 110 printf("kernel stack top: %p\n", (void*)stackTop); 111 112 /* TODO: ? 113 mmu_init_for_kernel(); 114 smp_boot_other_cpus(); 115 */ 116 117 status_t error = arch_start_kernel(&gKernelArgs, kernelEntry, stackTop); 118 119 panic("Kernel returned! Return value: %ld\n", error); 120 } 121 122 123 extern "C" void 124 platform_exit(void) 125 { 126 of_interpret("reset-all", 0, 0); 127 } 128 129 130 extern "C" uint32 131 platform_boot_options(void) 132 { 133 return sBootOptions; 134 } 135 136 137 extern "C" void 138 _start(uint32 _unused1, uint32 _unused3, void *openFirmwareEntry) 139 { 140 // According to the PowerPC bindings, OpenFirmware should have created 141 // a stack of 32kB or higher for us at this point 142 143 clear_bss(); 144 call_ctors(); 145 // call C++ constructors before doing anything else 146 147 start(openFirmwareEntry); 148 } 149 150 151 extern "C" void 152 start(void *openFirmwareEntry) 153 { 154 char bootargs[512]; 155 156 // stage2 args - might be set via the command line one day 157 stage2_args args; 158 args.heap_size = HEAP_SIZE; 159 args.arguments = NULL; 160 161 of_init((int (*)(void*))openFirmwareEntry); 162 163 // check for arguments 164 if (of_getprop(gChosen, "bootargs", bootargs, sizeof(bootargs)) 165 != OF_FAILED) { 166 static const char *sArgs[] = { NULL, NULL }; 167 sArgs[0] = (const char *)bootargs; 168 args.arguments = sArgs; 169 args.arguments_count = 1; 170 } 171 172 determine_machine(); 173 console_init(); 174 175 if ((gMachine & MACHINE_QEMU) != 0) 176 dprintf("OpenBIOS (QEMU?) OpenFirmware machine detected\n"); 177 else if ((gMachine & MACHINE_PEGASOS) != 0) 178 dprintf("Pegasos PowerPC machine detected\n"); 179 else 180 dprintf("Apple PowerPC machine assumed\n"); 181 182 // Initialize and take over MMU and set the OpenFirmware callbacks - it 183 // will ask us for memory after that instead of maintaining it itself 184 // (the kernel will need to adjust the callback later on as well) 185 arch_mmu_init(); 186 187 if (boot_arch_cpu_init() != B_OK) 188 of_exit(); 189 190 if (init_real_time_clock() != B_OK) 191 of_exit(); 192 193 // check for key presses once 194 sBootOptions = 0; 195 int key = console_check_for_key(); 196 if (key == 32) { 197 // space bar: option menu 198 sBootOptions |= BOOT_OPTION_MENU; 199 } else if (key == 27) { 200 // ESC: debug output 201 sBootOptions |= BOOT_OPTION_DEBUG_OUTPUT; 202 } 203 204 gKernelArgs.platform_args.openfirmware_entry = openFirmwareEntry; 205 206 main(&args); 207 // if everything goes fine, main() never returns 208 209 of_exit(); 210 } 211