From fabe8c62ff591d112290ac797243751693981bab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Mon, 27 Mar 2006 17:01:10 +0000 Subject: [PATCH] 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 --- .../boot/platform/bios_ia32/devices.cpp | 13 ++- src/system/kernel/fs/vfs_boot.cpp | 106 ++++++++++++++++-- 2 files changed, 109 insertions(+), 10 deletions(-) diff --git a/src/system/boot/platform/bios_ia32/devices.cpp b/src/system/boot/platform/bios_ia32/devices.cpp index d6b305cae7..5916ee4463 100644 --- a/src/system/boot/platform/bios_ia32/devices.cpp +++ b/src/system/boot/platform/bios_ia32/devices.cpp @@ -14,7 +14,7 @@ #include -#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 diff --git a/src/system/kernel/fs/vfs_boot.cpp b/src/system/kernel/fs/vfs_boot.cpp index 9ba68b0f47..1cd7e8d6f1 100644 --- a/src/system/kernel/fs/vfs_boot.cpp +++ b/src/system/kernel/fs/vfs_boot.cpp @@ -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; }