static PCM_PARTIAL_RESOURCE_LIST GetHarddiskConfigurationData(UCHAR DriveNumber, ULONG* pSize) { PCM_PARTIAL_RESOURCE_LIST PartialResourceList; PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry; //EXTENDED_GEOMETRY ExtGeometry; GEOMETRY Geometry; ULONG Size; // // Initialize returned size // *pSize = 0; /* Set 'Configuration Data' value */ Size = sizeof(CM_PARTIAL_RESOURCE_LIST) + sizeof(CM_DISK_GEOMETRY_DEVICE_DATA); PartialResourceList = MmHeapAlloc(Size); if (PartialResourceList == NULL) { ERR("Failed to allocate a full resource descriptor\n"); return NULL; } memset(PartialResourceList, 0, Size); PartialResourceList->Version = 1; PartialResourceList->Revision = 1; PartialResourceList->Count = 1; PartialResourceList->PartialDescriptors[0].Type = CmResourceTypeDeviceSpecific; // PartialResourceList->PartialDescriptors[0].ShareDisposition = // PartialResourceList->PartialDescriptors[0].Flags = PartialResourceList->PartialDescriptors[0].u.DeviceSpecificData.DataSize = sizeof(CM_DISK_GEOMETRY_DEVICE_DATA); /* Get pointer to geometry data */ DiskGeometry = (PVOID)(((ULONG_PTR)PartialResourceList) + sizeof(CM_PARTIAL_RESOURCE_LIST)); /* Get the disk geometry */ //ExtGeometry.Size = sizeof(EXTENDED_GEOMETRY); if(MachDiskGetDriveGeometry(DriveNumber, &Geometry)) { DiskGeometry->BytesPerSector = Geometry.BytesPerSector; DiskGeometry->NumberOfCylinders = Geometry.Cylinders; DiskGeometry->SectorsPerTrack = Geometry.Sectors; DiskGeometry->NumberOfHeads = Geometry.Heads; } else { ERR("Reading disk geometry failed\n"); MmHeapFree(PartialResourceList); return NULL; } TRACE("Disk %x: %u Cylinders %u Heads %u Sectors %u Bytes\n", DriveNumber, DiskGeometry->NumberOfCylinders, DiskGeometry->NumberOfHeads, DiskGeometry->SectorsPerTrack, DiskGeometry->BytesPerSector); // // Return configuration data // *pSize = Size; return PartialResourceList; }
BOOLEAN CacheInitializeDrive(UCHAR DriveNumber) { PCACHE_BLOCK NextCacheBlock; GEOMETRY DriveGeometry; // If we already have a cache for this drive then // by all means lets keep it, unless it is a removable // drive, in which case we'll invalidate the cache if ((CacheManagerInitialized == TRUE) && (DriveNumber == CacheManagerDrive.DriveNumber) && (DriveNumber >= 0x80) && (CacheManagerDataInvalid != TRUE)) { return TRUE; } CacheManagerDataInvalid = FALSE; // // If we have already been initialized then free // the old data // if (CacheManagerInitialized) { CacheManagerInitialized = FALSE; TRACE("CacheBlockCount: %d\n", CacheBlockCount); TRACE("CacheSizeLimit: %d\n", CacheSizeLimit); TRACE("CacheSizeCurrent: %d\n", CacheSizeCurrent); // // Loop through and free the cache blocks // while (!IsListEmpty(&CacheManagerDrive.CacheBlockHead)) { NextCacheBlock = CONTAINING_RECORD(RemoveHeadList(&CacheManagerDrive.CacheBlockHead), CACHE_BLOCK, ListEntry); FrLdrTempFree(NextCacheBlock->BlockData, TAG_CACHE_DATA); FrLdrTempFree(NextCacheBlock, TAG_CACHE_BLOCK); } } // Initialize the structure RtlZeroMemory(&CacheManagerDrive, sizeof(CACHE_DRIVE)); InitializeListHead(&CacheManagerDrive.CacheBlockHead); CacheManagerDrive.DriveNumber = DriveNumber; if (!MachDiskGetDriveGeometry(DriveNumber, &DriveGeometry)) { return FALSE; } CacheManagerDrive.BytesPerSector = DriveGeometry.BytesPerSector; // Get the number of sectors in each cache block CacheManagerDrive.BlockSize = MachDiskGetCacheableBlockCount(DriveNumber); CacheBlockCount = 0; CacheSizeLimit = TotalPagesInLookupTable / 8 * MM_PAGE_SIZE; CacheSizeCurrent = 0; if (CacheSizeLimit > TEMP_HEAP_SIZE - (128 * 1024)) { CacheSizeLimit = TEMP_HEAP_SIZE - (128 * 1024); } CacheManagerInitialized = TRUE; TRACE("Initializing BIOS drive 0x%x.\n", DriveNumber); TRACE("BytesPerSector: %d.\n", CacheManagerDrive.BytesPerSector); TRACE("BlockSize: %d.\n", CacheManagerDrive.BlockSize); TRACE("CacheSizeLimit: %d.\n", CacheSizeLimit); return TRUE; }
static VOID DetectBiosDisks(PCONFIGURATION_COMPONENT_DATA SystemKey, PCONFIGURATION_COMPONENT_DATA BusKey) { PCM_PARTIAL_RESOURCE_LIST PartialResourceList; PCM_INT13_DRIVE_PARAMETER Int13Drives; GEOMETRY Geometry; PCONFIGURATION_COMPONENT_DATA DiskKey, ControllerKey; UCHAR DiskCount, i; ULONG Size; BOOLEAN Changed; /* Count the number of visible drives */ DiskReportError(FALSE); DiskCount = 0; /* There are some really broken BIOSes out there. There are even BIOSes * that happily report success when you ask them to read from non-existent * harddisks. So, we set the buffer to known contents first, then try to * read. If the BIOS reports success but the buffer contents haven't * changed then we fail anyway */ memset((PVOID) DISKREADBUFFER, 0xcd, 512); while (MachDiskReadLogicalSectors(0x80 + DiskCount, 0ULL, 1, (PVOID)DISKREADBUFFER)) { Changed = FALSE; for (i = 0; ! Changed && i < 512; i++) { Changed = ((PUCHAR)DISKREADBUFFER)[i] != 0xcd; } if (! Changed) { TRACE("BIOS reports success for disk %d but data didn't change\n", (int)DiskCount); break; } DiskCount++; memset((PVOID) DISKREADBUFFER, 0xcd, 512); } DiskReportError(TRUE); TRACE("BIOS reports %d harddisk%s\n", (int)DiskCount, (DiskCount == 1) ? "": "s"); //DetectBiosFloppyController(BusKey); /* Allocate resource descriptor */ Size = sizeof(CM_PARTIAL_RESOURCE_LIST) + sizeof(CM_INT13_DRIVE_PARAMETER) * DiskCount; PartialResourceList = MmHeapAlloc(Size); if (PartialResourceList == NULL) { ERR("Failed to allocate resource descriptor\n"); return; } /* Initialize resource descriptor */ memset(PartialResourceList, 0, Size); PartialResourceList->Version = 1; PartialResourceList->Revision = 1; PartialResourceList->Count = 1; PartialResourceList->PartialDescriptors[0].Type = CmResourceTypeDeviceSpecific; PartialResourceList->PartialDescriptors[0].ShareDisposition = 0; PartialResourceList->PartialDescriptors[0].Flags = 0; PartialResourceList->PartialDescriptors[0].u.DeviceSpecificData.DataSize = sizeof(CM_INT13_DRIVE_PARAMETER) * DiskCount; /* Get harddisk Int13 geometry data */ Int13Drives = (PVOID)(((ULONG_PTR)PartialResourceList) + sizeof(CM_PARTIAL_RESOURCE_LIST)); for (i = 0; i < DiskCount; i++) { if (MachDiskGetDriveGeometry(0x80 + i, &Geometry)) { Int13Drives[i].DriveSelect = 0x80 + i; Int13Drives[i].MaxCylinders = Geometry.Cylinders - 1; Int13Drives[i].SectorsPerTrack = (USHORT)Geometry.Sectors; Int13Drives[i].MaxHeads = (USHORT)Geometry.Heads - 1; Int13Drives[i].NumberDrives = DiskCount; TRACE( "Disk %x: %u Cylinders %u Heads %u Sectors %u Bytes\n", 0x80 + i, Geometry.Cylinders - 1, Geometry.Heads -1, Geometry.Sectors, Geometry.BytesPerSector); } } FldrCreateComponentKey(BusKey, ControllerClass, DiskController, Output | Input, 0, 0xFFFFFFFF, NULL, PartialResourceList, Size, &ControllerKey); TRACE("Created key: DiskController\\0\n"); MmHeapFree(PartialResourceList); /* Create and fill subkey for each harddisk */ for (i = 0; i < DiskCount; i++) { PCM_PARTIAL_RESOURCE_LIST PartialResourceList; ULONG Size; CHAR Identifier[20]; /* Get disk values */ PartialResourceList = GetHarddiskConfigurationData(0x80 + i, &Size); GetHarddiskIdentifier(Identifier, 0x80 + i); /* Create disk key */ FldrCreateComponentKey(ControllerKey, PeripheralClass, DiskPeripheral, Output | Input, 0, 0xFFFFFFFF, Identifier, PartialResourceList, Size, &DiskKey); if (PartialResourceList) MmHeapFree(PartialResourceList); } }
static BOOLEAN PcDiskReadLogicalSectorsCHS(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer) { UCHAR PhysicalSector; UCHAR PhysicalHead; ULONG PhysicalTrack; GEOMETRY DriveGeometry; ULONG NumberOfSectorsToRead; REGS RegsIn, RegsOut; ULONG RetryCount; TRACE("PcDiskReadLogicalSectorsCHS()\n"); /* Get the drive geometry */ if (!MachDiskGetDriveGeometry(DriveNumber, &DriveGeometry) || DriveGeometry.Sectors == 0 || DriveGeometry.Heads == 0) { return FALSE; } while (SectorCount) { /* * Calculate the physical disk offsets. * Note: DriveGeometry.Sectors < 64 */ PhysicalSector = 1 + (UCHAR)(SectorNumber % DriveGeometry.Sectors); PhysicalHead = (UCHAR)((SectorNumber / DriveGeometry.Sectors) % DriveGeometry.Heads); PhysicalTrack = (ULONG)((SectorNumber / DriveGeometry.Sectors) / DriveGeometry.Heads); /* Calculate how many sectors we need to read this round */ if (PhysicalSector > 1) { if (SectorCount >= (DriveGeometry.Sectors - (PhysicalSector - 1))) NumberOfSectorsToRead = (DriveGeometry.Sectors - (PhysicalSector - 1)); else NumberOfSectorsToRead = SectorCount; } else { if (SectorCount >= DriveGeometry.Sectors) NumberOfSectorsToRead = DriveGeometry.Sectors; else NumberOfSectorsToRead = SectorCount; } /* Make sure the read is within the geometry boundaries */ if ((PhysicalHead >= DriveGeometry.Heads) || (PhysicalTrack >= DriveGeometry.Cylinders) || ((NumberOfSectorsToRead + PhysicalSector) > (DriveGeometry.Sectors + 1)) || (PhysicalSector > DriveGeometry.Sectors)) { DiskError("Disk read exceeds drive geometry limits.", 0); return FALSE; } /* * BIOS Int 13h, function 2 - Read Disk Sectors * AH = 02h * AL = number of sectors to read (must be nonzero) * CH = low eight bits of cylinder number * CL = sector number 1-63 (bits 0-5) * high two bits of cylinder (bits 6-7, hard disk only) * DH = head number * DL = drive number (bit 7 set for hard disk) * ES:BX -> data buffer * Return: * CF set on error * if AH = 11h (corrected ECC error), AL = burst length * CF clear if successful * AH = status * AL = number of sectors transferred * (only valid if CF set for some BIOSes) */ RegsIn.b.ah = 0x02; RegsIn.b.al = (UCHAR)NumberOfSectorsToRead; RegsIn.b.ch = (PhysicalTrack & 0xFF); RegsIn.b.cl = (UCHAR)(PhysicalSector + ((PhysicalTrack & 0x300) >> 2)); RegsIn.b.dh = PhysicalHead; RegsIn.b.dl = DriveNumber; RegsIn.w.es = (USHORT)(((ULONG_PTR)Buffer) >> 4); RegsIn.w.bx = ((ULONG_PTR)Buffer) & 0x0F; /* Perform the read. Retry 3 times. */ for (RetryCount=0; RetryCount<3; RetryCount++) { Int386(0x13, &RegsIn, &RegsOut); /* If it worked break out */ if (INT386_SUCCESS(RegsOut)) { break; } /* If it was a corrected ECC error then the data is still good */ else if (RegsOut.b.ah == 0x11) { break; } /* If it failed the do the next retry */ else { DiskResetController(DriveNumber); continue; } } /* If we retried 3 times then fail */ if (RetryCount >= 3) { ERR("Disk Read Failed in CHS mode, after retrying 3 times: %x\n", RegsOut.b.ah); return FALSE; } // I have learned that not all BIOSes return // the sector read count in the AL register (at least mine doesn't) // even if the sectors were read correctly. So instead // of checking the sector read count we will rely solely // on the carry flag being set on error Buffer = (PVOID)((ULONG_PTR)Buffer + (NumberOfSectorsToRead * DriveGeometry.BytesPerSector)); SectorCount -= NumberOfSectorsToRead; SectorNumber += NumberOfSectorsToRead; } return TRUE; }