1 /*++ 2 3 Copyright (C) Microsoft Corporation, 1991 - 1999 4 5 Module Name: 6 7 geometry.c 8 9 Abstract: 10 11 SCSI disk class driver - this module contains all the code for generating 12 disk geometries. 13 14 Environment: 15 16 kernel mode only 17 18 Notes: 19 20 Revision History: 21 22 --*/ 23 24 25 #include "disk.h" 26 #include "ntddstor.h" 27 28 #ifdef DEBUG_USE_WPP 29 #include "geometry.tmh" 30 #endif 31 32 #if defined(_X86_) || defined(_AMD64_) 33 34 DISK_GEOMETRY_SOURCE 35 DiskUpdateGeometry( 36 IN PFUNCTIONAL_DEVICE_EXTENSION DeviceExtension 37 ); 38 39 NTSTATUS 40 DiskUpdateRemovableGeometry ( 41 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 42 ); 43 44 VOID 45 DiskScanBusDetectInfo( 46 IN PDRIVER_OBJECT DriverObject, 47 IN HANDLE BusKey 48 ); 49 50 NTSTATUS 51 DiskSaveBusDetectInfo( 52 IN PDRIVER_OBJECT DriverObject, 53 IN HANDLE TargetKey, 54 IN ULONG DiskNumber 55 ); 56 57 NTSTATUS 58 DiskSaveGeometryDetectInfo( 59 IN PDRIVER_OBJECT DriverObject, 60 IN HANDLE HardwareKey 61 ); 62 63 NTSTATUS 64 DiskGetPortGeometry( 65 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 66 OUT PDISK_GEOMETRY Geometry 67 ); 68 69 typedef struct _DISK_DETECT_INFO { 70 BOOLEAN Initialized; 71 ULONG Style; 72 ULONG Signature; 73 ULONG MbrCheckSum; 74 PDEVICE_OBJECT Device; 75 CM_INT13_DRIVE_PARAMETER DriveParameters; 76 } DISK_DETECT_INFO, *PDISK_DETECT_INFO; 77 78 // 79 // Information about the disk geometries collected and saved into the registry 80 // by NTDETECT.COM or the system firmware. 81 // 82 83 PDISK_DETECT_INFO DetectInfoList = NULL; 84 ULONG DetectInfoCount = 0; 85 LONG DetectInfoUsedCount = 0; 86 87 #define GET_STARTING_SECTOR(p) ( \ 88 (ULONG) (p->StartingSectorLsb0) + \ 89 (ULONG) (p->StartingSectorLsb1 << 8 ) + \ 90 (ULONG) (p->StartingSectorMsb0 << 16) + \ 91 (ULONG) (p->StartingSectorMsb1 << 24) ) 92 93 #define GET_ENDING_S_OF_CHS(p) ( \ 94 (UCHAR) (p->EndingCylinderLsb & 0x3F) ) 95 96 // 97 // Definitions from hal.h 98 // 99 100 // 101 // Boot record disk partition table entry structure format 102 // 103 104 typedef struct _PARTITION_DESCRIPTOR 105 { 106 UCHAR ActiveFlag; 107 UCHAR StartingTrack; 108 UCHAR StartingCylinderLsb; 109 UCHAR StartingCylinderMsb; 110 UCHAR PartitionType; 111 UCHAR EndingTrack; 112 UCHAR EndingCylinderLsb; 113 UCHAR EndingCylinderMsb; 114 UCHAR StartingSectorLsb0; 115 UCHAR StartingSectorLsb1; 116 UCHAR StartingSectorMsb0; 117 UCHAR StartingSectorMsb1; 118 UCHAR PartitionLengthLsb0; 119 UCHAR PartitionLengthLsb1; 120 UCHAR PartitionLengthMsb0; 121 UCHAR PartitionLengthMsb1; 122 123 } PARTITION_DESCRIPTOR, *PPARTITION_DESCRIPTOR; 124 125 // 126 // Number of partition table entries 127 // 128 129 #define NUM_PARTITION_TABLE_ENTRIES 4 130 131 // 132 // Partition table record and boot signature offsets in 16-bit words 133 // 134 135 #define PARTITION_TABLE_OFFSET ( 0x1be / 2) 136 #define BOOT_SIGNATURE_OFFSET ((0x200 / 2) - 1) 137 138 // 139 // Boot record signature value 140 // 141 142 #define BOOT_RECORD_SIGNATURE (0xaa55) 143 144 145 #ifdef ALLOC_PRAGMA 146 #pragma alloc_text(INIT, DiskSaveDetectInfo) 147 #pragma alloc_text(INIT, DiskScanBusDetectInfo) 148 #pragma alloc_text(INIT, DiskSaveBusDetectInfo) 149 #pragma alloc_text(INIT, DiskSaveGeometryDetectInfo) 150 151 #pragma alloc_text(PAGE, DiskUpdateGeometry) 152 #pragma alloc_text(PAGE, DiskUpdateRemovableGeometry) 153 #pragma alloc_text(PAGE, DiskGetPortGeometry) 154 #pragma alloc_text(PAGE, DiskIsNT4Geometry) 155 #pragma alloc_text(PAGE, DiskGetDetectInfo) 156 #pragma alloc_text(PAGE, DiskReadSignature) 157 #endif 158 159 160 NTSTATUS 161 DiskSaveDetectInfo( 162 PDRIVER_OBJECT DriverObject 163 ) 164 165 /*++ 166 167 Routine Description: 168 169 This routine saves away the firmware information about the disks which has 170 been saved in the registry. It generates a list (DetectInfoList) which 171 contains the disk geometries, signatures & checksums of all drives which 172 were examined by NtDetect. This list is later used to assign geometries 173 to disks as they are initialized. 174 175 Arguments: 176 177 DriverObject - the driver being initialized. This is used to get to the 178 hardware database. 179 180 Return Value: 181 182 status. 183 184 --*/ 185 186 { 187 OBJECT_ATTRIBUTES objectAttributes = {0}; 188 HANDLE hardwareKey; 189 190 UNICODE_STRING unicodeString; 191 HANDLE busKey; 192 193 NTSTATUS status; 194 195 PAGED_CODE(); 196 197 InitializeObjectAttributes( 198 &objectAttributes, 199 DriverObject->HardwareDatabase, 200 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 201 NULL, 202 NULL); 203 204 // 205 // Create the hardware base key. 206 // 207 208 status = ZwOpenKey(&hardwareKey, KEY_READ, &objectAttributes); 209 210 if(!NT_SUCCESS(status)) { 211 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveDetectInfo: Cannot open hardware data. " 212 "Name: %wZ\n", 213 DriverObject->HardwareDatabase)); 214 return status; 215 } 216 217 status = DiskSaveGeometryDetectInfo(DriverObject, hardwareKey); 218 219 if(!NT_SUCCESS(status)) { 220 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveDetectInfo: Can't query configuration data " 221 "(%#08lx)\n", 222 status)); 223 ZwClose(hardwareKey); 224 return status; 225 } 226 227 // 228 // Open EISA bus key. 229 // 230 231 RtlInitUnicodeString(&unicodeString, L"EisaAdapter"); 232 InitializeObjectAttributes(&objectAttributes, 233 &unicodeString, 234 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 235 hardwareKey, 236 NULL); 237 238 status = ZwOpenKey(&busKey, 239 KEY_READ, 240 &objectAttributes); 241 242 if(NT_SUCCESS(status)) { 243 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskSaveDetectInfo: Opened EisaAdapter key\n")); 244 DiskScanBusDetectInfo(DriverObject, busKey); 245 ZwClose(busKey); 246 } 247 248 // 249 // Open MultiFunction bus key. 250 // 251 252 RtlInitUnicodeString(&unicodeString, L"MultifunctionAdapter"); 253 InitializeObjectAttributes(&objectAttributes, 254 &unicodeString, 255 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 256 hardwareKey, 257 NULL); 258 259 status = ZwOpenKey(&busKey, 260 KEY_READ, 261 &objectAttributes); 262 263 if(NT_SUCCESS(status)) { 264 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskSaveDetectInfo: Opened MultifunctionAdapter key\n")); 265 DiskScanBusDetectInfo(DriverObject, busKey); 266 ZwClose(busKey); 267 } 268 269 ZwClose(hardwareKey); 270 271 return STATUS_SUCCESS; 272 } 273 274 275 VOID 276 DiskCleanupDetectInfo( 277 IN PDRIVER_OBJECT DriverObject 278 ) 279 /*++ 280 281 Routine Description: 282 283 This routine will cleanup the data structure built by DiskSaveDetectInfo. 284 285 Arguments: 286 287 DriverObject - a pointer to the kernel object for this driver. 288 289 Return Value: 290 291 none 292 293 --*/ 294 295 { 296 UNREFERENCED_PARAMETER(DriverObject); 297 FREE_POOL(DetectInfoList); 298 return; 299 } 300 301 302 NTSTATUS 303 DiskSaveGeometryDetectInfo( 304 IN PDRIVER_OBJECT DriverObject, 305 IN HANDLE HardwareKey 306 ) 307 { 308 UNICODE_STRING unicodeString; 309 PKEY_VALUE_FULL_INFORMATION keyData; 310 ULONG length; 311 312 PCM_FULL_RESOURCE_DESCRIPTOR fullDescriptor; 313 PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptor; 314 315 PCM_INT13_DRIVE_PARAMETER driveParameters; 316 ULONG numberOfDrives; 317 318 ULONG i; 319 320 NTSTATUS status; 321 322 PAGED_CODE(); 323 UNREFERENCED_PARAMETER(DriverObject); 324 325 // 326 // Get disk BIOS geometry information. 327 // 328 329 RtlInitUnicodeString(&unicodeString, L"Configuration Data"); 330 331 keyData = ExAllocatePoolWithTag(PagedPool, 332 VALUE_BUFFER_SIZE, 333 DISK_TAG_UPDATE_GEOM); 334 335 if(keyData == NULL) { 336 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveGeometryDetectInfo: Can't allocate config " 337 "data buffer\n")); 338 return STATUS_INSUFFICIENT_RESOURCES; 339 } 340 341 status = ZwQueryValueKey(HardwareKey, 342 &unicodeString, 343 KeyValueFullInformation, 344 keyData, 345 VALUE_BUFFER_SIZE, 346 &length); 347 348 if(!NT_SUCCESS(status)) { 349 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveGeometryDetectInfo: Can't query configuration " 350 "data (%#08lx)\n", 351 status)); 352 FREE_POOL(keyData); 353 return status; 354 } 355 356 // 357 // Extract the resource list out of the key data. 358 // 359 360 fullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR) 361 (((PUCHAR) keyData) + keyData->DataOffset); 362 partialDescriptor = 363 fullDescriptor->PartialResourceList.PartialDescriptors; 364 length = partialDescriptor->u.DeviceSpecificData.DataSize; 365 366 if((keyData->DataLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) || 367 (fullDescriptor->PartialResourceList.Count == 0) || 368 (partialDescriptor->Type != CmResourceTypeDeviceSpecific) || 369 (length < sizeof(ULONG))) { 370 371 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveGeometryDetectInfo: BIOS header data too small " 372 "or invalid\n")); 373 FREE_POOL(keyData); 374 return STATUS_INVALID_PARAMETER; 375 } 376 377 // 378 // Point to the BIOS data. THe BIOS data is located after the first 379 // partial Resource list which should be device specific data. 380 // 381 382 { 383 PUCHAR buffer = (PUCHAR) keyData; 384 buffer += keyData->DataOffset; 385 buffer += sizeof(CM_FULL_RESOURCE_DESCRIPTOR); 386 driveParameters = (PCM_INT13_DRIVE_PARAMETER) buffer; 387 } 388 389 numberOfDrives = length / sizeof(CM_INT13_DRIVE_PARAMETER); 390 391 // 392 // Allocate our detect info list now that we know how many entries there 393 // are going to be. No other routine allocates detect info and this is 394 // done out of DriverEntry so we don't need to synchronize it's creation. 395 // 396 397 length = sizeof(DISK_DETECT_INFO) * numberOfDrives; 398 DetectInfoList = ExAllocatePoolWithTag(PagedPool, 399 length, 400 DISK_TAG_UPDATE_GEOM); 401 402 if(DetectInfoList == NULL) { 403 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveGeometryDetectInfo: Couldn't allocate %x bytes " 404 "for DetectInfoList\n", 405 length)); 406 407 FREE_POOL(keyData); 408 return STATUS_INSUFFICIENT_RESOURCES; 409 } 410 411 DetectInfoCount = numberOfDrives; 412 413 RtlZeroMemory(DetectInfoList, length); 414 415 // 416 // Copy the information out of the key data and into the list we've 417 // allocated. 418 // 419 420 for(i = 0; i < numberOfDrives; i++) { 421 #ifdef _MSC_VER 422 #pragma warning(suppress: 6386) // PREFast bug means it doesn't correctly remember the size of DetectInfoList 423 #endif 424 DetectInfoList[i].DriveParameters = driveParameters[i]; 425 } 426 427 FREE_POOL(keyData); 428 return STATUS_SUCCESS; 429 } 430 431 432 VOID 433 DiskScanBusDetectInfo( 434 IN PDRIVER_OBJECT DriverObject, 435 IN HANDLE BusKey 436 ) 437 /*++ 438 439 Routine Description: 440 441 The routine queries the registry to determine which disks are visible to 442 the BIOS. If a disk is visable to the BIOS then the geometry information 443 is updated with the disk's signature and MBR checksum. 444 445 Arguments: 446 447 DriverObject - the object for this driver. 448 BusKey - handle to the bus key to be enumerated. 449 450 Return Value: 451 452 status 453 454 --*/ 455 { 456 ULONG busNumber; 457 458 NTSTATUS status; 459 460 for(busNumber = 0; ; busNumber++) { 461 462 WCHAR buffer[32] = { 0 }; 463 UNICODE_STRING unicodeString; 464 465 OBJECT_ATTRIBUTES objectAttributes = {0}; 466 467 HANDLE spareKey; 468 HANDLE adapterKey; 469 470 ULONG adapterNumber; 471 472 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Scanning bus %d\n", busNumber)); 473 474 // 475 // Open controller name key. 476 // 477 478 status = RtlStringCchPrintfW(buffer, sizeof(buffer) / sizeof(buffer[0]) - 1, L"%d", busNumber); 479 if (!NT_SUCCESS(status)) { 480 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Format symbolic link failed with error: 0x%X\n", status)); 481 break; 482 } 483 484 RtlInitUnicodeString(&unicodeString, buffer); 485 486 InitializeObjectAttributes(&objectAttributes, 487 &unicodeString, 488 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 489 BusKey, 490 NULL); 491 492 status = ZwOpenKey(&spareKey, KEY_READ, &objectAttributes); 493 494 if(!NT_SUCCESS(status)) { 495 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Error %#08lx opening bus " 496 "key %#x\n", 497 status, busNumber)); 498 break; 499 } 500 501 // 502 // Open up a controller ordinal key. 503 // 504 505 RtlInitUnicodeString(&unicodeString, L"DiskController"); 506 InitializeObjectAttributes(&objectAttributes, 507 &unicodeString, 508 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 509 spareKey, 510 NULL); 511 512 status = ZwOpenKey(&adapterKey, KEY_READ, &objectAttributes); 513 ZwClose(spareKey); 514 515 if(!NT_SUCCESS(status)) { 516 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Error %#08lx opening " 517 "DiskController key\n", 518 status)); 519 continue; 520 } 521 522 for(adapterNumber = 0; ; adapterNumber++) { 523 524 HANDLE diskKey; 525 ULONG diskNumber; 526 527 // 528 // Open disk key. 529 // 530 531 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Scanning disk key " 532 "%d\\DiskController\\%d\\DiskPeripheral\n", 533 busNumber, adapterNumber)); 534 535 status = RtlStringCchPrintfW(buffer, sizeof(buffer) / sizeof(buffer[0]) - 1, L"%d\\DiskPeripheral", adapterNumber); 536 if (!NT_SUCCESS(status)) { 537 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Format symbolic link failed with error: 0x%X\n", status)); 538 break; 539 } 540 541 RtlInitUnicodeString(&unicodeString, buffer); 542 543 InitializeObjectAttributes(&objectAttributes, 544 &unicodeString, 545 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 546 adapterKey, 547 NULL); 548 549 status = ZwOpenKey(&diskKey, KEY_READ, &objectAttributes); 550 551 if(!NT_SUCCESS(status)) { 552 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Error %#08lx opening " 553 "disk key\n", 554 status)); 555 break; 556 } 557 558 for(diskNumber = 0; ; diskNumber++) { 559 560 HANDLE targetKey; 561 562 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Scanning target key " 563 "%d\\DiskController\\%d\\DiskPeripheral\\%d\n", 564 busNumber, adapterNumber, diskNumber)); 565 566 status = RtlStringCchPrintfW(buffer, sizeof(buffer) / sizeof(buffer[0]) - 1, L"%d", diskNumber); 567 if (!NT_SUCCESS(status)) { 568 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Format symbolic link failed with error: 0x%X\n", status)); 569 break; 570 } 571 572 RtlInitUnicodeString(&unicodeString, buffer); 573 574 InitializeObjectAttributes(&objectAttributes, 575 &unicodeString, 576 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 577 diskKey, 578 NULL); 579 580 status = ZwOpenKey(&targetKey, KEY_READ, &objectAttributes); 581 582 if(!NT_SUCCESS(status)) { 583 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Error %#08lx " 584 "opening target key\n", 585 status)); 586 break; 587 } 588 589 DiskSaveBusDetectInfo(DriverObject, targetKey, diskNumber); 590 591 ZwClose(targetKey); 592 } 593 594 ZwClose(diskKey); 595 } 596 597 ZwClose(adapterKey); 598 } 599 600 return; 601 } 602 603 604 NTSTATUS 605 DiskSaveBusDetectInfo( 606 IN PDRIVER_OBJECT DriverObject, 607 IN HANDLE TargetKey, 608 IN ULONG DiskNumber 609 ) 610 /*++ 611 612 Routine Description: 613 614 This routine will transfer the firmware/ntdetect reported information 615 in the specified target key into the appropriate entry in the 616 DetectInfoList. 617 618 Arguments: 619 620 DriverObject - the object for this driver. 621 622 TargetKey - the key for the disk being saved. 623 624 DiskNumber - the ordinal of the entry in the DiskPeripheral tree for this 625 entry 626 627 Return Value: 628 629 status 630 631 --*/ 632 { 633 PDISK_DETECT_INFO diskInfo; 634 635 UNICODE_STRING unicodeString; 636 637 PKEY_VALUE_FULL_INFORMATION keyData; 638 ULONG length; 639 640 NTSTATUS status; 641 642 PAGED_CODE(); 643 UNREFERENCED_PARAMETER(DriverObject); 644 645 if (DiskNumber >= DetectInfoCount) 646 { 647 return STATUS_UNSUCCESSFUL; 648 } 649 650 diskInfo = &(DetectInfoList[DiskNumber]); 651 652 if(diskInfo->Initialized) { 653 654 NT_ASSERT(FALSE); 655 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveBusDetectInfo: disk entry %#x already has a " 656 "signature of %#08lx and mbr checksum of %#08lx\n", 657 DiskNumber, 658 diskInfo->Signature, 659 diskInfo->MbrCheckSum)); 660 return STATUS_UNSUCCESSFUL; 661 } 662 663 RtlInitUnicodeString(&unicodeString, L"Identifier"); 664 665 keyData = ExAllocatePoolWithTag(PagedPool, 666 VALUE_BUFFER_SIZE, 667 DISK_TAG_UPDATE_GEOM); 668 669 if(keyData == NULL) { 670 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveBusDetectInfo: Couldn't allocate space for " 671 "registry data\n")); 672 return STATUS_INSUFFICIENT_RESOURCES; 673 } 674 675 // 676 // Get disk peripheral identifier. 677 // 678 679 status = ZwQueryValueKey(TargetKey, 680 &unicodeString, 681 KeyValueFullInformation, 682 keyData, 683 VALUE_BUFFER_SIZE, 684 &length); 685 686 if(!NT_SUCCESS(status)) { 687 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveBusDetectInfo: Error %#08lx getting " 688 "Identifier\n", 689 status)); 690 FREE_POOL(keyData); 691 return status; 692 693 } else if (keyData->DataLength < 9*sizeof(WCHAR)) { 694 695 // 696 // the data is too short to use (we subtract 9 chars in normal path) 697 // 698 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveBusDetectInfo: Saved data was invalid, " 699 "not enough data in registry!\n")); 700 FREE_POOL(keyData); 701 return STATUS_UNSUCCESSFUL; 702 703 } else { 704 705 UNICODE_STRING identifier; 706 ULONG value; 707 708 // 709 // Complete unicode string. 710 // 711 712 identifier.Buffer = (PWSTR) ((PUCHAR)keyData + keyData->DataOffset); 713 identifier.Length = (USHORT) keyData->DataLength; 714 identifier.MaximumLength = (USHORT) keyData->DataLength; 715 716 // 717 // Get the first value out of the identifier - this will be the MBR 718 // checksum. 719 // 720 721 status = RtlUnicodeStringToInteger(&identifier, 16, &value); 722 723 if(!NT_SUCCESS(status)) { 724 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveBusDetectInfo: Error %#08lx converting " 725 "identifier %wZ into MBR xsum\n", 726 status, 727 &identifier)); 728 FREE_POOL(keyData); 729 return status; 730 } 731 732 diskInfo->MbrCheckSum = value; 733 734 // 735 // Shift the string over to get the disk signature 736 // 737 738 identifier.Buffer += 9; 739 identifier.Length -= 9 * sizeof(WCHAR); 740 identifier.MaximumLength -= 9 * sizeof(WCHAR); 741 742 status = RtlUnicodeStringToInteger(&identifier, 16, &value); 743 744 if(!NT_SUCCESS(status)) { 745 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveBusDetectInfo: Error %#08lx converting " 746 "identifier %wZ into disk signature\n", 747 status, 748 &identifier)); 749 value = 0; 750 } 751 752 diskInfo->Signature = value; 753 } 754 755 // 756 // Here is where we would save away the extended int13 data. 757 // 758 759 // 760 // Mark this entry as initialized so we can make sure not to do it again. 761 // 762 763 diskInfo->Initialized = TRUE; 764 765 FREE_POOL(keyData); 766 767 return STATUS_SUCCESS; 768 } 769 770 771 DISK_GEOMETRY_SOURCE 772 DiskUpdateGeometry( 773 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 774 ) 775 /*++ 776 777 Routine Description: 778 779 This routine checks the DetectInfoList saved away during disk driver init 780 to see if any geometry information was reported for this drive. If the 781 geometry data exists (determined by matching non-zero signatures or 782 non-zero MBR checksums) then it will be saved in the RealGeometry member 783 of the disk data block. 784 785 ClassReadDriveCapacity MUST be called after calling this routine to update 786 the cylinder count based on the size of the disk and the presence of any 787 disk management software. 788 789 Arguments: 790 791 DeviceExtension - Supplies a pointer to the device information for disk. 792 793 Return Value: 794 795 Inidicates whether the "RealGeometry" in the data block is now valid. 796 797 --*/ 798 799 { 800 PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData; 801 802 ULONG i; 803 PDISK_DETECT_INFO diskInfo = NULL; 804 805 BOOLEAN found = FALSE; 806 807 NTSTATUS status; 808 809 PAGED_CODE(); 810 811 812 NT_ASSERT((FdoExtension->DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) == 0); 813 814 // 815 // If we've already set a non-default geometry for this drive then there's 816 // no need to try and update again. 817 // 818 819 if(diskData->GeometrySource != DiskGeometryUnknown) { 820 return diskData->GeometrySource; 821 } 822 823 // 824 // Scan through the saved detect info to see if we can find a match 825 // for this device. 826 // 827 828 for(i = 0; i < DetectInfoCount; i++) { 829 830 NT_ASSERT(DetectInfoList != NULL); 831 832 diskInfo = &(DetectInfoList[i]); 833 834 if((diskData->Mbr.Signature != 0) && 835 (diskData->Mbr.Signature == diskInfo->Signature)) { 836 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskUpdateGeometry: found match for signature " 837 "%#08lx\n", 838 diskData->Mbr.Signature)); 839 found = TRUE; 840 break; 841 } else if((diskData->Mbr.Signature == 0) && 842 (diskData->Mbr.MbrCheckSum != 0) && 843 (diskData->Mbr.MbrCheckSum == diskInfo->MbrCheckSum)) { 844 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskUpdateGeometry: found match for xsum %#08lx\n", 845 diskData->Mbr.MbrCheckSum)); 846 found = TRUE; 847 break; 848 } 849 } 850 851 if(found) { 852 853 ULONG cylinders; 854 ULONG sectorsPerTrack; 855 ULONG tracksPerCylinder; 856 857 ULONG length; 858 859 // 860 // Point to the array of drive parameters. 861 // 862 863 cylinders = diskInfo->DriveParameters.MaxCylinders + 1; 864 sectorsPerTrack = diskInfo->DriveParameters.SectorsPerTrack; 865 tracksPerCylinder = diskInfo->DriveParameters.MaxHeads + 1; 866 867 // 868 // Since the BIOS may not report the full drive, recalculate the drive 869 // size based on the volume size and the BIOS values for tracks per 870 // cylinder and sectors per track.. 871 // 872 873 length = tracksPerCylinder * sectorsPerTrack; 874 875 if (length == 0) { 876 877 // 878 // The BIOS information is bogus. 879 // 880 881 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskUpdateGeometry: H (%d) or S(%d) is zero\n", 882 tracksPerCylinder, sectorsPerTrack)); 883 return DiskGeometryUnknown; 884 } 885 886 // 887 // since we are copying the structure RealGeometry here, we should 888 // really initialize all the fields, especially since a zero'd 889 // BytesPerSector field would cause a trap in xHalReadPartitionTable() 890 // 891 892 diskData->RealGeometry = FdoExtension->DiskGeometry; 893 894 // 895 // Save the geometry information away in the disk data block and 896 // set the bit indicating that we found a valid one. 897 // 898 899 diskData->RealGeometry.SectorsPerTrack = sectorsPerTrack; 900 diskData->RealGeometry.TracksPerCylinder = tracksPerCylinder; 901 diskData->RealGeometry.Cylinders.QuadPart = (LONGLONG)cylinders; 902 903 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskUpdateGeometry: BIOS spt %#x, #heads %#x, " 904 "#cylinders %#x\n", 905 sectorsPerTrack, tracksPerCylinder, cylinders)); 906 907 diskData->GeometrySource = DiskGeometryFromBios; 908 diskInfo->Device = FdoExtension->DeviceObject; 909 910 // 911 // Increment the count of used geometry entries. 912 // 913 914 InterlockedIncrement(&DetectInfoUsedCount); 915 916 } else { 917 918 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskUpdateGeometry: no match found for signature %#08lx\n", diskData->Mbr.Signature)); 919 } 920 921 if(diskData->GeometrySource == DiskGeometryUnknown) { 922 923 // 924 // We couldn't find a geometry from the BIOS. Check with the port 925 // driver and see if it can provide one. 926 // 927 928 status = DiskGetPortGeometry(FdoExtension, &(diskData->RealGeometry)); 929 930 if(NT_SUCCESS(status)) { 931 932 // 933 // Check the geometry to make sure it's valid. 934 // 935 936 if((diskData->RealGeometry.TracksPerCylinder * 937 diskData->RealGeometry.SectorsPerTrack) != 0) { 938 939 diskData->GeometrySource = DiskGeometryFromPort; 940 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskUpdateGeometry: using Port geometry for disk %#p\n", FdoExtension)); 941 942 if (diskData->RealGeometry.BytesPerSector == 0) { 943 944 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskDriverReinit: Port driver failed to " 945 "set BytesPerSector in the RealGeometry\n")); 946 diskData->RealGeometry.BytesPerSector = 947 FdoExtension->DiskGeometry.BytesPerSector; 948 if (diskData->RealGeometry.BytesPerSector == 0) { 949 NT_ASSERT(!"BytesPerSector is still zero!"); 950 } 951 952 } 953 } 954 } 955 } 956 957 // 958 // If we came up with a "real" geometry for this drive then set it in the 959 // device extension. 960 // 961 962 if (diskData->GeometrySource != DiskGeometryUnknown) { 963 964 FdoExtension->DiskGeometry = diskData->RealGeometry; 965 } 966 967 return diskData->GeometrySource; 968 } 969 970 971 NTSTATUS 972 DiskUpdateRemovableGeometry ( 973 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 974 ) 975 976 /*++ 977 978 Routine Description: 979 980 This routine updates the geometry of the disk. It will query the port 981 driver to see if it can provide any geometry info. If not it will use 982 the current head & sector count. 983 984 Based on these values & the capacity of the drive as reported by 985 ClassReadDriveCapacity it will determine a new cylinder count for the 986 device. 987 988 Arguments: 989 990 Fdo - Supplies the functional device object whos size needs to be updated. 991 992 Return Value: 993 994 Returns the status of the opertion. 995 996 --*/ 997 { 998 PCOMMON_DEVICE_EXTENSION commonExtension = &(FdoExtension->CommonExtension); 999 PDISK_DATA diskData = commonExtension->DriverData; 1000 PDISK_GEOMETRY geometry = &(diskData->RealGeometry); 1001 1002 NTSTATUS status; 1003 1004 PAGED_CODE(); 1005 1006 if (FdoExtension->DeviceDescriptor) { 1007 NT_ASSERT(FdoExtension->DeviceDescriptor->RemovableMedia); 1008 } 1009 NT_ASSERT(TEST_FLAG(FdoExtension->DeviceObject->Characteristics, 1010 FILE_REMOVABLE_MEDIA)); 1011 1012 // 1013 // Attempt to determine the disk geometry. First we'll check with the 1014 // port driver to see what it suggests for a value. 1015 // 1016 1017 status = DiskGetPortGeometry(FdoExtension, geometry); 1018 1019 if(NT_SUCCESS(status) && 1020 ((geometry->TracksPerCylinder * geometry->SectorsPerTrack) != 0)) { 1021 1022 FdoExtension->DiskGeometry = (*geometry); 1023 } 1024 1025 return status; 1026 } 1027 1028 1029 NTSTATUS 1030 DiskGetPortGeometry( 1031 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 1032 OUT PDISK_GEOMETRY Geometry 1033 ) 1034 /*++ 1035 1036 Routine Description: 1037 1038 This routine will query the port driver for disk geometry. Some port 1039 drivers (in particular IDEPORT) may be able to provide geometry for the 1040 device. 1041 1042 Arguments: 1043 1044 FdoExtension - the device object for the disk. 1045 1046 Geometry - a structure to save the geometry information into (if any is 1047 available) 1048 1049 Return Value: 1050 1051 STATUS_SUCCESS if geometry information can be provided or 1052 error status indicating why it can't. 1053 1054 --*/ 1055 { 1056 PCOMMON_DEVICE_EXTENSION commonExtension = &(FdoExtension->CommonExtension); 1057 PIRP irp; 1058 PIO_STACK_LOCATION irpStack; 1059 KEVENT event; 1060 1061 NTSTATUS status; 1062 1063 PAGED_CODE(); 1064 1065 // 1066 // Build an irp to send IOCTL_DISK_GET_DRIVE_GEOMETRY to the lower driver. 1067 // 1068 1069 irp = IoAllocateIrp(commonExtension->LowerDeviceObject->StackSize, FALSE); 1070 1071 if(irp == NULL) { 1072 return STATUS_INSUFFICIENT_RESOURCES; 1073 } 1074 1075 irpStack = IoGetNextIrpStackLocation(irp); 1076 1077 irpStack->MajorFunction = IRP_MJ_DEVICE_CONTROL; 1078 1079 irpStack->Parameters.DeviceIoControl.IoControlCode = 1080 IOCTL_DISK_GET_DRIVE_GEOMETRY; 1081 irpStack->Parameters.DeviceIoControl.OutputBufferLength = 1082 sizeof(DISK_GEOMETRY); 1083 1084 irp->AssociatedIrp.SystemBuffer = Geometry; 1085 1086 KeInitializeEvent(&event, SynchronizationEvent, FALSE); 1087 1088 IoSetCompletionRoutine(irp, 1089 ClassSignalCompletion, 1090 &event, 1091 TRUE, 1092 TRUE, 1093 TRUE); 1094 1095 status = IoCallDriver(commonExtension->LowerDeviceObject, irp); 1096 if (status == STATUS_PENDING) { 1097 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 1098 status = irp->IoStatus.Status; 1099 } 1100 1101 IoFreeIrp(irp); 1102 1103 return status; 1104 } 1105 1106 1107 BOOLEAN 1108 DiskIsNT4Geometry( 1109 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 1110 ) 1111 1112 /*++ 1113 1114 Routine Description: 1115 1116 The default geometry that was used in partitioning disks under Windows NT 4.0 was 1117 1118 Sectors per Track = 0x20 = 32 1119 Tracks per Cylinder = 0x40 = 64 1120 1121 This was changed in Windows 2000 to 1122 1123 Sectors per Track = 0x3F = 63 1124 Tracks per Cylinder = 0xFF = 255 1125 1126 If neither the BIOS nor the port driver can report the correct geometry, we will 1127 default to the new numbers on such disks. Now LVM uses the geometry when creating 1128 logical volumes and dynamic disks. So reporting an incorrect geometry will cause 1129 the entire extended partition / dynamic disk to be destroyed 1130 1131 In this routine, we will look at the Master Boot Record. In 90% of the cases, the 1132 first entry corresponds to a partition that starts on the first track. If this is 1133 so, we shall retrieve the logical block address associated with it and calculate 1134 the correct geometry. Now, all partitions start on a cylinder boundary. So, for 1135 the remaining 10% we will look at the ending CHS number to determine the geometry 1136 1137 --*/ 1138 1139 { 1140 PUSHORT readBuffer = NULL; 1141 BOOLEAN bFoundNT4 = FALSE; 1142 1143 PAGED_CODE(); 1144 1145 readBuffer = ExAllocatePoolWithTag(NonPagedPoolNx, FdoExtension->DiskGeometry.BytesPerSector, DISK_TAG_UPDATE_GEOM); 1146 1147 if (readBuffer) 1148 { 1149 KEVENT event; 1150 LARGE_INTEGER diskOffset; 1151 IO_STATUS_BLOCK ioStatus = { 0 }; 1152 PIRP irp; 1153 1154 KeInitializeEvent(&event, NotificationEvent, FALSE); 1155 1156 // 1157 // Read the Master Boot Record at disk offset 0 1158 // 1159 1160 diskOffset.QuadPart = 0; 1161 1162 irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, FdoExtension->DeviceObject, readBuffer, FdoExtension->DiskGeometry.BytesPerSector, &diskOffset, &event, &ioStatus); 1163 1164 if (irp) 1165 { 1166 PIO_STACK_LOCATION irpSp = IoGetNextIrpStackLocation(irp); 1167 NTSTATUS status; 1168 1169 irpSp->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 1170 1171 status = IoCallDriver(FdoExtension->DeviceObject, irp); 1172 1173 if (status == STATUS_PENDING) 1174 { 1175 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 1176 status = ioStatus.Status; 1177 } 1178 1179 if (NT_SUCCESS(status)) 1180 { 1181 // 1182 // Match the boot record signature 1183 // 1184 1185 if (readBuffer[BOOT_SIGNATURE_OFFSET] == BOOT_RECORD_SIGNATURE) 1186 { 1187 PPARTITION_DESCRIPTOR partitionTableEntry = (PPARTITION_DESCRIPTOR)&readBuffer[PARTITION_TABLE_OFFSET]; 1188 ULONG uCount = 0; 1189 1190 // 1191 // Walk the entries looking for a clue as to what the geometry might be 1192 // 1193 1194 for (uCount = 0; uCount < NUM_PARTITION_TABLE_ENTRIES; uCount++) 1195 { 1196 // 1197 // We are only concerned if there might be a logical volume or if this disk is part of a dynamic set 1198 // 1199 1200 if (IsContainerPartition(partitionTableEntry->PartitionType) || partitionTableEntry->PartitionType == PARTITION_LDM) 1201 { 1202 // 1203 // In 90% of the cases, the first entry corresponds to a partition that starts on the first track 1204 // 1205 1206 if (partitionTableEntry->StartingTrack == 1 && GET_STARTING_SECTOR(partitionTableEntry) == 0x20) 1207 { 1208 bFoundNT4 = TRUE; 1209 break; 1210 } 1211 1212 // 1213 // In almost every case, the ending CHS number is on a cylinder boundary 1214 // 1215 1216 if (partitionTableEntry->EndingTrack == 0x3F && GET_ENDING_S_OF_CHS(partitionTableEntry) == 0x20) 1217 { 1218 bFoundNT4 = TRUE; 1219 break; 1220 } 1221 } 1222 1223 partitionTableEntry++; 1224 } 1225 } 1226 else 1227 { 1228 // 1229 // The Master Boot Record is invalid 1230 // 1231 } 1232 } 1233 } 1234 1235 FREE_POOL(readBuffer); 1236 } 1237 1238 return bFoundNT4; 1239 } 1240 1241 1242 NTSTATUS 1243 DiskReadDriveCapacity( 1244 IN PDEVICE_OBJECT Fdo 1245 ) 1246 /*++ 1247 1248 Routine Description: 1249 1250 This routine is used by disk.sys as a wrapper for the classpnp API 1251 ClassReadDriveCapacity. It will perform some additional operations to 1252 attempt to determine drive geometry before it calls the classpnp version 1253 of the routine. 1254 1255 For fixed disks this involves calling DiskUpdateGeometry which will check 1256 various sources (the BIOS, the port driver) for geometry information. 1257 1258 Arguments: 1259 1260 Fdo - a pointer to the device object to be checked. 1261 1262 Return Value: 1263 1264 status of ClassReadDriveCapacity. 1265 1266 --*/ 1267 1268 { 1269 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 1270 NTSTATUS status; 1271 1272 if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) { 1273 DiskUpdateRemovableGeometry(fdoExtension); 1274 } else { 1275 DiskUpdateGeometry(fdoExtension); 1276 } 1277 1278 status = ClassReadDriveCapacity(Fdo); 1279 1280 return status; 1281 } 1282 1283 1284 VOID 1285 DiskDriverReinitialization( 1286 IN PDRIVER_OBJECT DriverObject, 1287 IN PVOID Nothing, 1288 IN ULONG Count 1289 ) 1290 /*++ 1291 1292 Routine Description: 1293 1294 This routine will scan through the current list of disks and attempt to 1295 match them to any remaining geometry information. This will only be done 1296 on the first call to the routine. 1297 1298 Note: This routine assumes that the system will not be adding or removing 1299 devices during this phase of the init process. This is very likely 1300 a bad assumption but it greatly simplifies the code. 1301 1302 Arguments: 1303 1304 DriverObject - a pointer to the object for the disk driver. 1305 1306 Nothing - unused 1307 1308 Count - an indication of how many times this routine has been called. 1309 1310 Return Value: 1311 1312 none 1313 1314 --*/ 1315 1316 { 1317 PDEVICE_OBJECT deviceObject; 1318 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 1319 PDISK_DATA diskData; 1320 1321 ULONG unmatchedDiskCount; 1322 PDEVICE_OBJECT unmatchedDisk = NULL; 1323 1324 ULONG i; 1325 PDISK_DETECT_INFO diskInfo = NULL; 1326 1327 UNREFERENCED_PARAMETER(Nothing); 1328 1329 if(Count != 1) { 1330 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "DiskDriverReinitialization: ignoring call %d\n", 1331 Count)); 1332 return; 1333 } 1334 1335 // 1336 // Check to see how many entries in the detect info list have been matched. 1337 // If there's only one remaining we'll see if we can find a disk to go with 1338 // it. 1339 // 1340 1341 if(DetectInfoCount == 0) { 1342 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "DiskDriverReinitialization: no detect info saved\n")); 1343 return; 1344 } 1345 1346 if((DetectInfoCount - DetectInfoUsedCount) != 1) { 1347 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "DiskDriverReinitialization: %d of %d geometry entries " 1348 "used - will not attempt match\n", DetectInfoUsedCount, DetectInfoCount)); 1349 return; 1350 } 1351 1352 // 1353 // Scan through the list of disks and see if any of them are missing 1354 // geometry information. If there is only one such disk we'll try to 1355 // match it to the unmatched geometry. 1356 // 1357 1358 1359 // 1360 // ISSUE-2000/5/24-henrygab - figure out if there's a way to keep 1361 // removals from happening while doing this. 1362 // 1363 unmatchedDiskCount = 0; 1364 for(deviceObject = DriverObject->DeviceObject; 1365 deviceObject != NULL; 1366 #ifdef _MSC_VER 1367 #pragma prefast(suppress:28175, "Need to access the opaque field to scan through the list of disks") 1368 #endif 1369 deviceObject = deviceObject->NextDevice) { 1370 1371 fdoExtension = deviceObject->DeviceExtension; 1372 1373 if (!fdoExtension->CommonExtension.IsFdo) { 1374 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskDriverReinit: %#p is not an FDO\n", 1375 deviceObject)); 1376 continue; 1377 } 1378 1379 // 1380 // If the geometry for this one is already known then skip it. 1381 // 1382 1383 diskData = fdoExtension->CommonExtension.DriverData; 1384 if(diskData->GeometrySource != DiskGeometryUnknown) { 1385 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskDriverReinit: FDO %#p has a geometry\n", 1386 deviceObject)); 1387 continue; 1388 } 1389 1390 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "DiskDriverReinit: FDO %#p has no geometry\n", 1391 deviceObject)); 1392 1393 // 1394 // Mark this one as using the default. It's past the time when disk 1395 // might blunder across the geometry info. If we set the geometry 1396 // from the bios we'll reset this field down below. 1397 // 1398 1399 diskData->GeometrySource = DiskGeometryFromDefault; 1400 1401 // 1402 // As long as we've only got one unmatched disk we're fine. 1403 // 1404 1405 unmatchedDiskCount++; 1406 if(unmatchedDiskCount > 1) { 1407 NT_ASSERT(unmatchedDisk != NULL); 1408 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "DiskDriverReinit: FDO %#p also has no geometry\n", 1409 unmatchedDisk)); 1410 unmatchedDisk = NULL; 1411 break; 1412 } 1413 1414 unmatchedDisk = deviceObject; 1415 } 1416 1417 // 1418 // If there's more or less than one ungeometried disk then we can't do 1419 // anything about the geometry. 1420 // 1421 1422 if(unmatchedDiskCount != 1) { 1423 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskDriverReinit: Unable to match geometry\n")); 1424 return; 1425 1426 } 1427 1428 fdoExtension = unmatchedDisk->DeviceExtension; 1429 diskData = fdoExtension->CommonExtension.DriverData; 1430 1431 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskDriverReinit: Found possible match\n")); 1432 1433 // 1434 // Find the geometry which wasn't assigned. 1435 // 1436 1437 for(i = 0; i < DetectInfoCount; i++) { 1438 if(DetectInfoList[i].Device == NULL) { 1439 diskInfo = &(DetectInfoList[i]); 1440 break; 1441 } 1442 } 1443 1444 if (diskInfo != NULL) 1445 { 1446 // 1447 // Save the geometry information away in the disk data block and 1448 // set the bit indicating that we found a valid one. 1449 // 1450 1451 ULONG cylinders; 1452 ULONG sectorsPerTrack; 1453 ULONG tracksPerCylinder; 1454 1455 ULONG length; 1456 1457 // 1458 // Point to the array of drive parameters. 1459 // 1460 1461 cylinders = diskInfo->DriveParameters.MaxCylinders + 1; 1462 sectorsPerTrack = diskInfo->DriveParameters.SectorsPerTrack; 1463 tracksPerCylinder = diskInfo->DriveParameters.MaxHeads + 1; 1464 1465 // 1466 // Since the BIOS may not report the full drive, recalculate the drive 1467 // size based on the volume size and the BIOS values for tracks per 1468 // cylinder and sectors per track.. 1469 // 1470 1471 length = tracksPerCylinder * sectorsPerTrack; 1472 1473 if (length == 0) { 1474 1475 // 1476 // The BIOS information is bogus. 1477 // 1478 1479 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskDriverReinit: H (%d) or S(%d) is zero\n", 1480 tracksPerCylinder, sectorsPerTrack)); 1481 return; 1482 } 1483 1484 // 1485 // since we are copying the structure RealGeometry here, we should 1486 // really initialize all the fields, especially since a zero'd 1487 // BytesPerSector field would cause a trap in xHalReadPartitionTable() 1488 // 1489 1490 diskData->RealGeometry = fdoExtension->DiskGeometry; 1491 1492 // 1493 // Save the geometry information away in the disk data block and 1494 // set the bit indicating that we found a valid one. 1495 // 1496 1497 diskData->RealGeometry.SectorsPerTrack = sectorsPerTrack; 1498 diskData->RealGeometry.TracksPerCylinder = tracksPerCylinder; 1499 diskData->RealGeometry.Cylinders.QuadPart = (LONGLONG)cylinders; 1500 1501 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskDriverReinit: BIOS spt %#x, #heads %#x, " 1502 "#cylinders %#x\n", 1503 sectorsPerTrack, tracksPerCylinder, cylinders)); 1504 1505 diskData->GeometrySource = DiskGeometryGuessedFromBios; 1506 diskInfo->Device = unmatchedDisk; 1507 1508 // 1509 // Now copy the geometry over to the fdo extension and call 1510 // classpnp to redetermine the disk size and cylinder count. 1511 // 1512 1513 fdoExtension->DiskGeometry = diskData->RealGeometry; 1514 1515 (VOID)ClassReadDriveCapacity(unmatchedDisk); 1516 1517 if (diskData->RealGeometry.BytesPerSector == 0) { 1518 1519 // 1520 // if the BytesPerSector field is set to zero for a disk 1521 // listed in the bios, then the system will bugcheck in 1522 // xHalReadPartitionTable(). assert here since it is 1523 // easier to determine what is happening this way. 1524 // 1525 1526 NT_ASSERT(!"RealGeometry not set to non-zero bps\n"); 1527 } 1528 } 1529 1530 return; 1531 } 1532 1533 1534 NTSTATUS 1535 DiskGetDetectInfo( 1536 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 1537 OUT PDISK_DETECTION_INFO DetectInfo 1538 ) 1539 /*++ 1540 1541 Routine Description: 1542 1543 Get the Int13 information from the BIOS DetectInfoList. 1544 1545 Arguments: 1546 1547 FdoExtension - Supplies a pointer to the FDO extension that we want to 1548 obtain the detect information for. 1549 1550 DetectInfo - A buffer where the detect information will be copied to. 1551 1552 Return Value: 1553 1554 NTSTATUS code. 1555 1556 --*/ 1557 { 1558 ULONG i; 1559 BOOLEAN found = FALSE; 1560 PDISK_DETECT_INFO diskInfo = NULL; 1561 PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData; 1562 1563 PAGED_CODE (); 1564 1565 // 1566 // Fail for non-fixed drives. 1567 // 1568 1569 if (TEST_FLAG (FdoExtension->DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) { 1570 return STATUS_NOT_SUPPORTED; 1571 } 1572 1573 // 1574 // There is no GPT detection info, so fail this. 1575 // 1576 1577 if (diskData->PartitionStyle == PARTITION_STYLE_GPT) { 1578 return STATUS_NOT_SUPPORTED; 1579 } 1580 1581 for(i = 0; i < DetectInfoCount; i++) { 1582 1583 1584 NT_ASSERT(DetectInfoList != NULL); 1585 1586 diskInfo = &(DetectInfoList[i]); 1587 1588 if((diskData->Mbr.Signature != 0) && 1589 (diskData->Mbr.Signature == diskInfo->Signature)) { 1590 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskGetDetectInfo: found match for signature " 1591 "%#08lx\n", 1592 diskData->Mbr.Signature)); 1593 found = TRUE; 1594 break; 1595 } else if((diskData->Mbr.Signature == 0) && 1596 (diskData->Mbr.MbrCheckSum != 0) && 1597 (diskData->Mbr.MbrCheckSum == diskInfo->MbrCheckSum)) { 1598 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskGetDetectInfo: found match for xsum %#08lx\n", 1599 diskData->Mbr.MbrCheckSum)); 1600 found = TRUE; 1601 break; 1602 } 1603 } 1604 1605 if ( found ) { 1606 DetectInfo->DetectionType = DetectInt13; 1607 DetectInfo->Int13.DriveSelect = diskInfo->DriveParameters.DriveSelect; 1608 DetectInfo->Int13.MaxCylinders = diskInfo->DriveParameters.MaxCylinders; 1609 DetectInfo->Int13.SectorsPerTrack = diskInfo->DriveParameters.SectorsPerTrack; 1610 DetectInfo->Int13.MaxHeads = diskInfo->DriveParameters.MaxHeads; 1611 DetectInfo->Int13.NumberDrives = diskInfo->DriveParameters.NumberDrives; 1612 RtlZeroMemory (&DetectInfo->ExInt13, sizeof (DetectInfo->ExInt13)); 1613 } 1614 1615 return (found ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL); 1616 } 1617 1618 1619 NTSTATUS 1620 DiskReadSignature( 1621 IN PDEVICE_OBJECT Fdo 1622 ) 1623 1624 /*++ 1625 1626 Routine Description: 1627 1628 Read the disks signature from the drive. The signature can be either 1629 a MBR signature or a GPT/EFI signature. 1630 1631 The low-level signature reading is done by IoReadDiskSignature(). 1632 1633 Arguments: 1634 1635 Fdo - Pointer to the FDO of a disk to read the signature for. 1636 1637 Return Value: 1638 1639 NTSTATUS code. 1640 1641 --*/ 1642 1643 1644 { 1645 NTSTATUS Status; 1646 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 1647 PDISK_DATA diskData = fdoExtension->CommonExtension.DriverData; 1648 DISK_SIGNATURE Signature = { 0 }; 1649 1650 PAGED_CODE(); 1651 1652 Status = IoReadDiskSignature (Fdo, 1653 fdoExtension->DiskGeometry.BytesPerSector, 1654 &Signature); 1655 1656 if (!NT_SUCCESS (Status)) { 1657 return Status; 1658 } 1659 1660 if (Signature.PartitionStyle == PARTITION_STYLE_GPT) { 1661 diskData->PartitionStyle = PARTITION_STYLE_GPT; 1662 diskData->Efi.DiskId = Signature.Gpt.DiskId; 1663 } else if (Signature.PartitionStyle == PARTITION_STYLE_MBR) { 1664 diskData->PartitionStyle = PARTITION_STYLE_MBR; 1665 diskData->Mbr.Signature = Signature.Mbr.Signature; 1666 diskData->Mbr.MbrCheckSum = Signature.Mbr.CheckSum; 1667 } else { 1668 NT_ASSERT (FALSE); 1669 Status = STATUS_UNSUCCESSFUL; 1670 } 1671 1672 return Status; 1673 } 1674 1675 #endif // defined(_X86_) || defined(_AMD64_) 1676 1677