* 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 <directories.h>
#include <OS.h>
#include <util/list.h>
#include <boot/stage2.h>
#include <boot/vfs.h>
#include <boot/platform.h>
#include <boot/stdio.h>
#include <boot/partitions.h>
#include <unistd.h>
#include <string.h>
#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;
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)
{
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;
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) {
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);
}
}
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;
}