"Fossies" - the Fresh Open Source Software Archive

Member "src/Boot/Windows/BootDiskIo.cpp" (10 Oct 2018, 12343 Bytes) of package /windows/misc/VeraCrypt_1.23-Hotfix-2_Source.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "BootDiskIo.cpp" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.21_Source_vs_1.22_Source.

    1 /*
    2  Derived from source code of TrueCrypt 7.1a, which is
    3  Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed
    4  by the TrueCrypt License 3.0.
    5 
    6  Modifications and additions to the original source code (contained in this file)
    7  and all other portions of this file are Copyright (c) 2013-2017 IDRIX
    8  and are governed by the Apache License 2.0 the full text of which is
    9  contained in the file License.txt included in VeraCrypt binary and source
   10  code distribution packages.
   11 */
   12 
   13 #include "Bios.h"
   14 #include "BootConsoleIo.h"
   15 #include "BootConfig.h"
   16 #include "BootDebug.h"
   17 #include "BootDefs.h"
   18 #include "BootDiskIo.h"
   19 #include "BootStrings.h"
   20 
   21 
   22 byte SectorBuffer[TC_LB_SIZE];
   23 
   24 #ifdef TC_BOOT_DEBUG_ENABLED
   25 static bool SectorBufferInUse = false;
   26 
   27 void AcquireSectorBuffer ()
   28 {
   29     if (SectorBufferInUse)
   30         TC_THROW_FATAL_EXCEPTION;
   31 
   32     SectorBufferInUse = true;
   33 }
   34 
   35 
   36 void ReleaseSectorBuffer ()
   37 {
   38     SectorBufferInUse = false;
   39 }
   40 
   41 #endif
   42 
   43 
   44 bool IsLbaSupported (byte drive)
   45 {
   46     static byte CachedDrive = TC_INVALID_BIOS_DRIVE;
   47     static bool CachedStatus;
   48     uint16 result = 0;
   49 
   50     if (CachedDrive == drive)
   51         goto ret;
   52 
   53     __asm
   54     {
   55         mov bx, 0x55aa
   56         mov dl, drive
   57         mov ah, 0x41
   58         int 0x13
   59         jc err
   60         mov result, bx
   61     err:
   62     }
   63 
   64     CachedDrive = drive;
   65     CachedStatus = (result == 0xaa55);
   66 ret:
   67     return CachedStatus;
   68 }
   69 
   70 
   71 void PrintDiskError (BiosResult error, bool write, byte drive, const uint64 *sector, const ChsAddress *chs)
   72 {
   73     PrintEndl();
   74     Print (write ? "Write" : "Read"); Print (" error:");
   75     Print (error);
   76     Print (" Drive:");
   77     Print (drive ^ 0x80);
   78 
   79     if (sector)
   80     {
   81         Print (" Sector:");
   82         Print (*sector);
   83     }
   84 
   85     if (chs)
   86     {
   87         Print (" CHS:");
   88         Print (*chs);
   89     }
   90 
   91     PrintEndl();
   92     Beep();
   93 }
   94 
   95 
   96 void Print (const ChsAddress &chs)
   97 {
   98     Print (chs.Cylinder);
   99     PrintChar ('/');
  100     Print (chs.Head);
  101     PrintChar ('/');
  102     Print (chs.Sector);
  103 }
  104 
  105 
  106 void PrintSectorCountInMB (const uint64 &sectorCount)
  107 {
  108     Print (sectorCount >> (TC_LB_SIZE_BIT_SHIFT_DIVISOR + 2)); Print (" MB ");
  109 }
  110 
  111 
  112 BiosResult ReadWriteSectors (bool write, uint16 bufferSegment, uint16 bufferOffset, byte drive, const ChsAddress &chs, byte sectorCount, bool silent)
  113 {
  114     CheckStack();
  115 
  116     byte cylinderLow = (byte) chs.Cylinder;
  117     byte sector = chs.Sector;
  118     sector |= byte (chs.Cylinder >> 2) & 0xc0;
  119     byte function = write ? 0x03 : 0x02;
  120 
  121     BiosResult result;
  122     byte tryCount = TC_MAX_BIOS_DISK_IO_RETRIES;
  123 
  124     do
  125     {
  126         result = BiosResultSuccess;
  127 
  128         __asm
  129         {
  130             push es
  131             mov ax, bufferSegment
  132             mov es, ax
  133             mov bx, bufferOffset
  134             mov dl, drive
  135             mov ch, cylinderLow
  136             mov si, chs
  137             mov dh, [si].Head
  138             mov cl, sector
  139             mov al, sectorCount
  140             mov ah, function
  141             int 0x13
  142             jnc ok              // If CF=0, ignore AH to prevent issues caused by potential bugs in BIOSes
  143             mov result, ah
  144         ok:
  145             pop es
  146         }
  147 
  148         if (result == BiosResultEccCorrected)
  149             result = BiosResultSuccess;
  150 
  151     // Some BIOSes report I/O errors prematurely in some cases
  152     } while (result != BiosResultSuccess && --tryCount != 0);
  153 
  154     if (!silent && result != BiosResultSuccess)
  155         PrintDiskError (result, write, drive, nullptr, &chs);
  156 
  157     return result;
  158 }
  159 
  160 #ifdef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
  161 
  162 BiosResult ReadWriteSectors (bool write, byte *buffer, byte drive, const ChsAddress &chs, byte sectorCount, bool silent)
  163 {
  164     uint16 codeSeg;
  165     __asm mov codeSeg, cs
  166     return ReadWriteSectors (write, codeSeg, (uint16) buffer, drive, chs, sectorCount, silent);
  167 }
  168 
  169 BiosResult ReadSectors (byte *buffer, byte drive, const ChsAddress &chs, byte sectorCount, bool silent)
  170 {
  171     return ReadWriteSectors (false, buffer, drive, chs, sectorCount, silent);
  172 }
  173 
  174 #if 0
  175 BiosResult WriteSectors (byte *buffer, byte drive, const ChsAddress &chs, byte sectorCount, bool silent)
  176 {
  177     return ReadWriteSectors (true, buffer, drive, chs, sectorCount, silent);
  178 }
  179 #endif
  180 
  181 #endif
  182 
  183 static BiosResult ReadWriteSectors (bool write, BiosLbaPacket &dapPacket, byte drive, const uint64 &sector, uint16 sectorCount, bool silent)
  184 {
  185     CheckStack();
  186 
  187     if (!IsLbaSupported (drive))
  188     {
  189         DriveGeometry geometry;
  190 
  191         BiosResult result = GetDriveGeometry (drive, geometry, silent);
  192         if (result != BiosResultSuccess)
  193             return result;
  194 
  195         ChsAddress chs;
  196         LbaToChs (geometry, sector, chs);
  197         return ReadWriteSectors (write, (uint16) (dapPacket.Buffer >> 16), (uint16) dapPacket.Buffer, drive, chs, sectorCount, silent);
  198     }
  199 
  200     dapPacket.Size = sizeof (dapPacket);
  201     dapPacket.Reserved = 0;
  202     dapPacket.SectorCount = sectorCount;
  203     dapPacket.Sector = sector;
  204 
  205     byte function = write ? 0x43 : 0x42;
  206 
  207     BiosResult result;
  208     byte tryCount = TC_MAX_BIOS_DISK_IO_RETRIES;
  209 
  210     do
  211     {
  212         result = BiosResultSuccess;
  213 
  214         __asm
  215         {
  216             mov bx, 0x55aa
  217             mov dl, drive
  218             mov si, [dapPacket]
  219             mov ah, function
  220             xor al, al
  221             int 0x13
  222             jnc ok              // If CF=0, ignore AH to prevent issues caused by potential bugs in BIOSes
  223             mov result, ah
  224         ok:
  225         }
  226 
  227         if (result == BiosResultEccCorrected)
  228             result = BiosResultSuccess;
  229 
  230     // Some BIOSes report I/O errors prematurely in some cases
  231     } while (result != BiosResultSuccess && --tryCount != 0);
  232 
  233     if (!silent && result != BiosResultSuccess)
  234         PrintDiskError (result, write, drive, &sector);
  235 
  236     return result;
  237 }
  238 
  239 
  240 static BiosResult ReadWriteSectors (bool write, byte *buffer, byte drive, const uint64 &sector, uint16 sectorCount, bool silent)
  241 {
  242     BiosLbaPacket dapPacket;
  243     dapPacket.Buffer = (uint32) buffer;
  244     return ReadWriteSectors (write, dapPacket, drive, sector, sectorCount, silent);
  245 }
  246 
  247 
  248 BiosResult ReadWriteSectors (bool write, uint16 bufferSegment, uint16 bufferOffset, byte drive, const uint64 &sector, uint16 sectorCount, bool silent)
  249 {
  250     BiosLbaPacket dapPacket;
  251     dapPacket.Buffer = ((uint32) bufferSegment << 16) | bufferOffset;
  252     return ReadWriteSectors (write, dapPacket, drive, sector, sectorCount, silent);
  253 }
  254 
  255 BiosResult ReadSectors (uint16 bufferSegment, uint16 bufferOffset, byte drive, const uint64 &sector, uint16 sectorCount, bool silent)
  256 {
  257     return ReadWriteSectors (false, bufferSegment, bufferOffset, drive, sector, sectorCount, silent);
  258 }
  259 
  260 
  261 BiosResult ReadSectors (byte *buffer, byte drive, const uint64 &sector, uint16 sectorCount, bool silent)
  262 {
  263     BiosResult result;
  264     uint16 codeSeg;
  265     __asm mov codeSeg, cs
  266 
  267     result = ReadSectors (BootStarted ? codeSeg : TC_BOOT_LOADER_ALT_SEGMENT, (uint16) buffer, drive, sector, sectorCount, silent);
  268 
  269     // Alternative segment is used to prevent memory corruption caused by buggy BIOSes
  270     if (!BootStarted)
  271         CopyMemory (TC_BOOT_LOADER_ALT_SEGMENT, (uint16) buffer, buffer, sectorCount * TC_LB_SIZE);
  272 
  273     return result;
  274 }
  275 
  276 
  277 BiosResult WriteSectors (byte *buffer, byte drive, const uint64 &sector, uint16 sectorCount, bool silent)
  278 {
  279     return ReadWriteSectors (true, buffer, drive, sector, sectorCount, silent);
  280 }
  281 
  282 
  283 BiosResult GetDriveGeometry (byte drive, DriveGeometry &geometry, bool silent)
  284 {
  285     CheckStack();
  286 
  287     byte maxCylinderLow, maxHead, maxSector;
  288     BiosResult result;
  289     __asm
  290     {
  291         push es
  292         mov dl, drive
  293         mov ah, 0x08
  294         int 0x13
  295 
  296         mov result, ah
  297         mov maxCylinderLow, ch
  298         mov maxSector, cl
  299         mov maxHead, dh
  300         pop es
  301     }
  302 
  303     if (result == BiosResultSuccess)
  304     {
  305         geometry.Cylinders = (maxCylinderLow | (uint16 (maxSector & 0xc0) << 2)) + 1;
  306         geometry.Heads = maxHead + 1;
  307         geometry.Sectors = maxSector & ~0xc0;
  308     }
  309     else if (!silent)
  310     {
  311         Print ("Drive ");
  312         Print (drive ^ 0x80);
  313         Print (" not found: ");
  314         PrintErrorNoEndl ("");
  315         Print (result);
  316         PrintEndl();
  317     }
  318 
  319     return result;
  320 }
  321 
  322 
  323 void ChsToLba (const DriveGeometry &geometry, const ChsAddress &chs, uint64 &lba)
  324 {
  325     lba.HighPart = 0;
  326     lba.LowPart = (uint32 (chs.Cylinder) * geometry.Heads + chs.Head) * geometry.Sectors + chs.Sector - 1;
  327 }
  328 
  329 
  330 void LbaToChs (const DriveGeometry &geometry, const uint64 &lba, ChsAddress &chs)
  331 {
  332     chs.Sector = (byte) ((lba.LowPart % geometry.Sectors) + 1);
  333     uint32 ch = lba.LowPart / geometry.Sectors;
  334     chs.Head = (byte) (ch % geometry.Heads);
  335     chs.Cylinder = (uint16) (ch / geometry.Heads);
  336 }
  337 
  338 
  339 void PartitionEntryMBRToPartition (const PartitionEntryMBR &partEntry, Partition &partition)
  340 {
  341     partition.Active = partEntry.BootIndicator == 0x80;
  342     partition.EndSector.HighPart = 0;
  343     partition.EndSector.LowPart = partEntry.StartLBA + partEntry.SectorCountLBA - 1;
  344     partition.SectorCount.HighPart = 0;
  345     partition.SectorCount.LowPart = partEntry.SectorCountLBA;
  346     partition.StartSector.HighPart = 0;
  347     partition.StartSector.LowPart = partEntry.StartLBA;
  348     partition.Type = partEntry.Type;
  349 }
  350 
  351 
  352 BiosResult ReadWriteMBR (bool write, byte drive, bool silent)
  353 {
  354     uint64 mbrSector;
  355     mbrSector.HighPart = 0;
  356     mbrSector.LowPart = 0;
  357 
  358     if (write)
  359         return WriteSectors (SectorBuffer, drive, mbrSector, 1, silent);
  360 
  361     return ReadSectors (SectorBuffer, drive, mbrSector, 1, silent);     // Uses alternative segment
  362 }
  363 
  364 
  365 BiosResult GetDrivePartitions (byte drive, Partition *partitionArray, size_t partitionArrayCapacity, size_t &partitionCount, bool activeOnly, Partition *findPartitionFollowingThis, bool silent)
  366 {
  367     Partition *followingPartition;
  368     Partition tmpPartition;
  369 
  370     if (findPartitionFollowingThis)
  371     {
  372         assert (partitionArrayCapacity == 1);
  373         partitionArrayCapacity = 0xff;
  374         followingPartition = partitionArray;
  375         partitionArray = &tmpPartition;
  376 
  377         followingPartition->Drive = TC_INVALID_BIOS_DRIVE;
  378         followingPartition->StartSector.LowPart = 0xFFFFffffUL;
  379     }
  380 
  381     AcquireSectorBuffer();
  382     BiosResult result = ReadWriteMBR (false, drive, silent);
  383     ReleaseSectorBuffer();
  384 
  385     partitionCount = 0;
  386 
  387     MBR *mbr = (MBR *) SectorBuffer;
  388     if (result != BiosResultSuccess || mbr->Signature != 0xaa55)
  389         return result;
  390 
  391     PartitionEntryMBR mbrPartitions[4];
  392     memcpy (mbrPartitions, mbr->Partitions, sizeof (mbrPartitions));
  393     size_t partitionArrayPos = 0, partitionNumber;
  394 
  395     for (partitionNumber = 0;
  396         partitionNumber < array_capacity (mbrPartitions) && partitionArrayPos < partitionArrayCapacity;
  397         ++partitionNumber)
  398     {
  399         const PartitionEntryMBR &partEntry = mbrPartitions[partitionNumber];
  400 
  401         if (partEntry.SectorCountLBA > 0)
  402         {
  403             Partition &partition = partitionArray[partitionArrayPos];
  404             PartitionEntryMBRToPartition (partEntry, partition);
  405 
  406             if (activeOnly && !partition.Active)
  407                 continue;
  408 
  409             partition.Drive = drive;
  410             partition.Number = partitionArrayPos;
  411 
  412             if (partEntry.Type == 0x5 || partEntry.Type == 0xf) // Extended partition
  413             {
  414                 if (IsLbaSupported (drive))
  415                 {
  416                     // Find all extended partitions
  417                     uint64 firstExtStartLBA = partition.StartSector;
  418                     uint64 extStartLBA = partition.StartSector;
  419                     MBR *extMbr = (MBR *) SectorBuffer;
  420 
  421                     while (partitionArrayPos < partitionArrayCapacity &&
  422                         (result = ReadSectors ((byte *) extMbr, drive, extStartLBA, 1, silent)) == BiosResultSuccess
  423                         && extMbr->Signature == 0xaa55)
  424                     {
  425                         if (extMbr->Partitions[0].SectorCountLBA > 0)
  426                         {
  427                             Partition &logPart = partitionArray[partitionArrayPos];
  428                             PartitionEntryMBRToPartition (extMbr->Partitions[0], logPart);
  429                             logPart.Drive = drive;
  430 
  431                             logPart.Number = partitionArrayPos;
  432                             logPart.Primary = false;
  433 
  434                             logPart.StartSector.LowPart += extStartLBA.LowPart;
  435                             logPart.EndSector.LowPart += extStartLBA.LowPart;
  436 
  437                             if (findPartitionFollowingThis)
  438                             {
  439                                 if (logPart.StartSector.LowPart > findPartitionFollowingThis->EndSector.LowPart
  440                                     && logPart.StartSector.LowPart < followingPartition->StartSector.LowPart)
  441                                 {
  442                                     *followingPartition = logPart;
  443                                 }
  444                             }
  445                             else
  446                                 ++partitionArrayPos;
  447                         }
  448 
  449                         // Secondary extended
  450                         if (extMbr->Partitions[1].Type != 0x5 && extMbr->Partitions[1].Type == 0xf
  451                             || extMbr->Partitions[1].SectorCountLBA == 0)
  452                             break;
  453 
  454                         extStartLBA.LowPart = extMbr->Partitions[1].StartLBA + firstExtStartLBA.LowPart;
  455                     }
  456                 }
  457             }
  458             else
  459             {
  460                 partition.Primary = true;
  461 
  462                 if (findPartitionFollowingThis)
  463                 {
  464                     if (partition.StartSector.LowPart > findPartitionFollowingThis->EndSector.LowPart
  465                         && partition.StartSector.LowPart < followingPartition->StartSector.LowPart)
  466                     {
  467                         *followingPartition = partition;
  468                     }
  469                 }
  470                 else
  471                     ++partitionArrayPos;
  472             }
  473         }
  474     }
  475 
  476     partitionCount = partitionArrayPos;
  477     return result;
  478 }
  479 
  480 
  481 bool GetActivePartition (byte drive)
  482 {
  483     size_t partCount;
  484 
  485     if (GetDrivePartitions (drive, &ActivePartition, 1, partCount, true) != BiosResultSuccess || partCount < 1)
  486     {
  487         ActivePartition.Drive = TC_INVALID_BIOS_DRIVE;
  488         PrintError (TC_BOOT_STR_NO_BOOT_PARTITION);
  489         return false;
  490     }
  491 
  492     return true;
  493 }