--- truecrypt/boot/windows/bootdiskio.cpp 2018/04/24 16:49:04 1.1 +++ truecrypt/boot/windows/bootdiskio.cpp 2018/04/24 17:13:46 1.1.1.10 @@ -1,20 +1,51 @@ /* - Copyright (c) 2008 TrueCrypt Foundation. All rights reserved. + Copyright (c) 2008-2011 TrueCrypt Developers Association. All rights reserved. - Governed by the TrueCrypt License 2.4 the full text of which is contained - in the file License.txt included in TrueCrypt binary and source code - distribution packages. + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. */ #include "Bios.h" #include "BootConsoleIo.h" +#include "BootConfig.h" #include "BootDebug.h" +#include "BootDefs.h" #include "BootDiskIo.h" +#include "BootStrings.h" + + +byte SectorBuffer[TC_LB_SIZE]; + +#ifdef TC_BOOT_DEBUG_ENABLED +static bool SectorBufferInUse = false; + +void AcquireSectorBuffer () +{ + if (SectorBufferInUse) + TC_THROW_FATAL_EXCEPTION; + + SectorBufferInUse = true; +} + + +void ReleaseSectorBuffer () +{ + SectorBufferInUse = false; +} + +#endif bool IsLbaSupported (byte drive) { + static byte CachedDrive = TC_INVALID_BIOS_DRIVE; + static bool CachedStatus; uint16 result = 0; + + if (CachedDrive == drive) + goto ret; + __asm { mov bx, 0x55aa @@ -26,7 +57,10 @@ bool IsLbaSupported (byte drive) err: } - return result == 0xaa55; + CachedDrive = drive; + CachedStatus = (result == 0xaa55); +ret: + return CachedStatus; } @@ -34,9 +68,9 @@ void PrintDiskError (BiosResult error, b { PrintEndl(); Print (write ? "Write" : "Read"); Print (" error:"); - PrintHex (error); + Print (error); Print (" Drive:"); - Print (drive < TC_FIRST_BIOS_DRIVE ? drive : drive - TC_FIRST_BIOS_DRIVE); + Print (drive ^ 0x80); if (sector) { @@ -65,35 +99,54 @@ void Print (const ChsAddress &chs) } -BiosResult ReadWriteSectors (bool write, byte *buffer, byte drive, const ChsAddress &chs, byte sectorCount, bool silent) +void PrintSectorCountInMB (const uint64 §orCount) +{ + Print (sectorCount >> (TC_LB_SIZE_BIT_SHIFT_DIVISOR + 2)); Print (" MB "); +} + + +BiosResult ReadWriteSectors (bool write, uint16 bufferSegment, uint16 bufferOffset, byte drive, const ChsAddress &chs, byte sectorCount, bool silent) { + CheckStack(); + byte cylinderLow = (byte) chs.Cylinder; byte sector = chs.Sector; sector |= byte (chs.Cylinder >> 2) & 0xc0; byte function = write ? 0x03 : 0x02; - + BiosResult result; - __asm - { - push es - mov ax, ds - mov es, ax - mov bx, ss:buffer - mov dl, ss:drive - mov ch, ss:cylinderLow - mov si, chs - mov dh, ss:[si].Head - mov cl, ss:sector - mov al, ss:sectorCount - mov ah, function - int 0x13 - mov result, ah - pop es - } + byte tryCount = TC_MAX_BIOS_DISK_IO_RETRIES; - if (result == BiosResultEccCorrected) + do + { result = BiosResultSuccess; + __asm + { + push es + mov ax, bufferSegment + mov es, ax + mov bx, bufferOffset + mov dl, drive + mov ch, cylinderLow + mov si, chs + mov dh, [si].Head + mov cl, sector + mov al, sectorCount + mov ah, function + int 0x13 + jnc ok // If CF=0, ignore AH to prevent issues caused by potential bugs in BIOSes + mov result, ah + ok: + pop es + } + + if (result == BiosResultEccCorrected) + result = BiosResultSuccess; + + // Some BIOSes report I/O errors prematurely in some cases + } while (result != BiosResultSuccess && --tryCount != 0); + if (!silent && result != BiosResultSuccess) PrintDiskError (result, write, drive, nullptr, &chs); @@ -101,6 +154,14 @@ BiosResult ReadWriteSectors (bool write, } +BiosResult ReadWriteSectors (bool write, byte *buffer, byte drive, const ChsAddress &chs, byte sectorCount, bool silent) +{ + uint16 codeSeg; + __asm mov codeSeg, cs + return ReadWriteSectors (write, codeSeg, (uint16) buffer, drive, chs, sectorCount, silent); +} + + BiosResult ReadSectors (byte *buffer, byte drive, const ChsAddress &chs, byte sectorCount, bool silent) { return ReadWriteSectors (false, buffer, drive, chs, sectorCount, silent); @@ -115,6 +176,21 @@ BiosResult WriteSectors (byte *buffer, b static BiosResult ReadWriteSectors (bool write, BiosLbaPacket &dapPacket, byte drive, const uint64 §or, uint16 sectorCount, bool silent) { + CheckStack(); + + if (!IsLbaSupported (drive)) + { + DriveGeometry geometry; + + BiosResult result = GetDriveGeometry (drive, geometry, silent); + if (result != BiosResultSuccess) + return result; + + ChsAddress chs; + LbaToChs (geometry, sector, chs); + return ReadWriteSectors (write, (uint16) (dapPacket.Buffer >> 16), (uint16) dapPacket.Buffer, drive, chs, sectorCount, silent); + } + dapPacket.Size = sizeof (dapPacket); dapPacket.Reserved = 0; dapPacket.SectorCount = sectorCount; @@ -123,20 +199,31 @@ static BiosResult ReadWriteSectors (bool byte function = write ? 0x43 : 0x42; BiosResult result; - __asm - { - mov bx, 0x55aa - mov dl, drive - mov si, [dapPacket] - mov ah, function - xor al, al - int 0x13 - mov result, ah - } + byte tryCount = TC_MAX_BIOS_DISK_IO_RETRIES; - if (result == BiosResultEccCorrected) + do + { result = BiosResultSuccess; + __asm + { + mov bx, 0x55aa + mov dl, drive + mov si, [dapPacket] + mov ah, function + xor al, al + int 0x13 + jnc ok // If CF=0, ignore AH to prevent issues caused by potential bugs in BIOSes + mov result, ah + ok: + } + + if (result == BiosResultEccCorrected) + result = BiosResultSuccess; + + // Some BIOSes report I/O errors prematurely in some cases + } while (result != BiosResultSuccess && --tryCount != 0); + if (!silent && result != BiosResultSuccess) PrintDiskError (result, write, drive, §or); @@ -159,21 +246,25 @@ BiosResult ReadWriteSectors (bool write, return ReadWriteSectors (write, dapPacket, drive, sector, sectorCount, silent); } +BiosResult ReadSectors (uint16 bufferSegment, uint16 bufferOffset, byte drive, const uint64 §or, uint16 sectorCount, bool silent) +{ + return ReadWriteSectors (false, bufferSegment, bufferOffset, drive, sector, sectorCount, silent); +} + BiosResult ReadSectors (byte *buffer, byte drive, const uint64 §or, uint16 sectorCount, bool silent) { - if (IsLbaSupported (drive)) - return ReadWriteSectors (false, buffer, drive, sector, sectorCount, silent); - - DriveGeometry geometry; + BiosResult result; + uint16 codeSeg; + __asm mov codeSeg, cs + + result = ReadSectors (BootStarted ? codeSeg : TC_BOOT_LOADER_ALT_SEGMENT, (uint16) buffer, drive, sector, sectorCount, silent); - BiosResult result = GetDriveGeometry (drive, geometry, silent); - if (result != BiosResultSuccess) - return result; + // Alternative segment is used to prevent memory corruption caused by buggy BIOSes + if (!BootStarted) + CopyMemory (TC_BOOT_LOADER_ALT_SEGMENT, (uint16) buffer, buffer, sectorCount * TC_LB_SIZE); - ChsAddress chs; - LbaToChs (geometry, sector, chs); - return ReadWriteSectors (false, buffer, drive, chs, sectorCount, silent); + return result; } @@ -185,6 +276,8 @@ BiosResult WriteSectors (byte *buffer, b BiosResult GetDriveGeometry (byte drive, DriveGeometry &geometry, bool silent) { + CheckStack(); + byte maxCylinderLow, maxHead, maxSector; BiosResult result; __asm @@ -195,11 +288,9 @@ BiosResult GetDriveGeometry (byte drive, int 0x13 mov result, ah - jc err mov maxCylinderLow, ch mov maxSector, cl mov maxHead, dh -err: pop es } @@ -211,8 +302,11 @@ err: } else if (!silent) { - PrintError ("Cannot get geometry of drive ", true, false); - Print (drive); + Print ("Drive "); + Print (drive ^ 0x80); + Print (" not found: "); + PrintErrorNoEndl (""); + Print (result); PrintEndl(); } @@ -229,21 +323,10 @@ void ChsToLba (const DriveGeometry &geom void LbaToChs (const DriveGeometry &geometry, const uint64 &lba, ChsAddress &chs) { - chs.Sector = (lba.LowPart % geometry.Sectors) + 1; + chs.Sector = (byte) ((lba.LowPart % geometry.Sectors) + 1); uint32 ch = lba.LowPart / geometry.Sectors; - chs.Head = ch % geometry.Heads; - chs.Cylinder = ch / geometry.Heads; -} - - -BiosResult ReadMBR (byte drive, MBR &mbr, bool silent) -{ - ChsAddress chs; - chs.Cylinder = 0; - chs.Head = 0; - chs.Sector = 1; - - return ReadSectors ((byte *) &mbr, drive, chs, 1, silent); + chs.Head = (byte) (ch % geometry.Heads); + chs.Cylinder = (uint16) (ch / geometry.Heads); } @@ -256,31 +339,58 @@ void PartitionEntryMBRToPartition (const partition.SectorCount.LowPart = partEntry.SectorCountLBA; partition.StartSector.HighPart = 0; partition.StartSector.LowPart = partEntry.StartLBA; + partition.Type = partEntry.Type; +} - partition.StartChsAddress.Cylinder = partEntry.StartCylinder | (uint16 (partEntry.StartCylSector & 0xc0) << 2); - partition.StartChsAddress.Head = partEntry.StartHead; - partition.StartChsAddress.Sector = partEntry.StartCylSector & ~0xc0; - partition.Type = partEntry.Type; +BiosResult ReadWriteMBR (bool write, byte drive, bool silent) +{ + uint64 mbrSector; + mbrSector.HighPart = 0; + mbrSector.LowPart = 0; + + if (write) + return WriteSectors (SectorBuffer, drive, mbrSector, 1, silent); + + return ReadSectors (SectorBuffer, drive, mbrSector, 1, silent); // Uses alternative segment } -BiosResult GetDrivePartitions (byte drive, Partition *partitionArray, size_t partitionArrayCapacity, size_t &partitionCount, bool activeOnly, bool silent) +BiosResult GetDrivePartitions (byte drive, Partition *partitionArray, size_t partitionArrayCapacity, size_t &partitionCount, bool activeOnly, Partition *findPartitionFollowingThis, bool silent) { - MBR mbr; - BiosResult result = ReadMBR (drive, mbr, silent); + Partition *followingPartition; + Partition tmpPartition; + + if (findPartitionFollowingThis) + { + assert (partitionArrayCapacity == 1); + partitionArrayCapacity = 0xff; + followingPartition = partitionArray; + partitionArray = &tmpPartition; + + followingPartition->Drive = TC_INVALID_BIOS_DRIVE; + followingPartition->StartSector.LowPart = 0xFFFFffffUL; + } + + AcquireSectorBuffer(); + BiosResult result = ReadWriteMBR (false, drive, silent); + ReleaseSectorBuffer(); + partitionCount = 0; - - if (result != BiosResultSuccess || mbr.Signature != 0xaa55) + + MBR *mbr = (MBR *) SectorBuffer; + if (result != BiosResultSuccess || mbr->Signature != 0xaa55) return result; + PartitionEntryMBR mbrPartitions[4]; + memcpy (mbrPartitions, mbr->Partitions, sizeof (mbrPartitions)); size_t partitionArrayPos = 0, partitionNumber; for (partitionNumber = 0; - partitionNumber < array_capacity (mbr.Partitions) && partitionArrayPos < partitionArrayCapacity; + partitionNumber < array_capacity (mbrPartitions) && partitionArrayPos < partitionArrayCapacity; ++partitionNumber) { - const PartitionEntryMBR &partEntry = mbr.Partitions[partitionNumber]; + const PartitionEntryMBR &partEntry = mbrPartitions[partitionNumber]; if (partEntry.SectorCountLBA > 0) { @@ -291,7 +401,7 @@ BiosResult GetDrivePartitions (byte driv continue; partition.Drive = drive; - partition.Number = partitionNumber; + partition.Number = partitionArrayPos; if (partEntry.Type == 0x5 || partEntry.Type == 0xf) // Extended partition { @@ -300,38 +410,59 @@ BiosResult GetDrivePartitions (byte driv // Find all extended partitions uint64 firstExtStartLBA = partition.StartSector; uint64 extStartLBA = partition.StartSector; - MBR extMbr; + MBR *extMbr = (MBR *) SectorBuffer; while (partitionArrayPos < partitionArrayCapacity && - (result = ReadSectors ((byte *) &extMbr, drive, extStartLBA, 1, silent)) == BiosResultSuccess - && extMbr.Signature == 0xaa55) + (result = ReadSectors ((byte *) extMbr, drive, extStartLBA, 1, silent)) == BiosResultSuccess + && extMbr->Signature == 0xaa55) { - if (extMbr.Partitions[0].SectorCountLBA > 0) + if (extMbr->Partitions[0].SectorCountLBA > 0) { - Partition &logPart = partitionArray[partitionArrayPos++]; - PartitionEntryMBRToPartition (extMbr.Partitions[0], logPart); + Partition &logPart = partitionArray[partitionArrayPos]; + PartitionEntryMBRToPartition (extMbr->Partitions[0], logPart); logPart.Drive = drive; - logPart.Number = partitionNumber++; + logPart.Number = partitionArrayPos; logPart.Primary = false; logPart.StartSector.LowPart += extStartLBA.LowPart; logPart.EndSector.LowPart += extStartLBA.LowPart; + + if (findPartitionFollowingThis) + { + if (logPart.StartSector.LowPart > findPartitionFollowingThis->EndSector.LowPart + && logPart.StartSector.LowPart < followingPartition->StartSector.LowPart) + { + *followingPartition = logPart; + } + } + else + ++partitionArrayPos; } // Secondary extended - if (extMbr.Partitions[1].Type != 0x5 && extMbr.Partitions[1].Type == 0xf - || extMbr.Partitions[1].SectorCountLBA == 0) + if (extMbr->Partitions[1].Type != 0x5 && extMbr->Partitions[1].Type == 0xf + || extMbr->Partitions[1].SectorCountLBA == 0) break; - extStartLBA.LowPart = extMbr.Partitions[1].StartLBA + firstExtStartLBA.LowPart; + extStartLBA.LowPart = extMbr->Partitions[1].StartLBA + firstExtStartLBA.LowPart; } } } else { - ++partitionArrayPos; partition.Primary = true; + + if (findPartitionFollowingThis) + { + if (partition.StartSector.LowPart > findPartitionFollowingThis->EndSector.LowPart + && partition.StartSector.LowPart < followingPartition->StartSector.LowPart) + { + *followingPartition = partition; + } + } + else + ++partitionArrayPos; } } } @@ -341,7 +472,16 @@ BiosResult GetDrivePartitions (byte driv } -BiosResult GetActivePartition (byte drive, Partition &partition, size_t &partitionCount, bool silent) +bool GetActivePartition (byte drive) { - return GetDrivePartitions (drive, &partition, 1, partitionCount, true, silent); + size_t partCount; + + if (GetDrivePartitions (drive, &ActivePartition, 1, partCount, true) != BiosResultSuccess || partCount < 1) + { + ActivePartition.Drive = TC_INVALID_BIOS_DRIVE; + PrintError (TC_BOOT_STR_NO_BOOT_PARTITION); + return false; + } + + return true; }