The kernel boot code now supports the unknown bus/device method to identify the

boot volume. The other (better) methods are now disabled in the boot loader.
This fixes bug #241.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16895 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2006-03-27 17:01:10 +00:00
parent 855697b122
commit fabe8c62ff
2 changed files with 109 additions and 10 deletions

View File

@ -14,7 +14,7 @@
#include <string.h>
#define TRACE_DEVICES
//#define TRACE_DEVICES
#ifdef TRACE_DEVICES
# define TRACE(x) dprintf x
#else
@ -367,6 +367,7 @@ get_next_check_sum_offset(int32 index, off_t maxSize)
/** Computes a check sum for the specified block.
* The check sum is the sum of all data in that block interpreted as an
* array of uint32 values.
* Note, this must use the same method as the one used in kernel/fs/vfs_boot.cpp.
*/
static uint32
@ -699,11 +700,21 @@ BIOSDrive::FillIdentifier()
if (HasParameters()) {
// try all drive_parameters versions, beginning from the most informative
#if 0
if (fill_disk_identifier_v3(fIdentifier, fParameters) == B_OK)
return B_OK;
if (fill_disk_identifier_v2(fIdentifier, fParameters) == B_OK)
return B_OK;
#else
// TODO: the above version is the correct one - it's currently
// disabled, as the kernel boot code only supports the
// UNKNOWN_BUS/UNKNOWN_DEVICE way to find the correct boot
// device.
if (fill_disk_identifier_v3(fIdentifier, fParameters) != B_OK)
fill_disk_identifier_v2(fIdentifier, fParameters);
#endif
// no interesting information, we have to fall back to the default
// unknown interface/device type identifier

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2002-2006, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
@ -27,11 +27,9 @@
//#define TRACE_VFS
#ifdef TRACE_VFS
# define PRINT(x) dprintf x
# define FUNCTION(x) dprintf x
# define TRACE(x) dprintf x
#else
# define PRINT(x) ;
# define FUNCTION(x) ;
# define TRACE(x) ;
#endif
@ -109,10 +107,100 @@ compare_cd_boot(const void *_a, const void *_b)
}
/** Computes a check sum for the specified block.
* The check sum is the sum of all data in that block interpreted as an
* array of uint32 values.
* Note, this must use the same method as the one used in
* boot/platform/bios_ia32/devices.cpp (or similar solutions).
*/
static uint32
compute_check_sum(KDiskDevice *device, off_t offset)
{
char buffer[512];
ssize_t bytesRead = read_pos(device->FD(), offset, buffer, sizeof(buffer));
if (bytesRead < B_OK)
return 0;
if (bytesRead < (ssize_t)sizeof(buffer))
memset(buffer + bytesRead, 0, sizeof(buffer) - bytesRead);
uint32 *array = (uint32 *)buffer;
uint32 sum = 0;
for (uint32 i = 0; i < (bytesRead + sizeof(uint32) - 1) / sizeof(uint32); i++) {
sum += array[i];
}
return sum;
}
/** Checks if the device matches the boot device as specified by the
* boot loader.
*/
static bool
is_boot_device(kernel_args *args, KDiskDevice *device)
{
disk_identifier &disk = args->boot_disk.identifier;
TRACE(("boot device: bus %ld, device %ld\n", disk.bus_type,
disk.device_type));
switch (disk.bus_type) {
case PCI_BUS:
case LEGACY_BUS:
// TODO: implement this! (and then enable this feature in the boot loader)
// (we need a way to get the device_node of a device, then)
break;
case UNKNOWN_BUS:
// nothing to do here
break;
}
switch (disk.device_type) {
case UNKNOWN_DEVICE:
// test if the size of the device matches
if (device->Size() != disk.device.unknown.size)
return false;
// check if the check sums match, too
for (int32 i = 0; i < NUM_DISK_CHECK_SUMS; i++) {
if (disk.device.unknown.check_sums[i].offset == -1)
continue;
if (compute_check_sum(device, disk.device.unknown.check_sums[i].offset)
!= disk.device.unknown.check_sums[i].sum)
return false;
}
break;
case ATA_DEVICE:
case ATAPI_DEVICE:
case SCSI_DEVICE:
case USB_DEVICE:
case FIREWIRE_DEVICE:
case FIBRE_DEVICE:
// TODO: implement me!
break;
}
return true;
}
/** Make the boot partition (and probably others) available.
* The partitions that are a boot candidate a put into the /a partitions
* stack. If the user selected a boot device, there is will only be one
* entry in this stack; if not, the most likely is put up first.
* The boot code should then just try them one by one.
*/
static status_t
get_boot_partitions(kernel_args *args, PartitionStack &partitions)
{
// make the boot partition (and probably others) available
KDiskDeviceManager::CreateDefault();
KDiskDeviceManager *manager = KDiskDeviceManager::Default();
@ -129,9 +217,6 @@ get_boot_partitions(kernel_args *args, PartitionStack &partitions)
return status;
}
// ToDo: do this for real! It will currently only use the partition offset;
// it does not yet use the disk_identifier information.
struct BootPartitionVisitor : KPartitionVisitor {
BootPartitionVisitor(kernel_args &args, PartitionStack &stack)
: fArgs(args), fPartitions(stack) {}
@ -168,6 +253,9 @@ get_boot_partitions(kernel_args *args, PartitionStack &partitions)
KDiskDevice *device;
int32 cookie = 0;
while ((device = manager->NextDevice(&cookie)) != NULL) {
if (!is_boot_device(args, device))
continue;
if (device->VisitEachDescendant(&visitor) != NULL)
break;
}