The boot loader now has special support for being booted from a boot image

like floppy or CD boot.
This allows it to reduce the number of scans needed to identify the boot
partition - when booted from a real floppy, this speeds up the boot
process by a magnitude.
Also, the loader now has a fall back in case there were no "boot" links
on the disk - the current boot floppy script doesn't create them.
With these changes, I was able to boot into a HD based Haiku installation
from a floppy disk. It's not yet enough to boot from CD (as the boot
device selection is a bit too simplistic right now), but it will eventually
come next. Testing is a lot slower here, though, as neither qemu nor
Bochs support multi-session CDs (at least I have no idea how to get them
to do this).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@14380 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2005-10-14 11:34:18 +00:00
parent 313ffb09da
commit e3fcb58ebb
8 changed files with 112 additions and 40 deletions

View File

@ -10,6 +10,8 @@
#include <disk_device_manager.h>
struct file_system_module_info;
namespace boot {
class Partition : public Node, public partition_data {
@ -25,8 +27,8 @@ class Partition : public Node, public partition_data {
Partition *AddChild();
status_t Mount(Directory **_fileSystem = NULL);
status_t Scan(bool mountFileSystems);
status_t Mount(Directory **_fileSystem = NULL, bool isBootDevice = false);
status_t Scan(bool mountFileSystems, bool isBootDevice = false);
void SetParent(Partition *parent) { fParent = parent; }
Partition *Parent() const { return fParent; }
@ -38,6 +40,8 @@ class Partition : public Node, public partition_data {
int FD() const { return fFD; }
private:
status_t _Mount(file_system_module_info *module, Directory **_fileSystem);
int fFD;
NodeList fChildren;
Partition *fParent;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2003-2004, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
#ifndef KERNEL_BOOT_PLATFORM_H
@ -58,6 +58,7 @@ extern status_t platform_add_block_devices(struct stage2_args *args, NodeList *d
extern status_t platform_get_boot_partition(struct stage2_args *args, Node *bootDevice,
NodeList *partitions, boot::Partition **_partition);
extern status_t platform_register_boot_device(Node *device);
extern bool platform_boot_device_is_image();
/* menu functions */

View File

@ -1,5 +1,5 @@
/*
* Copyright 2003-2004, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
#ifndef KERNEL_BOOT_VFS_H
@ -84,8 +84,8 @@ extern int open_from(Directory *directory, const char *path, int mode);
extern Node *get_node_from(int fd);
extern status_t add_partitions_for(int fd, bool mountFileSystems);
extern status_t add_partitions_for(Node *device, bool mountFileSystems);
extern status_t add_partitions_for(int fd, bool mountFileSystems, bool isBootDevice = false);
extern status_t add_partitions_for(Node *device, bool mountFileSystems, bool isBootDevice = false);
#endif /* __cplusplus */

View File

@ -1,5 +1,5 @@
/*
* Copyright 2003-2004, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
@ -129,6 +129,10 @@ load_module(Directory *volume, const char *name)
while (true) {
int fd = open_from(base, moduleName, O_RDONLY);
if (fd >= B_OK) {
struct stat stat;
if (fstat(fd, &stat) != 0 || !S_ISREG(stat.st_mode))
return B_BAD_VALUE;
status_t status = elf_load_image(base, moduleName);
close(fd);
@ -155,22 +159,47 @@ load_module(Directory *volume, const char *name)
status_t
load_modules(stage2_args *args, Directory *volume)
{
int32 failed = 0;
// ToDo: this should be mostly replaced by a hardware oriented detection mechanism
for (int32 i = 0; sPaths[i]; i++) {
char path[B_FILE_NAME_LENGTH];
sprintf(path, "%s/boot", sPaths[i]);
load_modules_from(volume, path);
if (load_modules_from(volume, path) != B_OK)
failed++;
}
if (failed > 1) {
// couldn't load any boot modules
// fall back to load all modules (currently needed by the boot floppy)
const char *paths[] = { "bus_managers", "busses/ide", "busses/scsi",
"generic", "partitioning_systems", "drivers/bin", NULL};
for (int32 i = 0; paths[i]; i++) {
char path[B_FILE_NAME_LENGTH];
sprintf(path, "%s/%s", sPaths[0], paths[i]);
load_modules_from(volume, path);
}
}
// and now load all partitioning and file system modules
// needed to identify the boot volume
Partition *partition;
if (gRoot->GetPartitionFor(volume, &partition) == B_OK) {
while (partition != NULL) {
load_module(volume, partition->ModuleName());
partition = partition->Parent();
if (!platform_boot_device_is_image()) {
// iterate over the mounted volumes and load their file system
Partition *partition;
if (gRoot->GetPartitionFor(volume, &partition) == B_OK) {
while (partition != NULL) {
load_module(volume, partition->ModuleName());
partition = partition->Parent();
}
}
} else {
// just make sure BFS is loaded - the boot file system
// does not help our decision of what's needed
load_module(volume, "file_systems/bfs");
}
return B_OK;

View File

@ -1,7 +1,7 @@
/*
** Copyright 2003-2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
** Distributed under the terms of the Haiku License.
*/
* Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "RootFileSystem.h"
@ -182,25 +182,37 @@ Partition::AddChild()
status_t
Partition::Mount(Directory **_fileSystem)
Partition::_Mount(file_system_module_info *module, Directory **_fileSystem)
{
TRACE(("check for file_system: %s\n", module->pretty_name));
Directory *fileSystem;
if (module->get_file_system(this, &fileSystem) == B_OK) {
gRoot->AddVolume(fileSystem, this);
if (_fileSystem)
*_fileSystem = fileSystem;
// remember the module name that mounted us
fModuleName = module->module_name;
fIsFileSystem = true;
return B_OK;
}
return B_BAD_VALUE;
}
status_t
Partition::Mount(Directory **_fileSystem, bool isBootDevice)
{
if (isBootDevice && platform_boot_device_is_image())
return _Mount(&gTarFileSystemModule, _fileSystem);
for (int32 i = 0; i < sNumFileSystemModules; i++) {
file_system_module_info *module = sFileSystemModules[i];
TRACE(("check for file_system: %s\n", module->pretty_name));
Directory *fileSystem;
if (module->get_file_system(this, &fileSystem) == B_OK) {
gRoot->AddVolume(fileSystem, this);
if (_fileSystem)
*_fileSystem = fileSystem;
// remember the module name that mounted us
fModuleName = module->module_name;
fIsFileSystem = true;
status_t status = _Mount(sFileSystemModules[i], _fileSystem);
if (status == B_OK)
return B_OK;
}
}
return B_ENTRY_NOT_FOUND;
@ -208,12 +220,18 @@ Partition::Mount(Directory **_fileSystem)
status_t
Partition::Scan(bool mountFileSystems)
Partition::Scan(bool mountFileSystems, bool isBootDevice)
{
// scan for partitions first (recursively all eventual children as well)
TRACE(("Partition::Scan()\n"));
// if we were not booted from the real boot device, we won't scan
// the device we were booted from (which is likely to be a slow
// floppy or CD)
if (isBootDevice && platform_boot_device_is_image())
return B_ENTRY_NOT_FOUND;
const partition_module_info *bestModule = NULL;
void *bestCookie = NULL;
float bestPriority = -1;
@ -309,8 +327,13 @@ Partition::Scan(bool mountFileSystems)
// #pragma mark -
/** Scans the device passed in for partitioning systems. If none are found,
* a partition containing the whole device is created.
* All created partitions are added to the gPartitions list.
*/
status_t
add_partitions_for(int fd, bool mountFileSystems)
add_partitions_for(int fd, bool mountFileSystems, bool isBootDevice)
{
TRACE(("add_partitions_for(fd = %d, mountFS = %s)\n", fd, mountFileSystems ? "yes" : "no"));
@ -322,7 +345,7 @@ add_partitions_for(int fd, bool mountFileSystems)
// add this partition to the list of partitions, if it contains
// or might contain a file system
if ((partition->Scan(mountFileSystems) == B_OK && partition->IsFileSystem())
if ((partition->Scan(mountFileSystems, isBootDevice) == B_OK && partition->IsFileSystem())
|| (!partition->IsPartitioningSystem() && !mountFileSystems)) {
gPartitions.Add(partition);
return B_OK;
@ -344,7 +367,7 @@ add_partitions_for(int fd, bool mountFileSystems)
status_t
add_partitions_for(Node *device, bool mountFileSystems)
add_partitions_for(Node *device, bool mountFileSystems, bool isBootDevice)
{
TRACE(("add_partitions_for(%p, mountFS = %s)\n", device, mountFileSystems ? "yes" : "no"));
@ -352,7 +375,7 @@ add_partitions_for(Node *device, bool mountFileSystems)
if (fd < B_OK)
return fd;
status_t status = add_partitions_for(fd, mountFileSystems);
status_t status = add_partitions_for(fd, mountFileSystems, isBootDevice);
if (status < B_OK)
dprintf("add_partitions_for(%d) failed: %ld\n", fd, status);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2003-2004, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
@ -334,7 +334,7 @@ get_boot_file_system(stage2_args *args)
// add the boot device to the list of devices
gBootDevices.Add(device);
if (add_partitions_for(device, false) < B_OK)
if (add_partitions_for(device, false, true) < B_OK)
return NULL;
Partition *partition;
@ -342,7 +342,7 @@ get_boot_file_system(stage2_args *args)
return NULL;
Directory *fileSystem;
status_t status = partition->Mount(&fileSystem);
status_t status = partition->Mount(&fileSystem, true);
if (status < B_OK) {
// this partition doesn't contain any known file system; we

View File

@ -22,6 +22,7 @@
// exported from shell.S
extern uint8 gCDFloppyBoot;
extern uint8 gBootDriveID;
extern uint32 gBootPartitionOffset;
@ -571,3 +572,8 @@ platform_register_boot_device(Node *device)
}
bool
platform_boot_device_is_image()
{
return gCDFloppyBoot;
}

View File

@ -71,6 +71,12 @@ floppy_start:
#endif
start_loader:
// indicate that we were booted from CD/floppy
.code32
.byte 0x67
movb $1, gCDFloppyBoot - 0x7c00 // %ds is 0x7c0 right now
.code16
// set our environment and jump to the standard BFS boot block entry point
xor %dx, %dx // boot device ID and partition offset to 0
xor %eax, %eax
@ -355,6 +361,9 @@ gdt_descriptor:
.word 0x2f // 6 entries in the GDT (8 bytes each)
.long gdt
GLOBAL(gCDFloppyBoot):
.byte 0
GLOBAL(gBootDriveID):
.byte 0