/* * Copyright 2003-2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ #include "loader.h" #include "elf.h" #include "RootFileSystem.h" #include #include #include #include #include #include #include #include #include #include #ifndef BOOT_ARCH # error BOOT_ARCH has to be defined to differentiate the kernel per platform #endif #define SYSTEM_DIRECTORY_PREFIX "system/" #define KERNEL_IMAGE "kernel_" BOOT_ARCH #define KERNEL_PATH SYSTEM_DIRECTORY_PREFIX KERNEL_IMAGE #ifdef ALTERNATE_BOOT_ARCH # define ALTERNATE_KERNEL_IMAGE "kernel_" ALTERNATE_BOOT_ARCH # define ALTERNATE_KERNEL_PATH "system/" ALTERNATE_KERNEL_IMAGE #endif static const char* const kSystemDirectoryPrefix = SYSTEM_DIRECTORY_PREFIX; static const char *sKernelPaths[][2] = { { KERNEL_PATH, KERNEL_IMAGE }, #ifdef ALTERNATE_BOOT_ARCH { ALTERNATE_KERNEL_PATH, ALTERNATE_KERNEL_IMAGE }, #endif { NULL, NULL }, }; static const char *sAddonPaths[] = { kVolumeLocalSystemKernelAddonsDirectory, kVolumeLocalCommonNonpackagedKernelAddonsDirectory, kVolumeLocalCommonKernelAddonsDirectory, kVolumeLocalUserNonpackagedKernelAddonsDirectory, kVolumeLocalUserKernelAddonsDirectory, NULL }; int open_maybe_packaged(BootVolume& volume, const char* path, int openMode) { if (strncmp(path, kSystemDirectoryPrefix, strlen(kSystemDirectoryPrefix)) == 0) { path += strlen(kSystemDirectoryPrefix); return open_from(volume.SystemDirectory(), path, openMode); } return open_from(volume.RootDirectory(), path, openMode); } static int find_kernel(BootVolume& volume, const char** name = NULL) { for (int32 i = 0; sKernelPaths[i][0] != NULL; i++) { int fd = open_maybe_packaged(volume, sKernelPaths[i][0], O_RDONLY); if (fd >= 0) { if (name) *name = sKernelPaths[i][1]; return fd; } } return B_ENTRY_NOT_FOUND; } bool is_bootable(Directory *volume) { if (volume->IsEmpty()) return false; BootVolume bootVolume; if (bootVolume.SetTo(volume) != B_OK) return false; // check for the existance of a kernel (for our platform) int fd = find_kernel(bootVolume); if (fd < 0) return false; close(fd); return true; } status_t load_kernel(stage2_args* args, BootVolume& volume) { const char *name; int fd = find_kernel(volume, &name); if (fd < B_OK) return fd; dprintf("load kernel %s...\n", name); elf_init(); preloaded_image *image; status_t status = elf_load_image(fd, &image); close(fd); if (status < B_OK) { dprintf("loading kernel failed: %" B_PRIx32 "!\n", status); return status; } gKernelArgs.kernel_image = image; status = elf_relocate_image(gKernelArgs.kernel_image); if (status < B_OK) { dprintf("relocating kernel failed: %" B_PRIx32 "!\n", status); return status; } gKernelArgs.kernel_image->name = kernel_args_strdup(name); return B_OK; } static status_t load_modules_from(BootVolume& volume, const char* path) { // we don't have readdir() & co. (yet?)... int fd = open_maybe_packaged(volume, path, O_RDONLY); if (fd < B_OK) return fd; Directory *modules = (Directory *)get_node_from(fd); if (modules == NULL) return B_ENTRY_NOT_FOUND; void *cookie; if (modules->Open(&cookie, O_RDONLY) == B_OK) { char name[B_FILE_NAME_LENGTH]; while (modules->GetNextEntry(cookie, name, sizeof(name)) == B_OK) { if (!strcmp(name, ".") || !strcmp(name, "..")) continue; status_t status = elf_load_image(modules, name); if (status != B_OK) dprintf("Could not load \"%s\" error %" B_PRIx32 "\n", name, status); } modules->Close(cookie); } return B_OK; } status_t load_modules(stage2_args* args, BootVolume& volume) { int32 failed = 0; // ToDo: this should be mostly replaced by a hardware oriented detection mechanism int32 i = 0; for (; sAddonPaths[i]; i++) { char path[B_FILE_NAME_LENGTH]; snprintf(path, sizeof(path), "%s/boot", sAddonPaths[i]); if (load_modules_from(volume, path) != B_OK) failed++; } if (failed == i) { // couldn't load any boot modules // fall back to load all modules (currently needed by the boot floppy) const char *paths[] = { "bus_managers", "busses/ide", "busses/scsi", "generic", "partitioning_systems", "drivers/bin", NULL}; for (int32 i = 0; paths[i]; i++) { char path[B_FILE_NAME_LENGTH]; snprintf(path, sizeof(path), "%s/%s", sAddonPaths[0], paths[i]); load_modules_from(volume, path); } } // and now load all partitioning and file system modules char path[B_FILE_NAME_LENGTH]; snprintf(path, sizeof(path), "%s/%s", sAddonPaths[0], "file_systems"); load_modules_from(volume, path); snprintf(path, sizeof(path), "%s/%s", sAddonPaths[0], "partitioning_systems"); load_modules_from(volume, path); return B_OK; }