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