Introduction
In this chapter we complete the remaining code part of the loader.
if (bootVolume.IsValid()) {
// we got a volume to boot from!
// TODO: fix for riscv64
#ifndef __riscv
load_driver_settings(args, bootVolume.RootDirectory());
#endif
status_t status;
while ((status = load_kernel(args, bootVolume)) < B_OK) {
// loading the kernel failed, so let the user choose another
// volume to boot from until it works
bootVolume.Unset();
if (!mountedAllVolumes) {
// mount all other file systems, if not already happened
if (mount_file_systems(args) < B_OK)
panic("Could not locate any supported boot devices!\n");
mountedAllVolumes = true;
}
if (user_menu(bootVolume, pathBlocklist) != B_OK
|| !bootVolume.IsValid()) {
// user requested to quit the loader
goto out;
}
}
// if everything is okay, continue booting; the kernel
// is already loaded at this point and we definitely
// know our boot volume, too
if (status == B_OK) {
if (bootVolume.IsPackaged()) {
packagefs_apply_path_blocklist(bootVolume.SystemDirectory(),
pathBlocklist);
}
register_boot_file_system(bootVolume);
if ((platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT) == 0)
platform_switch_to_logo();
load_modules(args, bootVolume);
gKernelArgs.ucode_data = NULL;
gKernelArgs.ucode_data_size = 0;
platform_load_ucode(bootVolume);
// TODO: fix for riscv64
#ifndef __riscv
// apply boot settings
apply_boot_settings();
#endif
// set up kernel args version info
gKernelArgs.kernel_args_size = sizeof(kernel_args);
gKernelArgs.version = CURRENT_KERNEL_ARGS_VERSION;
if (gKernelArgs.ucode_data == NULL)
gKernelArgs.kernel_args_size = kernel_args_size_v1;
// clone the boot_volume KMessage into kernel accessible memory
// note, that we need to 8-byte align the buffer and thus allocate
// 7 more bytes
void* buffer = kernel_args_malloc(gBootVolume.ContentSize() + 7);
if (!buffer) {
panic("Could not allocate memory for the boot volume kernel "
"arguments");
}
buffer = (void*)(((addr_t)buffer + 7) & ~(addr_t)0x7);
memcpy(buffer, gBootVolume.Buffer(), gBootVolume.ContentSize());
gKernelArgs.boot_volume = buffer;
gKernelArgs.boot_volume_size = gBootVolume.ContentSize();
platform_cleanup_devices();
// TODO: cleanup, heap_release() etc.
heap_print_statistics();
platform_start_kernel();
}
}Boot Volume Validation
if (bootVolume.IsValid()) {
// code inside this block executes if a valid boot volume is present
}
- Checks if
bootVolumeis valid. If it is, the code proceeds to boot from it.
Load Driver Settings
#ifndef __riscv
load_driver_settings(args, bootVolume.RootDirectory());
#endif
- Loads driver settings from the root directory of the boot volume. This section is excluded for the RISC-V architecture.
- This function is defined at:
src/system/boot/loader/load_driver_settings.cpp.
load_driver_settings(…)
status_t
load_driver_settings(stage2_args* /*args*/, Directory* volume)
{
int fd = open_from(volume, "home/config/settings/kernel/drivers", O_RDONLY);
if (fd < B_OK)
return fd;
Directory* settings = (Directory*)get_node_from(fd);
if (settings == NULL)
return B_ENTRY_NOT_FOUND;
void* cookie;
if (settings->Open(&cookie, O_RDONLY) == B_OK) {
char name[B_FILE_NAME_LENGTH];
while (settings->GetNextEntry(cookie, name, sizeof(name)) == B_OK) {
if (!strcmp(name, ".") || !strcmp(name, ".."))
continue;
status_t status = load_driver_settings_file(settings, name);
if (status != B_OK)
dprintf("Could not load \"%s\" error %" B_PRIx32 "\n", name, status);
}
settings->Close(cookie);
}
return B_OK;
}Let's break down the code:
Function Signature
status_t load_driver_settings(stage2_args* /*args*/, Directory* volume)
- Parameters:
args: A pointer to an object of typestage2_args. (Note: Not used in the function)volume: A pointer to aDirectoryobject representing the volume from which driver settings should be loaded.
- Return Type:
status_t- A type commonly used in Haiku OS for error handling.B_OKindicate success, while other values represent specific error codes.
Open the Driver Settings File:
int fd = open_from(volume, "home/config/settings/kernel/drivers", O_RDONLY);
if (fd < B_OK)
return fd;
- Attempts to open the driver settings file located at “home/config/settings/kernel/drivers” on the specified volume.
- If unsuccessful, returns the error code.
Get the Settings Directory:
Directory* settings = (Directory*)get_node_from(fd);
if (settings == NULL)
return B_ENTRY_NOT_FOUND;
- Retrieves the
Directoryobject corresponding to the opened file descriptor (fd). - If the directory is not found, returns
B_ENTRY_NOT_FOUND.
Iterate Over Entries in the Settings Directory:
void* cookie;
if (settings->Open(&cookie, O_RDONLY) == B_OK) {
char name[B_FILE_NAME_LENGTH];
while (settings->GetNextEntry(cookie, name, sizeof(name)) == B_OK) {
// ...
}
settings->Close(cookie);
}
- Opens the setting directory for reading and initializes an iteration cookie.
- Iterates over entries in the directory.
Load Driver Settings From Each File:
if (!strcmp(name, ".") || !strcmp(name, ".."))
continue;
status_t status = load_driver_settings_file(settings, name);
if (status != B_OK)
dprintf("Could not load \"%s\" error %" B_PRIx32 "\n", name, status);
- Skips entries with the name “.” and “..”.
- Calls
load_driver_settings_filefunction to load settings from each file. - Prints an error message if the loading fails.
Close the Settings Directory and Return Success:
settings->Close(cookie);
return B_OK;
Load Kernel in Loop
status_t status;
while ((status = load_kernel(args, bootVolume)) < B_OK) {
// loading the kernel failed
// let the user choose another volume to boot from until it works
bootVolume.Unset();
// code to mount file systems if not already happened
// and prompt the user to choose another volume
// ...
}
- Uses a loop to attempt loading the kernel from the boot volume.
- If loading fails, the loop allows the user to choose another volume until successful.
load_kernel(args, bootVolume)function is defined at location:src/system/boot/loader/loader.cpp.
status_t
load_kernel(stage2_args* args, BootVolume& volume)
{
const char *name;
int fd = find_kernel(volume, &name);
if (fd < B_OK)
return fd;
dprintf("load kernel %s...\n", name);
elf_init();
preloaded_image *image;
status_t status = elf_load_image(fd, &image);
close(fd);
if (status < B_OK) {
dprintf("loading kernel failed: %" B_PRIx32 "!\n", status);
return status;
}
gKernelArgs.kernel_image = image;
status = elf_relocate_image(gKernelArgs.kernel_image);
if (status < B_OK) {
dprintf("relocating kernel failed: %" B_PRIx32 "!\n", status);
return status;
}
gKernelArgs.kernel_image->name = kernel_args_strdup(name);
return B_OK;
}Find Kernel and Open File Descriptor:
const char *name;
int fd = find_kernel(volume, &name);
if (fd < B_OK)
return fd;
- Calls
find_kernelfunction to locate the kernel on the specified BootVolume. - If unsuccessful (returns an error code), the function returns the error.
Print Debug Message:
dprintf("load kernel %s...\n", name);
// Ouput = load kernel kernel_x86_64...- Prints a debug message indicating that the kernel is being loaded.
Initialize ELF and Load Kernel Image:
elf_init();
preloaded_image *image;
status_t status = elf_load_image(fd, &image);
close(fd);
- Initializes ELF (Executable and Linkable Format) processing.
- Calls
elf_load_imageto load the kernel image from the file descriptor (fd). - Closes the file descriptor after loading.
Handle Loading Errors:
if (status < B_OK) {
dprintf("loading kernel failed: %" B_PRIx32 "!\n", status);
return status;
}
- Prints an error message and returns the error code if loading the kernel image fails.
Set Kernel Image in Global Structure:
gKernelArgs.kernel_image = image;
- Sets the kernel image in the global
gKernelArgsstructure.
Relocate Kernel Image:
status = elf_relocate_image(gKernelArgs.kernel_image);
if (status < B_OK) {
dprintf("relocating kernel failed: %" B_PRIx32 "!\n", status);
return status;
}
- Calls
elf_relocate_imageto relocate the loaded kernel image. - Prints an error message and returns the error code if relocation fails.
Set Kernel Image Name in Global Structure:
gKernelArgs.kernel_image->name = kernel_args_strdup(name);
- Allocates memory for and sets the name of the kernel image in the global
gKernelArgsstructure.
Return Success:
return B_OK;
- Returns
B_OKto indicate successful loading and relocation of the kernel image.
Continue Booting
if (status == B_OK) {
// code to continue booting after successful kernel loading
// ...
}
- If kernel loading is successful, it proceeds to continue the boot process.
Handle Packaged Boot Volume
if (bootVolume.IsPackaged()) {
packagefs_apply_path_blocklist(bootVolume.SystemDirectory(), pathBlocklist);
}
- If the boot volume is packaged, it applied a path blocklist to the system directory.
Register Boot File System
register_boot_file_system(bootVolume);
- Registers the boot file system.
Switch to Logo or Debug Output
if ((platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT) == 0)
platform_switch_to_logo();
- Switches to logo display unless debug output is requested.
Load Modules
load_modules(args, bootVolume);
- Load modules needed for the operating system.
Load Microcode
gKernelArgs.ucode_data = NULL;
gKernelArgs.ucode_data_size = 0;
platform_load_ucode(bootVolume);
- Prepares to load microcode. Sets microcode data and size to zero and calls a platform-specific function to load microcode from the boot volume.
Apply Boot Settings
#ifndef __riscv
apply_boot_settings();
#endif
- Applies boot settings. This section is excluded for the RISC-V architecture.
Set Up Kernel Args Version Info
#ifndef __riscv
apply_boot_settings();
#endif
- Sets up version information for kernel arguments.
Clone Boot Volume KMessage into Kernel Accessible Memory
void* buffer = kernel_args_malloc(gBootVolume.ContentSize() + 7);
// ...
memcpy(buffer, gBootVolume.Buffer(), gBootVolume.ContentSize());
gKernelArgs.boot_volume = buffer;
gKernelArgs.boot_volume_size = gBootVolume.ContentSize();
- Allocates memory for boot volume kernel arguments, aligns the buffer, and clones the boot volume information into this memory.
Cleanup Devices and Start Kernel
platform_cleanup_devices();
// TODO: cleanup, heap_release() etc.
heap_print_statistics();
platform_start_kernel();
- Cleans up devices, prints heap statistics, and starts the kernel.



Join the discussion
Sign in with your account to post comments, reply to others, and participate in the conversation.
Login to Comment