xref: /haiku/src/system/boot/loader/loader.cpp (revision d11ea2b5edf78d1018b1149a57a593af50687920)
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 
235af32e75SAxel Dörfler #ifndef BOOT_ARCH
245af32e75SAxel Dörfler #	error BOOT_ARCH has to be defined to differentiate the kernel per platform
255af32e75SAxel Dörfler #endif
265af32e75SAxel Dörfler 
27*d11ea2b5SIngo Weinhold #define SYSTEM_DIRECTORY_PREFIX	"system/"
285af32e75SAxel Dörfler #define KERNEL_IMAGE	"kernel_" BOOT_ARCH
29*d11ea2b5SIngo Weinhold #define KERNEL_PATH		SYSTEM_DIRECTORY_PREFIX KERNEL_IMAGE
30*d11ea2b5SIngo Weinhold 
31*d11ea2b5SIngo Weinhold 
32*d11ea2b5SIngo Weinhold static const char* const kSystemDirectoryPrefix = SYSTEM_DIRECTORY_PREFIX;
335af32e75SAxel Dörfler 
345af32e75SAxel Dörfler 
355af32e75SAxel Dörfler static const char *sPaths[] = {
363dfd9cb9SOliver Tappe 	kVolumeLocalSystemKernelAddonsDirectory,
373dfd9cb9SOliver Tappe 	kVolumeLocalCommonNonpackagedKernelAddonsDirectory,
383dfd9cb9SOliver Tappe 	kVolumeLocalCommonKernelAddonsDirectory,
393dfd9cb9SOliver Tappe 	kVolumeLocalUserNonpackagedKernelAddonsDirectory,
403dfd9cb9SOliver Tappe 	kVolumeLocalUserKernelAddonsDirectory,
415af32e75SAxel Dörfler 	NULL
425af32e75SAxel Dörfler };
435af32e75SAxel Dörfler 
445af32e75SAxel Dörfler 
45*d11ea2b5SIngo Weinhold static int
46*d11ea2b5SIngo Weinhold open_maybe_packaged(BootVolume& volume, const char* path, int openMode)
47*d11ea2b5SIngo Weinhold {
48*d11ea2b5SIngo Weinhold 	if (strncmp(path, kSystemDirectoryPrefix, strlen(kSystemDirectoryPrefix))
49*d11ea2b5SIngo Weinhold 			== 0) {
50*d11ea2b5SIngo Weinhold 		path += strlen(kSystemDirectoryPrefix);
51*d11ea2b5SIngo Weinhold 		return open_from(volume.SystemDirectory(), path, openMode);
52*d11ea2b5SIngo Weinhold 	}
53*d11ea2b5SIngo Weinhold 
54*d11ea2b5SIngo Weinhold 	return open_from(volume.RootDirectory(), path, openMode);
55*d11ea2b5SIngo Weinhold }
56*d11ea2b5SIngo Weinhold 
57*d11ea2b5SIngo Weinhold 
585af32e75SAxel Dörfler bool
595af32e75SAxel Dörfler is_bootable(Directory *volume)
605af32e75SAxel Dörfler {
615af32e75SAxel Dörfler 	if (volume->IsEmpty())
625af32e75SAxel Dörfler 		return false;
635af32e75SAxel Dörfler 
64*d11ea2b5SIngo Weinhold 	BootVolume bootVolume;
65*d11ea2b5SIngo Weinhold 	if (bootVolume.SetTo(volume) != B_OK)
66*d11ea2b5SIngo Weinhold 		return false;
67*d11ea2b5SIngo Weinhold 
685af32e75SAxel Dörfler 	// check for the existance of a kernel (for our platform)
69*d11ea2b5SIngo Weinhold 	int fd = open_maybe_packaged(bootVolume, KERNEL_PATH, O_RDONLY);
70*d11ea2b5SIngo Weinhold 	if (fd < 0)
715af32e75SAxel Dörfler 		return false;
725af32e75SAxel Dörfler 
735af32e75SAxel Dörfler 	close(fd);
745af32e75SAxel Dörfler 
755af32e75SAxel Dörfler 	return true;
765af32e75SAxel Dörfler }
775af32e75SAxel Dörfler 
785af32e75SAxel Dörfler 
795af32e75SAxel Dörfler status_t
80*d11ea2b5SIngo Weinhold load_kernel(stage2_args* args, BootVolume& volume)
815af32e75SAxel Dörfler {
82*d11ea2b5SIngo Weinhold 	int fd = open_maybe_packaged(volume, KERNEL_PATH, O_RDONLY);
835af32e75SAxel Dörfler 	if (fd < B_OK)
845af32e75SAxel Dörfler 		return fd;
855af32e75SAxel Dörfler 
865af32e75SAxel Dörfler 	dprintf("load kernel...\n");
875af32e75SAxel Dörfler 
885e972c0fSFredrik Holmqvist 	elf_init();
895af32e75SAxel Dörfler 	status_t status = elf_load_image(fd, &gKernelArgs.kernel_image);
905af32e75SAxel Dörfler 
915af32e75SAxel Dörfler 	close(fd);
925af32e75SAxel Dörfler 
935af32e75SAxel Dörfler 	if (status < B_OK) {
94957a1b17SIngo Weinhold 		dprintf("loading kernel failed: %lx!\n", status);
95957a1b17SIngo Weinhold 		return status;
96957a1b17SIngo Weinhold 	}
97957a1b17SIngo Weinhold 
98957a1b17SIngo Weinhold 	status = elf_relocate_image(&gKernelArgs.kernel_image);
99957a1b17SIngo Weinhold 	if (status < B_OK) {
100957a1b17SIngo Weinhold 		dprintf("relocating kernel failed: %lx!\n", status);
1015af32e75SAxel Dörfler 		return status;
1025af32e75SAxel Dörfler 	}
1035af32e75SAxel Dörfler 
1041cd8c4ccSIngo Weinhold 	gKernelArgs.kernel_image.name = kernel_args_strdup(KERNEL_IMAGE);
1051cd8c4ccSIngo Weinhold 
1065af32e75SAxel Dörfler 	return B_OK;
1075af32e75SAxel Dörfler }
1085af32e75SAxel Dörfler 
1095af32e75SAxel Dörfler 
1105af32e75SAxel Dörfler static status_t
111*d11ea2b5SIngo Weinhold load_modules_from(BootVolume& volume, const char* path)
1125af32e75SAxel Dörfler {
1135af32e75SAxel Dörfler 	// we don't have readdir() & co. (yet?)...
1145af32e75SAxel Dörfler 
115*d11ea2b5SIngo Weinhold 	int fd = open_maybe_packaged(volume, path, O_RDONLY);
1165af32e75SAxel Dörfler 	if (fd < B_OK)
1175af32e75SAxel Dörfler 		return fd;
1185af32e75SAxel Dörfler 
1195af32e75SAxel Dörfler 	Directory *modules = (Directory *)get_node_from(fd);
1205af32e75SAxel Dörfler 	if (modules == NULL)
1215af32e75SAxel Dörfler 		return B_ENTRY_NOT_FOUND;
1225af32e75SAxel Dörfler 
1235af32e75SAxel Dörfler 	void *cookie;
1245af32e75SAxel Dörfler 	if (modules->Open(&cookie, O_RDONLY) == B_OK) {
1255af32e75SAxel Dörfler 		char name[B_FILE_NAME_LENGTH];
1265af32e75SAxel Dörfler 		while (modules->GetNextEntry(cookie, name, sizeof(name)) == B_OK) {
1275af32e75SAxel Dörfler 			if (!strcmp(name, ".") || !strcmp(name, ".."))
1285af32e75SAxel Dörfler 				continue;
1295af32e75SAxel Dörfler 
1305af32e75SAxel Dörfler 			status_t status = elf_load_image(modules, name);
1315af32e75SAxel Dörfler 			if (status != B_OK)
1325af32e75SAxel Dörfler 				dprintf("Could not load \"%s\" error %ld\n", name, status);
1335af32e75SAxel Dörfler 		}
1345af32e75SAxel Dörfler 
1355af32e75SAxel Dörfler 		modules->Close(cookie);
1365af32e75SAxel Dörfler 	}
1375af32e75SAxel Dörfler 
1385af32e75SAxel Dörfler 	return B_OK;
1395af32e75SAxel Dörfler }
1405af32e75SAxel Dörfler 
1415af32e75SAxel Dörfler 
1420dc4d1e5SIngo Weinhold /** Loads a module by module name. This basically works in the same
1430dc4d1e5SIngo Weinhold  *	way as the kernel module loader; it will cut off the last part
1440dc4d1e5SIngo Weinhold  *	of the module name until it could find a module and loads it.
1450dc4d1e5SIngo Weinhold  *	It tests both, kernel and user module directories.
1465af32e75SAxel Dörfler  */
1470dc4d1e5SIngo Weinhold 
1485af32e75SAxel Dörfler static status_t
149*d11ea2b5SIngo Weinhold load_module(BootVolume& volume, const char* name)
1505af32e75SAxel Dörfler {
1515af32e75SAxel Dörfler 	char moduleName[B_FILE_NAME_LENGTH];
1525af32e75SAxel Dörfler 	if (strlcpy(moduleName, name, sizeof(moduleName)) > sizeof(moduleName))
1535af32e75SAxel Dörfler 		return B_NAME_TOO_LONG;
1545af32e75SAxel Dörfler 
1555af32e75SAxel Dörfler 	for (int32 i = 0; sPaths[i]; i++) {
1565af32e75SAxel Dörfler 		// get base path
157*d11ea2b5SIngo Weinhold 		int baseFD = open_maybe_packaged(volume, sPaths[i], O_RDONLY);
1585af32e75SAxel Dörfler 		if (baseFD < B_OK)
1595af32e75SAxel Dörfler 			continue;
1605af32e75SAxel Dörfler 
1615af32e75SAxel Dörfler 		Directory *base = (Directory *)get_node_from(baseFD);
16261aa1456SIngo Weinhold 		if (base == NULL) {
16361aa1456SIngo Weinhold 			close(baseFD);
16461aa1456SIngo Weinhold 			continue;
16561aa1456SIngo Weinhold 		}
1665af32e75SAxel Dörfler 
1675af32e75SAxel Dörfler 		while (true) {
1685af32e75SAxel Dörfler 			int fd = open_from(base, moduleName, O_RDONLY);
1695af32e75SAxel Dörfler 			if (fd >= B_OK) {
170e3fcb58eSAxel Dörfler 				struct stat stat;
171e3fcb58eSAxel Dörfler 				if (fstat(fd, &stat) != 0 || !S_ISREG(stat.st_mode))
172e3fcb58eSAxel Dörfler 					return B_BAD_VALUE;
173e3fcb58eSAxel Dörfler 
1745af32e75SAxel Dörfler 				status_t status = elf_load_image(base, moduleName);
1755af32e75SAxel Dörfler 
1765af32e75SAxel Dörfler 				close(fd);
1775af32e75SAxel Dörfler 				close(baseFD);
1785af32e75SAxel Dörfler 				return status;
1795af32e75SAxel Dörfler 			}
1805af32e75SAxel Dörfler 
1815af32e75SAxel Dörfler 			// cut off last name element (or stop trying if there are no more)
1825af32e75SAxel Dörfler 
1835af32e75SAxel Dörfler 			char *last = strrchr(moduleName, '/');
1845af32e75SAxel Dörfler 			if (last != NULL)
1855af32e75SAxel Dörfler 				last[0] = '\0';
1865af32e75SAxel Dörfler 			else
1875af32e75SAxel Dörfler 				break;
1885af32e75SAxel Dörfler 		}
1895af32e75SAxel Dörfler 
1905af32e75SAxel Dörfler 		close(baseFD);
1915af32e75SAxel Dörfler 	}
1925af32e75SAxel Dörfler 
1935af32e75SAxel Dörfler 	return B_OK;
1945af32e75SAxel Dörfler }
1955af32e75SAxel Dörfler 
1965af32e75SAxel Dörfler 
1975af32e75SAxel Dörfler status_t
198*d11ea2b5SIngo Weinhold load_modules(stage2_args* args, BootVolume& volume)
1995af32e75SAxel Dörfler {
200e3fcb58eSAxel Dörfler 	int32 failed = 0;
201e3fcb58eSAxel Dörfler 
202e3fcb58eSAxel Dörfler 	// ToDo: this should be mostly replaced by a hardware oriented detection mechanism
203e3fcb58eSAxel Dörfler 
2043dfd9cb9SOliver Tappe 	int32 i = 0;
2053dfd9cb9SOliver Tappe 	for (; sPaths[i]; i++) {
2065af32e75SAxel Dörfler 		char path[B_FILE_NAME_LENGTH];
20770fc8240SIngo Weinhold 		snprintf(path, sizeof(path), "%s/boot", sPaths[i]);
2085af32e75SAxel Dörfler 
209e3fcb58eSAxel Dörfler 		if (load_modules_from(volume, path) != B_OK)
210e3fcb58eSAxel Dörfler 			failed++;
211e3fcb58eSAxel Dörfler 	}
212e3fcb58eSAxel Dörfler 
2133dfd9cb9SOliver Tappe 	if (failed == i) {
214e3fcb58eSAxel Dörfler 		// couldn't load any boot modules
215e3fcb58eSAxel Dörfler 		// fall back to load all modules (currently needed by the boot floppy)
216e3fcb58eSAxel Dörfler 		const char *paths[] = { "bus_managers", "busses/ide", "busses/scsi",
217e3fcb58eSAxel Dörfler 			"generic", "partitioning_systems", "drivers/bin", NULL};
218e3fcb58eSAxel Dörfler 
219e3fcb58eSAxel Dörfler 		for (int32 i = 0; paths[i]; i++) {
220e3fcb58eSAxel Dörfler 			char path[B_FILE_NAME_LENGTH];
22170fc8240SIngo Weinhold 			snprintf(path, sizeof(path), "%s/%s", sPaths[0], paths[i]);
2225af32e75SAxel Dörfler 			load_modules_from(volume, path);
2235af32e75SAxel Dörfler 		}
224e3fcb58eSAxel Dörfler 	}
2255af32e75SAxel Dörfler 
2265af32e75SAxel Dörfler 	// and now load all partitioning and file system modules
2275af32e75SAxel Dörfler 	// needed to identify the boot volume
2285af32e75SAxel Dörfler 
2299e8dc2a9SIngo Weinhold 	if (!gKernelArgs.boot_volume.GetBool(BOOT_VOLUME_BOOTED_FROM_IMAGE,
2309e8dc2a9SIngo Weinhold 			false)) {
231e3fcb58eSAxel Dörfler 		// iterate over the mounted volumes and load their file system
2325af32e75SAxel Dörfler 		Partition *partition;
233*d11ea2b5SIngo Weinhold 		if (gRoot->GetPartitionFor(volume.RootDirectory(), &partition)
234*d11ea2b5SIngo Weinhold 				== B_OK) {
2355af32e75SAxel Dörfler 			while (partition != NULL) {
2365af32e75SAxel Dörfler 				load_module(volume, partition->ModuleName());
2375af32e75SAxel Dörfler 				partition = partition->Parent();
2385af32e75SAxel Dörfler 			}
2395af32e75SAxel Dörfler 		}
240e3fcb58eSAxel Dörfler 	} else {
2418423f6f4SAxel Dörfler 		// The boot image should only contain the file system
2428423f6f4SAxel Dörfler 		// needed to boot the system, so we just load it.
2438423f6f4SAxel Dörfler 		// ToDo: this is separate from the fall back from above
2448423f6f4SAxel Dörfler 		//	as this piece will survive a more intelligent module
2458423f6f4SAxel Dörfler 		//	loading approach...
2468423f6f4SAxel Dörfler 		char path[B_FILE_NAME_LENGTH];
24770fc8240SIngo Weinhold 		snprintf(path, sizeof(path), "%s/%s", sPaths[0], "file_systems");
2488423f6f4SAxel Dörfler 		load_modules_from(volume, path);
249e3fcb58eSAxel Dörfler 	}
2505af32e75SAxel Dörfler 
2515af32e75SAxel Dörfler 	return B_OK;
2525af32e75SAxel Dörfler }
2535af32e75SAxel Dörfler 
254