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