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 bool 202 are_extensions_available(uint8 drive) 203 { 204 struct bios_regs regs; 205 regs.eax = BIOS_IS_EXT_PRESENT; 206 regs.ebx = 0x55aa; 207 regs.edx = drive; 208 call_bios(0x13, ®s); 209 210 TRACE(("checking extensions: carry: %u; ebx: 0x%08lx; ecx: 0x%08lx\n", 211 regs.flags & CARRY_FLAG, regs.ebx, regs.ecx)); 212 return (regs.flags & CARRY_FLAG) == 0 && regs.ebx == 0xaa55 213 && (regs.ecx & 0x01 /* supports device access using packet */) != 0; 214 } 215 216 217 static status_t 218 get_ext_drive_parameters(uint8 drive, drive_parameters *targetParameters) 219 { 220 drive_parameters *parameter = (drive_parameters *)kDataSegmentScratch; 221 222 memset(parameter, 0, sizeof(drive_parameters)); 223 parameter->parameters_size = sizeof(drive_parameters); 224 225 struct bios_regs regs; 226 regs.eax = BIOS_GET_EXT_DRIVE_PARAMETERS; 227 regs.edx = drive; 228 regs.esi = (addr_t)parameter - kDataSegmentBase; 229 call_bios(0x13, ®s); 230 231 // filter out faulty BIOS return codes 232 if ((regs.flags & CARRY_FLAG) != 0 233 || parameter->sectors == 0) 234 return B_ERROR; 235 236 memcpy(targetParameters, parameter, sizeof(drive_parameters)); 237 return B_OK; 238 } 239 240 241 static status_t 242 get_drive_parameters(uint8 drive, drive_parameters *parameters) 243 { 244 struct bios_regs regs; 245 regs.eax = BIOS_GET_DRIVE_PARAMETERS; 246 regs.edx = drive; 247 regs.es = 0; 248 regs.edi = 0; // guard against faulty BIOS, see Ralf Brown's interrupt list 249 call_bios(0x13, ®s); 250 251 if ((regs.flags & CARRY_FLAG) != 0 || (regs.ecx & 0x3f) == 0) 252 return B_ERROR; 253 254 // fill drive_parameters structure with useful values 255 parameters->parameters_size = kParametersSizeVersion1; 256 parameters->flags = 0; 257 parameters->cylinders = (((regs.ecx & 0xc0) << 2) | ((regs.ecx >> 8) & 0xff)) + 1; 258 parameters->heads = ((regs.edx >> 8) & 0xff) + 1; 259 // heads and cylinders start counting from 0 260 parameters->sectors_per_track = regs.ecx & 0x3f; 261 parameters->sectors = parameters->cylinders * parameters->heads 262 * parameters->sectors_per_track; 263 parameters->bytes_per_sector = 512; 264 265 return B_OK; 266 } 267 268 269 static status_t 270 get_number_of_drives(uint8 *_count) 271 { 272 struct bios_regs regs; 273 regs.eax = BIOS_GET_DRIVE_PARAMETERS; 274 regs.edx = 0x80; 275 regs.es = 0; 276 regs.edi = 0; 277 call_bios(0x13, ®s); 278 279 if (regs.flags & CARRY_FLAG) 280 return B_ERROR; 281 282 *_count = regs.edx & 0xff; 283 return B_OK; 284 } 285 286 287 /** parse EDD 3.0 drive path information */ 288 289 static status_t 290 fill_disk_identifier_v3(disk_identifier &disk, const drive_parameters ¶meters) 291 { 292 if (parameters.parameters_size < kParametersSizeVersion3 293 || parameters.device_path_signature != kDevicePathSignature) 294 return B_BAD_TYPE; 295 296 // parse host bus 297 298 if (!strncmp(parameters.host_bus, "PCI", 3)) { 299 disk.bus_type = PCI_BUS; 300 301 disk.bus.pci.bus = parameters.interface.pci.bus; 302 disk.bus.pci.slot = parameters.interface.pci.slot; 303 disk.bus.pci.function = parameters.interface.pci.function; 304 } else if (!strncmp(parameters.host_bus, "ISA", 3)) { 305 disk.bus_type = LEGACY_BUS; 306 307 disk.bus.legacy.base_address = parameters.interface.legacy.base_address; 308 dprintf("legacy base address %x\n", disk.bus.legacy.base_address); 309 } else { 310 dprintf("unknown host bus \"%s\"\n", parameters.host_bus); 311 return B_BAD_DATA; 312 } 313 314 // parse interface 315 316 if (!strncmp(parameters.interface_type, "ATA", 3)) { 317 disk.device_type = ATA_DEVICE; 318 disk.device.ata.master = !parameters.device.ata.slave; 319 dprintf("ATA device, %s\n", disk.device.ata.master ? "master" : "slave"); 320 } else if (!strncmp(parameters.interface_type, "ATAPI", 3)) { 321 disk.device_type = ATAPI_DEVICE; 322 disk.device.atapi.master = !parameters.device.ata.slave; 323 disk.device.atapi.logical_unit = parameters.device.atapi.logical_unit; 324 } else if (!strncmp(parameters.interface_type, "SCSI", 3)) { 325 disk.device_type = SCSI_DEVICE; 326 disk.device.scsi.logical_unit = parameters.device.scsi.logical_unit; 327 } else if (!strncmp(parameters.interface_type, "USB", 3)) { 328 disk.device_type = USB_DEVICE; 329 disk.device.usb.tbd = parameters.device.usb.tbd; 330 } else if (!strncmp(parameters.interface_type, "1394", 3)) { 331 disk.device_type = FIREWIRE_DEVICE; 332 disk.device.firewire.guid = parameters.device.firewire.guid; 333 } else if (!strncmp(parameters.interface_type, "FIBRE", 3)) { 334 disk.device_type = FIBRE_DEVICE; 335 disk.device.fibre.wwd = parameters.device.fibre.wwd; 336 } else { 337 dprintf("unknown interface type \"%s\"\n", parameters.interface_type); 338 return B_BAD_DATA; 339 } 340 341 return B_OK; 342 } 343 344 345 /** EDD 2.0 drive table information */ 346 347 static status_t 348 fill_disk_identifier_v2(disk_identifier &disk, const drive_parameters ¶meters) 349 { 350 if (parameters.device_table.segment == 0xffff 351 && parameters.device_table.offset == 0xffff) 352 return B_BAD_TYPE; 353 354 device_table *table = (device_table *)LINEAR_ADDRESS(parameters.device_table.segment, 355 parameters.device_table.offset); 356 357 disk.bus_type = LEGACY_BUS; 358 disk.bus.legacy.base_address = table->base_address; 359 360 disk.device_type = ATA_DEVICE; 361 disk.device.ata.master = !table->is_slave; 362 363 return B_OK; 364 } 365 366 367 static off_t 368 get_next_check_sum_offset(int32 index, off_t maxSize) 369 { 370 // The boot block often contains the disk super block, and should be 371 // unique enough for most cases 372 if (index < 2) 373 return index * 512; 374 375 // Try some data in the first part of the drive 376 if (index < 4) 377 return (maxSize >> 10) + index * 2048; 378 379 // Some random value might do 380 return ((system_time() + index) % (maxSize >> 9)) * 512; 381 } 382 383 384 /** Computes a check sum for the specified block. 385 * The check sum is the sum of all data in that block interpreted as an 386 * array of uint32 values. 387 * Note, this must use the same method as the one used in kernel/fs/vfs_boot.cpp. 388 */ 389 390 static uint32 391 compute_check_sum(BIOSDrive *drive, off_t offset) 392 { 393 char buffer[512]; 394 ssize_t bytesRead = drive->ReadAt(NULL, offset, buffer, sizeof(buffer)); 395 if (bytesRead < B_OK) 396 return 0; 397 398 if (bytesRead < (ssize_t)sizeof(buffer)) 399 memset(buffer + bytesRead, 0, sizeof(buffer) - bytesRead); 400 401 uint32 *array = (uint32 *)buffer; 402 uint32 sum = 0; 403 404 for (uint32 i = 0; i < (bytesRead + sizeof(uint32) - 1) / sizeof(uint32); i++) { 405 sum += array[i]; 406 } 407 408 return sum; 409 } 410 411 412 static void 413 find_unique_check_sums(NodeList *devices) 414 { 415 NodeIterator iterator = devices->GetIterator(); 416 Node *device; 417 int32 index = 0; 418 off_t minSize = 0; 419 const int32 kMaxTries = 200; 420 421 while (index < kMaxTries) { 422 bool clash = false; 423 424 iterator.Rewind(); 425 426 while ((device = iterator.Next()) != NULL) { 427 BIOSDrive *drive = (BIOSDrive *)device; 428 #if 0 429 // there is no RTTI in the boot loader... 430 BIOSDrive *drive = dynamic_cast<BIOSDrive *>(device); 431 if (drive == NULL) 432 continue; 433 #endif 434 435 // TODO: currently, we assume that the BIOS provided us with unique 436 // disk identifiers... hopefully this is a good idea 437 if (drive->Identifier().device_type != UNKNOWN_DEVICE) 438 continue; 439 440 if (minSize == 0 || drive->Size() < minSize) 441 minSize = drive->Size(); 442 443 // check for clashes 444 445 NodeIterator compareIterator = devices->GetIterator(); 446 while ((device = compareIterator.Next()) != NULL) { 447 BIOSDrive *compareDrive = (BIOSDrive *)device; 448 449 if (compareDrive == drive 450 || compareDrive->Identifier().device_type != UNKNOWN_DEVICE) 451 continue; 452 453 if (!memcmp(&drive->Identifier(), &compareDrive->Identifier(), 454 sizeof(disk_identifier))) { 455 clash = true; 456 break; 457 } 458 } 459 460 if (clash) 461 break; 462 } 463 464 if (!clash) { 465 // our work here is done. 466 return; 467 } 468 469 // add a new block to the check sums 470 471 off_t offset = get_next_check_sum_offset(index, minSize); 472 int32 i = index % NUM_DISK_CHECK_SUMS; 473 iterator.Rewind(); 474 475 while ((device = iterator.Next()) != NULL) { 476 BIOSDrive *drive = (BIOSDrive *)device; 477 478 disk_identifier& disk = drive->Identifier(); 479 disk.device.unknown.check_sums[i].offset = offset; 480 disk.device.unknown.check_sums[i].sum = compute_check_sum(drive, offset); 481 482 TRACE(("disk %x, offset %Ld, sum %lu\n", drive->DriveID(), offset, 483 disk.device.unknown.check_sums[i].sum)); 484 } 485 486 index++; 487 } 488 489 // If we get here, we couldn't find a way to differentiate all disks from each other. 490 // It's very likely that one disk is an exact copy of the other, so there is nothing 491 // we could do, anyway. 492 493 dprintf("Could not make BIOS drives unique! Might boot from the wrong disk...\n"); 494 } 495 496 497 static status_t 498 add_block_devices(NodeList *devicesList, bool identifierMissing) 499 { 500 if (sBlockDevicesAdded) 501 return B_OK; 502 503 uint8 driveCount; 504 if (get_number_of_drives(&driveCount) != B_OK) 505 return B_ERROR; 506 507 dprintf("number of drives: %d\n", driveCount); 508 509 for (int32 i = 0; i < driveCount; i++) { 510 uint8 driveID = i + 0x80; 511 if (driveID == gBootDriveID) 512 continue; 513 514 BIOSDrive *drive = new(nothrow) BIOSDrive(driveID); 515 if (drive->InitCheck() != B_OK) { 516 dprintf("could not add drive %u\n", driveID); 517 delete drive; 518 continue; 519 } 520 521 devicesList->Add(drive); 522 523 if (drive->FillIdentifier() != B_OK) 524 identifierMissing = true; 525 } 526 527 if (identifierMissing) { 528 // we cannot distinguish between all drives by identifier, we need 529 // compute checksums for them 530 find_unique_check_sums(devicesList); 531 } 532 533 sBlockDevicesAdded = true; 534 return B_OK; 535 } 536 537 538 // #pragma mark - 539 540 541 BIOSDrive::BIOSDrive(uint8 driveID) 542 : 543 fDriveID(driveID) 544 { 545 TRACE(("drive ID %u\n", driveID)); 546 547 if (driveID < 0x80 || !are_extensions_available(driveID) 548 || get_ext_drive_parameters(driveID, &fParameters) != B_OK) { 549 // old style CHS support 550 551 if (get_drive_parameters(driveID, &fParameters) != B_OK) { 552 dprintf("getting drive parameters for: %u failed!\n", fDriveID); 553 return; 554 } 555 556 TRACE((" cylinders: %lu, heads: %lu, sectors: %lu, bytes_per_sector: %u\n", 557 fParameters.cylinders, fParameters.heads, fParameters.sectors_per_track, 558 fParameters.bytes_per_sector)); 559 TRACE((" total sectors: %Ld\n", fParameters.sectors)); 560 561 fBlockSize = 512; 562 fSize = fParameters.sectors * fBlockSize; 563 fLBA = false; 564 fHasParameters = false; 565 } else { 566 TRACE(("size: %x\n", fParameters.parameters_size)); 567 TRACE(("drive_path_signature: %x\n", fParameters.device_path_signature)); 568 TRACE(("host bus: \"%s\", interface: \"%s\"\n", fParameters.host_bus, 569 fParameters.interface_type)); 570 TRACE(("cylinders: %lu, heads: %lu, sectors: %lu, bytes_per_sector: %u\n", 571 fParameters.cylinders, fParameters.heads, fParameters.sectors_per_track, 572 fParameters.bytes_per_sector)); 573 TRACE(("total sectors: %Ld\n", fParameters.sectors)); 574 575 fBlockSize = fParameters.bytes_per_sector; 576 fSize = fParameters.sectors * fBlockSize; 577 fLBA = true; 578 fHasParameters = true; 579 } 580 } 581 582 583 BIOSDrive::~BIOSDrive() 584 { 585 } 586 587 588 status_t 589 BIOSDrive::InitCheck() const 590 { 591 return fSize > 0 ? B_OK : B_ERROR; 592 } 593 594 595 ssize_t 596 BIOSDrive::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize) 597 { 598 uint32 offset = pos % fBlockSize; 599 pos /= fBlockSize; 600 601 uint32 blocksLeft = (bufferSize + offset + fBlockSize - 1) / fBlockSize; 602 int32 totalBytesRead = 0; 603 604 //TRACE(("BIOS reads %lu bytes from %Ld (offset = %lu), drive %u\n", 605 // blocksLeft * fBlockSize, pos * fBlockSize, offset, fDriveID)); 606 607 uint32 scratchSize = 24 * 1024 / fBlockSize; 608 // maximum value allowed by Phoenix BIOS is 0x7f 609 610 while (blocksLeft > 0) { 611 uint32 blocksRead = blocksLeft; 612 if (blocksRead > scratchSize) 613 blocksRead = scratchSize; 614 615 if (fLBA) { 616 struct disk_address_packet *packet = (disk_address_packet *)kDataSegmentScratch; 617 memset(packet, 0, sizeof(disk_address_packet)); 618 619 packet->size = sizeof(disk_address_packet); 620 packet->number_of_blocks = blocksRead; 621 packet->buffer = kExtraSegmentScratch; 622 packet->lba = pos; 623 624 struct bios_regs regs; 625 regs.eax = BIOS_EXT_READ; 626 regs.edx = fDriveID; 627 regs.esi = (addr_t)packet - kDataSegmentBase; 628 call_bios(0x13, ®s); 629 630 if (regs.flags & CARRY_FLAG) 631 goto chs_read; 632 } else { 633 chs_read: 634 // Old style CHS read routine 635 636 // We can only read up to 64 kB this way, but since scratchSize 637 // is actually lower than this value, we don't have to take care 638 // of this here. 639 640 uint32 sector = pos % fParameters.sectors_per_track + 1; 641 // sectors start countint at 1 (unlike head and cylinder) 642 uint32 head = pos / fParameters.sectors_per_track; 643 uint32 cylinder = head / fParameters.heads; 644 head %= fParameters.heads; 645 646 if (cylinder >= fParameters.cylinders) { 647 TRACE(("cylinder value %lu bigger than available %lu\n", 648 cylinder, fParameters.cylinders)); 649 return B_BAD_VALUE; 650 } 651 652 // try to read from the device more than once, just to make sure it'll work 653 struct bios_regs regs; 654 int32 tries = 3; 655 bool readWorked = false; 656 657 while (tries-- > 0) { 658 regs.eax = BIOS_READ | blocksRead; 659 regs.edx = fDriveID | (head << 8); 660 regs.ecx = sector | ((cylinder >> 2) & 0xc0) | ((cylinder & 0xff) << 8); 661 regs.es = 0; 662 regs.ebx = kExtraSegmentScratch; 663 call_bios(0x13, ®s); 664 665 if ((regs.flags & CARRY_FLAG) == 0) { 666 readWorked = true; 667 break; 668 } 669 670 TRACE(("read failed\n")); 671 672 if (tries < 2) { 673 // reset disk system 674 TRACE(("reset disk system\n")); 675 regs.eax = BIOS_RESET_DISK_SYSTEM; 676 regs.edx = fDriveID; 677 call_bios(0x13, ®s); 678 } 679 680 // wait a bit between the retries (1/20 sec) 681 spin(50000); 682 } 683 684 if (!readWorked) { 685 dprintf("reading %ld bytes from drive %u failed at %Ld\n", 686 blocksRead, fDriveID, pos); 687 return B_ERROR; 688 } 689 } 690 691 uint32 bytesRead = fBlockSize * blocksRead - offset; 692 // copy no more than bufferSize bytes 693 if (bytesRead > bufferSize) 694 bytesRead = bufferSize; 695 696 memcpy(buffer, (void *)(kExtraSegmentScratch + offset), bytesRead); 697 pos += blocksRead; 698 offset = 0; 699 blocksLeft -= blocksRead; 700 bufferSize -= bytesRead; 701 buffer = (void *)((addr_t)buffer + bytesRead); 702 totalBytesRead += bytesRead; 703 } 704 705 return totalBytesRead; 706 } 707 708 709 ssize_t 710 BIOSDrive::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize) 711 { 712 // we don't have to know how to write 713 return B_NOT_ALLOWED; 714 } 715 716 717 off_t 718 BIOSDrive::Size() const 719 { 720 return fSize; 721 } 722 723 724 status_t 725 BIOSDrive::FillIdentifier() 726 { 727 if (HasParameters()) { 728 // try all drive_parameters versions, beginning from the most informative 729 730 #if 0 731 if (fill_disk_identifier_v3(fIdentifier, fParameters) == B_OK) 732 return B_OK; 733 734 if (fill_disk_identifier_v2(fIdentifier, fParameters) == B_OK) 735 return B_OK; 736 #else 737 // TODO: the above version is the correct one - it's currently 738 // disabled, as the kernel boot code only supports the 739 // UNKNOWN_BUS/UNKNOWN_DEVICE way to find the correct boot 740 // device. 741 if (fill_disk_identifier_v3(fIdentifier, fParameters) != B_OK) 742 fill_disk_identifier_v2(fIdentifier, fParameters); 743 744 #endif 745 746 // no interesting information, we have to fall back to the default 747 // unknown interface/device type identifier 748 } 749 750 fIdentifier.bus_type = UNKNOWN_BUS; 751 fIdentifier.device_type = UNKNOWN_DEVICE; 752 fIdentifier.device.unknown.size = Size(); 753 754 for (int32 i = 0; i < NUM_DISK_CHECK_SUMS; i++) { 755 fIdentifier.device.unknown.check_sums[i].offset = -1; 756 fIdentifier.device.unknown.check_sums[i].sum = 0; 757 } 758 759 return B_ERROR; 760 } 761 762 763 // #pragma mark - 764 765 766 status_t 767 platform_add_boot_device(struct stage2_args *args, NodeList *devicesList) 768 { 769 TRACE(("boot drive ID: %x\n", gBootDriveID)); 770 771 BIOSDrive *drive = new(nothrow) BIOSDrive(gBootDriveID); 772 if (drive->InitCheck() != B_OK) { 773 dprintf("no boot drive!\n"); 774 return B_ERROR; 775 } 776 777 devicesList->Add(drive); 778 779 if (drive->FillIdentifier() != B_OK) { 780 // We need to add all block devices to give the kernel the possibility 781 // to find the right boot volume 782 add_block_devices(devicesList, true); 783 } 784 785 TRACE(("boot drive size: %Ld bytes\n", drive->Size())); 786 gKernelArgs.boot_volume.SetBool(BOOT_VOLUME_BOOTED_FROM_IMAGE, 787 gBootedFromImage); 788 789 return B_OK; 790 } 791 792 793 status_t 794 platform_get_boot_partition(struct stage2_args *args, Node *bootDevice, 795 NodeList *list, boot::Partition **_partition) 796 { 797 BIOSDrive *drive = static_cast<BIOSDrive *>(bootDevice); 798 off_t offset = (off_t)gBootPartitionOffset * drive->BlockSize(); 799 800 dprintf("boot partition offset: %Ld\n", offset); 801 802 NodeIterator iterator = list->GetIterator(); 803 boot::Partition *partition = NULL; 804 while ((partition = (boot::Partition *)iterator.Next()) != NULL) { 805 TRACE(("partition offset = %Ld, size = %Ld\n", partition->offset, partition->size)); 806 // search for the partition that contains the partition 807 // offset as reported by the BFS boot block 808 if (offset >= partition->offset 809 && offset < partition->offset + partition->size) { 810 *_partition = partition; 811 return B_OK; 812 } 813 } 814 815 return B_ENTRY_NOT_FOUND; 816 } 817 818 819 status_t 820 platform_add_block_devices(stage2_args *args, NodeList *devicesList) 821 { 822 return add_block_devices(devicesList, false); 823 } 824 825 826 status_t 827 platform_register_boot_device(Node *device) 828 { 829 BIOSDrive *drive = (BIOSDrive *)device; 830 831 check_cd_boot(drive); 832 833 gKernelArgs.boot_volume.SetInt64("boot drive number", drive->DriveID()); 834 gKernelArgs.boot_volume.SetData(BOOT_VOLUME_DISK_IDENTIFIER, B_RAW_TYPE, 835 &drive->Identifier(), sizeof(disk_identifier)); 836 837 return B_OK; 838 } 839 840