1 /* 2 * COPYRIGHT: GPL - See COPYING in the top level directory 3 * PROJECT: ReactOS Virtual DOS Machine 4 * FILE: dskbios32.c 5 * PURPOSE: VDM 32-bit Disk BIOS 6 * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr) 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include "ntvdm.h" 12 13 #define NDEBUG 14 #include <debug.h> 15 16 #include "emulator.h" 17 // #include "../../memory.h" 18 // #include "cpu/bop.h" 19 #include "cpu/cpu.h" // for EMULATOR_FLAG_ZF 20 #include "int32.h" 21 22 #include "dskbios32.h" 23 // #include <bios/dskbios.h> 24 #include "bios32p.h" 25 26 #include "hardware/disk.h" 27 28 29 /* DEFINES ********************************************************************/ 30 31 // Disks which are currently supported by the BIOS Disk module. 32 // NOTE: For the current implementation those are arrays of pointers to 33 // DISK_IMAGEs maintained by the Generic Disk Controller. In the future 34 // they will be arrays of objects containing disk information needed by 35 // the BIOS only. 36 static PDISK_IMAGE FloppyDrive[2] = {NULL}; 37 static PDISK_IMAGE HardDrive[4] = {NULL}; 38 39 #pragma pack(push, 1) 40 41 // See: http://www.ctyme.com/intr/rb-2445.htm 42 typedef struct _FLOPPY_PARAM_TABLE 43 { 44 BYTE Unused0; 45 BYTE Unused1; 46 BYTE MotorOffDelay; 47 BYTE SectorSize; 48 BYTE SectorsPerTrack; 49 BYTE SectorGapLength; 50 BYTE DataLength; 51 BYTE FormatGapLength; 52 BYTE FormatFillByte; 53 BYTE HeadSettleTime; 54 BYTE MotorStartTime; 55 } FLOPPY_PARAM_TABLE, *PFLOPPY_PARAM_TABLE; 56 57 typedef struct _FLOPPY_PARAM_TABLE_EX 58 { 59 FLOPPY_PARAM_TABLE FloppyParamTable; 60 61 // IBM Additions 62 BYTE MaxTrackNumber; 63 BYTE DataTransferRate; 64 BYTE CmosDriveType; 65 } FLOPPY_PARAM_TABLE_EX, *PFLOPPY_PARAM_TABLE_EX; 66 67 #pragma pack(pop) 68 69 // Parameters for 1.44 MB Floppy, taken from SeaBIOS 70 71 #define FLOPPY_SIZE_CODE 0x02 // 512 byte sectors 72 #define FLOPPY_DATALEN 0xFF // Not used - because size code is 0x02 73 #define FLOPPY_MOTOR_TICKS 37 // ~2 seconds 74 #define FLOPPY_FILLBYTE 0xF6 75 #define FLOPPY_GAPLEN 0x1B 76 #define FLOPPY_FORMAT_GAPLEN 0x6C 77 78 static const FLOPPY_PARAM_TABLE_EX FloppyParamTable = 79 { 80 // PC-AT compatible table 81 { 82 0xAF, // step rate 12ms, head unload 240ms 83 0x02, // head load time 4ms, DMA used 84 FLOPPY_MOTOR_TICKS, // ~2 seconds 85 FLOPPY_SIZE_CODE, 86 18, 87 FLOPPY_GAPLEN, 88 FLOPPY_DATALEN, 89 FLOPPY_FORMAT_GAPLEN, 90 FLOPPY_FILLBYTE, 91 0x0F, // 15ms 92 0x08, // 1 second 93 }, 94 95 // IBM Additions 96 79, // maximum track 97 0, // data transfer rate 98 4, // drive type in CMOS 99 }; 100 101 102 #pragma pack(push, 1) 103 104 // See: http://www.ctyme.com/intr/rb-6135.htm 105 typedef struct _HARDDISK_PARAM_TABLE 106 { 107 WORD Cylinders; 108 BYTE Heads; 109 WORD Unused0; 110 WORD Unused1; 111 BYTE Unused2; 112 BYTE Control; 113 BYTE StandardTimeout; 114 BYTE FormatTimeout; 115 BYTE CheckingTimeout; 116 WORD LandZoneCylinder; 117 BYTE SectorsPerTrack; 118 BYTE Reserved; 119 } HARDDISK_PARAM_TABLE, *PHARDDISK_PARAM_TABLE; 120 121 #pragma pack(pop) 122 123 // static const HARDDISK_PARAM_TABLE HardDiskParamTable = 124 // {0}; 125 126 127 /* PRIVATE FUNCTIONS **********************************************************/ 128 129 static PDISK_IMAGE 130 GetDisk(IN BYTE DiskNumber) 131 { 132 if (DiskNumber & 0x80) 133 { 134 DiskNumber &= ~0x80; 135 136 if (DiskNumber >= ARRAYSIZE(HardDrive)) 137 { 138 DPRINT1("GetDisk: HDD number 0x%02X invalid\n", DiskNumber | 0x80); 139 return NULL; 140 } 141 142 return HardDrive[DiskNumber]; 143 } 144 else 145 { 146 if (DiskNumber >= ARRAYSIZE(FloppyDrive)) 147 { 148 DPRINT1("GetDisk: Floppy number 0x%02X invalid\n", DiskNumber); 149 return NULL; 150 } 151 152 return FloppyDrive[DiskNumber]; 153 } 154 } 155 156 static VOID 157 AllDisksReset(VOID) 158 { 159 Bda->LastDisketteOperation = 0; 160 Bda->LastDiskOperation = 0; 161 } 162 163 /*static*/ 164 VOID WINAPI BiosDiskService(LPWORD Stack) 165 { 166 BYTE Drive; 167 PDISK_IMAGE DiskImage; 168 169 switch (getAH()) 170 { 171 /* Disk -- Reset Disk System */ 172 case 0x00: 173 { 174 Drive = getDL(); 175 176 if (Drive & 0x80) 177 { 178 AllDisksReset(); 179 180 /* Return success */ 181 setAH(0x00); 182 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; 183 break; 184 } 185 186 Drive &= ~0x80; 187 188 if (Drive >= ARRAYSIZE(FloppyDrive)) 189 { 190 DPRINT1("BiosDiskService(0x00): Drive number 0x%02X invalid\n", Drive); 191 192 /* Return error */ 193 setAH(0x01); 194 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; 195 break; 196 } 197 198 // TODO: Reset drive 199 200 /* Return success */ 201 setAH(0x00); 202 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; 203 break; 204 } 205 206 /* Disk -- Get Status of Last Operation */ 207 case 0x01: 208 { 209 BYTE LastOperationStatus = 0x00; 210 211 Drive = getDL(); 212 DiskImage = GetDisk(Drive); 213 if (!DiskImage || !IsDiskPresent(DiskImage)) 214 { 215 DPRINT1("BiosDiskService(0x01): Disk number 0x%02X invalid\n", Drive); 216 217 /* Return error */ 218 setAH(0x01); 219 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; 220 break; 221 } 222 223 LastOperationStatus = DiskImage->LastOperationStatus; 224 225 if (Drive & 0x80) 226 Bda->LastDiskOperation = LastOperationStatus; 227 else 228 Bda->LastDisketteOperation = LastOperationStatus; 229 230 /* Return last error */ 231 setAH(LastOperationStatus); 232 if (LastOperationStatus == 0x00) 233 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; 234 else 235 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; 236 237 break; 238 } 239 240 /* Disk -- Read Sectors into Memory */ 241 case 0x02: 242 { 243 BYTE Status; 244 BYTE Head = getDH(); 245 BYTE NumSectors = getAL(); 246 247 // CH: Low eight bits of cylinder number 248 // CL: High two bits of cylinder (bits 6-7, hard disk only) 249 WORD Cylinder = MAKEWORD(getCH(), (getCL() >> 6) & 0x02); 250 251 // CL: Sector number 1-63 (bits 0-5) 252 BYTE Sector = (getCL() & 0x3F); // 1-based 253 254 Drive = getDL(); 255 DiskImage = GetDisk(Drive); 256 if (!DiskImage || !IsDiskPresent(DiskImage)) 257 { 258 DPRINT1("BiosDiskService(0x02): Disk number 0x%02X invalid\n", Drive); 259 260 /* Return error */ 261 setAH(0x01); 262 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; 263 break; 264 } 265 266 /* Read the sectors */ 267 Status = ReadDisk(DiskImage, Cylinder, Head, Sector, NumSectors); 268 if (Status == 0x00) 269 { 270 /* Return success */ 271 setAH(0x00); 272 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; 273 } 274 else 275 { 276 DPRINT1("BiosDiskService(0x02): Error when reading from disk number 0x%02X (0x%02X)\n", Drive, Status); 277 278 /* Return error */ 279 setAH(Status); 280 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; 281 } 282 283 break; 284 } 285 286 /* Disk -- Write Disk Sectors */ 287 case 0x03: 288 { 289 BYTE Status; 290 BYTE Head = getDH(); 291 BYTE NumSectors = getAL(); 292 293 // CH: Low eight bits of cylinder number 294 // CL: High two bits of cylinder (bits 6-7, hard disk only) 295 WORD Cylinder = MAKEWORD(getCH(), (getCL() >> 6) & 0x02); 296 297 // CL: Sector number 1-63 (bits 0-5) 298 BYTE Sector = (getCL() & 0x3F); // 1-based 299 300 Drive = getDL(); 301 DiskImage = GetDisk(Drive); 302 if (!DiskImage || !IsDiskPresent(DiskImage)) 303 { 304 DPRINT1("BiosDiskService(0x03): Disk number 0x%02X invalid\n", Drive); 305 306 /* Return error */ 307 setAH(0x01); 308 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; 309 break; 310 } 311 312 /* Write the sectors */ 313 Status = WriteDisk(DiskImage, Cylinder, Head, Sector, NumSectors); 314 if (Status == 0x00) 315 { 316 /* Return success */ 317 setAH(0x00); 318 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; 319 } 320 else 321 { 322 DPRINT1("BiosDiskService(0x03): Error when writing to disk number 0x%02X (0x%02X)\n", Drive, Status); 323 324 /* Return error */ 325 setAH(Status); 326 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; 327 } 328 329 break; 330 } 331 332 /* Disk -- Verify Disk Sectors */ 333 case 0x04: 334 335 /* Floppy/Fixed Disk -- Format Track */ 336 case 0x05: 337 338 /* Fixed Disk -- Format Track and Set Bad Sector Flags */ 339 case 0x06: 340 341 /* Fixed Disk -- Format Drive starting at Given Track */ 342 case 0x07: 343 goto Default; 344 345 /* Disk -- Get Drive Parameters */ 346 case 0x08: 347 { 348 WORD MaxCylinders; 349 BYTE MaxHeads; 350 BYTE PresentDrives = 0; 351 BYTE i; 352 353 Drive = getDL(); 354 DiskImage = GetDisk(Drive); 355 if (!DiskImage || !IsDiskPresent(DiskImage)) 356 { 357 DPRINT1("BiosDiskService(0x08): Disk number 0x%02X invalid\n", Drive); 358 359 /* Return error */ 360 setAH(0x01); 361 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; 362 break; 363 } 364 365 // Minus 2 because it's the maximum cylinder number (not count), 366 // and the last cylinder is reserved (for compatibility with BIOSes 367 // which reserve it for testing purposes). 368 MaxCylinders = DiskImage->DiskInfo.Cylinders - 2; 369 // Minus 1 because it's the maximum head number (not count). 370 MaxHeads = DiskImage->DiskInfo.Heads - 1; 371 372 // CL: Sector number 1-63 (bits 0-5) 373 // High two bits of cylinder (bits 6-7, hard disk only) 374 setCL((DiskImage->DiskInfo.Sectors & 0x3F) | 375 ((HIBYTE(MaxCylinders) & 0x02) << 6)); 376 // CH: Low eight bits of cylinder number 377 setCH(LOBYTE(MaxCylinders)); 378 379 setDH(MaxHeads); 380 381 if (Drive & 0x80) 382 { 383 /* Count the number of active HDDs */ 384 for (i = 0; i < ARRAYSIZE(HardDrive); ++i) 385 { 386 if (IsDiskPresent(HardDrive[i])) 387 ++PresentDrives; 388 } 389 390 /* Reset ES:DI to NULL */ 391 // FIXME: NONONO!! Apps expect (for example, MS-DOS kernel) 392 // that this function does not modify ES:DI if it was called 393 // for a HDD. 394 // setES(0x0000); 395 // setDI(0x0000); 396 } 397 else 398 { 399 /* Count the number of active floppies */ 400 for (i = 0; i < ARRAYSIZE(FloppyDrive); ++i) 401 { 402 if (IsDiskPresent(FloppyDrive[i])) 403 ++PresentDrives; 404 } 405 406 /* ES:DI points to the floppy parameter table */ 407 setES(HIWORD(((PULONG)BaseAddress)[0x1E])); 408 setDI(LOWORD(((PULONG)BaseAddress)[0x1E])); 409 } 410 setDL(PresentDrives); 411 412 setBL(DiskImage->DiskType); // DiskGeometryList[DiskImage->DiskType].biosval 413 setAL(0x00); 414 415 /* Return success */ 416 setAH(0x00); 417 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; 418 break; 419 } 420 421 /* Hard Disk -- Initialize Controller with Drive Parameters */ 422 case 0x09: 423 424 /* Hard Disk -- Read Long Sectors */ 425 case 0x0A: 426 427 /* Hard Disk -- Write Long Sectors */ 428 case 0x0B: 429 goto Default; 430 431 /* Hard Disk -- Seek to Cylinder */ 432 case 0x0C: 433 { 434 BYTE Status; 435 BYTE Head = getDH(); 436 437 // CH: Low eight bits of cylinder number 438 // CL: High two bits of cylinder (bits 6-7, hard disk only) 439 WORD Cylinder = MAKEWORD(getCH(), (getCL() >> 6) & 0x02); 440 441 // CL: Sector number 1-63 (bits 0-5) 442 BYTE Sector = (getCL() & 0x3F); // 1-based 443 444 Drive = getDL(); 445 if (!(Drive & 0x80)) 446 { 447 DPRINT1("BiosDiskService(0x0C): Disk number 0x%02X is not a HDD\n", Drive); 448 449 /* Return error */ 450 setAH(0x01); 451 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; 452 break; 453 } 454 455 DiskImage = GetDisk(Drive); 456 if (!DiskImage || !IsDiskPresent(DiskImage)) 457 { 458 DPRINT1("BiosDiskService(0x0C): Disk number 0x%02X invalid\n", Drive); 459 460 /* Return error */ 461 setAH(0x01); 462 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; 463 break; 464 } 465 466 /* Set position */ 467 Status = SeekDisk(DiskImage, Cylinder, Head, Sector); 468 if (Status == 0x00) 469 { 470 /* Return success */ 471 setAH(0x00); 472 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; 473 } 474 else 475 { 476 DPRINT1("BiosDiskService(0x0C): Error when seeking in disk number 0x%02X (0x%02X)\n", Drive, Status); 477 478 /* Return error */ 479 setAH(Status); 480 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; 481 } 482 483 break; 484 } 485 486 /* Hard Disk -- Reset Hard Disks */ 487 case 0x0D: 488 { 489 // FIXME: Should do what 0x11 does. 490 UNIMPLEMENTED; 491 } 492 493 /* Hard Disk -- Read Sector Buffer (XT only) */ 494 case 0x0E: 495 496 /* Hard Disk -- Write Sector Buffer (XT only) */ 497 case 0x0F: 498 goto Default; 499 500 /* Hard Disk -- Check if Drive is ready */ 501 case 0x10: 502 { 503 Drive = getDL(); 504 if (!(Drive & 0x80)) 505 { 506 DPRINT1("BiosDiskService(0x10): Disk number 0x%02X is not a HDD\n", Drive); 507 508 /* Return error */ 509 setAH(0x01); 510 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; 511 break; 512 } 513 514 DiskImage = GetDisk(Drive); 515 if (!DiskImage || !IsDiskPresent(DiskImage)) 516 { 517 DPRINT1("BiosDiskService(0x10): Disk number 0x%02X invalid\n", Drive); 518 519 /* Return error */ 520 setAH(0x01); 521 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; 522 break; 523 } 524 525 /* Return success */ 526 setAH(0x00); 527 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; 528 break; 529 } 530 531 /* Hard Disk -- Recalibrate Drive */ 532 case 0x11: 533 { 534 BYTE Status; 535 536 Drive = getDL(); 537 if (!(Drive & 0x80)) 538 { 539 DPRINT1("BiosDiskService(0x11): Disk number 0x%02X is not a HDD\n", Drive); 540 541 /* Return error */ 542 setAH(0x01); 543 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; 544 break; 545 } 546 547 DiskImage = GetDisk(Drive); 548 if (!DiskImage || !IsDiskPresent(DiskImage)) 549 { 550 DPRINT1("BiosDiskService(0x11): Disk number 0x%02X invalid\n", Drive); 551 552 /* Return error */ 553 setAH(0x01); 554 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; 555 break; 556 } 557 558 /* Set position to zero */ 559 Status = SeekDisk(DiskImage, /*Cylinder*/ 0, /*Head*/ 0, /*Sector*/ 1); 560 if (Status == 0x00) 561 { 562 /* Return success */ 563 setAH(0x00); 564 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; 565 } 566 else 567 { 568 DPRINT1("BiosDiskService(0x11): Error when recalibrating disk number 0x%02X (0x%02X)\n", Drive, Status); 569 570 /* Return error */ 571 setAH(Status); 572 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; 573 } 574 575 break; 576 } 577 578 /* Hard Disk -- Controller RAM Diagnostic */ 579 case 0x12: 580 581 /* Hard Disk -- Drive Diagnostic */ 582 case 0x13: 583 584 /* Hard Disk -- Controller Internal Diagnostic */ 585 case 0x14: 586 goto Default; 587 588 /* Disk -- Get Disk Type */ 589 case 0x15: 590 { 591 Drive = getDL(); 592 DiskImage = GetDisk(Drive); 593 if (!DiskImage || !IsDiskPresent(DiskImage)) 594 { 595 DPRINT1("BiosDiskService(0x15): Disk number 0x%02X invalid\n", Drive); 596 597 /* Return error */ 598 setAH(0x01); 599 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; 600 break; 601 } 602 603 if (Drive & 0x80) 604 { 605 ULONG NumSectors; 606 607 /* Hard disk */ 608 setAH(0x03); 609 610 /* Number of 512-byte sectors in CX:DX */ 611 NumSectors = (ULONG)((ULONG)DiskImage->DiskInfo.Cylinders * DiskImage->DiskInfo.Heads) 612 * DiskImage->DiskInfo.Sectors; 613 setCX(HIWORD(NumSectors)); 614 setDX(LOWORD(NumSectors)); 615 } 616 else 617 { 618 /* Floppy */ 619 setAH(0x01); 620 } 621 622 /* Return success */ 623 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; 624 break; 625 } 626 627 /* Floppy Disk -- Detect Disk Change */ 628 case 0x16: 629 630 /* Floppy Disk -- Set Disk Type for Format */ 631 case 0x17: 632 633 /* Disk -- Set Media Type for Format */ 634 case 0x18: 635 goto Default; 636 637 default: Default: 638 { 639 DPRINT1("BIOS Function INT 13h, AH = 0x%02X, AL = 0x%02X, BH = 0x%02X NOT IMPLEMENTED\n", 640 getAH(), getAL(), getBH()); 641 } 642 } 643 } 644 645 /* PUBLIC FUNCTIONS ***********************************************************/ 646 647 VOID DiskBios32Post(VOID) 648 { 649 /* 650 * Initialize BIOS Disk RAM dynamic data 651 */ 652 653 /* Some vectors are in fact addresses to tables */ 654 // Diskette Parameters 655 ((PULONG)BaseAddress)[0x1E] = MAKELONG(0xEFC7, BIOS_SEGMENT); 656 // Hard Disk 0 Parameter Table Address 657 ((PULONG)BaseAddress)[0x41] = NULL32; 658 // Hard Disk 1 Drive Parameter Table Address 659 ((PULONG)BaseAddress)[0x46] = NULL32; 660 661 /* Relocated services by the BIOS (when needed) */ 662 ((PULONG)BaseAddress)[0x40] = NULL32; // ROM BIOS Diskette Handler relocated by Hard Disk BIOS 663 // RegisterBiosInt32(0x40, NULL); // ROM BIOS Diskette Handler relocated by Hard Disk BIOS 664 665 /* Register the BIOS 32-bit Interrupts */ 666 RegisterBiosInt32(BIOS_DISK_INTERRUPT, BiosDiskService); 667 668 /* Initialize the BDA */ 669 // Bda->LastDisketteOperation = 0; 670 // Bda->LastDiskOperation = 0; 671 AllDisksReset(); 672 } 673 674 BOOLEAN DiskBios32Initialize(VOID) 675 { 676 /* 677 * Initialize BIOS Disk ROM static data 678 */ 679 680 /* Floppy Parameter Table */ 681 RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xEFC7), 682 &FloppyParamTable.FloppyParamTable, 683 sizeof(FloppyParamTable.FloppyParamTable)); 684 685 // 686 // FIXME: Must be done by HW floppy controller! 687 // 688 689 /* Detect and initialize the supported disks */ 690 // TODO: the "Detect" part is missing. 691 FloppyDrive[0] = RetrieveDisk(FLOPPY_DISK, 0); 692 FloppyDrive[1] = RetrieveDisk(FLOPPY_DISK, 1); 693 HardDrive[0] = RetrieveDisk(HARD_DISK, 0); 694 HardDrive[1] = RetrieveDisk(HARD_DISK, 1); 695 HardDrive[2] = RetrieveDisk(HARD_DISK, 2); 696 HardDrive[3] = RetrieveDisk(HARD_DISK, 3); 697 698 return TRUE; 699 } 700 701 VOID DiskBios32Cleanup(VOID) 702 { 703 } 704 705 /* EOF */ 706