Annotation of truecrypt/boot/windows/bootdiskio.cpp, revision 1.1.1.4

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.