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