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