|
|
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 §orCount) 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 §or, 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, §or); 211: 212: return result; 213: } 214: 215: 216: static BiosResult ReadWriteSectors (bool write, byte *buffer, byte drive, const uint64 §or, 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 §or, 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 §or, 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 §or, 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 §or, 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.