15af32e75SAxel Dörfler /* 2317bd7ddSAxel Dörfler * Copyright 2003-2009, Axel Dörfler, axeld@pinc-software.de. 35af32e75SAxel Dörfler * Distributed under the terms of the MIT License. 45af32e75SAxel Dörfler */ 55af32e75SAxel Dörfler 65af32e75SAxel Dörfler 75af32e75SAxel Dörfler #include "loader.h" 8ce624c69SJessica Hamilton #include "elf.h" 90f009937SJessica Hamilton #include "RootFileSystem.h" 105af32e75SAxel Dörfler 11ce624c69SJessica Hamilton #include <directories.h> 120f009937SJessica Hamilton #include <OS.h> 13ce624c69SJessica Hamilton #include <util/list.h> 140f009937SJessica Hamilton #include <boot/stage2.h> 150f009937SJessica Hamilton #include <boot/vfs.h> 160f009937SJessica Hamilton #include <boot/platform.h> 170f009937SJessica Hamilton #include <boot/stdio.h> 180f009937SJessica Hamilton #include <boot/partitions.h> 195af32e75SAxel Dörfler 20ce624c69SJessica Hamilton #include <unistd.h> 210f009937SJessica Hamilton #include <string.h> 225af32e75SAxel Dörfler 2325a7b01dSIngo Weinhold 245af32e75SAxel Dörfler #ifndef BOOT_ARCH 255af32e75SAxel Dörfler # error BOOT_ARCH has to be defined to differentiate the kernel per platform 265af32e75SAxel Dörfler #endif 275af32e75SAxel Dörfler 28d11ea2b5SIngo Weinhold #define SYSTEM_DIRECTORY_PREFIX "system/" 295af32e75SAxel Dörfler #define KERNEL_IMAGE "kernel_" BOOT_ARCH 30d11ea2b5SIngo Weinhold #define KERNEL_PATH SYSTEM_DIRECTORY_PREFIX KERNEL_IMAGE 31d11ea2b5SIngo Weinhold 327417d5edSAlex Smith #ifdef ALTERNATE_BOOT_ARCH 337417d5edSAlex Smith # define ALTERNATE_KERNEL_IMAGE "kernel_" ALTERNATE_BOOT_ARCH 347417d5edSAlex Smith # define ALTERNATE_KERNEL_PATH "system/" ALTERNATE_KERNEL_IMAGE 357417d5edSAlex Smith #endif 365af32e75SAxel Dörfler 37d11ea2b5SIngo Weinhold 38d11ea2b5SIngo Weinhold static const char* const kSystemDirectoryPrefix = SYSTEM_DIRECTORY_PREFIX; 395af32e75SAxel Dörfler 407417d5edSAlex Smith static const char *sKernelPaths[][2] = { 417417d5edSAlex Smith { KERNEL_PATH, KERNEL_IMAGE }, 427417d5edSAlex Smith #ifdef ALTERNATE_BOOT_ARCH 437417d5edSAlex Smith { ALTERNATE_KERNEL_PATH, ALTERNATE_KERNEL_IMAGE }, 447417d5edSAlex Smith #endif 457417d5edSAlex Smith { NULL, NULL }, 467417d5edSAlex Smith }; 475af32e75SAxel Dörfler 480f009937SJessica Hamilton static const char *sAddonPaths[] = { 490f009937SJessica Hamilton kVolumeLocalSystemKernelAddonsDirectory, 503dfd9cb9SOliver Tappe kVolumeLocalCommonNonpackagedKernelAddonsDirectory, 513dfd9cb9SOliver Tappe kVolumeLocalCommonKernelAddonsDirectory, 523dfd9cb9SOliver Tappe kVolumeLocalUserNonpackagedKernelAddonsDirectory, 530f009937SJessica Hamilton kVolumeLocalUserKernelAddonsDirectory, 540f009937SJessica Hamilton NULL 550f009937SJessica Hamilton }; 565af32e75SAxel Dörfler 575af32e75SAxel Dörfler 58d11ea2b5SIngo Weinhold static int 59d11ea2b5SIngo Weinhold open_maybe_packaged(BootVolume& volume, const char* path, int openMode) 60d11ea2b5SIngo Weinhold { 61d11ea2b5SIngo Weinhold if (strncmp(path, kSystemDirectoryPrefix, strlen(kSystemDirectoryPrefix)) 62d11ea2b5SIngo Weinhold == 0) { 63d11ea2b5SIngo Weinhold path += strlen(kSystemDirectoryPrefix); 64d11ea2b5SIngo Weinhold return open_from(volume.SystemDirectory(), path, openMode); 65d11ea2b5SIngo Weinhold } 66d11ea2b5SIngo Weinhold 67d11ea2b5SIngo Weinhold return open_from(volume.RootDirectory(), path, openMode); 68d11ea2b5SIngo Weinhold } 69d11ea2b5SIngo Weinhold 70d11ea2b5SIngo Weinhold 7125a7b01dSIngo Weinhold static int 7225a7b01dSIngo Weinhold find_kernel(BootVolume& volume, const char** name = NULL) 737417d5edSAlex Smith { 747417d5edSAlex Smith for (int32 i = 0; sKernelPaths[i][0] != NULL; i++) { 7525a7b01dSIngo Weinhold int fd = open_maybe_packaged(volume, sKernelPaths[i][0], O_RDONLY); 767417d5edSAlex Smith if (fd >= 0) { 777417d5edSAlex Smith if (name) 787417d5edSAlex Smith *name = sKernelPaths[i][1]; 797417d5edSAlex Smith 807417d5edSAlex Smith return fd; 817417d5edSAlex Smith } 827417d5edSAlex Smith } 837417d5edSAlex Smith 847417d5edSAlex Smith return B_ENTRY_NOT_FOUND; 857417d5edSAlex Smith } 867417d5edSAlex Smith 8725a7b01dSIngo Weinhold 885af32e75SAxel Dörfler bool 895af32e75SAxel Dörfler is_bootable(Directory *volume) 905af32e75SAxel Dörfler { 915af32e75SAxel Dörfler if (volume->IsEmpty()) 925af32e75SAxel Dörfler return false; 935af32e75SAxel Dörfler 94d11ea2b5SIngo Weinhold BootVolume bootVolume; 95d11ea2b5SIngo Weinhold if (bootVolume.SetTo(volume) != B_OK) 96d11ea2b5SIngo Weinhold return false; 97d11ea2b5SIngo Weinhold 985af32e75SAxel Dörfler // check for the existance of a kernel (for our platform) 9925a7b01dSIngo Weinhold int fd = find_kernel(bootVolume); 100d11ea2b5SIngo Weinhold if (fd < 0) 1015af32e75SAxel Dörfler return false; 1025af32e75SAxel Dörfler 1035af32e75SAxel Dörfler close(fd); 1045af32e75SAxel Dörfler 1055af32e75SAxel Dörfler return true; 1065af32e75SAxel Dörfler } 1075af32e75SAxel Dörfler 1085af32e75SAxel Dörfler 1095af32e75SAxel Dörfler status_t 110d11ea2b5SIngo Weinhold load_kernel(stage2_args* args, BootVolume& volume) 1115af32e75SAxel Dörfler { 1127417d5edSAlex Smith const char *name; 1137417d5edSAlex Smith int fd = find_kernel(volume, &name); 1145af32e75SAxel Dörfler if (fd < B_OK) 1155af32e75SAxel Dörfler return fd; 1165af32e75SAxel Dörfler 1177417d5edSAlex Smith dprintf("load kernel %s...\n", name); 1185af32e75SAxel Dörfler 1195e972c0fSFredrik Holmqvist elf_init(); 120f1244978SAlex Smith preloaded_image *image; 121f1244978SAlex Smith status_t status = elf_load_image(fd, &image); 1225af32e75SAxel Dörfler 1235af32e75SAxel Dörfler close(fd); 1245af32e75SAxel Dörfler 1255af32e75SAxel Dörfler if (status < B_OK) { 126211483cbSFredrik Holmqvist dprintf("loading kernel failed: %" B_PRIx32 "!\n", status); 127957a1b17SIngo Weinhold return status; 128957a1b17SIngo Weinhold } 129957a1b17SIngo Weinhold 130f1244978SAlex Smith gKernelArgs.kernel_image = image; 131f1244978SAlex Smith 132f1244978SAlex Smith status = elf_relocate_image(gKernelArgs.kernel_image); 133957a1b17SIngo Weinhold if (status < B_OK) { 134211483cbSFredrik Holmqvist dprintf("relocating kernel failed: %" B_PRIx32 "!\n", status); 1355af32e75SAxel Dörfler return status; 1365af32e75SAxel Dörfler } 1375af32e75SAxel Dörfler 138f1244978SAlex Smith gKernelArgs.kernel_image->name = kernel_args_strdup(name); 1391cd8c4ccSIngo Weinhold 1405af32e75SAxel Dörfler return B_OK; 1415af32e75SAxel Dörfler } 1425af32e75SAxel Dörfler 1435af32e75SAxel Dörfler 1445af32e75SAxel Dörfler static status_t 145d11ea2b5SIngo Weinhold load_modules_from(BootVolume& volume, const char* path) 1465af32e75SAxel Dörfler { 1475af32e75SAxel Dörfler // we don't have readdir() & co. (yet?)... 1485af32e75SAxel Dörfler 149d11ea2b5SIngo Weinhold int fd = open_maybe_packaged(volume, path, O_RDONLY); 1505af32e75SAxel Dörfler if (fd < B_OK) 1515af32e75SAxel Dörfler return fd; 1525af32e75SAxel Dörfler 1535af32e75SAxel Dörfler Directory *modules = (Directory *)get_node_from(fd); 1545af32e75SAxel Dörfler if (modules == NULL) 1555af32e75SAxel Dörfler return B_ENTRY_NOT_FOUND; 1565af32e75SAxel Dörfler 1575af32e75SAxel Dörfler void *cookie; 1585af32e75SAxel Dörfler if (modules->Open(&cookie, O_RDONLY) == B_OK) { 1595af32e75SAxel Dörfler char name[B_FILE_NAME_LENGTH]; 1605af32e75SAxel Dörfler while (modules->GetNextEntry(cookie, name, sizeof(name)) == B_OK) { 1615af32e75SAxel Dörfler if (!strcmp(name, ".") || !strcmp(name, "..")) 1625af32e75SAxel Dörfler continue; 1635af32e75SAxel Dörfler 1645af32e75SAxel Dörfler status_t status = elf_load_image(modules, name); 1655af32e75SAxel Dörfler if (status != B_OK) 1660f009937SJessica Hamilton dprintf("Could not load \"%s\" error %" B_PRIx32 "\n", name, status); 1675af32e75SAxel Dörfler } 1685af32e75SAxel Dörfler 1695af32e75SAxel Dörfler modules->Close(cookie); 1705af32e75SAxel Dörfler } 1715af32e75SAxel Dörfler 1725af32e75SAxel Dörfler return B_OK; 1735af32e75SAxel Dörfler } 1745af32e75SAxel Dörfler 1755af32e75SAxel Dörfler 1760f009937SJessica Hamilton /** Loads a module by module name. This basically works in the same 1770f009937SJessica Hamilton * way as the kernel module loader; it will cut off the last part 1780f009937SJessica Hamilton * of the module name until it could find a module and loads it. 1790f009937SJessica Hamilton * It tests both, kernel and user module directories. 1800f009937SJessica Hamilton */ 1810f009937SJessica Hamilton 1820f009937SJessica Hamilton static status_t 1830f009937SJessica Hamilton load_module(BootVolume& volume, const char* name) 1840f009937SJessica Hamilton { 1850f009937SJessica Hamilton char moduleName[B_FILE_NAME_LENGTH]; 1860f009937SJessica Hamilton if (strlcpy(moduleName, name, sizeof(moduleName)) > sizeof(moduleName)) 1870f009937SJessica Hamilton return B_NAME_TOO_LONG; 1880f009937SJessica Hamilton 1890f009937SJessica Hamilton for (int32 i = 0; sAddonPaths[i]; i++) { 1900f009937SJessica Hamilton // get base path 1910f009937SJessica Hamilton int baseFD = open_maybe_packaged(volume, sAddonPaths[i], O_RDONLY); 1920f009937SJessica Hamilton if (baseFD < B_OK) 1930f009937SJessica Hamilton continue; 1940f009937SJessica Hamilton 1950f009937SJessica Hamilton Directory *base = (Directory *)get_node_from(baseFD); 1960f009937SJessica Hamilton if (base == NULL) { 1970f009937SJessica Hamilton close(baseFD); 1980f009937SJessica Hamilton continue; 1990f009937SJessica Hamilton } 2000f009937SJessica Hamilton 2010f009937SJessica Hamilton while (true) { 2020f009937SJessica Hamilton int fd = open_from(base, moduleName, O_RDONLY); 2030f009937SJessica Hamilton if (fd >= B_OK) { 2040f009937SJessica Hamilton struct stat stat; 2050f009937SJessica Hamilton if (fstat(fd, &stat) != 0 || !S_ISREG(stat.st_mode)) 2060f009937SJessica Hamilton return B_BAD_VALUE; 2070f009937SJessica Hamilton 2080f009937SJessica Hamilton status_t status = elf_load_image(base, moduleName); 2090f009937SJessica Hamilton 2100f009937SJessica Hamilton close(fd); 2110f009937SJessica Hamilton close(baseFD); 2120f009937SJessica Hamilton return status; 2130f009937SJessica Hamilton } 2140f009937SJessica Hamilton 2150f009937SJessica Hamilton // cut off last name element (or stop trying if there are no more) 2160f009937SJessica Hamilton 2170f009937SJessica Hamilton char *last = strrchr(moduleName, '/'); 2180f009937SJessica Hamilton if (last != NULL) 2190f009937SJessica Hamilton last[0] = '\0'; 2200f009937SJessica Hamilton else 2210f009937SJessica Hamilton break; 2220f009937SJessica Hamilton } 2230f009937SJessica Hamilton 2240f009937SJessica Hamilton close(baseFD); 2250f009937SJessica Hamilton } 2260f009937SJessica Hamilton 2270f009937SJessica Hamilton return B_OK; 2280f009937SJessica Hamilton } 2290f009937SJessica Hamilton 2300f009937SJessica Hamilton 2315af32e75SAxel Dörfler status_t 232d11ea2b5SIngo Weinhold load_modules(stage2_args* args, BootVolume& volume) 2335af32e75SAxel Dörfler { 234e3fcb58eSAxel Dörfler int32 failed = 0; 235e3fcb58eSAxel Dörfler 2360f009937SJessica Hamilton // ToDo: this should be mostly replaced by a hardware oriented detection mechanism 237e3fcb58eSAxel Dörfler 2383dfd9cb9SOliver Tappe int32 i = 0; 2397417d5edSAlex Smith for (; sAddonPaths[i]; i++) { 2405af32e75SAxel Dörfler char path[B_FILE_NAME_LENGTH]; 2417417d5edSAlex Smith snprintf(path, sizeof(path), "%s/boot", sAddonPaths[i]); 2425af32e75SAxel Dörfler 243e3fcb58eSAxel Dörfler if (load_modules_from(volume, path) != B_OK) 244e3fcb58eSAxel Dörfler failed++; 245e3fcb58eSAxel Dörfler } 246e3fcb58eSAxel Dörfler 2473dfd9cb9SOliver Tappe if (failed == i) { 248e3fcb58eSAxel Dörfler // couldn't load any boot modules 249e3fcb58eSAxel Dörfler // fall back to load all modules (currently needed by the boot floppy) 250e3fcb58eSAxel Dörfler const char *paths[] = { "bus_managers", "busses/ide", "busses/scsi", 251e3fcb58eSAxel Dörfler "generic", "partitioning_systems", "drivers/bin", NULL}; 252e3fcb58eSAxel Dörfler 253e3fcb58eSAxel Dörfler for (int32 i = 0; paths[i]; i++) { 254e3fcb58eSAxel Dörfler char path[B_FILE_NAME_LENGTH]; 2557417d5edSAlex Smith snprintf(path, sizeof(path), "%s/%s", sAddonPaths[0], paths[i]); 2565af32e75SAxel Dörfler load_modules_from(volume, path); 2575af32e75SAxel Dörfler } 258e3fcb58eSAxel Dörfler } 2595af32e75SAxel Dörfler 2605af32e75SAxel Dörfler // and now load all partitioning and file system modules 2618423f6f4SAxel Dörfler char path[B_FILE_NAME_LENGTH]; 2627417d5edSAlex Smith snprintf(path, sizeof(path), "%s/%s", sAddonPaths[0], "file_systems"); 2638423f6f4SAxel Dörfler load_modules_from(volume, path); 264*bab060e9SJessica Hamilton snprintf(path, sizeof(path), "%s/%s", sAddonPaths[0], "partitioning_systems"); 265*bab060e9SJessica Hamilton load_modules_from(volume, path); 2665af32e75SAxel Dörfler 2675af32e75SAxel Dörfler return B_OK; 2685af32e75SAxel Dörfler } 269