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
58*11f8b65aSJérôme Duval int
open_maybe_packaged(BootVolume & volume,const char * path,int openMode)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
find_kernel(BootVolume & volume,const char ** name=NULL)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
is_bootable(Directory * volume)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
load_kernel(stage2_args * args,BootVolume & volume)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
load_modules_from(BootVolume & volume,const char * path)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
1765af32e75SAxel Dörfler status_t
load_modules(stage2_args * args,BootVolume & volume)177d11ea2b5SIngo Weinhold load_modules(stage2_args* args, BootVolume& volume)
1785af32e75SAxel Dörfler {
179e3fcb58eSAxel Dörfler int32 failed = 0;
180e3fcb58eSAxel Dörfler
1810f009937SJessica Hamilton // ToDo: this should be mostly replaced by a hardware oriented detection mechanism
182e3fcb58eSAxel Dörfler
1833dfd9cb9SOliver Tappe int32 i = 0;
1847417d5edSAlex Smith for (; sAddonPaths[i]; i++) {
1855af32e75SAxel Dörfler char path[B_FILE_NAME_LENGTH];
1867417d5edSAlex Smith snprintf(path, sizeof(path), "%s/boot", sAddonPaths[i]);
1875af32e75SAxel Dörfler
188e3fcb58eSAxel Dörfler if (load_modules_from(volume, path) != B_OK)
189e3fcb58eSAxel Dörfler failed++;
190e3fcb58eSAxel Dörfler }
191e3fcb58eSAxel Dörfler
1923dfd9cb9SOliver Tappe if (failed == i) {
193e3fcb58eSAxel Dörfler // couldn't load any boot modules
194e3fcb58eSAxel Dörfler // fall back to load all modules (currently needed by the boot floppy)
195e3fcb58eSAxel Dörfler const char *paths[] = { "bus_managers", "busses/ide", "busses/scsi",
196e3fcb58eSAxel Dörfler "generic", "partitioning_systems", "drivers/bin", NULL};
197e3fcb58eSAxel Dörfler
198e3fcb58eSAxel Dörfler for (int32 i = 0; paths[i]; i++) {
199e3fcb58eSAxel Dörfler char path[B_FILE_NAME_LENGTH];
2007417d5edSAlex Smith snprintf(path, sizeof(path), "%s/%s", sAddonPaths[0], paths[i]);
2015af32e75SAxel Dörfler load_modules_from(volume, path);
2025af32e75SAxel Dörfler }
203e3fcb58eSAxel Dörfler }
2045af32e75SAxel Dörfler
2055af32e75SAxel Dörfler // and now load all partitioning and file system modules
2068423f6f4SAxel Dörfler char path[B_FILE_NAME_LENGTH];
2077417d5edSAlex Smith snprintf(path, sizeof(path), "%s/%s", sAddonPaths[0], "file_systems");
2088423f6f4SAxel Dörfler load_modules_from(volume, path);
209bab060e9SJessica Hamilton snprintf(path, sizeof(path), "%s/%s", sAddonPaths[0], "partitioning_systems");
210bab060e9SJessica Hamilton load_modules_from(volume, path);
2115af32e75SAxel Dörfler
2125af32e75SAxel Dörfler return B_OK;
2135af32e75SAxel Dörfler }
214