xref: /haiku/src/system/boot/loader/loader.cpp (revision 25a7b01d15612846f332751841da3579db313082)
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"
85af32e75SAxel Dörfler #include "elf.h"
95af32e75SAxel Dörfler #include "RootFileSystem.h"
105af32e75SAxel Dörfler 
113dfd9cb9SOliver Tappe #include <directories.h>
125af32e75SAxel Dörfler #include <OS.h>
135af32e75SAxel Dörfler #include <util/list.h>
145af32e75SAxel Dörfler #include <boot/stage2.h>
155af32e75SAxel Dörfler #include <boot/vfs.h>
165af32e75SAxel Dörfler #include <boot/platform.h>
175af32e75SAxel Dörfler #include <boot/stdio.h>
185af32e75SAxel Dörfler #include <boot/partitions.h>
195af32e75SAxel Dörfler 
205af32e75SAxel Dörfler #include <unistd.h>
215af32e75SAxel Dörfler #include <string.h>
225af32e75SAxel Dörfler 
23*25a7b01dSIngo 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 
487417d5edSAlex Smith static const char *sAddonPaths[] = {
493dfd9cb9SOliver Tappe 	kVolumeLocalSystemKernelAddonsDirectory,
503dfd9cb9SOliver Tappe 	kVolumeLocalCommonNonpackagedKernelAddonsDirectory,
513dfd9cb9SOliver Tappe 	kVolumeLocalCommonKernelAddonsDirectory,
523dfd9cb9SOliver Tappe 	kVolumeLocalUserNonpackagedKernelAddonsDirectory,
533dfd9cb9SOliver Tappe 	kVolumeLocalUserKernelAddonsDirectory,
545af32e75SAxel Dörfler 	NULL
555af32e75SAxel Dörfler };
565af32e75SAxel Dörfler 
575af32e75SAxel Dörfler 
58d11ea2b5SIngo Weinhold static int
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 
71*25a7b01dSIngo Weinhold static int
72*25a7b01dSIngo Weinhold find_kernel(BootVolume& volume, const char** name = NULL)
737417d5edSAlex Smith {
747417d5edSAlex Smith 	for (int32 i = 0; sKernelPaths[i][0] != NULL; i++) {
75*25a7b01dSIngo 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 
87*25a7b01dSIngo Weinhold 
885af32e75SAxel Dörfler bool
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)
99*25a7b01dSIngo 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
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) {
126957a1b17SIngo Weinhold 		dprintf("loading kernel failed: %lx!\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) {
134957a1b17SIngo Weinhold 		dprintf("relocating kernel failed: %lx!\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
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)
1665af32e75SAxel Dörfler 				dprintf("Could not load \"%s\" error %ld\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 
1760dc4d1e5SIngo Weinhold /** Loads a module by module name. This basically works in the same
1770dc4d1e5SIngo Weinhold  *	way as the kernel module loader; it will cut off the last part
1780dc4d1e5SIngo Weinhold  *	of the module name until it could find a module and loads it.
1790dc4d1e5SIngo Weinhold  *	It tests both, kernel and user module directories.
1805af32e75SAxel Dörfler  */
1810dc4d1e5SIngo Weinhold 
1825af32e75SAxel Dörfler static status_t
183d11ea2b5SIngo Weinhold load_module(BootVolume& volume, const char* name)
1845af32e75SAxel Dörfler {
1855af32e75SAxel Dörfler 	char moduleName[B_FILE_NAME_LENGTH];
1865af32e75SAxel Dörfler 	if (strlcpy(moduleName, name, sizeof(moduleName)) > sizeof(moduleName))
1875af32e75SAxel Dörfler 		return B_NAME_TOO_LONG;
1885af32e75SAxel Dörfler 
1897417d5edSAlex Smith 	for (int32 i = 0; sAddonPaths[i]; i++) {
1905af32e75SAxel Dörfler 		// get base path
191*25a7b01dSIngo Weinhold 		int baseFD = open_maybe_packaged(volume, sAddonPaths[i], O_RDONLY);
1925af32e75SAxel Dörfler 		if (baseFD < B_OK)
1935af32e75SAxel Dörfler 			continue;
1945af32e75SAxel Dörfler 
1955af32e75SAxel Dörfler 		Directory *base = (Directory *)get_node_from(baseFD);
19661aa1456SIngo Weinhold 		if (base == NULL) {
19761aa1456SIngo Weinhold 			close(baseFD);
19861aa1456SIngo Weinhold 			continue;
19961aa1456SIngo Weinhold 		}
2005af32e75SAxel Dörfler 
2015af32e75SAxel Dörfler 		while (true) {
2025af32e75SAxel Dörfler 			int fd = open_from(base, moduleName, O_RDONLY);
2035af32e75SAxel Dörfler 			if (fd >= B_OK) {
204e3fcb58eSAxel Dörfler 				struct stat stat;
205e3fcb58eSAxel Dörfler 				if (fstat(fd, &stat) != 0 || !S_ISREG(stat.st_mode))
206e3fcb58eSAxel Dörfler 					return B_BAD_VALUE;
207e3fcb58eSAxel Dörfler 
2085af32e75SAxel Dörfler 				status_t status = elf_load_image(base, moduleName);
2095af32e75SAxel Dörfler 
2105af32e75SAxel Dörfler 				close(fd);
2115af32e75SAxel Dörfler 				close(baseFD);
2125af32e75SAxel Dörfler 				return status;
2135af32e75SAxel Dörfler 			}
2145af32e75SAxel Dörfler 
2155af32e75SAxel Dörfler 			// cut off last name element (or stop trying if there are no more)
2165af32e75SAxel Dörfler 
2175af32e75SAxel Dörfler 			char *last = strrchr(moduleName, '/');
2185af32e75SAxel Dörfler 			if (last != NULL)
2195af32e75SAxel Dörfler 				last[0] = '\0';
2205af32e75SAxel Dörfler 			else
2215af32e75SAxel Dörfler 				break;
2225af32e75SAxel Dörfler 		}
2235af32e75SAxel Dörfler 
2245af32e75SAxel Dörfler 		close(baseFD);
2255af32e75SAxel Dörfler 	}
2265af32e75SAxel Dörfler 
2275af32e75SAxel Dörfler 	return B_OK;
2285af32e75SAxel Dörfler }
2295af32e75SAxel Dörfler 
2305af32e75SAxel Dörfler 
2315af32e75SAxel Dörfler status_t
232d11ea2b5SIngo Weinhold load_modules(stage2_args* args, BootVolume& volume)
2335af32e75SAxel Dörfler {
234e3fcb58eSAxel Dörfler 	int32 failed = 0;
235e3fcb58eSAxel Dörfler 
236e3fcb58eSAxel Dörfler 	// ToDo: this should be mostly replaced by a hardware oriented detection mechanism
237e3fcb58eSAxel Dörfler 
2383dfd9cb9SOliver Tappe 	int32 i = 0;
2397417d5edSAlex Smith 	for (; sAddonPaths[i]; i++) {
2405af32e75SAxel Dörfler 		char path[B_FILE_NAME_LENGTH];
2417417d5edSAlex Smith 		snprintf(path, sizeof(path), "%s/boot", sAddonPaths[i]);
2425af32e75SAxel Dörfler 
243e3fcb58eSAxel Dörfler 		if (load_modules_from(volume, path) != B_OK)
244e3fcb58eSAxel Dörfler 			failed++;
245e3fcb58eSAxel Dörfler 	}
246e3fcb58eSAxel Dörfler 
2473dfd9cb9SOliver Tappe 	if (failed == i) {
248e3fcb58eSAxel Dörfler 		// couldn't load any boot modules
249e3fcb58eSAxel Dörfler 		// fall back to load all modules (currently needed by the boot floppy)
250e3fcb58eSAxel Dörfler 		const char *paths[] = { "bus_managers", "busses/ide", "busses/scsi",
251e3fcb58eSAxel Dörfler 			"generic", "partitioning_systems", "drivers/bin", NULL};
252e3fcb58eSAxel Dörfler 
253e3fcb58eSAxel Dörfler 		for (int32 i = 0; paths[i]; i++) {
254e3fcb58eSAxel Dörfler 			char path[B_FILE_NAME_LENGTH];
2557417d5edSAlex Smith 			snprintf(path, sizeof(path), "%s/%s", sAddonPaths[0], paths[i]);
2565af32e75SAxel Dörfler 			load_modules_from(volume, path);
2575af32e75SAxel Dörfler 		}
258e3fcb58eSAxel Dörfler 	}
2595af32e75SAxel Dörfler 
2605af32e75SAxel Dörfler 	// and now load all partitioning and file system modules
2615af32e75SAxel Dörfler 	// needed to identify the boot volume
2625af32e75SAxel Dörfler 
26393cb9538SAlex Smith 	if (!gBootVolume.GetBool(BOOT_VOLUME_BOOTED_FROM_IMAGE, false)) {
264e3fcb58eSAxel Dörfler 		// iterate over the mounted volumes and load their file system
2655af32e75SAxel Dörfler 		Partition *partition;
266d11ea2b5SIngo Weinhold 		if (gRoot->GetPartitionFor(volume.RootDirectory(), &partition)
267d11ea2b5SIngo Weinhold 				== B_OK) {
2685af32e75SAxel Dörfler 			while (partition != NULL) {
2695af32e75SAxel Dörfler 				load_module(volume, partition->ModuleName());
2705af32e75SAxel Dörfler 				partition = partition->Parent();
2715af32e75SAxel Dörfler 			}
2725af32e75SAxel Dörfler 		}
273e3fcb58eSAxel Dörfler 	} else {
2748423f6f4SAxel Dörfler 		// The boot image should only contain the file system
2758423f6f4SAxel Dörfler 		// needed to boot the system, so we just load it.
2768423f6f4SAxel Dörfler 		// ToDo: this is separate from the fall back from above
2778423f6f4SAxel Dörfler 		//	as this piece will survive a more intelligent module
2788423f6f4SAxel Dörfler 		//	loading approach...
2798423f6f4SAxel Dörfler 		char path[B_FILE_NAME_LENGTH];
2807417d5edSAlex Smith 		snprintf(path, sizeof(path), "%s/%s", sAddonPaths[0], "file_systems");
2818423f6f4SAxel Dörfler 		load_modules_from(volume, path);
282e3fcb58eSAxel Dörfler 	}
2835af32e75SAxel Dörfler 
2845af32e75SAxel Dörfler 	return B_OK;
2855af32e75SAxel Dörfler }
2865af32e75SAxel Dörfler 
287