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

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

unix.superglobalmegacorp.com

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