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