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