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 <KernelExport.h> 8 #include <boot/platform.h> 9 #include <boot/partitions.h> 10 #include <boot/stdio.h> 11 #include <boot/stage2.h> 12 13 #include <string.h> 14 15 #include "Handle.h" 16 #include "toscalls.h" 17 18 #define TRACE_DEVICES 19 #ifdef TRACE_DEVICES 20 # define TRACE(x) dprintf x 21 #else 22 # define TRACE(x) ; 23 #endif 24 25 26 // exported from shell.S 27 extern uint8 gBootedFromImage; 28 extern uint8 gBootDriveID; 29 extern uint32 gBootPartitionOffset; 30 31 #define SCRATCH_SIZE (2*4096) 32 static uint8 gScratchBuffer[4096]; 33 34 static const uint16 kParametersSizeVersion1 = sizeof(struct tos_bpb); 35 static const uint16 kParametersSizeVersion2 = 0x1e; 36 static const uint16 kParametersSizeVersion3 = 0x42; 37 38 static const uint16 kDevicePathSignature = 0xbedd; 39 40 //XXX clean this up! 41 struct drive_parameters { 42 struct tos_bpb bpb; 43 uint16 parameters_size; 44 uint16 flags; 45 uint32 cylinders; 46 uint32 heads; 47 uint32 sectors_per_track; 48 uint64 sectors; 49 uint16 bytes_per_sector; 50 /* edd 2.0 */ 51 //real_addr device_table; 52 /* edd 3.0 */ 53 uint16 device_path_signature; 54 uint8 device_path_size; 55 uint8 reserved1[3]; 56 char host_bus[4]; 57 char interface_type[8]; 58 union { 59 struct { 60 uint16 base_address; 61 } legacy; 62 struct { 63 uint8 bus; 64 uint8 slot; 65 uint8 function; 66 } pci; 67 uint8 reserved[8]; 68 } interface; 69 union { 70 struct { 71 uint8 slave; 72 } ata; 73 struct { 74 uint8 slave; 75 uint8 logical_unit; 76 } atapi; 77 struct { 78 uint8 logical_unit; 79 } scsi; 80 struct { 81 uint8 tbd; 82 } usb; 83 struct { 84 uint64 guid; 85 } firewire; 86 struct { 87 uint64 wwd; 88 } fibre; 89 } device; 90 uint8 reserved2; 91 uint8 checksum; 92 } _PACKED; 93 94 struct device_table { 95 uint16 base_address; 96 uint16 control_port_address; 97 uint8 _reserved1 : 4; 98 uint8 is_slave : 1; 99 uint8 _reserved2 : 1; 100 uint8 lba_enabled : 1; 101 } _PACKED; 102 103 struct specification_packet { 104 uint8 size; 105 uint8 media_type; 106 uint8 drive_number; 107 uint8 controller_index; 108 uint32 start_emulation; 109 uint16 device_specification; 110 uint8 _more_[9]; 111 } _PACKED; 112 113 class BlockHandle : public Handle { 114 public: 115 BlockHandle(int handle); 116 virtual ~BlockHandle(); 117 118 virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize); 119 virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize); 120 121 virtual off_t Size() const { return fSize; }; 122 123 uint32 BlockSize() const { return fBlockSize; } 124 125 bool HasParameters() const { return fHasParameters; } 126 const drive_parameters &Parameters() const { return fParameters; } 127 128 virtual status_t FillIdentifier(); 129 130 disk_identifier &Identifier() { return fIdentifier; } 131 uint8 DriveID() const { return fHandle; } 132 status_t InitCheck() const { return fSize > 0 ? B_OK : B_ERROR; }; 133 134 135 136 virtual ssize_t ReadBlocks(void *buffer, off_t first, int32 count); 137 138 protected: 139 uint64 fSize; 140 uint32 fBlockSize; 141 bool fHasParameters; 142 drive_parameters fParameters; 143 disk_identifier fIdentifier; 144 }; 145 146 147 class BIOSDrive : public BlockHandle { 148 public: 149 BIOSDrive(int handle); 150 virtual ~BIOSDrive(); 151 152 status_t FillIdentifier(); 153 154 virtual ssize_t ReadBlocks(void *buffer, off_t first, int32 count); 155 156 protected: 157 status_t ReadBPB(struct tos_bpb *bpb); 158 }; 159 160 161 class XHDIDrive : public BlockHandle { 162 public: 163 XHDIDrive(int handle, uint16 major, uint16 minor); 164 virtual ~XHDIDrive(); 165 166 status_t FillIdentifier(); 167 168 virtual ssize_t ReadBlocks(void *buffer, off_t first, int32 count); 169 170 protected: 171 uint16 fMajor; 172 uint16 fMinor; 173 }; 174 175 176 static bool sBlockDevicesAdded = false; 177 178 179 static status_t 180 read_bpb(uint8 drive, struct tos_bpb *bpb) 181 { 182 struct tos_bpb *p; 183 p = Getbpb(drive); 184 memcpy(bpb, p, sizeof(struct tos_bpb)); 185 /* Getbpb is buggy so we must force a media change */ 186 //XXX: docs seems to assume we should loop until it works 187 Mediach(drive); 188 return B_OK; 189 } 190 191 static status_t 192 get_drive_parameters(uint8 drive, drive_parameters *parameters) 193 { 194 status_t err; 195 err = read_bpb(drive, ¶meters->bpb); 196 197 #if 0 198 // fill drive_parameters structure with useful values 199 parameters->parameters_size = kParametersSizeVersion1; 200 parameters->flags = 0; 201 parameters->cylinders = (((regs.ecx & 0xc0) << 2) | ((regs.ecx >> 8) & 0xff)) + 1; 202 parameters->heads = ((regs.edx >> 8) & 0xff) + 1; 203 // heads and cylinders start counting from 0 204 parameters->sectors_per_track = regs.ecx & 0x3f; 205 parameters->sectors = parameters->cylinders * parameters->heads 206 * parameters->sectors_per_track; 207 parameters->bytes_per_sector = 512; 208 #endif 209 return B_OK; 210 } 211 212 213 #if 0 214 /** parse EDD 3.0 drive path information */ 215 216 static status_t 217 fill_disk_identifier_v3(disk_identifier &disk, const drive_parameters ¶meters) 218 { 219 if (parameters.parameters_size < kParametersSizeVersion3 220 || parameters.device_path_signature != kDevicePathSignature) 221 return B_BAD_TYPE; 222 223 // parse host bus 224 225 if (!strncmp(parameters.host_bus, "PCI", 3)) { 226 disk.bus_type = PCI_BUS; 227 228 disk.bus.pci.bus = parameters.interface.pci.bus; 229 disk.bus.pci.slot = parameters.interface.pci.slot; 230 disk.bus.pci.function = parameters.interface.pci.function; 231 } else if (!strncmp(parameters.host_bus, "ISA", 3)) { 232 disk.bus_type = LEGACY_BUS; 233 234 disk.bus.legacy.base_address = parameters.interface.legacy.base_address; 235 dprintf("legacy base address %x\n", disk.bus.legacy.base_address); 236 } else { 237 dprintf("unknown host bus \"%s\"\n", parameters.host_bus); 238 return B_BAD_DATA; 239 } 240 241 // parse interface 242 243 if (!strncmp(parameters.interface_type, "ATA", 3)) { 244 disk.device_type = ATA_DEVICE; 245 disk.device.ata.master = !parameters.device.ata.slave; 246 dprintf("ATA device, %s\n", disk.device.ata.master ? "master" : "slave"); 247 } else if (!strncmp(parameters.interface_type, "ATAPI", 3)) { 248 disk.device_type = ATAPI_DEVICE; 249 disk.device.atapi.master = !parameters.device.ata.slave; 250 disk.device.atapi.logical_unit = parameters.device.atapi.logical_unit; 251 } else if (!strncmp(parameters.interface_type, "SCSI", 3)) { 252 disk.device_type = SCSI_DEVICE; 253 disk.device.scsi.logical_unit = parameters.device.scsi.logical_unit; 254 } else if (!strncmp(parameters.interface_type, "USB", 3)) { 255 disk.device_type = USB_DEVICE; 256 disk.device.usb.tbd = parameters.device.usb.tbd; 257 } else if (!strncmp(parameters.interface_type, "1394", 3)) { 258 disk.device_type = FIREWIRE_DEVICE; 259 disk.device.firewire.guid = parameters.device.firewire.guid; 260 } else if (!strncmp(parameters.interface_type, "FIBRE", 3)) { 261 disk.device_type = FIBRE_DEVICE; 262 disk.device.fibre.wwd = parameters.device.fibre.wwd; 263 } else { 264 dprintf("unknown interface type \"%s\"\n", parameters.interface_type); 265 return B_BAD_DATA; 266 } 267 268 return B_OK; 269 } 270 271 272 /** EDD 2.0 drive table information */ 273 274 static status_t 275 fill_disk_identifier_v2(disk_identifier &disk, const drive_parameters ¶meters) 276 { 277 if (parameters.device_table.segment == 0xffff 278 && parameters.device_table.offset == 0xffff) 279 return B_BAD_TYPE; 280 281 device_table *table = (device_table *)LINEAR_ADDRESS(parameters.device_table.segment, 282 parameters.device_table.offset); 283 284 disk.bus_type = LEGACY_BUS; 285 disk.bus.legacy.base_address = table->base_address; 286 287 disk.device_type = ATA_DEVICE; 288 disk.device.ata.master = !table->is_slave; 289 290 return B_OK; 291 } 292 #endif 293 294 static off_t 295 get_next_check_sum_offset(int32 index, off_t maxSize) 296 { 297 // The boot block often contains the disk super block, and should be 298 // unique enough for most cases 299 if (index < 2) 300 return index * 512; 301 302 // Try some data in the first part of the drive 303 if (index < 4) 304 return (maxSize >> 10) + index * 2048; 305 306 // Some random value might do 307 return ((system_time() + index) % (maxSize >> 9)) * 512; 308 } 309 310 311 /** Computes a check sum for the specified block. 312 * The check sum is the sum of all data in that block interpreted as an 313 * array of uint32 values. 314 * Note, this must use the same method as the one used in kernel/fs/vfs_boot.cpp. 315 */ 316 317 static uint32 318 compute_check_sum(BlockHandle *drive, off_t offset) 319 { 320 char buffer[512]; 321 ssize_t bytesRead = drive->ReadAt(NULL, offset, buffer, sizeof(buffer)); 322 if (bytesRead < B_OK) 323 return 0; 324 325 if (bytesRead < (ssize_t)sizeof(buffer)) 326 memset(buffer + bytesRead, 0, sizeof(buffer) - bytesRead); 327 328 uint32 *array = (uint32 *)buffer; 329 uint32 sum = 0; 330 331 for (uint32 i = 0; i < (bytesRead + sizeof(uint32) - 1) / sizeof(uint32); i++) { 332 sum += array[i]; 333 } 334 335 return sum; 336 } 337 338 339 static void 340 find_unique_check_sums(NodeList *devices) 341 { 342 NodeIterator iterator = devices->GetIterator(); 343 Node *device; 344 int32 index = 0; 345 off_t minSize = 0; 346 const int32 kMaxTries = 200; 347 348 while (index < kMaxTries) { 349 bool clash = false; 350 351 iterator.Rewind(); 352 353 while ((device = iterator.Next()) != NULL) { 354 BlockHandle *drive = (BlockHandle *)device; 355 #if 0 356 // there is no RTTI in the boot loader... 357 BlockHandle *drive = dynamic_cast<BlockHandle *>(device); 358 if (drive == NULL) 359 continue; 360 #endif 361 362 // TODO: currently, we assume that the BIOS provided us with unique 363 // disk identifiers... hopefully this is a good idea 364 if (drive->Identifier().device_type != UNKNOWN_DEVICE) 365 continue; 366 367 if (minSize == 0 || drive->Size() < minSize) 368 minSize = drive->Size(); 369 370 // check for clashes 371 372 NodeIterator compareIterator = devices->GetIterator(); 373 while ((device = compareIterator.Next()) != NULL) { 374 BlockHandle *compareDrive = (BlockHandle *)device; 375 376 if (compareDrive == drive 377 || compareDrive->Identifier().device_type != UNKNOWN_DEVICE) 378 continue; 379 380 if (!memcmp(&drive->Identifier(), &compareDrive->Identifier(), 381 sizeof(disk_identifier))) { 382 clash = true; 383 break; 384 } 385 } 386 387 if (clash) 388 break; 389 } 390 391 if (!clash) { 392 // our work here is done. 393 return; 394 } 395 396 // add a new block to the check sums 397 398 off_t offset = get_next_check_sum_offset(index, minSize); 399 int32 i = index % NUM_DISK_CHECK_SUMS; 400 iterator.Rewind(); 401 402 while ((device = iterator.Next()) != NULL) { 403 BlockHandle *drive = (BlockHandle *)device; 404 405 disk_identifier& disk = drive->Identifier(); 406 disk.device.unknown.check_sums[i].offset = offset; 407 disk.device.unknown.check_sums[i].sum = compute_check_sum(drive, offset); 408 409 TRACE(("disk %x, offset %Ld, sum %lu\n", drive->DriveID(), offset, 410 disk.device.unknown.check_sums[i].sum)); 411 } 412 413 index++; 414 } 415 416 // If we get here, we couldn't find a way to differentiate all disks from each other. 417 // It's very likely that one disk is an exact copy of the other, so there is nothing 418 // we could do, anyway. 419 420 dprintf("Could not make BIOS drives unique! Might boot from the wrong disk...\n"); 421 } 422 423 424 static status_t 425 add_block_devices(NodeList *devicesList, bool identifierMissing) 426 { 427 int32 map; 428 uint8 driveID; 429 uint8 driveCount = 0; 430 431 if (sBlockDevicesAdded) 432 return B_OK; 433 434 if (init_xhdi() >= B_OK) { 435 uint16 major; 436 uint16 minor; 437 uint32 blocksize; 438 uint32 blocksize2; 439 uint32 blocks; 440 uint32 devflags; 441 uint32 lastacc; 442 char product[33]; 443 int32 err; 444 445 map = XHDrvMap(); 446 dprintf("XDrvMap() 0x%08lx\n", map); 447 // sadly XDrvmap() has the same issues as XBIOS, it only lists known partitions. 448 // so we just iterate on each major and try to see if there is something. 449 for (driveID = 0; driveID < 32; driveID++) { 450 uint32 startsect; 451 err = XHInqDev(driveID, &major, &minor, &startsect, NULL); 452 if (err < 0) { 453 ;//dprintf("XHInqDev(%d) error %d\n", driveID, err); 454 } else { 455 dprintf("XHInqDev(%d): (%d,%d):%d\n", driveID, major, minor, startsect); 456 } 457 } 458 459 product[32] = '\0'; 460 for (major = 0; major < 256; major++) { 461 if (major == 64) // we don't want floppies 462 continue; 463 if (major > 23) // extensions and non-standard stuff... skip for speed. 464 break; 465 466 for (minor = 0; minor < 255; minor++) { 467 if (minor && (major < 8 || major >15)) 468 break; // minor only used for the SCSI LUN AFAIK. 469 if (minor > 15) // are more used at all ? 470 break; 471 472 product[0] = '\0'; 473 blocksize = 0; 474 blocksize2 = 0; 475 #if 0 476 err = XHLastAccess(major, minor, &lastacc); 477 if (err < 0) { 478 ;//dprintf("XHLastAccess(%d,%d) error %d\n", major, minor, err); 479 } else 480 dprintf("XHLastAccess(%d,%d): %ld\n", major, minor, lastacc); 481 //continue; 482 #endif 483 // we can pass NULL pointers but just to play safe we don't. 484 err = XHInqTarget(major, minor, &blocksize, &devflags, product); 485 if (err < 0) { 486 dprintf("XHInqTarget(%d,%d) error %d\n", major, minor, err); 487 continue; 488 } 489 err = XHGetCapacity(major, minor, &blocks, &blocksize2); 490 if (err < 0) { 491 //dprintf("XHGetCapacity(%d,%d) error %d\n", major, minor, err); 492 continue; 493 } 494 495 if (blocksize == 0) { 496 dprintf("XHDI: blocksize for (%d,%d) is 0!\n", major, minor); 497 } 498 //dprintf("XHDI: (%d,%d) blocksize1 %ld blocksize2 %ld\n", major, minor, blocksize, blocksize2); 499 500 dprintf("XHDI(%d,%d): blksize %d, blocks %d, flags 0x%08lx, '%s'\n", major, minor, blocksize, blocks, devflags, product); 501 driveID = (uint8)major; 502 503 //if (driveID == gBootDriveID) 504 // continue; 505 //continue; 506 507 BlockHandle *drive = new(nothrow) XHDIDrive(driveID, major, minor); 508 if (drive->InitCheck() != B_OK) { 509 dprintf("could not add drive (%d,%d)\n", major, minor); 510 delete drive; 511 continue; 512 } 513 514 devicesList->Add(drive); 515 driveCount++; 516 517 if (drive->FillIdentifier() != B_OK) 518 identifierMissing = true; 519 } 520 } 521 } 522 if (!driveCount) { // try to fallback to BIOS XXX: use MetaDOS 523 map = Drvmap(); 524 dprintf("Drvmap(): 0x%08lx\n", map); 525 for (driveID = 0; driveID < 32; driveID++) { 526 bool present = map & 0x1; 527 map >>= 1; 528 if (!present) 529 continue; 530 531 if (driveID == gBootDriveID) 532 continue; 533 534 BlockHandle *drive = new(nothrow) BlockHandle(driveID); 535 if (drive->InitCheck() != B_OK) { 536 dprintf("could not add drive %u\n", driveID); 537 delete drive; 538 continue; 539 } 540 541 devicesList->Add(drive); 542 driveCount++; 543 544 if (drive->FillIdentifier() != B_OK) 545 identifierMissing = true; 546 } 547 } 548 dprintf("number of drives: %d\n", driveCount); 549 550 if (identifierMissing) { 551 // we cannot distinguish between all drives by identifier, we need 552 // compute checksums for them 553 find_unique_check_sums(devicesList); 554 } 555 556 sBlockDevicesAdded = true; 557 return B_OK; 558 } 559 560 561 // #pragma mark - 562 563 564 BlockHandle::BlockHandle(int handle) 565 : Handle(handle) 566 { 567 TRACE(("BlockHandle::%s(): drive ID %u\n", __FUNCTION__, fHandle)); 568 } 569 570 571 BlockHandle::~BlockHandle() 572 { 573 } 574 575 576 ssize_t 577 BlockHandle::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize) 578 { 579 ssize_t ret; 580 uint32 offset = pos % fBlockSize; 581 pos /= fBlockSize; 582 TRACE(("BlockHandle::%s: (%d) %Ld, %d\n", __FUNCTION__, fHandle, pos, bufferSize)); 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 // read partial block 591 if (offset) { 592 ret = ReadBlocks(gScratchBuffer, pos, 1); 593 if (ret < 0) 594 return ret; 595 totalBytesRead += fBlockSize - offset; 596 memcpy(buffer, gScratchBuffer + offset, totalBytesRead); 597 598 } 599 600 uint32 scratchSize = SCRATCH_SIZE / fBlockSize; 601 602 while (blocksLeft > 0) { 603 uint32 blocksRead = blocksLeft; 604 if (blocksRead > scratchSize) 605 blocksRead = scratchSize; 606 607 ret = ReadBlocks(gScratchBuffer, pos, blocksRead); 608 if (ret < 0) 609 return ret; 610 611 uint32 bytesRead = fBlockSize * blocksRead - offset; 612 // copy no more than bufferSize bytes 613 if (bytesRead > bufferSize) 614 bytesRead = bufferSize; 615 616 memcpy(buffer, (void *)(gScratchBuffer + offset), bytesRead); 617 pos += blocksRead; 618 offset = 0; 619 blocksLeft -= blocksRead; 620 bufferSize -= bytesRead; 621 buffer = (void *)((addr_t)buffer + bytesRead); 622 totalBytesRead += bytesRead; 623 } 624 625 return totalBytesRead; 626 } 627 628 629 ssize_t 630 BlockHandle::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize) 631 { 632 // we don't have to know how to write 633 return B_NOT_ALLOWED; 634 } 635 636 637 ssize_t 638 BlockHandle::ReadBlocks(void *buffer, off_t first, int32 count) 639 { 640 return B_NOT_ALLOWED; 641 } 642 643 644 status_t 645 BlockHandle::FillIdentifier() 646 { 647 return B_NOT_ALLOWED; 648 } 649 650 // #pragma mark - 651 652 /* 653 * BIOS based disk access. 654 * Only for fallback from missing XHDI. 655 * XXX: This is broken! 656 * XXX: check for physical drives in PUN_INFO 657 * XXX: at least try to use MetaDOS calls instead. 658 */ 659 660 661 BIOSDrive::BIOSDrive(int handle) 662 : BlockHandle(handle) 663 { 664 TRACE(("BIOSDrive::%s(%d)\n", __FUNCTION__, fHandle)); 665 666 /* first check if the drive exists */ 667 /* note floppy B can be reported present anyway... */ 668 uint32 map = Drvmap(); 669 if (!(map & (1 << fHandle))) { 670 fSize = 0LL; 671 return; 672 } 673 //XXX: check size 674 675 if (get_drive_parameters(fHandle, &fParameters) != B_OK) { 676 dprintf("getting drive parameters for: %u failed!\n", fHandle); 677 return; 678 } 679 fBlockSize = 512; 680 fSize = fParameters.sectors * fBlockSize; 681 fHasParameters = false; 682 683 #if 0 684 if (get_ext_drive_parameters(driveID, &fParameters) != B_OK) { 685 // old style CHS support 686 687 if (get_drive_parameters(driveID, &fParameters) != B_OK) { 688 dprintf("getting drive parameters for: %u failed!\n", fDriveID); 689 return; 690 } 691 692 TRACE((" cylinders: %lu, heads: %lu, sectors: %lu, bytes_per_sector: %u\n", 693 fParameters.cylinders, fParameters.heads, fParameters.sectors_per_track, 694 fParameters.bytes_per_sector)); 695 TRACE((" total sectors: %Ld\n", fParameters.sectors)); 696 697 fBlockSize = 512; 698 fSize = fParameters.sectors * fBlockSize; 699 fLBA = false; 700 fHasParameters = false; 701 } else { 702 TRACE(("size: %x\n", fParameters.parameters_size)); 703 TRACE(("drive_path_signature: %x\n", fParameters.device_path_signature)); 704 TRACE(("host bus: \"%s\", interface: \"%s\"\n", fParameters.host_bus, 705 fParameters.interface_type)); 706 TRACE(("cylinders: %lu, heads: %lu, sectors: %lu, bytes_per_sector: %u\n", 707 fParameters.cylinders, fParameters.heads, fParameters.sectors_per_track, 708 fParameters.bytes_per_sector)); 709 TRACE(("total sectors: %Ld\n", fParameters.sectors)); 710 711 fBlockSize = fParameters.bytes_per_sector; 712 fSize = fParameters.sectors * fBlockSize; 713 fLBA = true; 714 fHasParameters = true; 715 } 716 #endif 717 } 718 719 720 BIOSDrive::~BIOSDrive() 721 { 722 } 723 724 725 status_t 726 BIOSDrive::FillIdentifier() 727 { 728 TRACE(("BIOSDrive::%s: (%d)\n", __FUNCTION__, fHandle)); 729 #if 0 730 if (HasParameters()) { 731 // try all drive_parameters versions, beginning from the most informative 732 733 #if 0 734 if (fill_disk_identifier_v3(fIdentifier, fParameters) == B_OK) 735 return B_OK; 736 737 if (fill_disk_identifier_v2(fIdentifier, fParameters) == B_OK) 738 return B_OK; 739 #else 740 // TODO: the above version is the correct one - it's currently 741 // disabled, as the kernel boot code only supports the 742 // UNKNOWN_BUS/UNKNOWN_DEVICE way to find the correct boot 743 // device. 744 if (fill_disk_identifier_v3(fIdentifier, fParameters) != B_OK) 745 fill_disk_identifier_v2(fIdentifier, fParameters); 746 747 #endif 748 749 // no interesting information, we have to fall back to the default 750 // unknown interface/device type identifier 751 } 752 753 fIdentifier.bus_type = UNKNOWN_BUS; 754 fIdentifier.device_type = UNKNOWN_DEVICE; 755 fIdentifier.device.unknown.size = Size(); 756 757 for (int32 i = 0; i < NUM_DISK_CHECK_SUMS; i++) { 758 fIdentifier.device.unknown.check_sums[i].offset = -1; 759 fIdentifier.device.unknown.check_sums[i].sum = 0; 760 } 761 #endif 762 763 return B_ERROR; 764 } 765 766 767 ssize_t 768 BIOSDrive::ReadBlocks(void *buffer, off_t first, int32 count) 769 { 770 int sectorsPerBlocks = (fBlockSize / 256); 771 int32 ret; 772 TRACE(("BIOSDrive::%s(%Ld,%ld) (%d)\n", __FUNCTION__, first, count, fHandle)); 773 // XXX: check for AHDI 3.0 before using long recno!!! 774 ret = Rwabs(RW_READ | RW_NOTRANSLATE, buffer, sectorsPerBlocks, -1, fHandle, first * sectorsPerBlocks); 775 if (ret < 0) 776 return toserror(ret); 777 return ret; 778 } 779 780 781 // #pragma mark - 782 783 /* 784 * XHDI based devices 785 */ 786 787 788 XHDIDrive::XHDIDrive(int handle, uint16 major, uint16 minor) 789 : BlockHandle(handle) 790 { 791 /* first check if the drive exists */ 792 int32 err; 793 uint32 devflags; 794 uint32 blocks; 795 uint32 blocksize; 796 char product[33]; 797 798 fMajor = major; 799 fMinor = minor; 800 TRACE(("XHDIDrive::%s(%d, %d,%d)\n", __FUNCTION__, handle, fMajor, fMinor)); 801 802 product[32] = '\0'; 803 err = XHInqTarget(major, minor, &fBlockSize, &devflags, product); 804 if (err < 0) 805 return; 806 //XXX: check size 807 err = XHGetCapacity(major, minor, &blocks, &blocksize); 808 if (err < 0) 809 return; 810 811 if (fBlockSize == 0) 812 fBlockSize = 512; 813 814 fSize = blocks * fBlockSize; 815 fHasParameters = false; 816 #if 0 817 if (get_drive_parameters(fHandle, &fParameters) != B_OK) { 818 dprintf("getting drive parameters for: %u failed!\n", fHandle); 819 return; 820 } 821 fBlockSize = 512; 822 fSize = fParameters.sectors * fBlockSize; 823 fHasParameters = false; 824 #endif 825 #if 0 826 if (get_ext_drive_parameters(driveID, &fParameters) != B_OK) { 827 // old style CHS support 828 829 if (get_drive_parameters(driveID, &fParameters) != B_OK) { 830 dprintf("getting drive parameters for: %u failed!\n", fDriveID); 831 return; 832 } 833 834 TRACE((" cylinders: %lu, heads: %lu, sectors: %lu, bytes_per_sector: %u\n", 835 fParameters.cylinders, fParameters.heads, fParameters.sectors_per_track, 836 fParameters.bytes_per_sector)); 837 TRACE((" total sectors: %Ld\n", fParameters.sectors)); 838 839 fBlockSize = 512; 840 fSize = fParameters.sectors * fBlockSize; 841 fLBA = false; 842 fHasParameters = false; 843 } else { 844 TRACE(("size: %x\n", fParameters.parameters_size)); 845 TRACE(("drive_path_signature: %x\n", fParameters.device_path_signature)); 846 TRACE(("host bus: \"%s\", interface: \"%s\"\n", fParameters.host_bus, 847 fParameters.interface_type)); 848 TRACE(("cylinders: %lu, heads: %lu, sectors: %lu, bytes_per_sector: %u\n", 849 fParameters.cylinders, fParameters.heads, fParameters.sectors_per_track, 850 fParameters.bytes_per_sector)); 851 TRACE(("total sectors: %Ld\n", fParameters.sectors)); 852 853 fBlockSize = fParameters.bytes_per_sector; 854 fSize = fParameters.sectors * fBlockSize; 855 fLBA = true; 856 fHasParameters = true; 857 } 858 #endif 859 } 860 861 862 XHDIDrive::~XHDIDrive() 863 { 864 } 865 866 867 status_t 868 XHDIDrive::FillIdentifier() 869 { 870 TRACE(("XHDIDrive::%s: (%d,%d)\n", __FUNCTION__, fMajor, fMinor)); 871 872 fIdentifier.bus_type = UNKNOWN_BUS; 873 fIdentifier.device_type = UNKNOWN_DEVICE; 874 fIdentifier.device.unknown.size = Size(); 875 #if 0 876 // cf. http://toshyp.atari.org/010008.htm#XHDI-Terminologie 877 if (fMajor >= 8 && fMajor <= 15) { // scsi 878 fIdentifier.device_type = SCSI_DEVICE; 879 fIdentifier.device.scsi.logical_unit = fMinor; 880 //XXX: where am I supposed to put the ID ??? 881 } 882 #endif 883 884 for (int32 i = 0; i < NUM_DISK_CHECK_SUMS; i++) { 885 fIdentifier.device.unknown.check_sums[i].offset = -1; 886 fIdentifier.device.unknown.check_sums[i].sum = 0; 887 } 888 889 return B_ERROR; 890 } 891 892 893 ssize_t 894 XHDIDrive::ReadBlocks(void *buffer, off_t first, int32 count) 895 { 896 int sectorsPerBlocks = (fBlockSize / 256); 897 int32 ret; 898 uint16 flags = RW_READ; 899 TRACE(("XHDIDrive::%s(%Ld, %d) (%d,%d)\n", __FUNCTION__, first, count, fMajor, fMinor)); 900 ret = XHReadWrite(fMajor, fMinor, flags, (uint32)first, (uint16)count, buffer); 901 if (ret < 0) 902 return xhdierror(ret); 903 //TRACE(("XHReadWrite: %ld\n", ret)); 904 /* 905 uint8 *b = (uint8 *)buffer; 906 int i = 0; 907 for (i = 0; i < 512; i+=16) { 908 TRACE(("[%8Ld+%3ld] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", 909 first, i, b[i], b[i+1], b[i+2], b[i+3], b[i+4], b[i+5], b[i+6], b[i+7], 910 b[i+8], b[i+9], b[i+10], b[i+11], b[i+12], b[i+13], b[i+14], b[i+15])); 911 //break; 912 } 913 */ 914 return ret; 915 } 916 917 918 919 920 // #pragma mark - 921 922 923 status_t 924 platform_add_boot_device(struct stage2_args *args, NodeList *devicesList) 925 { 926 TRACE(("boot drive ID: %x\n", gBootDriveID)); 927 init_xhdi(); 928 929 //XXX: FIXME 930 BlockHandle *drive = new(nothrow) BlockHandle(gBootDriveID); 931 if (drive->InitCheck() != B_OK) { 932 dprintf("no boot drive!\n"); 933 return B_ERROR; 934 } 935 936 devicesList->Add(drive); 937 938 if (drive->FillIdentifier() != B_OK) { 939 // We need to add all block devices to give the kernel the possibility 940 // to find the right boot volume 941 add_block_devices(devicesList, true); 942 } 943 944 TRACE(("boot drive size: %Ld bytes\n", drive->Size())); 945 gKernelArgs.boot_volume.SetInt32(BOOT_VOLUME_BOOTED_FROM_IMAGE, 946 gBootedFromImage); 947 948 return B_OK; 949 } 950 951 952 status_t 953 platform_get_boot_partition(struct stage2_args *args, Node *bootDevice, 954 NodeList *list, boot::Partition **_partition) 955 { 956 BlockHandle *drive = static_cast<BlockHandle *>(bootDevice); 957 off_t offset = (off_t)gBootPartitionOffset * drive->BlockSize(); 958 959 dprintf("boot partition offset: %Ld\n", offset); 960 961 NodeIterator iterator = list->GetIterator(); 962 boot::Partition *partition = NULL; 963 while ((partition = (boot::Partition *)iterator.Next()) != NULL) { 964 TRACE(("partition offset = %Ld, size = %Ld\n", partition->offset, partition->size)); 965 // search for the partition that contains the partition 966 // offset as reported by the BFS boot block 967 if (offset >= partition->offset 968 && offset < partition->offset + partition->size) { 969 *_partition = partition; 970 return B_OK; 971 } 972 } 973 974 return B_ENTRY_NOT_FOUND; 975 } 976 977 978 status_t 979 platform_add_block_devices(stage2_args *args, NodeList *devicesList) 980 { 981 init_xhdi(); 982 return add_block_devices(devicesList, false); 983 } 984 985 986 status_t 987 platform_register_boot_device(Node *device) 988 { 989 BlockHandle *drive = (BlockHandle *)device; 990 991 #if 0 992 check_cd_boot(drive); 993 #endif 994 995 gKernelArgs.boot_volume.SetInt64("boot drive number", drive->DriveID()); 996 gKernelArgs.boot_volume.SetData(BOOT_VOLUME_DISK_IDENTIFIER, B_RAW_TYPE, 997 &drive->Identifier(), sizeof(disk_identifier)); 998 999 return B_OK; 1000 } 1001 1002