16072286aSAxel Dörfler/*
2317bd7ddSAxel Dörfler * Copyright 2003-2009, Axel D��rfler, axeld@pinc-software.de.
3925f2cabSAxel Dörfler * Distributed under the terms of the MIT License.
4925f2cabSAxel Dörfler */
56072286aSAxel Dörfler
66072286aSAxel Dörfler
76072286aSAxel Dörfler#include "loader.h"
8ce624c69SJessica Hamilton#include "elf.h"
90f009937SJessica Hamilton#include "RootFileSystem.h"
106072286aSAxel Dörfler
110f009937SJessica Hamilton#include <directories.h>
126072286aSAxel Dörfler#include <OS.h>
130f009937SJessica Hamilton#include <util/list.h>
14ce624c69SJessica Hamilton#include <boot/stage2.h>
15ce624c69SJessica Hamilton#include <boot/vfs.h>
160f009937SJessica Hamilton#include <boot/platform.h>
170f009937SJessica Hamilton#include <boot/stdio.h>
180f009937SJessica Hamilton#include <boot/partitions.h>
196072286aSAxel Dörfler
20ce624c69SJessica Hamilton#include <unistd.h>
210f009937SJessica Hamilton#include <string.h>
226072286aSAxel Dörfler
2325a7b01dSIngo Weinhold
246072286aSAxel Dörfler#ifndef BOOT_ARCH
250f009937SJessica Hamilton#	error BOOT_ARCH has to be defined to differentiate the kernel per platform
266072286aSAxel Dörfler#endif
276072286aSAxel Dörfler
280f009937SJessica Hamilton#define SYSTEM_DIRECTORY_PREFIX	"system/"
290f009937SJessica Hamilton#define KERNEL_IMAGE	"kernel_" BOOT_ARCH
300f009937SJessica Hamilton#define KERNEL_PATH		SYSTEM_DIRECTORY_PREFIX KERNEL_IMAGE
31d11ea2b5SIngo Weinhold
327417d5edSAlex Smith#ifdef ALTERNATE_BOOT_ARCH
330f009937SJessica Hamilton# define ALTERNATE_KERNEL_IMAGE	"kernel_" ALTERNATE_BOOT_ARCH
340f009937SJessica Hamilton# define ALTERNATE_KERNEL_PATH	"system/" ALTERNATE_KERNEL_IMAGE
357417d5edSAlex Smith#endif
367417d5edSAlex Smith
37d11ea2b5SIngo Weinhold
38d11ea2b5SIngo Weinholdstatic const char* const kSystemDirectoryPrefix = SYSTEM_DIRECTORY_PREFIX;
396072286aSAxel Dörfler
400f009937SJessica Hamiltonstatic const char *sKernelPaths[][2] = {
410f009937SJessica Hamilton	{ KERNEL_PATH, KERNEL_IMAGE },
427417d5edSAlex Smith#ifdef ALTERNATE_BOOT_ARCH
430f009937SJessica Hamilton	{ ALTERNATE_KERNEL_PATH, ALTERNATE_KERNEL_IMAGE },
447417d5edSAlex Smith#endif
450f009937SJessica Hamilton	{ NULL, NULL },
467417d5edSAlex Smith};
476072286aSAxel Dörfler
480f009937SJessica Hamiltonstatic const char *sAddonPaths[] = {
490f009937SJessica Hamilton	kVolumeLocalSystemKernelAddonsDirectory,
503dfd9cb9SOliver Tappe	kVolumeLocalCommonNonpackagedKernelAddonsDirectory,
513dfd9cb9SOliver Tappe	kVolumeLocalCommonKernelAddonsDirectory,
523dfd9cb9SOliver Tappe	kVolumeLocalUserNonpackagedKernelAddonsDirectory,
530f009937SJessica Hamilton	kVolumeLocalUserKernelAddonsDirectory,
540f009937SJessica Hamilton	NULL
550f009937SJessica Hamilton};
56a1b4720eSAxel Dörfler
57a1b4720eSAxel Dörfler
5811f8b65aSJérôme Duvalint
59d11ea2b5SIngo Weinholdopen_maybe_packaged(BootVolume& volume, const char* path, int openMode)
60d11ea2b5SIngo Weinhold{
61d11ea2b5SIngo Weinhold	if (strncmp(path, kSystemDirectoryPrefix, strlen(kSystemDirectoryPrefix))
620f009937SJessica Hamilton			== 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 Weinholdstatic int
7225a7b01dSIngo Weinholdfind_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
886072286aSAxel Dörflerbool
890f009937SJessica Hamiltonis_bootable(Directory *volume)
906072286aSAxel Dörfler{
916072286aSAxel Dörfler	if (volume->IsEmpty())
926072286aSAxel Dörfler		return false;
936072286aSAxel Dörfler
94d11ea2b5SIngo Weinhold	BootVolume bootVolume;
95d11ea2b5SIngo Weinhold	if (bootVolume.SetTo(volume) != B_OK)
96d11ea2b5SIngo Weinhold		return false;
97d11ea2b5SIngo Weinhold
986072286aSAxel Dörfler	// check for the existance of a kernel (for our platform)
9925a7b01dSIngo Weinhold	int fd = find_kernel(bootVolume);
100d11ea2b5SIngo Weinhold	if (fd < 0)
1016072286aSAxel Dörfler		return false;
1026072286aSAxel Dörfler
1036072286aSAxel Dörfler	close(fd);
1046072286aSAxel Dörfler
1056072286aSAxel Dörfler	return true;
1066072286aSAxel Dörfler}
1076072286aSAxel Dörfler
1086072286aSAxel Dörfler
1091cd8c4ccSIngo Weinholdstatus_t
110d11ea2b5SIngo Weinholdload_kernel(stage2_args* args, BootVolume& volume)
1116072286aSAxel Dörfler{
1120f009937SJessica Hamilton	const char *name;
1137417d5edSAlex Smith	int fd = find_kernel(volume, &name);
114384be729SAxel Dörfler	if (fd < B_OK)
115384be729SAxel Dörfler		return fd;
1166072286aSAxel Dörfler
1177417d5edSAlex Smith	dprintf("load kernel %s...\n", name);
1186072286aSAxel Dörfler
1195e972c0fSFredrik Holmqvist	elf_init();
1200f009937SJessica Hamilton	preloaded_image *image;
121f1244978SAlex Smith	status_t status = elf_load_image(fd, &image);
1226072286aSAxel Dörfler
123384be729SAxel Dörfler	close(fd);
124384be729SAxel Dörfler
125a7210984SAxel 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);
135384be729SAxel Dörfler		return status;
136a7210984SAxel Dörfler	}
137384be729SAxel Dörfler
138f1244978SAlex Smith	gKernelArgs.kernel_image->name = kernel_args_strdup(name);
1391cd8c4ccSIngo Weinhold
1406072286aSAxel Dörfler	return B_OK;
1416072286aSAxel Dörfler}
1426072286aSAxel Dörfler
1436072286aSAxel Dörfler
144d15df01cSAxel Dörflerstatic status_t
145d11ea2b5SIngo Weinholdload_modules_from(BootVolume& volume, const char* path)
1466072286aSAxel Dörfler{
147dc4eb9dbSAxel Dörfler	// we don't have readdir() & co. (yet?)...
148384be729SAxel Dörfler
149d11ea2b5SIngo Weinhold	int fd = open_maybe_packaged(volume, path, O_RDONLY);
150384be729SAxel Dörfler	if (fd < B_OK)
151384be729SAxel Dörfler		return fd;
152384be729SAxel Dörfler
1530f009937SJessica Hamilton	Directory *modules = (Directory *)get_node_from(fd);
154384be729SAxel Dörfler	if (modules == NULL)
155384be729SAxel Dörfler		return B_ENTRY_NOT_FOUND;
156384be729SAxel Dörfler
1570f009937SJessica Hamilton	void *cookie;
158384be729SAxel Dörfler	if (modules->Open(&cookie, O_RDONLY) == B_OK) {
159384be729SAxel Dörfler		char name[B_FILE_NAME_LENGTH];
160d15df01cSAxel Dörfler		while (modules->GetNextEntry(cookie, name, sizeof(name)) == B_OK) {
161d15df01cSAxel Dörfler			if (!strcmp(name, ".") || !strcmp(name, ".."))
162d15df01cSAxel Dörfler				continue;
163d15df01cSAxel Dörfler
164d15df01cSAxel Dörfler			status_t status = elf_load_image(modules, name);
165d15df01cSAxel Dörfler			if (status != B_OK)
1660f009937SJessica Hamilton				dprintf("Could not load \"%s\" error %" B_PRIx32 "\n", name, status);
167d15df01cSAxel Dörfler		}
168384be729SAxel Dörfler
169384be729SAxel Dörfler		modules->Close(cookie);
170384be729SAxel Dörfler	}
171384be729SAxel Dörfler
1726072286aSAxel Dörfler	return B_OK;
1736072286aSAxel Dörfler}
1746072286aSAxel Dörfler
175d15df01cSAxel Dörfler
1761cd8c4ccSIngo Weinholdstatus_t
177d11ea2b5SIngo Weinholdload_modules(stage2_args* args, BootVolume& volume)
178d15df01cSAxel 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++) {
185a1b4720eSAxel Dörfler		char path[B_FILE_NAME_LENGTH];
1867417d5edSAlex Smith		snprintf(path, sizeof(path), "%s/boot", sAddonPaths[i]);
187a1b4720eSAxel 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)
1950f009937SJessica Hamilton		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]);
201e3fcb58eSAxel Dörfler			load_modules_from(volume, path);
202e3fcb58eSAxel Dörfler		}
203a1b4720eSAxel Dörfler	}
204a1b4720eSAxel Dörfler
205a1b4720eSAxel Dörfler	// and now load all partitioning and file system modules
206bab060e9SJessica Hamilton	char path[B_FILE_NAME_LENGTH];
207bab060e9SJessica Hamilton	snprintf(path, sizeof(path), "%s/%s", sAddonPaths[0], "file_systems");
208bab060e9SJessica Hamilton	load_modules_from(volume, path);
209bab060e9SJessica Hamilton	snprintf(path, sizeof(path), "%s/%s", sAddonPaths[0], "partitioning_systems");
210bab060e9SJessica Hamilton	load_modules_from(volume, path);
211d15df01cSAxel Dörfler
212d15df01cSAxel Dörfler	return B_OK;
213d15df01cSAxel Dörfler}
214