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