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

1.1       root        1: /*
1.1.1.5 ! root        2:  Copyright (c) 2008-2009 TrueCrypt Foundation. All rights reserved.
1.1       root        3: 
1.1.1.5 ! root        4:  Governed by the TrueCrypt License 2.7 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.1.5 ! root      117:        BiosResult result = BiosResultSuccess;
1.1       root      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
1.1.1.5 ! root      132:                jnc ok                          // Ignore AH if CF=0 to prevent potential bugs in BIOSes
1.1       root      133:                mov     result, ah
1.1.1.5 ! root      134:        ok:
1.1       root      135:                pop es
                    136:        }
                    137: 
                    138:        if (result == BiosResultEccCorrected)
                    139:                result = BiosResultSuccess;
                    140: 
                    141:        if (!silent && result != BiosResultSuccess)
                    142:                PrintDiskError (result, write, drive, nullptr, &chs);
                    143: 
                    144:        return result;
                    145: }
                    146: 
                    147: 
1.1.1.2   root      148: BiosResult ReadWriteSectors (bool write, byte *buffer, byte drive, const ChsAddress &chs, byte sectorCount, bool silent)
                    149: {
                    150:        uint16 codeSeg;
                    151:        __asm mov codeSeg, cs
1.1.1.3   root      152:        return ReadWriteSectors (write, codeSeg, (uint16) buffer, drive, chs, sectorCount, silent);
1.1.1.2   root      153: }
                    154: 
                    155: 
1.1       root      156: BiosResult ReadSectors (byte *buffer, byte drive, const ChsAddress &chs, byte sectorCount, bool silent)
                    157: {
                    158:        return ReadWriteSectors (false, buffer, drive, chs, sectorCount, silent);
                    159: }
                    160: 
                    161: 
                    162: BiosResult WriteSectors (byte *buffer, byte drive, const ChsAddress &chs, byte sectorCount, bool silent)
                    163: {
                    164:        return ReadWriteSectors (true, buffer, drive, chs, sectorCount, silent);
                    165: }
                    166: 
                    167: 
                    168: static BiosResult ReadWriteSectors (bool write, BiosLbaPacket &dapPacket, byte drive, const uint64 &sector, uint16 sectorCount, bool silent)
                    169: {
1.1.1.2   root      170:        CheckStack();
                    171: 
1.1.1.4   root      172:        if (!IsLbaSupported (drive))
                    173:        {
                    174:                DriveGeometry geometry;
                    175: 
                    176:                BiosResult result = GetDriveGeometry (drive, geometry, silent);
                    177:                if (result != BiosResultSuccess)
                    178:                        return result;
                    179: 
                    180:                ChsAddress chs;
                    181:                LbaToChs (geometry, sector, chs);
                    182:                return ReadWriteSectors (write, (uint16) (dapPacket.Buffer >> 16), (uint16) dapPacket.Buffer, drive, chs, sectorCount, silent);
                    183:        }
                    184: 
1.1       root      185:        dapPacket.Size = sizeof (dapPacket);
                    186:        dapPacket.Reserved = 0;
                    187:        dapPacket.SectorCount = sectorCount;
                    188:        dapPacket.Sector = sector;
                    189: 
                    190:        byte function = write ? 0x43 : 0x42;
                    191:        
1.1.1.5 ! root      192:        BiosResult result = BiosResultSuccess;
1.1       root      193:        __asm
                    194:        {
                    195:                mov     bx, 0x55aa
                    196:                mov     dl, drive
                    197:                mov si, [dapPacket]
                    198:                mov     ah, function
                    199:                xor al, al
                    200:                int     0x13
1.1.1.5 ! root      201:                jnc ok                          // Ignore AH if CF=0 to prevent potential bugs in BIOSes
1.1       root      202:                mov     result, ah
1.1.1.5 ! root      203:        ok:
1.1       root      204:        }
                    205: 
                    206:        if (result == BiosResultEccCorrected)
                    207:                result = BiosResultSuccess;
                    208: 
                    209:        if (!silent && result != BiosResultSuccess)
                    210:                PrintDiskError (result, write, drive, &sector);
                    211: 
                    212:        return result;
                    213: }
                    214: 
                    215: 
                    216: static BiosResult ReadWriteSectors (bool write, byte *buffer, byte drive, const uint64 &sector, uint16 sectorCount, bool silent)
                    217: {
                    218:        BiosLbaPacket dapPacket;
                    219:        dapPacket.Buffer = (uint32) buffer;
                    220:        return ReadWriteSectors (write, dapPacket, drive, sector, sectorCount, silent);
                    221: }
                    222: 
                    223: 
                    224: BiosResult ReadWriteSectors (bool write, uint16 bufferSegment, uint16 bufferOffset, byte drive, const uint64 &sector, uint16 sectorCount, bool silent)
                    225: {
                    226:        BiosLbaPacket dapPacket;
                    227:        dapPacket.Buffer = ((uint32) bufferSegment << 16) | bufferOffset;
                    228:        return ReadWriteSectors (write, dapPacket, drive, sector, sectorCount, silent);
                    229: }
                    230: 
1.1.1.2   root      231: BiosResult ReadSectors (uint16 bufferSegment, uint16 bufferOffset, byte drive, const uint64 &sector, uint16 sectorCount, bool silent)
1.1       root      232: {
1.1.1.4   root      233:        return ReadWriteSectors (false, bufferSegment, bufferOffset, drive, sector, sectorCount, silent);
1.1.1.2   root      234: }
                    235: 
                    236: 
                    237: BiosResult ReadSectors (byte *buffer, byte drive, const uint64 &sector, uint16 sectorCount, bool silent)
                    238: {
1.1.1.4   root      239:        BiosResult result;
1.1.1.2   root      240:        uint16 codeSeg;
                    241:        __asm mov codeSeg, cs
1.1.1.4   root      242:        
                    243:        result = ReadSectors (BootStarted ? codeSeg : TC_BOOT_LOADER_ALT_SEGMENT, (uint16) buffer, drive, sector, sectorCount, silent);
                    244: 
                    245:        // Alternative segment is used to prevent memory corruption caused by buggy BIOSes
                    246:        if (!BootStarted)
                    247:                CopyMemory (TC_BOOT_LOADER_ALT_SEGMENT, (uint16) buffer, buffer, sectorCount * TC_LB_SIZE);
                    248: 
                    249:        return result;
1.1       root      250: }
                    251: 
                    252: 
                    253: BiosResult WriteSectors (byte *buffer, byte drive, const uint64 &sector, uint16 sectorCount, bool silent)
                    254: {
                    255:        return ReadWriteSectors (true, buffer, drive, sector, sectorCount, silent);
                    256: }
                    257: 
                    258: 
                    259: BiosResult GetDriveGeometry (byte drive, DriveGeometry &geometry, bool silent)
                    260: {
1.1.1.2   root      261:        CheckStack();
                    262: 
1.1       root      263:        byte maxCylinderLow, maxHead, maxSector;
                    264:        BiosResult result;
                    265:        __asm
                    266:        {
                    267:                push es
                    268:                mov dl, drive
                    269:                mov ah, 0x08
                    270:                int     0x13
                    271: 
                    272:                mov     result, ah
                    273:                mov maxCylinderLow, ch
                    274:                mov maxSector, cl
                    275:                mov maxHead, dh
                    276:                pop es
                    277:        }
                    278: 
                    279:        if (result == BiosResultSuccess)
                    280:        {
                    281:                geometry.Cylinders = (maxCylinderLow | (uint16 (maxSector & 0xc0) << 2)) + 1;
                    282:                geometry.Heads = maxHead + 1;
                    283:                geometry.Sectors = maxSector & ~0xc0;
                    284:        }
                    285:        else if (!silent)
                    286:        {
                    287:                PrintError ("Cannot get geometry of drive ", true, false);
1.1.1.4   root      288:                PrintHex (drive);
1.1       root      289:                PrintEndl();
                    290:        }
                    291: 
                    292:        return result;
                    293: }
                    294: 
                    295: 
                    296: void ChsToLba (const DriveGeometry &geometry, const ChsAddress &chs, uint64 &lba)
                    297: {
                    298:        lba.HighPart = 0;
                    299:        lba.LowPart = (uint32 (chs.Cylinder) * geometry.Heads + chs.Head) * geometry.Sectors + chs.Sector - 1;
                    300: }
                    301: 
                    302: 
                    303: void LbaToChs (const DriveGeometry &geometry, const uint64 &lba, ChsAddress &chs)
                    304: {
                    305:        chs.Sector = (lba.LowPart % geometry.Sectors) + 1;
                    306:        uint32 ch = lba.LowPart / geometry.Sectors;
                    307:        chs.Head = ch % geometry.Heads;
                    308:        chs.Cylinder = ch / geometry.Heads;
                    309: }
                    310: 
                    311: 
                    312: void PartitionEntryMBRToPartition (const PartitionEntryMBR &partEntry, Partition &partition)
                    313: {
                    314:        partition.Active = partEntry.BootIndicator == 0x80;
                    315:        partition.EndSector.HighPart = 0;
                    316:        partition.EndSector.LowPart = partEntry.StartLBA + partEntry.SectorCountLBA - 1;
                    317:        partition.SectorCount.HighPart = 0;
                    318:        partition.SectorCount.LowPart = partEntry.SectorCountLBA;
                    319:        partition.StartSector.HighPart = 0;
                    320:        partition.StartSector.LowPart = partEntry.StartLBA;
                    321:        partition.Type = partEntry.Type;
                    322: }
                    323: 
                    324: 
1.1.1.3   root      325: BiosResult ReadWriteMBR (bool write, byte drive, bool silent)
1.1       root      326: {
1.1.1.4   root      327:        uint64 mbrSector;
                    328:        mbrSector.HighPart = 0;
                    329:        mbrSector.LowPart = 0;
                    330: 
                    331:        if (write)
                    332:                return WriteSectors (SectorBuffer, drive, mbrSector, 1, silent);
1.1.1.2   root      333: 
1.1.1.4   root      334:        return ReadSectors (SectorBuffer, drive, mbrSector, 1, silent);         // Uses alternative segment
1.1.1.3   root      335: }
                    336: 
                    337: 
                    338: BiosResult GetDrivePartitions (byte drive, Partition *partitionArray, size_t partitionArrayCapacity, size_t &partitionCount, bool activeOnly, Partition *findPartitionFollowingThis, bool silent)
                    339: {
                    340:        Partition *followingPartition;
                    341:        Partition tmpPartition;
                    342: 
                    343:        if (findPartitionFollowingThis)
                    344:        {
                    345:                assert (partitionArrayCapacity == 1);
                    346:                partitionArrayCapacity = 0xff;
                    347:                followingPartition = partitionArray;
                    348:                partitionArray = &tmpPartition;
                    349: 
                    350:                followingPartition->Drive = TC_INVALID_BIOS_DRIVE;
                    351:                followingPartition->StartSector.LowPart = 0xFFFFffffUL;
                    352:        }
                    353: 
1.1.1.2   root      354:        AcquireSectorBuffer();
1.1.1.3   root      355:        BiosResult result = ReadWriteMBR (false, drive, silent);
1.1.1.2   root      356:        ReleaseSectorBuffer();
1.1.1.3   root      357: 
1.1.1.2   root      358:        partitionCount = 0;
                    359: 
                    360:        MBR *mbr = (MBR *) SectorBuffer;
                    361:        if (result != BiosResultSuccess || mbr->Signature != 0xaa55)
1.1       root      362:                return result;
                    363: 
1.1.1.2   root      364:        PartitionEntryMBR mbrPartitions[4];
                    365:        memcpy (mbrPartitions, mbr->Partitions, sizeof (mbrPartitions));
1.1       root      366:        size_t partitionArrayPos = 0, partitionNumber;
                    367:        
                    368:        for (partitionNumber = 0;
1.1.1.2   root      369:                partitionNumber < array_capacity (mbrPartitions) && partitionArrayPos < partitionArrayCapacity;
1.1       root      370:                ++partitionNumber)
                    371:        {
1.1.1.2   root      372:                const PartitionEntryMBR &partEntry = mbrPartitions[partitionNumber];
1.1       root      373:                
                    374:                if (partEntry.SectorCountLBA > 0)
                    375:                {
                    376:                        Partition &partition = partitionArray[partitionArrayPos];
                    377:                        PartitionEntryMBRToPartition (partEntry, partition);
                    378: 
                    379:                        if (activeOnly && !partition.Active)
                    380:                                continue;
                    381: 
                    382:                        partition.Drive = drive;
                    383:                        partition.Number = partitionNumber;
                    384: 
                    385:                        if (partEntry.Type == 0x5 || partEntry.Type == 0xf) // Extended partition
                    386:                        {
                    387:                                if (IsLbaSupported (drive))
                    388:                                {
                    389:                                        // Find all extended partitions
                    390:                                        uint64 firstExtStartLBA = partition.StartSector;
                    391:                                        uint64 extStartLBA = partition.StartSector;
1.1.1.2   root      392:                                        MBR *extMbr = (MBR *) SectorBuffer;
1.1       root      393: 
                    394:                                        while (partitionArrayPos < partitionArrayCapacity &&
1.1.1.2   root      395:                                                (result = ReadSectors ((byte *) extMbr, drive, extStartLBA, 1, silent)) == BiosResultSuccess
                    396:                                                && extMbr->Signature == 0xaa55)
1.1       root      397:                                        {
1.1.1.2   root      398:                                                if (extMbr->Partitions[0].SectorCountLBA > 0)
1.1       root      399:                                                {
1.1.1.3   root      400:                                                        Partition &logPart = partitionArray[partitionArrayPos];
1.1.1.2   root      401:                                                        PartitionEntryMBRToPartition (extMbr->Partitions[0], logPart);
1.1       root      402:                                                        logPart.Drive = drive;
                    403: 
                    404:                                                        logPart.Number = partitionNumber++;
                    405:                                                        logPart.Primary = false;
                    406: 
                    407:                                                        logPart.StartSector.LowPart += extStartLBA.LowPart;
                    408:                                                        logPart.EndSector.LowPart += extStartLBA.LowPart;
1.1.1.3   root      409: 
                    410:                                                        if (findPartitionFollowingThis)
                    411:                                                        {
                    412:                                                                if (logPart.StartSector.LowPart > findPartitionFollowingThis->EndSector.LowPart
                    413:                                                                        && logPart.StartSector.LowPart < followingPartition->StartSector.LowPart)
                    414:                                                                {
                    415:                                                                        *followingPartition = logPart;
                    416:                                                                }
                    417:                                                        }
                    418:                                                        else
                    419:                                                                ++partitionArrayPos;
1.1       root      420:                                                }
                    421: 
                    422:                                                // Secondary extended
1.1.1.2   root      423:                                                if (extMbr->Partitions[1].Type != 0x5 && extMbr->Partitions[1].Type == 0xf
                    424:                                                        || extMbr->Partitions[1].SectorCountLBA == 0)
1.1       root      425:                                                        break;
                    426: 
1.1.1.2   root      427:                                                extStartLBA.LowPart = extMbr->Partitions[1].StartLBA + firstExtStartLBA.LowPart;
1.1       root      428:                                        }
                    429:                                }
                    430:                        }
                    431:                        else
                    432:                        {
                    433:                                partition.Primary = true;
1.1.1.3   root      434: 
                    435:                                if (findPartitionFollowingThis)
                    436:                                {
                    437:                                        if (partition.StartSector.LowPart > findPartitionFollowingThis->EndSector.LowPart
                    438:                                                && partition.StartSector.LowPart < followingPartition->StartSector.LowPart)
                    439:                                        {
                    440:                                                *followingPartition = partition;
                    441:                                        }
                    442:                                }
                    443:                                else
                    444:                                        ++partitionArrayPos;
1.1       root      445:                        }
                    446:                }
                    447:        }
                    448: 
                    449:        partitionCount = partitionArrayPos;
                    450:        return result;
                    451: }
                    452: 
                    453: 
1.1.1.3   root      454: bool GetActiveAndFollowingPartition (byte drive)
1.1       root      455: {
1.1.1.3   root      456:        size_t partCount;
                    457: 
                    458:        // Find active partition
                    459:        if (GetDrivePartitions (drive, &ActivePartition, 1, partCount, true) != BiosResultSuccess || partCount < 1)
                    460:        {
                    461:                ActivePartition.Drive = TC_INVALID_BIOS_DRIVE;
1.1.1.4   root      462:                PrintError (TC_BOOT_STR_NO_BOOT_PARTITION);
1.1.1.3   root      463:                return false;
                    464:        }
                    465: 
                    466:        // Find partition following the active one
                    467:        GetDrivePartitions (drive, &PartitionFollowingActive, 1, partCount, false, &ActivePartition);
                    468: 
                    469:        return true;
1.1       root      470: }

unix.superglobalmegacorp.com

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