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