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 "RootFileSystem.h" 9 #include "elf.h" 10 11 #include <OS.h> 12 #include <boot/partitions.h> 13 #include <boot/platform.h> 14 #include <boot/stage2.h> 15 #include <boot/stdio.h> 16 #include <boot/vfs.h> 17 #include <directories.h> 18 #include <util/list.h> 19 20 #include <string.h> 21 #include <unistd.h> 22 23 24 #ifndef BOOT_ARCH 25 #error BOOT_ARCH has to be defined to differentiate the kernel per platform 26 #endif 27 28 #define SYSTEM_DIRECTORY_PREFIX "system/" 29 #define KERNEL_IMAGE "kernel_" BOOT_ARCH 30 #define KERNEL_PATH SYSTEM_DIRECTORY_PREFIX KERNEL_IMAGE 31 32 #ifdef ALTERNATE_BOOT_ARCH 33 #define ALTERNATE_KERNEL_IMAGE "kernel_" ALTERNATE_BOOT_ARCH 34 #define ALTERNATE_KERNEL_PATH "system/" ALTERNATE_KERNEL_IMAGE 35 #endif 36 37 38 static const char* const kSystemDirectoryPrefix = SYSTEM_DIRECTORY_PREFIX; 39 40 static const char* sKernelPaths[][2] = { 41 {KERNEL_PATH, KERNEL_IMAGE}, 42 #ifdef ALTERNATE_BOOT_ARCH 43 {ALTERNATE_KERNEL_PATH, ALTERNATE_KERNEL_IMAGE}, 44 #endif 45 {NULL, NULL}, 46 }; 47 48 static const char* sAddonPaths[] = {kVolumeLocalSystemKernelAddonsDirectory, 49 kVolumeLocalCommonNonpackagedKernelAddonsDirectory, 50 kVolumeLocalCommonKernelAddonsDirectory, 51 kVolumeLocalUserNonpackagedKernelAddonsDirectory, 52 kVolumeLocalUserKernelAddonsDirectory, NULL}; 53 54 55 static int 56 open_maybe_packaged(BootVolume& volume, const char* path, int openMode) 57 { 58 if (strncmp(path, kSystemDirectoryPrefix, strlen(kSystemDirectoryPrefix)) 59 == 0) { 60 path += strlen(kSystemDirectoryPrefix); 61 return open_from(volume.SystemDirectory(), path, openMode); 62 } 63 64 return open_from(volume.RootDirectory(), path, openMode); 65 } 66 67 68 static int 69 find_kernel(BootVolume& volume, const char** name = NULL) 70 { 71 for (int32 i = 0; sKernelPaths[i][0] != NULL; i++) { 72 int fd = open_maybe_packaged(volume, sKernelPaths[i][0], O_RDONLY); 73 if (fd >= 0) { 74 if (name) 75 *name = sKernelPaths[i][1]; 76 77 return fd; 78 } 79 } 80 81 return B_ENTRY_NOT_FOUND; 82 } 83 84 85 bool 86 is_bootable(Directory* volume) 87 { 88 if (volume->IsEmpty()) 89 return false; 90 91 BootVolume bootVolume; 92 if (bootVolume.SetTo(volume) != B_OK) 93 return false; 94 95 // check for the existance of a kernel (for our platform) 96 int fd = find_kernel(bootVolume); 97 if (fd < 0) 98 return false; 99 100 close(fd); 101 102 return true; 103 } 104 105 106 status_t 107 load_kernel(stage2_args* args, BootVolume& volume) 108 { 109 const char* name; 110 int fd = find_kernel(volume, &name); 111 if (fd < B_OK) 112 return fd; 113 114 dprintf("load kernel %s...\n", name); 115 116 elf_init(); 117 preloaded_image* image; 118 status_t status = elf_load_image(fd, &image); 119 120 close(fd); 121 122 if (status < B_OK) { 123 dprintf("loading kernel failed: %" B_PRIx32 "!\n", status); 124 return status; 125 } 126 127 gKernelArgs.kernel_image = image; 128 129 status = elf_relocate_image(gKernelArgs.kernel_image); 130 if (status < B_OK) { 131 dprintf("relocating kernel failed: %" B_PRIx32 "!\n", status); 132 return status; 133 } 134 135 gKernelArgs.kernel_image->name = kernel_args_strdup(name); 136 137 return B_OK; 138 } 139 140 141 static status_t 142 load_modules_from(BootVolume& volume, const char* path) 143 { 144 // we don't have readdir() & co. (yet?)... 145 146 int fd = open_maybe_packaged(volume, path, O_RDONLY); 147 if (fd < B_OK) 148 return fd; 149 150 Directory* modules = (Directory*)get_node_from(fd); 151 if (modules == NULL) 152 return B_ENTRY_NOT_FOUND; 153 154 void* cookie; 155 if (modules->Open(&cookie, O_RDONLY) == B_OK) { 156 char name[B_FILE_NAME_LENGTH]; 157 while (modules->GetNextEntry(cookie, name, sizeof(name)) == B_OK) { 158 if (!strcmp(name, ".") || !strcmp(name, "..")) 159 continue; 160 161 status_t status = elf_load_image(modules, name); 162 if (status != B_OK) 163 dprintf("Could not load \"%s\" error %" B_PRIx32 "\n", name, 164 status); 165 } 166 167 modules->Close(cookie); 168 } 169 170 return B_OK; 171 } 172 173 174 status_t 175 load_modules(stage2_args* args, BootVolume& volume) 176 { 177 int32 failed = 0; 178 179 // ToDo: this should be mostly replaced by a hardware oriented detection 180 // mechanism 181 182 int32 i = 0; 183 for (; sAddonPaths[i]; i++) { 184 char path[B_FILE_NAME_LENGTH]; 185 snprintf(path, sizeof(path), "%s/boot", sAddonPaths[i]); 186 187 if (load_modules_from(volume, path) != B_OK) 188 failed++; 189 } 190 191 if (failed == i) { 192 // couldn't load any boot modules 193 // fall back to load all modules (currently needed by the boot floppy) 194 const char* paths[] = {"bus_managers", "busses/ide", "busses/scsi", 195 "generic", "partitioning_systems", "drivers/bin", NULL}; 196 197 for (int32 i = 0; paths[i]; i++) { 198 char path[B_FILE_NAME_LENGTH]; 199 snprintf(path, sizeof(path), "%s/%s", sAddonPaths[0], paths[i]); 200 load_modules_from(volume, path); 201 } 202 } 203 204 // and now load all partitioning and file system modules 205 char path[B_FILE_NAME_LENGTH]; 206 snprintf(path, sizeof(path), "%s/%s", sAddonPaths[0], "file_systems"); 207 load_modules_from(volume, path); 208 snprintf( 209 path, sizeof(path), "%s/%s", sAddonPaths[0], "partitioning_systems"); 210 load_modules_from(volume, path); 211 212 return B_OK; 213 } 214