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" 85af32e75SAxel Dörfler #include "elf.h" 95af32e75SAxel Dörfler #include "RootFileSystem.h" 105af32e75SAxel Dörfler 113dfd9cb9SOliver Tappe #include <directories.h> 125af32e75SAxel Dörfler #include <OS.h> 135af32e75SAxel Dörfler #include <util/list.h> 145af32e75SAxel Dörfler #include <boot/stage2.h> 155af32e75SAxel Dörfler #include <boot/vfs.h> 165af32e75SAxel Dörfler #include <boot/platform.h> 175af32e75SAxel Dörfler #include <boot/stdio.h> 185af32e75SAxel Dörfler #include <boot/partitions.h> 195af32e75SAxel Dörfler 205af32e75SAxel Dörfler #include <unistd.h> 215af32e75SAxel Dörfler #include <string.h> 225af32e75SAxel Dörfler 235af32e75SAxel Dörfler #ifndef BOOT_ARCH 245af32e75SAxel Dörfler # error BOOT_ARCH has to be defined to differentiate the kernel per platform 255af32e75SAxel Dörfler #endif 265af32e75SAxel Dörfler 27*d11ea2b5SIngo Weinhold #define SYSTEM_DIRECTORY_PREFIX "system/" 285af32e75SAxel Dörfler #define KERNEL_IMAGE "kernel_" BOOT_ARCH 29*d11ea2b5SIngo Weinhold #define KERNEL_PATH SYSTEM_DIRECTORY_PREFIX KERNEL_IMAGE 30*d11ea2b5SIngo Weinhold 31*d11ea2b5SIngo Weinhold 32*d11ea2b5SIngo Weinhold static const char* const kSystemDirectoryPrefix = SYSTEM_DIRECTORY_PREFIX; 335af32e75SAxel Dörfler 345af32e75SAxel Dörfler 355af32e75SAxel Dörfler static const char *sPaths[] = { 363dfd9cb9SOliver Tappe kVolumeLocalSystemKernelAddonsDirectory, 373dfd9cb9SOliver Tappe kVolumeLocalCommonNonpackagedKernelAddonsDirectory, 383dfd9cb9SOliver Tappe kVolumeLocalCommonKernelAddonsDirectory, 393dfd9cb9SOliver Tappe kVolumeLocalUserNonpackagedKernelAddonsDirectory, 403dfd9cb9SOliver Tappe kVolumeLocalUserKernelAddonsDirectory, 415af32e75SAxel Dörfler NULL 425af32e75SAxel Dörfler }; 435af32e75SAxel Dörfler 445af32e75SAxel Dörfler 45*d11ea2b5SIngo Weinhold static int 46*d11ea2b5SIngo Weinhold open_maybe_packaged(BootVolume& volume, const char* path, int openMode) 47*d11ea2b5SIngo Weinhold { 48*d11ea2b5SIngo Weinhold if (strncmp(path, kSystemDirectoryPrefix, strlen(kSystemDirectoryPrefix)) 49*d11ea2b5SIngo Weinhold == 0) { 50*d11ea2b5SIngo Weinhold path += strlen(kSystemDirectoryPrefix); 51*d11ea2b5SIngo Weinhold return open_from(volume.SystemDirectory(), path, openMode); 52*d11ea2b5SIngo Weinhold } 53*d11ea2b5SIngo Weinhold 54*d11ea2b5SIngo Weinhold return open_from(volume.RootDirectory(), path, openMode); 55*d11ea2b5SIngo Weinhold } 56*d11ea2b5SIngo Weinhold 57*d11ea2b5SIngo Weinhold 585af32e75SAxel Dörfler bool 595af32e75SAxel Dörfler is_bootable(Directory *volume) 605af32e75SAxel Dörfler { 615af32e75SAxel Dörfler if (volume->IsEmpty()) 625af32e75SAxel Dörfler return false; 635af32e75SAxel Dörfler 64*d11ea2b5SIngo Weinhold BootVolume bootVolume; 65*d11ea2b5SIngo Weinhold if (bootVolume.SetTo(volume) != B_OK) 66*d11ea2b5SIngo Weinhold return false; 67*d11ea2b5SIngo Weinhold 685af32e75SAxel Dörfler // check for the existance of a kernel (for our platform) 69*d11ea2b5SIngo Weinhold int fd = open_maybe_packaged(bootVolume, KERNEL_PATH, O_RDONLY); 70*d11ea2b5SIngo Weinhold if (fd < 0) 715af32e75SAxel Dörfler return false; 725af32e75SAxel Dörfler 735af32e75SAxel Dörfler close(fd); 745af32e75SAxel Dörfler 755af32e75SAxel Dörfler return true; 765af32e75SAxel Dörfler } 775af32e75SAxel Dörfler 785af32e75SAxel Dörfler 795af32e75SAxel Dörfler status_t 80*d11ea2b5SIngo Weinhold load_kernel(stage2_args* args, BootVolume& volume) 815af32e75SAxel Dörfler { 82*d11ea2b5SIngo Weinhold int fd = open_maybe_packaged(volume, KERNEL_PATH, O_RDONLY); 835af32e75SAxel Dörfler if (fd < B_OK) 845af32e75SAxel Dörfler return fd; 855af32e75SAxel Dörfler 865af32e75SAxel Dörfler dprintf("load kernel...\n"); 875af32e75SAxel Dörfler 885e972c0fSFredrik Holmqvist elf_init(); 895af32e75SAxel Dörfler status_t status = elf_load_image(fd, &gKernelArgs.kernel_image); 905af32e75SAxel Dörfler 915af32e75SAxel Dörfler close(fd); 925af32e75SAxel Dörfler 935af32e75SAxel Dörfler if (status < B_OK) { 94957a1b17SIngo Weinhold dprintf("loading kernel failed: %lx!\n", status); 95957a1b17SIngo Weinhold return status; 96957a1b17SIngo Weinhold } 97957a1b17SIngo Weinhold 98957a1b17SIngo Weinhold status = elf_relocate_image(&gKernelArgs.kernel_image); 99957a1b17SIngo Weinhold if (status < B_OK) { 100957a1b17SIngo Weinhold dprintf("relocating kernel failed: %lx!\n", status); 1015af32e75SAxel Dörfler return status; 1025af32e75SAxel Dörfler } 1035af32e75SAxel Dörfler 1041cd8c4ccSIngo Weinhold gKernelArgs.kernel_image.name = kernel_args_strdup(KERNEL_IMAGE); 1051cd8c4ccSIngo Weinhold 1065af32e75SAxel Dörfler return B_OK; 1075af32e75SAxel Dörfler } 1085af32e75SAxel Dörfler 1095af32e75SAxel Dörfler 1105af32e75SAxel Dörfler static status_t 111*d11ea2b5SIngo Weinhold load_modules_from(BootVolume& volume, const char* path) 1125af32e75SAxel Dörfler { 1135af32e75SAxel Dörfler // we don't have readdir() & co. (yet?)... 1145af32e75SAxel Dörfler 115*d11ea2b5SIngo Weinhold int fd = open_maybe_packaged(volume, path, O_RDONLY); 1165af32e75SAxel Dörfler if (fd < B_OK) 1175af32e75SAxel Dörfler return fd; 1185af32e75SAxel Dörfler 1195af32e75SAxel Dörfler Directory *modules = (Directory *)get_node_from(fd); 1205af32e75SAxel Dörfler if (modules == NULL) 1215af32e75SAxel Dörfler return B_ENTRY_NOT_FOUND; 1225af32e75SAxel Dörfler 1235af32e75SAxel Dörfler void *cookie; 1245af32e75SAxel Dörfler if (modules->Open(&cookie, O_RDONLY) == B_OK) { 1255af32e75SAxel Dörfler char name[B_FILE_NAME_LENGTH]; 1265af32e75SAxel Dörfler while (modules->GetNextEntry(cookie, name, sizeof(name)) == B_OK) { 1275af32e75SAxel Dörfler if (!strcmp(name, ".") || !strcmp(name, "..")) 1285af32e75SAxel Dörfler continue; 1295af32e75SAxel Dörfler 1305af32e75SAxel Dörfler status_t status = elf_load_image(modules, name); 1315af32e75SAxel Dörfler if (status != B_OK) 1325af32e75SAxel Dörfler dprintf("Could not load \"%s\" error %ld\n", name, status); 1335af32e75SAxel Dörfler } 1345af32e75SAxel Dörfler 1355af32e75SAxel Dörfler modules->Close(cookie); 1365af32e75SAxel Dörfler } 1375af32e75SAxel Dörfler 1385af32e75SAxel Dörfler return B_OK; 1395af32e75SAxel Dörfler } 1405af32e75SAxel Dörfler 1415af32e75SAxel Dörfler 1420dc4d1e5SIngo Weinhold /** Loads a module by module name. This basically works in the same 1430dc4d1e5SIngo Weinhold * way as the kernel module loader; it will cut off the last part 1440dc4d1e5SIngo Weinhold * of the module name until it could find a module and loads it. 1450dc4d1e5SIngo Weinhold * It tests both, kernel and user module directories. 1465af32e75SAxel Dörfler */ 1470dc4d1e5SIngo Weinhold 1485af32e75SAxel Dörfler static status_t 149*d11ea2b5SIngo Weinhold load_module(BootVolume& volume, const char* name) 1505af32e75SAxel Dörfler { 1515af32e75SAxel Dörfler char moduleName[B_FILE_NAME_LENGTH]; 1525af32e75SAxel Dörfler if (strlcpy(moduleName, name, sizeof(moduleName)) > sizeof(moduleName)) 1535af32e75SAxel Dörfler return B_NAME_TOO_LONG; 1545af32e75SAxel Dörfler 1555af32e75SAxel Dörfler for (int32 i = 0; sPaths[i]; i++) { 1565af32e75SAxel Dörfler // get base path 157*d11ea2b5SIngo Weinhold int baseFD = open_maybe_packaged(volume, sPaths[i], O_RDONLY); 1585af32e75SAxel Dörfler if (baseFD < B_OK) 1595af32e75SAxel Dörfler continue; 1605af32e75SAxel Dörfler 1615af32e75SAxel Dörfler Directory *base = (Directory *)get_node_from(baseFD); 16261aa1456SIngo Weinhold if (base == NULL) { 16361aa1456SIngo Weinhold close(baseFD); 16461aa1456SIngo Weinhold continue; 16561aa1456SIngo Weinhold } 1665af32e75SAxel Dörfler 1675af32e75SAxel Dörfler while (true) { 1685af32e75SAxel Dörfler int fd = open_from(base, moduleName, O_RDONLY); 1695af32e75SAxel Dörfler if (fd >= B_OK) { 170e3fcb58eSAxel Dörfler struct stat stat; 171e3fcb58eSAxel Dörfler if (fstat(fd, &stat) != 0 || !S_ISREG(stat.st_mode)) 172e3fcb58eSAxel Dörfler return B_BAD_VALUE; 173e3fcb58eSAxel Dörfler 1745af32e75SAxel Dörfler status_t status = elf_load_image(base, moduleName); 1755af32e75SAxel Dörfler 1765af32e75SAxel Dörfler close(fd); 1775af32e75SAxel Dörfler close(baseFD); 1785af32e75SAxel Dörfler return status; 1795af32e75SAxel Dörfler } 1805af32e75SAxel Dörfler 1815af32e75SAxel Dörfler // cut off last name element (or stop trying if there are no more) 1825af32e75SAxel Dörfler 1835af32e75SAxel Dörfler char *last = strrchr(moduleName, '/'); 1845af32e75SAxel Dörfler if (last != NULL) 1855af32e75SAxel Dörfler last[0] = '\0'; 1865af32e75SAxel Dörfler else 1875af32e75SAxel Dörfler break; 1885af32e75SAxel Dörfler } 1895af32e75SAxel Dörfler 1905af32e75SAxel Dörfler close(baseFD); 1915af32e75SAxel Dörfler } 1925af32e75SAxel Dörfler 1935af32e75SAxel Dörfler return B_OK; 1945af32e75SAxel Dörfler } 1955af32e75SAxel Dörfler 1965af32e75SAxel Dörfler 1975af32e75SAxel Dörfler status_t 198*d11ea2b5SIngo Weinhold load_modules(stage2_args* args, BootVolume& volume) 1995af32e75SAxel Dörfler { 200e3fcb58eSAxel Dörfler int32 failed = 0; 201e3fcb58eSAxel Dörfler 202e3fcb58eSAxel Dörfler // ToDo: this should be mostly replaced by a hardware oriented detection mechanism 203e3fcb58eSAxel Dörfler 2043dfd9cb9SOliver Tappe int32 i = 0; 2053dfd9cb9SOliver Tappe for (; sPaths[i]; i++) { 2065af32e75SAxel Dörfler char path[B_FILE_NAME_LENGTH]; 20770fc8240SIngo Weinhold snprintf(path, sizeof(path), "%s/boot", sPaths[i]); 2085af32e75SAxel Dörfler 209e3fcb58eSAxel Dörfler if (load_modules_from(volume, path) != B_OK) 210e3fcb58eSAxel Dörfler failed++; 211e3fcb58eSAxel Dörfler } 212e3fcb58eSAxel Dörfler 2133dfd9cb9SOliver Tappe if (failed == i) { 214e3fcb58eSAxel Dörfler // couldn't load any boot modules 215e3fcb58eSAxel Dörfler // fall back to load all modules (currently needed by the boot floppy) 216e3fcb58eSAxel Dörfler const char *paths[] = { "bus_managers", "busses/ide", "busses/scsi", 217e3fcb58eSAxel Dörfler "generic", "partitioning_systems", "drivers/bin", NULL}; 218e3fcb58eSAxel Dörfler 219e3fcb58eSAxel Dörfler for (int32 i = 0; paths[i]; i++) { 220e3fcb58eSAxel Dörfler char path[B_FILE_NAME_LENGTH]; 22170fc8240SIngo Weinhold snprintf(path, sizeof(path), "%s/%s", sPaths[0], paths[i]); 2225af32e75SAxel Dörfler load_modules_from(volume, path); 2235af32e75SAxel Dörfler } 224e3fcb58eSAxel Dörfler } 2255af32e75SAxel Dörfler 2265af32e75SAxel Dörfler // and now load all partitioning and file system modules 2275af32e75SAxel Dörfler // needed to identify the boot volume 2285af32e75SAxel Dörfler 2299e8dc2a9SIngo Weinhold if (!gKernelArgs.boot_volume.GetBool(BOOT_VOLUME_BOOTED_FROM_IMAGE, 2309e8dc2a9SIngo Weinhold false)) { 231e3fcb58eSAxel Dörfler // iterate over the mounted volumes and load their file system 2325af32e75SAxel Dörfler Partition *partition; 233*d11ea2b5SIngo Weinhold if (gRoot->GetPartitionFor(volume.RootDirectory(), &partition) 234*d11ea2b5SIngo Weinhold == B_OK) { 2355af32e75SAxel Dörfler while (partition != NULL) { 2365af32e75SAxel Dörfler load_module(volume, partition->ModuleName()); 2375af32e75SAxel Dörfler partition = partition->Parent(); 2385af32e75SAxel Dörfler } 2395af32e75SAxel Dörfler } 240e3fcb58eSAxel Dörfler } else { 2418423f6f4SAxel Dörfler // The boot image should only contain the file system 2428423f6f4SAxel Dörfler // needed to boot the system, so we just load it. 2438423f6f4SAxel Dörfler // ToDo: this is separate from the fall back from above 2448423f6f4SAxel Dörfler // as this piece will survive a more intelligent module 2458423f6f4SAxel Dörfler // loading approach... 2468423f6f4SAxel Dörfler char path[B_FILE_NAME_LENGTH]; 24770fc8240SIngo Weinhold snprintf(path, sizeof(path), "%s/%s", sPaths[0], "file_systems"); 2488423f6f4SAxel Dörfler load_modules_from(volume, path); 249e3fcb58eSAxel Dörfler } 2505af32e75SAxel Dörfler 2515af32e75SAxel Dörfler return B_OK; 2525af32e75SAxel Dörfler } 2535af32e75SAxel Dörfler 254