diff options
Diffstat (limited to 'src/Boot/Windows/BootDiskIo.cpp')
-rw-r--r-- | src/Boot/Windows/BootDiskIo.cpp | 982 |
1 files changed, 491 insertions, 491 deletions
diff --git a/src/Boot/Windows/BootDiskIo.cpp b/src/Boot/Windows/BootDiskIo.cpp index 31917a64..bf3fe9fc 100644 --- a/src/Boot/Windows/BootDiskIo.cpp +++ b/src/Boot/Windows/BootDiskIo.cpp @@ -1,491 +1,491 @@ -/*
- Derived from source code of TrueCrypt 7.1a, which is
- Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed
- by the TrueCrypt License 3.0.
-
- Modifications and additions to the original source code (contained in this file)
- and all other portions of this file are Copyright (c) 2013-2016 IDRIX
- and are governed by the Apache License 2.0 the full text of which is
- contained in the file License.txt included in VeraCrypt 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
- mov dl, drive
- mov ah, 0x41
- int 0x13
- jc err
- mov result, bx
- err:
- }
-
- CachedDrive = drive;
- CachedStatus = (result == 0xaa55);
-ret:
- return CachedStatus;
-}
-
-
-void PrintDiskError (BiosResult error, bool write, byte drive, const uint64 *sector, const ChsAddress *chs)
-{
- PrintEndl();
- Print (write ? "Write" : "Read"); Print (" error:");
- Print (error);
- Print (" Drive:");
- Print (drive ^ 0x80);
-
- if (sector)
- {
- Print (" Sector:");
- Print (*sector);
- }
-
- if (chs)
- {
- Print (" CHS:");
- Print (*chs);
- }
-
- PrintEndl();
- Beep();
-}
-
-
-void Print (const ChsAddress &chs)
-{
- Print (chs.Cylinder);
- PrintChar ('/');
- Print (chs.Head);
- PrintChar ('/');
- Print (chs.Sector);
-}
-
-
-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;
- byte tryCount = TC_MAX_BIOS_DISK_IO_RETRIES;
-
- 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);
-
- return result;
-}
-
-
-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);
-}
-
-
-BiosResult WriteSectors (byte *buffer, byte drive, const ChsAddress &chs, byte sectorCount, bool silent)
-{
- return ReadWriteSectors (true, buffer, drive, chs, sectorCount, silent);
-}
-
-
-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;
- dapPacket.Sector = sector;
-
- byte function = write ? 0x43 : 0x42;
-
- BiosResult result;
- byte tryCount = TC_MAX_BIOS_DISK_IO_RETRIES;
-
- 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);
-
- return result;
-}
-
-
-static BiosResult ReadWriteSectors (bool write, byte *buffer, byte drive, const uint64 §or, uint16 sectorCount, bool silent)
-{
- BiosLbaPacket dapPacket;
- dapPacket.Buffer = (uint32) buffer;
- return ReadWriteSectors (write, dapPacket, drive, sector, sectorCount, silent);
-}
-
-
-BiosResult ReadWriteSectors (bool write, uint16 bufferSegment, uint16 bufferOffset, byte drive, const uint64 §or, uint16 sectorCount, bool silent)
-{
- BiosLbaPacket dapPacket;
- dapPacket.Buffer = ((uint32) bufferSegment << 16) | bufferOffset;
- 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)
-{
- BiosResult result;
- uint16 codeSeg;
- __asm mov codeSeg, cs
-
- result = ReadSectors (BootStarted ? codeSeg : TC_BOOT_LOADER_ALT_SEGMENT, (uint16) buffer, drive, sector, sectorCount, silent);
-
- // 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);
-
- return result;
-}
-
-
-BiosResult WriteSectors (byte *buffer, byte drive, const uint64 §or, uint16 sectorCount, bool silent)
-{
- return ReadWriteSectors (true, buffer, drive, sector, sectorCount, silent);
-}
-
-
-BiosResult GetDriveGeometry (byte drive, DriveGeometry &geometry, bool silent)
-{
- CheckStack();
-
- byte maxCylinderLow, maxHead, maxSector;
- BiosResult result;
- __asm
- {
- push es
- mov dl, drive
- mov ah, 0x08
- int 0x13
-
- mov result, ah
- mov maxCylinderLow, ch
- mov maxSector, cl
- mov maxHead, dh
- pop es
- }
-
- if (result == BiosResultSuccess)
- {
- geometry.Cylinders = (maxCylinderLow | (uint16 (maxSector & 0xc0) << 2)) + 1;
- geometry.Heads = maxHead + 1;
- geometry.Sectors = maxSector & ~0xc0;
- }
- else if (!silent)
- {
- Print ("Drive ");
- Print (drive ^ 0x80);
- Print (" not found: ");
- PrintErrorNoEndl ("");
- Print (result);
- PrintEndl();
- }
-
- return result;
-}
-
-
-void ChsToLba (const DriveGeometry &geometry, const ChsAddress &chs, uint64 &lba)
-{
- lba.HighPart = 0;
- lba.LowPart = (uint32 (chs.Cylinder) * geometry.Heads + chs.Head) * geometry.Sectors + chs.Sector - 1;
-}
-
-
-void LbaToChs (const DriveGeometry &geometry, const uint64 &lba, ChsAddress &chs)
-{
- chs.Sector = (byte) ((lba.LowPart % geometry.Sectors) + 1);
- uint32 ch = lba.LowPart / geometry.Sectors;
- chs.Head = (byte) (ch % geometry.Heads);
- chs.Cylinder = (uint16) (ch / geometry.Heads);
-}
-
-
-void PartitionEntryMBRToPartition (const PartitionEntryMBR &partEntry, Partition &partition)
-{
- partition.Active = partEntry.BootIndicator == 0x80;
- partition.EndSector.HighPart = 0;
- partition.EndSector.LowPart = partEntry.StartLBA + partEntry.SectorCountLBA - 1;
- partition.SectorCount.HighPart = 0;
- partition.SectorCount.LowPart = partEntry.SectorCountLBA;
- partition.StartSector.HighPart = 0;
- partition.StartSector.LowPart = partEntry.StartLBA;
- 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, Partition *findPartitionFollowingThis, bool 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;
-
- 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 (mbrPartitions) && partitionArrayPos < partitionArrayCapacity;
- ++partitionNumber)
- {
- const PartitionEntryMBR &partEntry = mbrPartitions[partitionNumber];
-
- if (partEntry.SectorCountLBA > 0)
- {
- Partition &partition = partitionArray[partitionArrayPos];
- PartitionEntryMBRToPartition (partEntry, partition);
-
- if (activeOnly && !partition.Active)
- continue;
-
- partition.Drive = drive;
- partition.Number = partitionArrayPos;
-
- if (partEntry.Type == 0x5 || partEntry.Type == 0xf) // Extended partition
- {
- if (IsLbaSupported (drive))
- {
- // Find all extended partitions
- uint64 firstExtStartLBA = partition.StartSector;
- uint64 extStartLBA = partition.StartSector;
- MBR *extMbr = (MBR *) SectorBuffer;
-
- while (partitionArrayPos < partitionArrayCapacity &&
- (result = ReadSectors ((byte *) extMbr, drive, extStartLBA, 1, silent)) == BiosResultSuccess
- && extMbr->Signature == 0xaa55)
- {
- if (extMbr->Partitions[0].SectorCountLBA > 0)
- {
- Partition &logPart = partitionArray[partitionArrayPos];
- PartitionEntryMBRToPartition (extMbr->Partitions[0], logPart);
- logPart.Drive = drive;
-
- 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)
- break;
-
- extStartLBA.LowPart = extMbr->Partitions[1].StartLBA + firstExtStartLBA.LowPart;
- }
- }
- }
- else
- {
- partition.Primary = true;
-
- if (findPartitionFollowingThis)
- {
- if (partition.StartSector.LowPart > findPartitionFollowingThis->EndSector.LowPart
- && partition.StartSector.LowPart < followingPartition->StartSector.LowPart)
- {
- *followingPartition = partition;
- }
- }
- else
- ++partitionArrayPos;
- }
- }
- }
-
- partitionCount = partitionArrayPos;
- return result;
-}
-
-
-bool GetActivePartition (byte drive)
-{
- 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;
-}
+/* + Derived from source code of TrueCrypt 7.1a, which is + Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed + by the TrueCrypt License 3.0. + + Modifications and additions to the original source code (contained in this file) + and all other portions of this file are Copyright (c) 2013-2016 IDRIX + and are governed by the Apache License 2.0 the full text of which is + contained in the file License.txt included in VeraCrypt 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 + mov dl, drive + mov ah, 0x41 + int 0x13 + jc err + mov result, bx + err: + } + + CachedDrive = drive; + CachedStatus = (result == 0xaa55); +ret: + return CachedStatus; +} + + +void PrintDiskError (BiosResult error, bool write, byte drive, const uint64 *sector, const ChsAddress *chs) +{ + PrintEndl(); + Print (write ? "Write" : "Read"); Print (" error:"); + Print (error); + Print (" Drive:"); + Print (drive ^ 0x80); + + if (sector) + { + Print (" Sector:"); + Print (*sector); + } + + if (chs) + { + Print (" CHS:"); + Print (*chs); + } + + PrintEndl(); + Beep(); +} + + +void Print (const ChsAddress &chs) +{ + Print (chs.Cylinder); + PrintChar ('/'); + Print (chs.Head); + PrintChar ('/'); + Print (chs.Sector); +} + + +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; + byte tryCount = TC_MAX_BIOS_DISK_IO_RETRIES; + + 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); + + return result; +} + + +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); +} + + +BiosResult WriteSectors (byte *buffer, byte drive, const ChsAddress &chs, byte sectorCount, bool silent) +{ + return ReadWriteSectors (true, buffer, drive, chs, sectorCount, silent); +} + + +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; + dapPacket.Sector = sector; + + byte function = write ? 0x43 : 0x42; + + BiosResult result; + byte tryCount = TC_MAX_BIOS_DISK_IO_RETRIES; + + 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); + + return result; +} + + +static BiosResult ReadWriteSectors (bool write, byte *buffer, byte drive, const uint64 §or, uint16 sectorCount, bool silent) +{ + BiosLbaPacket dapPacket; + dapPacket.Buffer = (uint32) buffer; + return ReadWriteSectors (write, dapPacket, drive, sector, sectorCount, silent); +} + + +BiosResult ReadWriteSectors (bool write, uint16 bufferSegment, uint16 bufferOffset, byte drive, const uint64 §or, uint16 sectorCount, bool silent) +{ + BiosLbaPacket dapPacket; + dapPacket.Buffer = ((uint32) bufferSegment << 16) | bufferOffset; + 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) +{ + BiosResult result; + uint16 codeSeg; + __asm mov codeSeg, cs + + result = ReadSectors (BootStarted ? codeSeg : TC_BOOT_LOADER_ALT_SEGMENT, (uint16) buffer, drive, sector, sectorCount, silent); + + // 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); + + return result; +} + + +BiosResult WriteSectors (byte *buffer, byte drive, const uint64 §or, uint16 sectorCount, bool silent) +{ + return ReadWriteSectors (true, buffer, drive, sector, sectorCount, silent); +} + + +BiosResult GetDriveGeometry (byte drive, DriveGeometry &geometry, bool silent) +{ + CheckStack(); + + byte maxCylinderLow, maxHead, maxSector; + BiosResult result; + __asm + { + push es + mov dl, drive + mov ah, 0x08 + int 0x13 + + mov result, ah + mov maxCylinderLow, ch + mov maxSector, cl + mov maxHead, dh + pop es + } + + if (result == BiosResultSuccess) + { + geometry.Cylinders = (maxCylinderLow | (uint16 (maxSector & 0xc0) << 2)) + 1; + geometry.Heads = maxHead + 1; + geometry.Sectors = maxSector & ~0xc0; + } + else if (!silent) + { + Print ("Drive "); + Print (drive ^ 0x80); + Print (" not found: "); + PrintErrorNoEndl (""); + Print (result); + PrintEndl(); + } + + return result; +} + + +void ChsToLba (const DriveGeometry &geometry, const ChsAddress &chs, uint64 &lba) +{ + lba.HighPart = 0; + lba.LowPart = (uint32 (chs.Cylinder) * geometry.Heads + chs.Head) * geometry.Sectors + chs.Sector - 1; +} + + +void LbaToChs (const DriveGeometry &geometry, const uint64 &lba, ChsAddress &chs) +{ + chs.Sector = (byte) ((lba.LowPart % geometry.Sectors) + 1); + uint32 ch = lba.LowPart / geometry.Sectors; + chs.Head = (byte) (ch % geometry.Heads); + chs.Cylinder = (uint16) (ch / geometry.Heads); +} + + +void PartitionEntryMBRToPartition (const PartitionEntryMBR &partEntry, Partition &partition) +{ + partition.Active = partEntry.BootIndicator == 0x80; + partition.EndSector.HighPart = 0; + partition.EndSector.LowPart = partEntry.StartLBA + partEntry.SectorCountLBA - 1; + partition.SectorCount.HighPart = 0; + partition.SectorCount.LowPart = partEntry.SectorCountLBA; + partition.StartSector.HighPart = 0; + partition.StartSector.LowPart = partEntry.StartLBA; + 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, Partition *findPartitionFollowingThis, bool 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; + + 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 (mbrPartitions) && partitionArrayPos < partitionArrayCapacity; + ++partitionNumber) + { + const PartitionEntryMBR &partEntry = mbrPartitions[partitionNumber]; + + if (partEntry.SectorCountLBA > 0) + { + Partition &partition = partitionArray[partitionArrayPos]; + PartitionEntryMBRToPartition (partEntry, partition); + + if (activeOnly && !partition.Active) + continue; + + partition.Drive = drive; + partition.Number = partitionArrayPos; + + if (partEntry.Type == 0x5 || partEntry.Type == 0xf) // Extended partition + { + if (IsLbaSupported (drive)) + { + // Find all extended partitions + uint64 firstExtStartLBA = partition.StartSector; + uint64 extStartLBA = partition.StartSector; + MBR *extMbr = (MBR *) SectorBuffer; + + while (partitionArrayPos < partitionArrayCapacity && + (result = ReadSectors ((byte *) extMbr, drive, extStartLBA, 1, silent)) == BiosResultSuccess + && extMbr->Signature == 0xaa55) + { + if (extMbr->Partitions[0].SectorCountLBA > 0) + { + Partition &logPart = partitionArray[partitionArrayPos]; + PartitionEntryMBRToPartition (extMbr->Partitions[0], logPart); + logPart.Drive = drive; + + 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) + break; + + extStartLBA.LowPart = extMbr->Partitions[1].StartLBA + firstExtStartLBA.LowPart; + } + } + } + else + { + partition.Primary = true; + + if (findPartitionFollowingThis) + { + if (partition.StartSector.LowPart > findPartitionFollowingThis->EndSector.LowPart + && partition.StartSector.LowPart < followingPartition->StartSector.LowPart) + { + *followingPartition = partition; + } + } + else + ++partitionArrayPos; + } + } + } + + partitionCount = partitionArrayPos; + return result; +} + + +bool GetActivePartition (byte drive) +{ + 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; +} |