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