2 * Copyright 2003-2009, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
9 #include "RootFileSystem.h"
11 #include <directories.h>
13 #include <util/list.h>
14 #include <boot/stage2.h>
16 #include <boot/platform.h>
17 #include <boot/stdio.h>
18 #include <boot/partitions.h>
25 # error BOOT_ARCH has to be defined to differentiate the kernel per platform
28 #define SYSTEM_DIRECTORY_PREFIX "system/"
29 #define KERNEL_IMAGE "kernel_" BOOT_ARCH
30 #define KERNEL_PATH SYSTEM_DIRECTORY_PREFIX KERNEL_IMAGE
32 #ifdef ALTERNATE_BOOT_ARCH
33 # define ALTERNATE_KERNEL_IMAGE "kernel_" ALTERNATE_BOOT_ARCH
34 # define ALTERNATE_KERNEL_PATH "system/" ALTERNATE_KERNEL_IMAGE
38 static const char* const kSystemDirectoryPrefix
= SYSTEM_DIRECTORY_PREFIX
;
40 static const char *sKernelPaths
[][2] = {
41 { KERNEL_PATH
, KERNEL_IMAGE
},
42 #ifdef ALTERNATE_BOOT_ARCH
43 { ALTERNATE_KERNEL_PATH
, ALTERNATE_KERNEL_IMAGE
},
48 static const char *sAddonPaths
[] = {
49 kVolumeLocalSystemKernelAddonsDirectory
,
50 kVolumeLocalCommonNonpackagedKernelAddonsDirectory
,
51 kVolumeLocalCommonKernelAddonsDirectory
,
52 kVolumeLocalUserNonpackagedKernelAddonsDirectory
,
53 kVolumeLocalUserKernelAddonsDirectory
,
59 open_maybe_packaged(BootVolume
& volume
, const char* path
, int openMode
)
61 if (strncmp(path
, kSystemDirectoryPrefix
, strlen(kSystemDirectoryPrefix
))
63 path
+= strlen(kSystemDirectoryPrefix
);
64 return open_from(volume
.SystemDirectory(), path
, openMode
);
67 return open_from(volume
.RootDirectory(), path
, openMode
);
72 find_kernel(BootVolume
& volume
, const char** name
= NULL
)
74 for (int32 i
= 0; sKernelPaths
[i
][0] != NULL
; i
++) {
75 int fd
= open_maybe_packaged(volume
, sKernelPaths
[i
][0], O_RDONLY
);
78 *name
= sKernelPaths
[i
][1];
84 return B_ENTRY_NOT_FOUND
;
89 is_bootable(Directory
*volume
)
91 if (volume
->IsEmpty())
94 BootVolume bootVolume
;
95 if (bootVolume
.SetTo(volume
) != B_OK
)
98 // check for the existance of a kernel (for our platform)
99 int fd
= find_kernel(bootVolume
);
110 load_kernel(stage2_args
* args
, BootVolume
& volume
)
113 int fd
= find_kernel(volume
, &name
);
117 dprintf("load kernel %s...\n", name
);
120 preloaded_image
*image
;
121 status_t status
= elf_load_image(fd
, &image
);
126 dprintf("loading kernel failed: %" B_PRIx32
"!\n", status
);
130 gKernelArgs
.kernel_image
= image
;
132 status
= elf_relocate_image(gKernelArgs
.kernel_image
);
134 dprintf("relocating kernel failed: %" B_PRIx32
"!\n", status
);
138 gKernelArgs
.kernel_image
->name
= kernel_args_strdup(name
);
145 load_modules_from(BootVolume
& volume
, const char* path
)
147 // we don't have readdir() & co. (yet?)...
149 int fd
= open_maybe_packaged(volume
, path
, O_RDONLY
);
153 Directory
*modules
= (Directory
*)get_node_from(fd
);
155 return B_ENTRY_NOT_FOUND
;
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
, ".."))
164 status_t status
= elf_load_image(modules
, name
);
166 dprintf("Could not load \"%s\" error %" B_PRIx32
"\n", name
, status
);
169 modules
->Close(cookie
);
176 /** Loads a module by module name. This basically works in the same
177 * way as the kernel module loader; it will cut off the last part
178 * of the module name until it could find a module and loads it.
179 * It tests both, kernel and user module directories.
183 load_module(BootVolume
& volume
, const char* name
)
185 char moduleName
[B_FILE_NAME_LENGTH
];
186 if (strlcpy(moduleName
, name
, sizeof(moduleName
)) > sizeof(moduleName
))
187 return B_NAME_TOO_LONG
;
189 for (int32 i
= 0; sAddonPaths
[i
]; i
++) {
191 int baseFD
= open_maybe_packaged(volume
, sAddonPaths
[i
], O_RDONLY
);
195 Directory
*base
= (Directory
*)get_node_from(baseFD
);
202 int fd
= open_from(base
, moduleName
, O_RDONLY
);
205 if (fstat(fd
, &stat
) != 0 || !S_ISREG(stat
.st_mode
))
208 status_t status
= elf_load_image(base
, moduleName
);
215 // cut off last name element (or stop trying if there are no more)
217 char *last
= strrchr(moduleName
, '/');
232 load_modules(stage2_args
* args
, BootVolume
& volume
)
236 // ToDo: this should be mostly replaced by a hardware oriented detection mechanism
239 for (; sAddonPaths
[i
]; i
++) {
240 char path
[B_FILE_NAME_LENGTH
];
241 snprintf(path
, sizeof(path
), "%s/boot", sAddonPaths
[i
]);
243 if (load_modules_from(volume
, path
) != B_OK
)
248 // couldn't load any boot modules
249 // fall back to load all modules (currently needed by the boot floppy)
250 const char *paths
[] = { "bus_managers", "busses/ide", "busses/scsi",
251 "generic", "partitioning_systems", "drivers/bin", NULL
};
253 for (int32 i
= 0; paths
[i
]; i
++) {
254 char path
[B_FILE_NAME_LENGTH
];
255 snprintf(path
, sizeof(path
), "%s/%s", sAddonPaths
[0], paths
[i
]);
256 load_modules_from(volume
, path
);
260 // and now load all partitioning and file system modules
261 // needed to identify the boot volume
263 if (!gBootVolume
.GetBool(BOOT_VOLUME_BOOTED_FROM_IMAGE
, false)) {
264 // iterate over the mounted volumes and load their file system
265 Partition
*partition
;
266 if (gRoot
->GetPartitionFor(volume
.RootDirectory(), &partition
)
268 while (partition
!= NULL
) {
269 load_module(volume
, partition
->ModuleName());
270 partition
= partition
->Parent();
274 // The boot image should only contain the file system
275 // needed to boot the system, so we just load it.
276 // ToDo: this is separate from the fall back from above
277 // as this piece will survive a more intelligent module
278 // loading approach...
279 char path
[B_FILE_NAME_LENGTH
];
280 snprintf(path
, sizeof(path
), "%s/%s", sAddonPaths
[0], "file_systems");
281 load_modules_from(volume
, path
);