1 /* 2 * Copyright 2003-2006, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "bios.h" 8 9 #include <KernelExport.h> 10 #include <boot/platform.h> 11 #include <boot/partitions.h> 12 #include <boot/stdio.h> 13 #include <boot/stage2.h> 14 15 #include <string.h> 16 17 //#define TRACE_DEVICES 18 #ifdef TRACE_DEVICES 19 # define TRACE(x) dprintf x 20 #else 21 # define TRACE(x) ; 22 #endif 23 24 25 // exported from shell.S 26 extern uint8 gBootedFromImage; 27 extern uint8 gBootDriveID; 28 extern uint32 gBootPartitionOffset; 29 30 // int 0x13 definitions 31 #define BIOS_RESET_DISK_SYSTEM 0x0000 32 #define BIOS_READ 0x0200 33 #define BIOS_GET_DRIVE_PARAMETERS 0x0800 34 #define BIOS_IS_EXT_PRESENT 0x4100 35 #define BIOS_EXT_READ 0x4200 36 #define BIOS_GET_EXT_DRIVE_PARAMETERS 0x4800 37 #define BIOS_BOOT_CD_GET_STATUS 0x4b01 38 39 struct real_addr { 40 uint16 offset; 41 uint16 segment; 42 }; 43 44 struct disk_address_packet { 45 uint8 size; 46 uint8 reserved; 47 uint16 number_of_blocks; 48 uint32 buffer; 49 uint64 lba; 50 uint64 flat_buffer; 51 }; 52 53 static const uint16 kParametersSizeVersion1 = 0x1a; 54 static const uint16 kParametersSizeVersion2 = 0x1e; 55 static const uint16 kParametersSizeVersion3 = 0x42; 56 57 static const uint16 kDevicePathSignature = 0xbedd; 58 59 struct drive_parameters { 60 uint16 parameters_size; 61 uint16 flags; 62 uint32 cylinders; 63 uint32 heads; 64 uint32 sectors_per_track; 65 uint64 sectors; 66 uint16 bytes_per_sector; 67 /* edd 2.0 */ 68 real_addr device_table; 69 /* edd 3.0 */ 70 uint16 device_path_signature; 71 uint8 device_path_size; 72 uint8 reserved1[3]; 73 char host_bus[4]; 74 char interface_type[8]; 75 union { 76 struct { 77 uint16 base_address; 78 } legacy; 79 struct { 80 uint8 bus; 81 uint8 slot; 82 uint8 function; 83 } pci; 84 uint8 reserved[8]; 85 } interface; 86 union { 87 struct { 88 uint8 slave; 89 } ata; 90 struct { 91 uint8 slave; 92 uint8 logical_unit; 93 } atapi; 94 struct { 95 uint8 logical_unit; 96 } scsi; 97 struct { 98 uint8 tbd; 99 } usb; 100 struct { 101 uint64 guid; 102 } firewire; 103 struct { 104 uint64 wwd; 105 } fibre; 106 } device; 107 uint8 reserved2; 108 uint8 checksum; 109 } _PACKED; 110 111 struct device_table { 112 uint16 base_address; 113 uint16 control_port_address; 114 uint8 _reserved1 : 4; 115 uint8 is_slave : 1; 116 uint8 _reserved2 : 1; 117 uint8 lba_enabled : 1; 118 } _PACKED; 119 120 struct specification_packet { 121 uint8 size; 122 uint8 media_type; 123 uint8 drive_number; 124 uint8 controller_index; 125 uint32 start_emulation; 126 uint16 device_specification; 127 uint8 _more_[9]; 128 } _PACKED; 129 130 class BIOSDrive : public Node { 131 public: 132 BIOSDrive(uint8 driveID); 133 virtual ~BIOSDrive(); 134 135 status_t InitCheck() const; 136 137 virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize); 138 virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize); 139 140 virtual off_t Size() const; 141 142 uint32 BlockSize() const { return fBlockSize; } 143 144 status_t FillIdentifier(); 145 146 bool HasParameters() const { return fHasParameters; } 147 const drive_parameters &Parameters() const { return fParameters; } 148 149 disk_identifier &Identifier() { return fIdentifier; } 150 uint8 DriveID() const { return fDriveID; } 151 152 protected: 153 uint8 fDriveID; 154 bool fLBA; 155 uint64 fSize; 156 uint32 fBlockSize; 157 bool fHasParameters; 158 drive_parameters fParameters; 159 disk_identifier fIdentifier; 160 }; 161 162 163 static bool sBlockDevicesAdded = false; 164 165 166 static void 167 check_cd_boot(BIOSDrive *drive) 168 { 169 gKernelArgs.boot_volume.SetInt32(BOOT_METHOD, BOOT_METHOD_HARD_DISK); 170 171 if (drive->DriveID() != 0) 172 return; 173 174 struct bios_regs regs; 175 regs.eax = BIOS_BOOT_CD_GET_STATUS; 176 regs.edx = 0; 177 regs.esi = kDataSegmentScratch; 178 call_bios(0x13, ®s); 179 180 if ((regs.flags & CARRY_FLAG) != 0) 181 return; 182 183 // we obviously were booted from CD! 184 185 specification_packet *packet = (specification_packet *)kDataSegmentScratch; 186 if (packet->media_type != 0) 187 gKernelArgs.boot_volume.SetInt32(BOOT_METHOD, BOOT_METHOD_CD); 188 189 #if 0 190 dprintf("got CD boot spec:\n"); 191 dprintf(" size: %#x\n", packet->size); 192 dprintf(" media type: %u\n", packet->media_type); 193 dprintf(" drive_number: %u\n", packet->drive_number); 194 dprintf(" controller index: %u\n", packet->controller_index); 195 dprintf(" start emulation: %lu\n", packet->start_emulation); 196 dprintf(" device_specification: %u\n", packet->device_specification); 197 #endif 198 } 199 200 201 static status_t 202 get_ext_drive_parameters(uint8 drive, drive_parameters *targetParameters) 203 { 204 drive_parameters *parameter = (drive_parameters *)kDataSegmentScratch; 205 206 memset(parameter, 0, sizeof(drive_parameters)); 207 parameter->parameters_size = sizeof(drive_parameters); 208 209 struct bios_regs regs; 210 regs.eax = BIOS_GET_EXT_DRIVE_PARAMETERS; 211 regs.edx = drive; 212 regs.esi = (addr_t)parameter - kDataSegmentBase; 213 call_bios(0x13, ®s); 214 215 // filter out faulty BIOS return codes 216 if ((regs.flags & CARRY_FLAG) != 0 217 || parameter->sectors == 0) 218 return B_ERROR; 219 220 memcpy(targetParameters, parameter, sizeof(drive_parameters)); 221 return B_OK; 222 } 223 224 225 static status_t 226 get_drive_parameters(uint8 drive, drive_parameters *parameters) 227 { 228 struct bios_regs regs; 229 regs.eax = BIOS_GET_DRIVE_PARAMETERS; 230 regs.edx = drive; 231 regs.es = 0; 232 regs.edi = 0; // guard against faulty BIOS, see Ralf Brown's interrupt list 233 call_bios(0x13, ®s); 234 235 if ((regs.flags & CARRY_FLAG) != 0 || (regs.ecx & 0x3f) == 0) 236 return B_ERROR; 237 238 // fill drive_parameters structure with useful values 239 parameters->parameters_size = kParametersSizeVersion1; 240 parameters->flags = 0; 241 parameters->cylinders = (((regs.ecx & 0xc0) << 2) | ((regs.ecx >> 8) & 0xff)) + 1; 242 parameters->heads = ((regs.edx >> 8) & 0xff) + 1; 243 // heads and cylinders start counting from 0 244 parameters->sectors_per_track = regs.ecx & 0x3f; 245 parameters->sectors = parameters->cylinders * parameters->heads 246 * parameters->sectors_per_track; 247 parameters->bytes_per_sector = 512; 248 249 return B_OK; 250 } 251 252 253 static status_t 254 get_number_of_drives(uint8 *_count) 255 { 256 struct bios_regs regs; 257 regs.eax = BIOS_GET_DRIVE_PARAMETERS; 258 regs.edx = 0x80; 259 regs.es = 0; 260 regs.edi = 0; 261 call_bios(0x13, ®s); 262 263 if (regs.flags & CARRY_FLAG) 264 return B_ERROR; 265 266 *_count = regs.edx & 0xff; 267 return B_OK; 268 } 269 270 271 /** parse EDD 3.0 drive path information */ 272 273 static status_t 274 fill_disk_identifier_v3(disk_identifier &disk, const drive_parameters ¶meters) 275 { 276 if (parameters.parameters_size < kParametersSizeVersion3 277 || parameters.device_path_signature != kDevicePathSignature) 278 return B_BAD_TYPE; 279 280 // parse host bus 281 282 if (!strncmp(parameters.host_bus, "PCI", 3)) { 283 disk.bus_type = PCI_BUS; 284 285 disk.bus.pci.bus = parameters.interface.pci.bus; 286 disk.bus.pci.slot = parameters.interface.pci.slot; 287 disk.bus.pci.function = parameters.interface.pci.function; 288 } else if (!strncmp(parameters.host_bus, "ISA", 3)) { 289 disk.bus_type = LEGACY_BUS; 290 291 disk.bus.legacy.base_address = parameters.interface.legacy.base_address; 292 dprintf("legacy base address %x\n", disk.bus.legacy.base_address); 293 } else { 294 dprintf("unknown host bus \"%s\"\n", parameters.host_bus); 295 return B_BAD_DATA; 296 } 297 298 // parse interface 299 300 if (!strncmp(parameters.interface_type, "ATA", 3)) { 301 disk.device_type = ATA_DEVICE; 302 disk.device.ata.master = !parameters.device.ata.slave; 303 dprintf("ATA device, %s\n", disk.device.ata.master ? "master" : "slave"); 304 } else if (!strncmp(parameters.interface_type, "ATAPI", 3)) { 305 disk.device_type = ATAPI_DEVICE; 306 disk.device.atapi.master = !parameters.device.ata.slave; 307 disk.device.atapi.logical_unit = parameters.device.atapi.logical_unit; 308 } else if (!strncmp(parameters.interface_type, "SCSI", 3)) { 309 disk.device_type = SCSI_DEVICE; 310 disk.device.scsi.logical_unit = parameters.device.scsi.logical_unit; 311 } else if (!strncmp(parameters.interface_type, "USB", 3)) { 312 disk.device_type = USB_DEVICE; 313 disk.device.usb.tbd = parameters.device.usb.tbd; 314 } else if (!strncmp(parameters.interface_type, "1394", 3)) { 315 disk.device_type = FIREWIRE_DEVICE; 316 disk.device.firewire.guid = parameters.device.firewire.guid; 317 } else if (!strncmp(parameters.interface_type, "FIBRE", 3)) { 318 disk.device_type = FIBRE_DEVICE; 319 disk.device.fibre.wwd = parameters.device.fibre.wwd; 320 } else { 321 dprintf("unknown interface type \"%s\"\n", parameters.interface_type); 322 return B_BAD_DATA; 323 } 324 325 return B_OK; 326 } 327 328 329 /** EDD 2.0 drive table information */ 330 331 static status_t 332 fill_disk_identifier_v2(disk_identifier &disk, const drive_parameters ¶meters) 333 { 334 if (parameters.device_table.segment == 0xffff 335 && parameters.device_table.offset == 0xffff) 336 return B_BAD_TYPE; 337 338 device_table *table = (device_table *)LINEAR_ADDRESS(parameters.device_table.segment, 339 parameters.device_table.offset); 340 341 disk.bus_type = LEGACY_BUS; 342 disk.bus.legacy.base_address = table->base_address; 343 344 disk.device_type = ATA_DEVICE; 345 disk.device.ata.master = !table->is_slave; 346 347 return B_OK; 348 } 349 350 351 static off_t 352 get_next_check_sum_offset(int32 index, off_t maxSize) 353 { 354 // The boot block often contains the disk super block, and should be 355 // unique enough for most cases 356 if (index < 2) 357 return index * 512; 358 359 // Try some data in the first part of the drive 360 if (index < 4) 361 return (maxSize >> 10) + index * 2048; 362 363 // Some random value might do 364 return ((system_time() + index) % (maxSize >> 9)) * 512; 365 } 366 367 368 /** Computes a check sum for the specified block. 369 * The check sum is the sum of all data in that block interpreted as an 370 * array of uint32 values. 371 * Note, this must use the same method as the one used in kernel/fs/vfs_boot.cpp. 372 */ 373 374 static uint32 375 compute_check_sum(BIOSDrive *drive, off_t offset) 376 { 377 char buffer[512]; 378 ssize_t bytesRead = drive->ReadAt(NULL, offset, buffer, sizeof(buffer)); 379 if (bytesRead < B_OK) 380 return 0; 381 382 if (bytesRead < (ssize_t)sizeof(buffer)) 383 memset(buffer + bytesRead, 0, sizeof(buffer) - bytesRead); 384 385 uint32 *array = (uint32 *)buffer; 386 uint32 sum = 0; 387 388 for (uint32 i = 0; i < (bytesRead + sizeof(uint32) - 1) / sizeof(uint32); i++) { 389 sum += array[i]; 390 } 391 392 return sum; 393 } 394 395 396 static void 397 find_unique_check_sums(NodeList *devices) 398 { 399 NodeIterator iterator = devices->GetIterator(); 400 Node *device; 401 int32 index = 0; 402 off_t minSize = 0; 403 const int32 kMaxTries = 200; 404 405 while (index < kMaxTries) { 406 bool clash = false; 407 408 iterator.Rewind(); 409 410 while ((device = iterator.Next()) != NULL) { 411 BIOSDrive *drive = (BIOSDrive *)device; 412 #if 0 413 // there is no RTTI in the boot loader... 414 BIOSDrive *drive = dynamic_cast<BIOSDrive *>(device); 415 if (drive == NULL) 416 continue; 417 #endif 418 419 // TODO: currently, we assume that the BIOS provided us with unique 420 // disk identifiers... hopefully this is a good idea 421 if (drive->Identifier().device_type != UNKNOWN_DEVICE) 422 continue; 423 424 if (minSize == 0 || drive->Size() < minSize) 425 minSize = drive->Size(); 426 427 // check for clashes 428 429 NodeIterator compareIterator = devices->GetIterator(); 430 while ((device = compareIterator.Next()) != NULL) { 431 BIOSDrive *compareDrive = (BIOSDrive *)device; 432 433 if (compareDrive == drive 434 || compareDrive->Identifier().device_type != UNKNOWN_DEVICE) 435 continue; 436 437 if (!memcmp(&drive->Identifier(), &compareDrive->Identifier(), 438 sizeof(disk_identifier))) { 439 clash = true; 440 break; 441 } 442 } 443 444 if (clash) 445 break; 446 } 447 448 if (!clash) { 449 // our work here is done. 450 return; 451 } 452 453 // add a new block to the check sums 454 455 off_t offset = get_next_check_sum_offset(index, minSize); 456 int32 i = index % NUM_DISK_CHECK_SUMS; 457 iterator.Rewind(); 458 459 while ((device = iterator.Next()) != NULL) { 460 BIOSDrive *drive = (BIOSDrive *)device; 461 462 disk_identifier& disk = drive->Identifier(); 463 disk.device.unknown.check_sums[i].offset = offset; 464 disk.device.unknown.check_sums[i].sum = compute_check_sum(drive, offset); 465 466 TRACE(("disk %x, offset %Ld, sum %lu\n", drive->DriveID(), offset, 467 disk.device.unknown.check_sums[i].sum)); 468 } 469 470 index++; 471 } 472 473 // If we get here, we couldn't find a way to differentiate all disks from each other. 474 // It's very likely that one disk is an exact copy of the other, so there is nothing 475 // we could do, anyway. 476 477 dprintf("Could not make BIOS drives unique! Might boot from the wrong disk...\n"); 478 } 479 480 481 static status_t 482 add_block_devices(NodeList *devicesList, bool identifierMissing) 483 { 484 if (sBlockDevicesAdded) 485 return B_OK; 486 487 uint8 driveCount; 488 if (get_number_of_drives(&driveCount) != B_OK) 489 return B_ERROR; 490 491 dprintf("number of drives: %d\n", driveCount); 492 493 for (int32 i = 0; i < driveCount; i++) { 494 uint8 driveID = i + 0x80; 495 if (driveID == gBootDriveID) 496 continue; 497 498 BIOSDrive *drive = new(nothrow) BIOSDrive(driveID); 499 if (drive->InitCheck() != B_OK) { 500 dprintf("could not add drive %u\n", driveID); 501 delete drive; 502 continue; 503 } 504 505 devicesList->Add(drive); 506 507 if (drive->FillIdentifier() != B_OK) 508 identifierMissing = true; 509 } 510 511 if (identifierMissing) { 512 // we cannot distinguish between all drives by identifier, we need 513 // compute checksums for them 514 find_unique_check_sums(devicesList); 515 } 516 517 sBlockDevicesAdded = true; 518 return B_OK; 519 } 520 521 522 // #pragma mark - 523 524 525 BIOSDrive::BIOSDrive(uint8 driveID) 526 : 527 fDriveID(driveID) 528 { 529 TRACE(("drive ID %u\n", driveID)); 530 531 if (get_ext_drive_parameters(driveID, &fParameters) != B_OK) { 532 // old style CHS support 533 534 if (get_drive_parameters(driveID, &fParameters) != B_OK) { 535 dprintf("getting drive parameters for: %u failed!\n", fDriveID); 536 return; 537 } 538 539 TRACE((" cylinders: %lu, heads: %lu, sectors: %lu, bytes_per_sector: %u\n", 540 fParameters.cylinders, fParameters.heads, fParameters.sectors_per_track, 541 fParameters.bytes_per_sector)); 542 TRACE((" total sectors: %Ld\n", fParameters.sectors)); 543 544 fBlockSize = 512; 545 fSize = fParameters.sectors * fBlockSize; 546 fLBA = false; 547 fHasParameters = false; 548 } else { 549 TRACE(("size: %x\n", fParameters.parameters_size)); 550 TRACE(("drive_path_signature: %x\n", fParameters.device_path_signature)); 551 TRACE(("host bus: \"%s\", interface: \"%s\"\n", fParameters.host_bus, 552 fParameters.interface_type)); 553 TRACE(("cylinders: %lu, heads: %lu, sectors: %lu, bytes_per_sector: %u\n", 554 fParameters.cylinders, fParameters.heads, fParameters.sectors_per_track, 555 fParameters.bytes_per_sector)); 556 TRACE(("total sectors: %Ld\n", fParameters.sectors)); 557 558 fBlockSize = fParameters.bytes_per_sector; 559 fSize = fParameters.sectors * fBlockSize; 560 fLBA = true; 561 fHasParameters = true; 562 } 563 } 564 565 566 BIOSDrive::~BIOSDrive() 567 { 568 } 569 570 571 status_t 572 BIOSDrive::InitCheck() const 573 { 574 return fSize > 0 ? B_OK : B_ERROR; 575 } 576 577 578 ssize_t 579 BIOSDrive::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize) 580 { 581 uint32 offset = pos % fBlockSize; 582 pos /= fBlockSize; 583 584 uint32 blocksLeft = (bufferSize + offset + fBlockSize - 1) / fBlockSize; 585 int32 totalBytesRead = 0; 586 587 //TRACE(("BIOS reads %lu bytes from %Ld (offset = %lu), drive %u\n", 588 // blocksLeft * fBlockSize, pos * fBlockSize, offset, fDriveID)); 589 590 uint32 scratchSize = 24 * 1024 / fBlockSize; 591 // maximum value allowed by Phoenix BIOS is 0x7f 592 593 while (blocksLeft > 0) { 594 uint32 blocksRead = blocksLeft; 595 if (blocksRead > scratchSize) 596 blocksRead = scratchSize; 597 598 if (fLBA) { 599 struct disk_address_packet *packet = (disk_address_packet *)kDataSegmentScratch; 600 memset(packet, 0, sizeof(disk_address_packet)); 601 602 packet->size = sizeof(disk_address_packet); 603 packet->number_of_blocks = blocksRead; 604 packet->buffer = kExtraSegmentScratch; 605 packet->lba = pos; 606 607 struct bios_regs regs; 608 regs.eax = BIOS_EXT_READ; 609 regs.edx = fDriveID; 610 regs.esi = (addr_t)packet - kDataSegmentBase; 611 call_bios(0x13, ®s); 612 613 if (regs.flags & CARRY_FLAG) 614 goto chs_read; 615 } else { 616 chs_read: 617 // Old style CHS read routine 618 619 // We can only read up to 64 kB this way, but since scratchSize 620 // is actually lower than this value, we don't have to take care 621 // of this here. 622 623 uint32 sector = pos % fParameters.sectors_per_track + 1; 624 // sectors start countint at 1 (unlike head and cylinder) 625 uint32 head = pos / fParameters.sectors_per_track; 626 uint32 cylinder = head / fParameters.heads; 627 head %= fParameters.heads; 628 629 if (cylinder >= fParameters.cylinders) 630 return B_BAD_VALUE; 631 632 // try to read from the device more than once, just to make sure it'll work 633 struct bios_regs regs; 634 int32 tries = 3; 635 636 while (tries-- > 0) { 637 regs.eax = BIOS_READ | blocksRead; 638 regs.edx = fDriveID | (head << 8); 639 regs.ecx = sector | ((cylinder >> 2) & 0xc0) | ((cylinder & 0xff) << 8); 640 regs.es = 0; 641 regs.ebx = kExtraSegmentScratch; 642 call_bios(0x13, ®s); 643 644 if ((regs.flags & CARRY_FLAG) == 0) 645 break; 646 647 if (tries < 2) { 648 // reset disk system 649 regs.eax = BIOS_RESET_DISK_SYSTEM; 650 regs.edx = fDriveID; 651 call_bios(0x13, ®s); 652 } 653 654 // wait a bit between the retries (1/20 sec) 655 spin(50000); 656 } 657 658 if (regs.flags & CARRY_FLAG) { 659 dprintf("reading %ld bytes from drive %u failed at %Ld\n", 660 blocksRead, fDriveID, pos); 661 return B_ERROR; 662 } 663 } 664 665 uint32 bytesRead = fBlockSize * blocksRead - offset; 666 // copy no more than bufferSize bytes 667 if (bytesRead > bufferSize) 668 bytesRead = bufferSize; 669 670 memcpy(buffer, (void *)(kExtraSegmentScratch + offset), bytesRead); 671 pos += blocksRead; 672 offset = 0; 673 blocksLeft -= blocksRead; 674 bufferSize -= bytesRead; 675 buffer = (void *)((addr_t)buffer + bytesRead); 676 totalBytesRead += bytesRead; 677 } 678 679 return totalBytesRead; 680 } 681 682 683 ssize_t 684 BIOSDrive::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize) 685 { 686 // we don't have to know how to write 687 return B_NOT_ALLOWED; 688 } 689 690 691 off_t 692 BIOSDrive::Size() const 693 { 694 return fSize; 695 } 696 697 698 status_t 699 BIOSDrive::FillIdentifier() 700 { 701 if (HasParameters()) { 702 // try all drive_parameters versions, beginning from the most informative 703 704 #if 0 705 if (fill_disk_identifier_v3(fIdentifier, fParameters) == B_OK) 706 return B_OK; 707 708 if (fill_disk_identifier_v2(fIdentifier, fParameters) == B_OK) 709 return B_OK; 710 #else 711 // TODO: the above version is the correct one - it's currently 712 // disabled, as the kernel boot code only supports the 713 // UNKNOWN_BUS/UNKNOWN_DEVICE way to find the correct boot 714 // device. 715 if (fill_disk_identifier_v3(fIdentifier, fParameters) != B_OK) 716 fill_disk_identifier_v2(fIdentifier, fParameters); 717 718 #endif 719 720 // no interesting information, we have to fall back to the default 721 // unknown interface/device type identifier 722 } 723 724 fIdentifier.bus_type = UNKNOWN_BUS; 725 fIdentifier.device_type = UNKNOWN_DEVICE; 726 fIdentifier.device.unknown.size = Size(); 727 728 for (int32 i = 0; i < NUM_DISK_CHECK_SUMS; i++) { 729 fIdentifier.device.unknown.check_sums[i].offset = -1; 730 fIdentifier.device.unknown.check_sums[i].sum = 0; 731 } 732 733 return B_ERROR; 734 } 735 736 737 // #pragma mark - 738 739 740 status_t 741 platform_add_boot_device(struct stage2_args *args, NodeList *devicesList) 742 { 743 TRACE(("boot drive ID: %x\n", gBootDriveID)); 744 745 BIOSDrive *drive = new(nothrow) BIOSDrive(gBootDriveID); 746 if (drive->InitCheck() != B_OK) { 747 dprintf("no boot drive!\n"); 748 return B_ERROR; 749 } 750 751 devicesList->Add(drive); 752 753 if (drive->FillIdentifier() != B_OK) { 754 // We need to add all block devices to give the kernel the possibility 755 // to find the right boot volume 756 add_block_devices(devicesList, true); 757 } 758 759 TRACE(("boot drive size: %Ld bytes\n", drive->Size())); 760 gKernelArgs.boot_volume.SetInt32(BOOT_VOLUME_BOOTED_FROM_IMAGE, 761 gBootedFromImage); 762 763 return B_OK; 764 } 765 766 767 status_t 768 platform_get_boot_partition(struct stage2_args *args, Node *bootDevice, 769 NodeList *list, boot::Partition **_partition) 770 { 771 BIOSDrive *drive = static_cast<BIOSDrive *>(bootDevice); 772 off_t offset = (off_t)gBootPartitionOffset * drive->BlockSize(); 773 774 dprintf("boot partition offset: %Ld\n", offset); 775 776 NodeIterator iterator = list->GetIterator(); 777 boot::Partition *partition = NULL; 778 while ((partition = (boot::Partition *)iterator.Next()) != NULL) { 779 TRACE(("partition offset = %Ld, size = %Ld\n", partition->offset, partition->size)); 780 // search for the partition that contains the partition 781 // offset as reported by the BFS boot block 782 if (offset >= partition->offset 783 && offset < partition->offset + partition->size) { 784 *_partition = partition; 785 return B_OK; 786 } 787 } 788 789 return B_ENTRY_NOT_FOUND; 790 } 791 792 793 status_t 794 platform_add_block_devices(stage2_args *args, NodeList *devicesList) 795 { 796 return add_block_devices(devicesList, false); 797 } 798 799 800 status_t 801 platform_register_boot_device(Node *device) 802 { 803 BIOSDrive *drive = (BIOSDrive *)device; 804 805 check_cd_boot(drive); 806 807 gKernelArgs.boot_volume.SetInt64("boot drive number", drive->DriveID()); 808 gKernelArgs.boot_volume.SetData(BOOT_VOLUME_DISK_IDENTIFIER, B_RAW_TYPE, 809 &drive->Identifier(), sizeof(disk_identifier)); 810 811 return B_OK; 812 } 813 814