/*
* Copyright 2003-2006, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
#include "bios.h"
#include <KernelExport.h>
#include <boot/platform.h>
#include <boot/partitions.h>
#include <boot/stdio.h>
#include <boot/stage2.h>
#include <string.h>
//#define TRACE_DEVICES
#ifdef TRACE_DEVICES
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
#endif
// exported from shell.S
extern uint8 gBootedFromImage;
extern uint8 gBootDriveID;
extern uint32 gBootPartitionOffset;
// int 0x13 definitions
#define BIOS_RESET_DISK_SYSTEM 0x0000
#define BIOS_READ 0x0200
#define BIOS_GET_DRIVE_PARAMETERS 0x0800
#define BIOS_IS_EXT_PRESENT 0x4100
#define BIOS_EXT_READ 0x4200
#define BIOS_EXT_WRITE 0x4300
#define BIOS_GET_EXT_DRIVE_PARAMETERS 0x4800
#define BIOS_BOOT_CD_GET_STATUS 0x4b01
struct real_addr {
uint16 offset;
uint16 segment;
};
struct disk_address_packet {
uint8 size;
uint8 reserved;
uint16 number_of_blocks;
uint32 buffer;
uint64 lba;
} _PACKED;
static const uint16 kParametersSizeVersion1 = 0x1a;
static const uint16 kParametersSizeVersion2 = 0x1e;
static const uint16 kParametersSizeVersion3 = 0x42;
static const uint16 kDevicePathSignature = 0xbedd;
struct drive_parameters {
uint16 parameters_size;
uint16 flags;
uint32 cylinders;
uint32 heads;
uint32 sectors_per_track;
uint64 sectors;
uint16 bytes_per_sector;
/* edd 2.0 */
real_addr device_table;
/* edd 3.0 */
uint16 device_path_signature;
uint8 device_path_size;
uint8 reserved1[3];
char host_bus[4];
char interface_type[8];
union {
struct {
uint16 base_address;
} legacy;
struct {
uint8 bus;
uint8 slot;
uint8 function;
} pci;
uint8 reserved[8];
} interface;
union {
struct {
uint8 slave;
} ata;
struct {
uint8 slave;
uint8 logical_unit;
} atapi;
struct {
uint8 logical_unit;
} scsi;
struct {
uint8 tbd;
} usb;
struct {
uint64 guid;
} firewire;
struct {
uint64 wwd;
} fibre;
} device;
uint8 reserved2;
uint8 checksum;
} _PACKED;
struct device_table {
uint16 base_address;
uint16 control_port_address;
uint8 _reserved1 : 4;
uint8 is_slave : 1;
uint8 _reserved2 : 1;
uint8 lba_enabled : 1;
} _PACKED;
struct specification_packet {
uint8 size;
uint8 media_type;
uint8 drive_number;
uint8 controller_index;
uint32 start_emulation;
uint16 device_specification;
uint8 _more_[9];
} _PACKED;
class BIOSDrive : public Node {
public:
BIOSDrive(uint8 driveID);
virtual ~BIOSDrive();
status_t InitCheck() const;
virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize);
virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize);
virtual off_t Size() const;
uint32 BlockSize() const { return fBlockSize; }
status_t FillIdentifier();
bool HasParameters() const { return fHasParameters; }
const drive_parameters &Parameters() const { return fParameters; }
disk_identifier &Identifier() { return fIdentifier; }
uint8 DriveID() const { return fDriveID; }
protected:
uint8 fDriveID;
bool fLBA;
uint64 fSize;
uint32 fBlockSize;
bool fHasParameters;
drive_parameters fParameters;
disk_identifier fIdentifier;
};
static bool sBlockDevicesAdded = false;
static void
check_cd_boot(BIOSDrive *drive)
{
gBootVolume.SetInt32(BOOT_METHOD, BOOT_METHOD_HARD_DISK);
if (drive->DriveID() != 0)
return;
struct bios_regs regs;
regs.eax = BIOS_BOOT_CD_GET_STATUS;
regs.edx = 0;
regs.esi = kDataSegmentScratch;
call_bios(0x13, ®s);
if ((regs.flags & CARRY_FLAG) != 0)
return;
// we obviously were booted from CD!
specification_packet *packet = (specification_packet *)kDataSegmentScratch;
if (packet->media_type != 0)
gBootVolume.SetInt32(BOOT_METHOD, BOOT_METHOD_CD);
#if 0
dprintf("got CD boot spec:\n");
dprintf(" size: %#x\n", packet->size);
dprintf(" media type: %u\n", packet->media_type);
dprintf(" drive_number: %u\n", packet->drive_number);
dprintf(" controller index: %u\n", packet->controller_index);
dprintf(" start emulation: %lu\n", packet->start_emulation);
dprintf(" device_specification: %u\n", packet->device_specification);
#endif
}
static bool
are_extensions_available(uint8 drive)
{
struct bios_regs regs;
regs.eax = BIOS_IS_EXT_PRESENT;
regs.ebx = 0x55aa;
regs.edx = drive;
call_bios(0x13, ®s);
TRACE(("checking extensions: carry: %u; ebx: 0x%08lx; ecx: 0x%08lx\n",
regs.flags & CARRY_FLAG, regs.ebx, regs.ecx));
return (regs.flags & CARRY_FLAG) == 0 && regs.ebx == 0xaa55
&& (regs.ecx & 0x01 /* supports device access using packet */) != 0;
}
static status_t
get_ext_drive_parameters(uint8 drive, drive_parameters *targetParameters)
{
drive_parameters *parameter = (drive_parameters *)kDataSegmentScratch;
memset(parameter, 0, sizeof(drive_parameters));
parameter->parameters_size = sizeof(drive_parameters);
struct bios_regs regs;
regs.eax = BIOS_GET_EXT_DRIVE_PARAMETERS;
regs.edx = drive;
regs.esi = (addr_t)parameter - kDataSegmentBase;
call_bios(0x13, ®s);
// filter out faulty BIOS return codes
if ((regs.flags & CARRY_FLAG) != 0
|| parameter->sectors == 0)
return B_ERROR;
memcpy(targetParameters, parameter, sizeof(drive_parameters));
return B_OK;
}
static status_t
get_drive_parameters(uint8 drive, drive_parameters *parameters)
{
struct bios_regs regs;
regs.eax = BIOS_GET_DRIVE_PARAMETERS;
regs.edx = drive;
regs.es = 0;
regs.edi = 0; // guard against faulty BIOS, see Ralf Brown's interrupt list
call_bios(0x13, ®s);
if ((regs.flags & CARRY_FLAG) != 0 || (regs.ecx & 0x3f) == 0)
return B_ERROR;
// fill drive_parameters structure with useful values
parameters->parameters_size = kParametersSizeVersion1;
parameters->flags = 0;
parameters->cylinders = (((regs.ecx & 0xc0) << 2) | ((regs.ecx >> 8) & 0xff)) + 1;
parameters->heads = ((regs.edx >> 8) & 0xff) + 1;
// heads and cylinders start counting from 0
parameters->sectors_per_track = regs.ecx & 0x3f;
parameters->sectors = parameters->cylinders * parameters->heads
* parameters->sectors_per_track;
parameters->bytes_per_sector = 512;
return B_OK;
}
static status_t
get_number_of_drives(uint8 *_count)
{
struct bios_regs regs;
regs.eax = BIOS_GET_DRIVE_PARAMETERS;
regs.edx = 0x80;
regs.es = 0;
regs.edi = 0;
call_bios(0x13, ®s);
if (regs.flags & CARRY_FLAG)
return B_ERROR;
*_count = regs.edx & 0xff;
return B_OK;
}
/** parse EDD 3.0 drive path information */
static status_t
fill_disk_identifier_v3(disk_identifier &disk, const drive_parameters ¶meters)
{
if (parameters.parameters_size < kParametersSizeVersion3
|| parameters.device_path_signature != kDevicePathSignature)
return B_BAD_TYPE;
// parse host bus
if (!strncmp(parameters.host_bus, "PCI", 3)) {
disk.bus_type = PCI_BUS;
disk.bus.pci.bus = parameters.interface.pci.bus;
disk.bus.pci.slot = parameters.interface.pci.slot;
disk.bus.pci.function = parameters.interface.pci.function;
} else if (!strncmp(parameters.host_bus, "ISA", 3)) {
disk.bus_type = LEGACY_BUS;
disk.bus.legacy.base_address = parameters.interface.legacy.base_address;
dprintf("legacy base address %x\n", disk.bus.legacy.base_address);
} else {
dprintf("unknown host bus \"%s\"\n", parameters.host_bus);
return B_BAD_DATA;
}
// parse interface
if (!strncmp(parameters.interface_type, "ATA", 3)) {
disk.device_type = ATA_DEVICE;
disk.device.ata.master = !parameters.device.ata.slave;
dprintf("ATA device, %s\n", disk.device.ata.master ? "master" : "slave");
} else if (!strncmp(parameters.interface_type, "ATAPI", 3)) {
disk.device_type = ATAPI_DEVICE;
disk.device.atapi.master = !parameters.device.ata.slave;
disk.device.atapi.logical_unit = parameters.device.atapi.logical_unit;
} else if (!strncmp(parameters.interface_type, "SCSI", 3)) {
disk.device_type = SCSI_DEVICE;
disk.device.scsi.logical_unit = parameters.device.scsi.logical_unit;
} else if (!strncmp(parameters.interface_type, "USB", 3)) {
disk.device_type = USB_DEVICE;
disk.device.usb.tbd = parameters.device.usb.tbd;
} else if (!strncmp(parameters.interface_type, "1394", 3)) {
disk.device_type = FIREWIRE_DEVICE;
disk.device.firewire.guid = parameters.device.firewire.guid;
} else if (!strncmp(parameters.interface_type, "FIBRE", 3)) {
disk.device_type = FIBRE_DEVICE;
disk.device.fibre.wwd = parameters.device.fibre.wwd;
} else {
dprintf("unknown interface type \"%s\"\n", parameters.interface_type);
return B_BAD_DATA;
}
return B_OK;
}
/** EDD 2.0 drive table information */
static status_t
fill_disk_identifier_v2(disk_identifier &disk, const drive_parameters ¶meters)
{
if (parameters.device_table.segment == 0xffff
&& parameters.device_table.offset == 0xffff)
return B_BAD_TYPE;
device_table *table = (device_table *)LINEAR_ADDRESS(parameters.device_table.segment,
parameters.device_table.offset);
disk.bus_type = LEGACY_BUS;
disk.bus.legacy.base_address = table->base_address;
disk.device_type = ATA_DEVICE;
disk.device.ata.master = !table->is_slave;
return B_OK;
}
static off_t
get_next_check_sum_offset(int32 index, off_t maxSize)
{
// The boot block often contains the disk superblock, and should be
// unique enough for most cases
if (index < 2)
return index * 512;
// Try some data in the first part of the drive
if (index < 4)
return (maxSize >> 10) + index * 2048;
// Some random value might do
return ((system_time() + index) % (maxSize >> 9)) * 512;
}
/** 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
compute_check_sum(BIOSDrive *drive, off_t offset)
{
char buffer[512];
ssize_t bytesRead = drive->ReadAt(NULL, 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 specified drive is usable for reading.
*/
static bool
is_drive_readable(BIOSDrive *drive)
{
char buffer;
return drive->ReadAt(NULL, 0, &buffer, sizeof(buffer)) > 0;
}
static void
find_unique_check_sums(NodeList *devices)
{
NodeIterator iterator = devices->GetIterator();
Node *device;
int32 index = 0;
off_t minSize = 0;
const int32 kMaxTries = 200;
while (index < kMaxTries) {
bool clash = false;
iterator.Rewind();
while ((device = iterator.Next()) != NULL) {
BIOSDrive *drive = (BIOSDrive *)device;
#if 0
// there is no RTTI in the boot loader...
BIOSDrive *drive = dynamic_cast<BIOSDrive *>(device);
if (drive == NULL)
continue;
#endif
// TODO: currently, we assume that the BIOS provided us with unique
// disk identifiers... hopefully this is a good idea
if (drive->Identifier().device_type != UNKNOWN_DEVICE)
continue;
if (minSize == 0 || drive->Size() < minSize)
minSize = drive->Size();
// check for clashes
NodeIterator compareIterator = devices->GetIterator();
while ((device = compareIterator.Next()) != NULL) {
BIOSDrive *compareDrive = (BIOSDrive *)device;
if (compareDrive == drive
|| compareDrive->Identifier().device_type != UNKNOWN_DEVICE)
continue;
// TODO: Until we can actually get and compare *all* fields of the disk
// identifier in the kernel, we cannot compare the whole structure (we also
// should be more careful zeroing the structure before we fill it).
#if 0
if (!memcmp(&drive->Identifier(), &compareDrive->Identifier(),
sizeof(disk_identifier))) {
clash = true;
break;
}
#else
const disk_identifier& ourId = drive->Identifier();
const disk_identifier& otherId = compareDrive->Identifier();
if (memcmp(&ourId.device.unknown.check_sums,
&otherId.device.unknown.check_sums,
sizeof(ourId.device.unknown.check_sums)) == 0) {
clash = true;
}
#endif
}
if (clash)
break;
}
if (!clash) {
// our work here is done.
return;
}
// add a new block to the check sums
off_t offset = get_next_check_sum_offset(index, minSize);
int32 i = index % NUM_DISK_CHECK_SUMS;
iterator.Rewind();
while ((device = iterator.Next()) != NULL) {
BIOSDrive *drive = (BIOSDrive *)device;
disk_identifier& disk = drive->Identifier();
disk.device.unknown.check_sums[i].offset = offset;
disk.device.unknown.check_sums[i].sum = compute_check_sum(drive, offset);
TRACE(("disk %x, offset %Ld, sum %lu\n", drive->DriveID(), offset,
disk.device.unknown.check_sums[i].sum));
}
index++;
}
// If we get here, we couldn't find a way to differentiate all disks from each other.
// It's very likely that one disk is an exact copy of the other, so there is nothing
// we could do, anyway.
dprintf("Could not make BIOS drives unique! Might boot from the wrong disk...\n");
}
static status_t
add_block_devices(NodeList *devicesList, bool identifierMissing)
{
if (sBlockDevicesAdded)
return B_OK;
uint8 driveCount;
if (get_number_of_drives(&driveCount) != B_OK)
return B_ERROR;
dprintf("number of drives: %d\n", driveCount);
for (int32 i = 0; i < driveCount; i++) {
uint8 driveID = i + 0x80;
if (driveID == gBootDriveID)
continue;
BIOSDrive *drive = new(nothrow) BIOSDrive(driveID);
if (drive->InitCheck() != B_OK) {
dprintf("could not add drive %u\n", driveID);
delete drive;
continue;
}
// Only add usable drives
if (is_drive_readable(drive))
devicesList->Add(drive);
else {
dprintf("could not read from drive %" B_PRIu8 ", not adding\n", driveID);
delete drive;
continue;
}
if (drive->FillIdentifier() != B_OK)
identifierMissing = true;
}
if (identifierMissing) {
// we cannot distinguish between all drives by identifier, we need
// compute checksums for them
find_unique_check_sums(devicesList);
}
sBlockDevicesAdded = true;
return B_OK;
}
// #pragma mark -
BIOSDrive::BIOSDrive(uint8 driveID)
:
fDriveID(driveID),
fSize(0)
{
TRACE(("drive ID %u\n", driveID));
if (driveID < 0x80 || !are_extensions_available(driveID)
|| get_ext_drive_parameters(driveID, &fParameters) != B_OK) {
// old style CHS support
if (get_drive_parameters(driveID, &fParameters) != B_OK) {
dprintf("getting drive parameters for: %u failed!\n", fDriveID);
return;
}
TRACE((" cylinders: %lu, heads: %lu, sectors: %lu, bytes_per_sector: %u\n",
fParameters.cylinders, fParameters.heads, fParameters.sectors_per_track,
fParameters.bytes_per_sector));
TRACE((" total sectors: %Ld\n", fParameters.sectors));
fBlockSize = 512;
fSize = fParameters.sectors * fBlockSize;
fLBA = false;
fHasParameters = false;
} else {
TRACE(("size: %x\n", fParameters.parameters_size));
TRACE(("drive_path_signature: %x\n", fParameters.device_path_signature));
TRACE(("host bus: \"%s\", interface: \"%s\"\n", fParameters.host_bus,
fParameters.interface_type));
TRACE(("cylinders: %lu, heads: %lu, sectors: %lu, bytes_per_sector: %u\n",
fParameters.cylinders, fParameters.heads, fParameters.sectors_per_track,
fParameters.bytes_per_sector));
TRACE(("total sectors: %Ld\n", fParameters.sectors));
fBlockSize = fParameters.bytes_per_sector;
fSize = fParameters.sectors * fBlockSize;
fLBA = true;
fHasParameters = true;
}
}
BIOSDrive::~BIOSDrive()
{
}
status_t
BIOSDrive::InitCheck() const
{
return fSize > 0 ? B_OK : B_ERROR;
}
ssize_t
BIOSDrive::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
{
uint32 offset = pos % fBlockSize;
pos /= fBlockSize;
uint32 blocksLeft = (bufferSize + offset + fBlockSize - 1) / fBlockSize;
int32 totalBytesRead = 0;
//TRACE(("BIOS reads %lu bytes from %Ld (offset = %lu), drive %u\n",
// blocksLeft * fBlockSize, pos * fBlockSize, offset, fDriveID));
uint32 scratchSize = 24 * 1024 / fBlockSize;
// maximum value allowed by Phoenix BIOS is 0x7f
while (blocksLeft > 0) {
uint32 blocksRead = blocksLeft;
if (blocksRead > scratchSize)
blocksRead = scratchSize;
if (fLBA) {
struct disk_address_packet *packet = (disk_address_packet *)kDataSegmentScratch;
memset(packet, 0, sizeof(disk_address_packet));
packet->size = sizeof(disk_address_packet);
packet->number_of_blocks = blocksRead;
packet->buffer = kExtraSegmentScratch;
packet->lba = pos;
struct bios_regs regs;
regs.eax = BIOS_EXT_READ;
regs.edx = fDriveID;
regs.esi = (addr_t)packet - kDataSegmentBase;
call_bios(0x13, ®s);
if (regs.flags & CARRY_FLAG)
goto chs_read;
} else {
chs_read:
// Old style CHS read routine
// We can only read up to 64 kB this way, but since scratchSize
// is actually lower than this value, we don't have to take care
// of this here.
uint32 sector = pos % fParameters.sectors_per_track + 1;
// sectors start countint at 1 (unlike head and cylinder)
uint32 head = pos / fParameters.sectors_per_track;
uint32 cylinder = head / fParameters.heads;
head %= fParameters.heads;
if (cylinder >= fParameters.cylinders) {
TRACE(("cylinder value %lu bigger than available %lu\n",
cylinder, fParameters.cylinders));
return B_BAD_VALUE;
}
// try to read from the device more than once, just to make sure it'll work
struct bios_regs regs;
int32 tries = 3;
bool readWorked = false;
while (tries-- > 0) {
regs.eax = BIOS_READ | blocksRead;
regs.edx = fDriveID | (head << 8);
regs.ecx = sector | ((cylinder >> 2) & 0xc0) | ((cylinder & 0xff) << 8);
regs.es = 0;
regs.ebx = kExtraSegmentScratch;
call_bios(0x13, ®s);
if ((regs.flags & CARRY_FLAG) == 0) {
readWorked = true;
break;
}
TRACE(("read failed\n"));
if (tries < 2) {
// reset disk system
TRACE(("reset disk system\n"));
regs.eax = BIOS_RESET_DISK_SYSTEM;
regs.edx = fDriveID;
call_bios(0x13, ®s);
}
// wait a bit between the retries (1/20 sec)
spin(50000);
}
if (!readWorked) {
dprintf("reading %ld bytes from drive %u failed at %Ld\n",
blocksRead, fDriveID, pos);
return B_ERROR;
}
}
uint32 bytesRead = fBlockSize * blocksRead - offset;
// copy no more than bufferSize bytes
if (bytesRead > bufferSize)
bytesRead = bufferSize;
memcpy(buffer, (void *)(kExtraSegmentScratch + offset), bytesRead);
pos += blocksRead;
offset = 0;
blocksLeft -= blocksRead;
bufferSize -= bytesRead;
buffer = (void *)((addr_t)buffer + bytesRead);
totalBytesRead += bytesRead;
}
return totalBytesRead;
}
ssize_t
BIOSDrive::WriteAt(void* cookie, off_t pos, const void* buffer,
size_t bufferSize)
{
// we support only LBA addressing
if (!fLBA) {
dprintf("BIOSDrive::WriteAt(): CHS addressing not supported\n");
return B_UNSUPPORTED;
}
// we support only block-aligned writes
if (pos % fBlockSize != 0 || bufferSize % fBlockSize != 0) {
dprintf("BIOSDrive::WriteAt(pos: %" B_PRIdOFF ", size: %" B_PRIuSIZE
"): Block-unaligned write not supported.\n", pos, bufferSize);
return B_UNSUPPORTED;
}
pos /= fBlockSize;
uint32 blocksLeft = bufferSize / fBlockSize;
int32 totalBytesWritten = 0;
uint32 scratchSize = 24 * 1024 / fBlockSize;
// maximum value allowed by Phoenix BIOS is 0x7f
while (blocksLeft > 0) {
uint32 blocksToWrite = blocksLeft;
if (blocksToWrite > scratchSize)
blocksToWrite = scratchSize;
uint32 bytesToWrite = blocksToWrite * fBlockSize;
memcpy((void*)kExtraSegmentScratch, buffer, bytesToWrite);
struct disk_address_packet* packet
= (disk_address_packet*)kDataSegmentScratch;
memset(packet, 0, sizeof(disk_address_packet));
packet->size = sizeof(disk_address_packet);
packet->number_of_blocks = blocksToWrite;
packet->buffer = kExtraSegmentScratch;
packet->lba = pos;
struct bios_regs regs;
regs.eax = BIOS_EXT_WRITE; // al = 0x00 -- no write verify
regs.edx = fDriveID;
regs.esi = (addr_t)packet - kDataSegmentBase;
call_bios(0x13, ®s);
if (regs.flags & CARRY_FLAG)
return B_ERROR;
pos += blocksToWrite;
blocksLeft -= blocksToWrite;
bufferSize -= bytesToWrite;
buffer = (void*)((addr_t)buffer + bytesToWrite);
totalBytesWritten += bytesToWrite;
}
return totalBytesWritten;
}
off_t
BIOSDrive::Size() const
{
return fSize;
}
status_t
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
}
fIdentifier.bus_type = UNKNOWN_BUS;
fIdentifier.device_type = UNKNOWN_DEVICE;
fIdentifier.device.unknown.size = Size();
for (int32 i = 0; i < NUM_DISK_CHECK_SUMS; i++) {
fIdentifier.device.unknown.check_sums[i].offset = -1;
fIdentifier.device.unknown.check_sums[i].sum = 0;
}
return B_ERROR;
}
// #pragma mark -
status_t
platform_add_boot_device(struct stage2_args *args, NodeList *devicesList)
{
TRACE(("boot drive ID: %x\n", gBootDriveID));
BIOSDrive *drive = new(nothrow) BIOSDrive(gBootDriveID);
if (drive->InitCheck() != B_OK) {
dprintf("no boot drive!\n");
delete drive;
return B_ERROR;
}
devicesList->Add(drive);
if (drive->FillIdentifier() != B_OK) {
// We need to add all block devices to give the kernel the possibility
// to find the right boot volume
add_block_devices(devicesList, true);
}
TRACE(("boot drive size: %Ld bytes\n", drive->Size()));
gBootVolume.SetBool(BOOT_VOLUME_BOOTED_FROM_IMAGE, gBootedFromImage);
return B_OK;
}
status_t
platform_get_boot_partitions(struct stage2_args *args, Node *bootDevice,
NodeList *list, NodeList *bootList)
{
BIOSDrive *drive = static_cast<BIOSDrive *>(bootDevice);
off_t offset = (off_t)gBootPartitionOffset * drive->BlockSize();
dprintf("boot partition offset: %Ld\n", offset);
NodeIterator iterator = list->GetIterator();
boot::Partition *partition = NULL;
while ((partition = (boot::Partition *)iterator.Next()) != NULL) {
TRACE(("partition offset = %Ld, size = %Ld\n", partition->offset, partition->size));
// search for the partition that contains the partition
// offset as reported by the BFS boot block
if (offset >= partition->offset
&& offset < partition->offset + partition->size) {
bootList->Insert(partition);
return B_OK;
}
}
return B_ENTRY_NOT_FOUND;
}
status_t
platform_add_block_devices(stage2_args *args, NodeList *devicesList)
{
return add_block_devices(devicesList, false);
}
status_t
platform_register_boot_device(Node *device)
{
BIOSDrive *drive = (BIOSDrive *)device;
check_cd_boot(drive);
gBootVolume.SetInt64("boot drive number", drive->DriveID());
gBootVolume.SetData(BOOT_VOLUME_DISK_IDENTIFIER, B_RAW_TYPE,
&drive->Identifier(), sizeof(disk_identifier));
return B_OK;
}
void
platform_cleanup_devices()
{
}
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: fIdentifier.
↑ V576 Potentially incorrect format string is passed to the 'dprintf' function. Prefix 'L' is not applicable to conversion specifier 'd'.
↑ V576 Potentially incorrect format string is passed to the 'dprintf' function. Prefix 'L' is not applicable to conversion specifier 'd'.