1/*
2 * Copyright 2003-2009, Axel D��rfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "loader.h"
8#include "elf.h"
9#include "RootFileSystem.h"
10
11#include <directories.h>
12#include <OS.h>
13#include <util/list.h>
14#include <boot/stage2.h>
15#include <boot/vfs.h>
16#include <boot/platform.h>
17#include <boot/stdio.h>
18#include <boot/partitions.h>
19
20#include <unistd.h>
21#include <string.h>
22
23
24#ifndef BOOT_ARCH
25#	error BOOT_ARCH has to be defined to differentiate the kernel per platform
26#endif
27
28#define SYSTEM_DIRECTORY_PREFIX	"system/"
29#define KERNEL_IMAGE	"kernel_" BOOT_ARCH
30#define KERNEL_PATH		SYSTEM_DIRECTORY_PREFIX KERNEL_IMAGE
31
32#ifdef ALTERNATE_BOOT_ARCH
33# define ALTERNATE_KERNEL_IMAGE	"kernel_" ALTERNATE_BOOT_ARCH
34# define ALTERNATE_KERNEL_PATH	"system/" ALTERNATE_KERNEL_IMAGE
35#endif
36
37
38static const char* const kSystemDirectoryPrefix = SYSTEM_DIRECTORY_PREFIX;
39
40static const char *sKernelPaths[][2] = {
41	{ KERNEL_PATH, KERNEL_IMAGE },
42#ifdef ALTERNATE_BOOT_ARCH
43	{ ALTERNATE_KERNEL_PATH, ALTERNATE_KERNEL_IMAGE },
44#endif
45	{ NULL, NULL },
46};
47
48static const char *sAddonPaths[] = {
49	kVolumeLocalSystemKernelAddonsDirectory,
50	kVolumeLocalCommonNonpackagedKernelAddonsDirectory,
51	kVolumeLocalCommonKernelAddonsDirectory,
52	kVolumeLocalUserNonpackagedKernelAddonsDirectory,
53	kVolumeLocalUserKernelAddonsDirectory,
54	NULL
55};
56
57
58int
59open_maybe_packaged(BootVolume& volume, const char* path, int openMode)
60{
61	if (strncmp(path, kSystemDirectoryPrefix, strlen(kSystemDirectoryPrefix))
62			== 0) {
63		path += strlen(kSystemDirectoryPrefix);
64		return open_from(volume.SystemDirectory(), path, openMode);
65	}
66
67	return open_from(volume.RootDirectory(), path, openMode);
68}
69
70
71static int
72find_kernel(BootVolume& volume, const char** name = NULL)
73{
74	for (int32 i = 0; sKernelPaths[i][0] != NULL; i++) {
75		int fd = open_maybe_packaged(volume, sKernelPaths[i][0], O_RDONLY);
76		if (fd >= 0) {
77			if (name)
78				*name = sKernelPaths[i][1];
79
80			return fd;
81		}
82	}
83
84	return B_ENTRY_NOT_FOUND;
85}
86
87
88bool
89is_bootable(Directory *volume)
90{
91	if (volume->IsEmpty())
92		return false;
93
94	BootVolume bootVolume;
95	if (bootVolume.SetTo(volume) != B_OK)
96		return false;
97
98	// check for the existance of a kernel (for our platform)
99	int fd = find_kernel(bootVolume);
100	if (fd < 0)
101		return false;
102
103	close(fd);
104
105	return true;
106}
107
108
109status_t
110load_kernel(stage2_args* args, BootVolume& volume)
111{
112	const char *name;
113	int fd = find_kernel(volume, &name);
114	if (fd < B_OK)
115		return fd;
116
117	dprintf("load kernel %s...\n", name);
118
119	elf_init();
120	preloaded_image *image;
121	status_t status = elf_load_image(fd, &image);
122
123	close(fd);
124
125	if (status < B_OK) {
126		dprintf("loading kernel failed: %" B_PRIx32 "!\n", status);
127		return status;
128	}
129
130	gKernelArgs.kernel_image = image;
131
132	status = elf_relocate_image(gKernelArgs.kernel_image);
133	if (status < B_OK) {
134		dprintf("relocating kernel failed: %" B_PRIx32 "!\n", status);
135		return status;
136	}
137
138	gKernelArgs.kernel_image->name = kernel_args_strdup(name);
139
140	return B_OK;
141}
142
143
144static status_t
145load_modules_from(BootVolume& volume, const char* path)
146{
147	// we don't have readdir() & co. (yet?)...
148
149	int fd = open_maybe_packaged(volume, path, O_RDONLY);
150	if (fd < B_OK)
151		return fd;
152
153	Directory *modules = (Directory *)get_node_from(fd);
154	if (modules == NULL)
155		return B_ENTRY_NOT_FOUND;
156
157	void *cookie;
158	if (modules->Open(&cookie, O_RDONLY) == B_OK) {
159		char name[B_FILE_NAME_LENGTH];
160		while (modules->GetNextEntry(cookie, name, sizeof(name)) == B_OK) {
161			if (!strcmp(name, ".") || !strcmp(name, ".."))
162				continue;
163
164			status_t status = elf_load_image(modules, name);
165			if (status != B_OK)
166				dprintf("Could not load \"%s\" error %" B_PRIx32 "\n", name, status);
167		}
168
169		modules->Close(cookie);
170	}
171
172	return B_OK;
173}
174
175
176status_t
177load_modules(stage2_args* args, BootVolume& volume)
178{
179	int32 failed = 0;
180
181	// ToDo: this should be mostly replaced by a hardware oriented detection mechanism
182
183	int32 i = 0;
184	for (; sAddonPaths[i]; i++) {
185		char path[B_FILE_NAME_LENGTH];
186		snprintf(path, sizeof(path), "%s/boot", sAddonPaths[i]);
187
188		if (load_modules_from(volume, path) != B_OK)
189			failed++;
190	}
191
192	if (failed == i) {
193		// couldn't load any boot modules
194		// fall back to load all modules (currently needed by the boot floppy)
195		const char *paths[] = { "bus_managers", "busses/ide", "busses/scsi",
196			"generic", "partitioning_systems", "drivers/bin", NULL};
197
198		for (int32 i = 0; paths[i]; i++) {
199			char path[B_FILE_NAME_LENGTH];
200			snprintf(path, sizeof(path), "%s/%s", sAddonPaths[0], paths[i]);
201			load_modules_from(volume, path);
202		}
203	}
204
205	// and now load all partitioning and file system modules
206	char path[B_FILE_NAME_LENGTH];
207	snprintf(path, sizeof(path), "%s/%s", sAddonPaths[0], "file_systems");
208	load_modules_from(volume, path);
209	snprintf(path, sizeof(path), "%s/%s", sAddonPaths[0], "partitioning_systems");
210	load_modules_from(volume, path);
211
212	return B_OK;
213}
214