|
|
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 §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.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 §or, 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, §or); 229: 230: return result; 231: } 232: 233: 234: static BiosResult ReadWriteSectors (bool write, byte *buffer, byte drive, const uint64 §or, 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 §or, 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 §or, 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 §or, 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 §or, 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.