1 /* 2 * Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "loader.h" 8 #include "elf.h" 9 #include "RootFileSystem.h" 10 11 #include <OS.h> 12 #include <util/list.h> 13 #include <boot/stage2.h> 14 #include <boot/vfs.h> 15 #include <boot/platform.h> 16 #include <boot/stdio.h> 17 #include <boot/partitions.h> 18 19 #include <unistd.h> 20 #include <string.h> 21 22 #ifndef BOOT_ARCH 23 # error BOOT_ARCH has to be defined to differentiate the kernel per platform 24 #endif 25 26 #define KERNEL_IMAGE "kernel_" BOOT_ARCH 27 #define KERNEL_PATH "beos/system/" KERNEL_IMAGE 28 29 30 static const char *sPaths[] = { 31 "beos/system/add-ons/kernel", 32 "home/config/add-ons/kernel", 33 NULL 34 }; 35 36 37 bool 38 is_bootable(Directory *volume) 39 { 40 if (volume->IsEmpty()) 41 return false; 42 43 // check for the existance of a kernel (for our platform) 44 int fd = open_from(volume, KERNEL_PATH, O_RDONLY); 45 if (fd < B_OK) 46 return false; 47 48 close(fd); 49 50 return true; 51 } 52 53 54 status_t 55 load_kernel(stage2_args *args, Directory *volume) 56 { 57 int fd = open_from(volume, KERNEL_PATH, O_RDONLY); 58 if (fd < B_OK) 59 return fd; 60 61 dprintf("load kernel...\n"); 62 63 status_t status = elf_load_image(fd, &gKernelArgs.kernel_image); 64 65 close(fd); 66 67 if (status < B_OK) { 68 dprintf("loading kernel failed: %lx!\n", status); 69 return status; 70 } 71 72 status = elf_relocate_image(&gKernelArgs.kernel_image); 73 if (status < B_OK) { 74 dprintf("relocating kernel failed: %lx!\n", status); 75 return status; 76 } 77 78 return B_OK; 79 } 80 81 82 static status_t 83 load_modules_from(Directory *volume, const char *path) 84 { 85 // we don't have readdir() & co. (yet?)... 86 87 int fd = open_from(volume, path, O_RDONLY); 88 if (fd < B_OK) 89 return fd; 90 91 Directory *modules = (Directory *)get_node_from(fd); 92 if (modules == NULL) 93 return B_ENTRY_NOT_FOUND; 94 95 void *cookie; 96 if (modules->Open(&cookie, O_RDONLY) == B_OK) { 97 char name[B_FILE_NAME_LENGTH]; 98 while (modules->GetNextEntry(cookie, name, sizeof(name)) == B_OK) { 99 if (!strcmp(name, ".") || !strcmp(name, "..")) 100 continue; 101 102 status_t status = elf_load_image(modules, name); 103 if (status != B_OK) 104 dprintf("Could not load \"%s\" error %ld\n", name, status); 105 } 106 107 modules->Close(cookie); 108 } 109 110 return B_OK; 111 } 112 113 114 /** Loads a module by module name. This basically works in the same 115 * way as the kernel module loader; it will cut off the last part 116 * of the module name until it could find a module and loads it. 117 * It tests both, kernel and user module directories. 118 */ 119 120 static status_t 121 load_module(Directory *volume, const char *name) 122 { 123 char moduleName[B_FILE_NAME_LENGTH]; 124 if (strlcpy(moduleName, name, sizeof(moduleName)) > sizeof(moduleName)) 125 return B_NAME_TOO_LONG; 126 127 for (int32 i = 0; sPaths[i]; i++) { 128 // get base path 129 int baseFD = open_from(volume, sPaths[i], O_RDONLY); 130 if (baseFD < B_OK) 131 continue; 132 133 Directory *base = (Directory *)get_node_from(baseFD); 134 135 while (true) { 136 int fd = open_from(base, moduleName, O_RDONLY); 137 if (fd >= B_OK) { 138 struct stat stat; 139 if (fstat(fd, &stat) != 0 || !S_ISREG(stat.st_mode)) 140 return B_BAD_VALUE; 141 142 status_t status = elf_load_image(base, moduleName); 143 144 close(fd); 145 close(baseFD); 146 return status; 147 } 148 149 // cut off last name element (or stop trying if there are no more) 150 151 char *last = strrchr(moduleName, '/'); 152 if (last != NULL) 153 last[0] = '\0'; 154 else 155 break; 156 } 157 158 close(baseFD); 159 } 160 161 return B_OK; 162 } 163 164 165 status_t 166 load_modules(stage2_args *args, Directory *volume) 167 { 168 int32 failed = 0; 169 170 // ToDo: this should be mostly replaced by a hardware oriented detection mechanism 171 172 for (int32 i = 0; sPaths[i]; i++) { 173 char path[B_FILE_NAME_LENGTH]; 174 sprintf(path, "%s/boot", sPaths[i]); 175 176 if (load_modules_from(volume, path) != B_OK) 177 failed++; 178 } 179 180 if (failed > 1) { 181 // couldn't load any boot modules 182 // fall back to load all modules (currently needed by the boot floppy) 183 const char *paths[] = { "bus_managers", "busses/ide", "busses/scsi", 184 "generic", "partitioning_systems", "drivers/bin", NULL}; 185 186 for (int32 i = 0; paths[i]; i++) { 187 char path[B_FILE_NAME_LENGTH]; 188 sprintf(path, "%s/%s", sPaths[0], paths[i]); 189 load_modules_from(volume, path); 190 } 191 } 192 193 // and now load all partitioning and file system modules 194 // needed to identify the boot volume 195 196 if (!gKernelArgs.boot_disk.booted_from_image) { 197 // iterate over the mounted volumes and load their file system 198 Partition *partition; 199 if (gRoot->GetPartitionFor(volume, &partition) == B_OK) { 200 while (partition != NULL) { 201 load_module(volume, partition->ModuleName()); 202 partition = partition->Parent(); 203 } 204 } 205 } else { 206 // The boot image should only contain the file system 207 // needed to boot the system, so we just load it. 208 // ToDo: this is separate from the fall back from above 209 // as this piece will survive a more intelligent module 210 // loading approach... 211 char path[B_FILE_NAME_LENGTH]; 212 sprintf(path, "%s/%s", sPaths[0], "file_systems"); 213 load_modules_from(volume, path); 214 } 215 216 return B_OK; 217 } 218 219