|
|
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.6 ! root 4: Governed by the TrueCrypt License 2.8 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:"); 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.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.6 ! root 132: jnc ok // If CF=0, ignore AH to prevent issues caused by 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.6 ! root 201: jnc ok // If CF=0, ignore AH to prevent issues caused by 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: { 1.1.1.6 ! root 287: Print ("Drive "); ! 288: Print (drive ^ 0x80); ! 289: Print (" not found: "); ! 290: PrintErrorNoEndl (""); ! 291: Print (result); 1.1 root 292: PrintEndl(); 293: } 294: 295: return result; 296: } 297: 298: 299: void ChsToLba (const DriveGeometry &geometry, const ChsAddress &chs, uint64 &lba) 300: { 301: lba.HighPart = 0; 302: lba.LowPart = (uint32 (chs.Cylinder) * geometry.Heads + chs.Head) * geometry.Sectors + chs.Sector - 1; 303: } 304: 305: 306: void LbaToChs (const DriveGeometry &geometry, const uint64 &lba, ChsAddress &chs) 307: { 1.1.1.6 ! root 308: chs.Sector = (byte) ((lba.LowPart % geometry.Sectors) + 1); 1.1 root 309: uint32 ch = lba.LowPart / geometry.Sectors; 1.1.1.6 ! root 310: chs.Head = (byte) (ch % geometry.Heads); ! 311: chs.Cylinder = (uint16) (ch / geometry.Heads); 1.1 root 312: } 313: 314: 315: void PartitionEntryMBRToPartition (const PartitionEntryMBR &partEntry, Partition &partition) 316: { 317: partition.Active = partEntry.BootIndicator == 0x80; 318: partition.EndSector.HighPart = 0; 319: partition.EndSector.LowPart = partEntry.StartLBA + partEntry.SectorCountLBA - 1; 320: partition.SectorCount.HighPart = 0; 321: partition.SectorCount.LowPart = partEntry.SectorCountLBA; 322: partition.StartSector.HighPart = 0; 323: partition.StartSector.LowPart = partEntry.StartLBA; 324: partition.Type = partEntry.Type; 325: } 326: 327: 1.1.1.3 root 328: BiosResult ReadWriteMBR (bool write, byte drive, bool silent) 1.1 root 329: { 1.1.1.4 root 330: uint64 mbrSector; 331: mbrSector.HighPart = 0; 332: mbrSector.LowPart = 0; 333: 334: if (write) 335: return WriteSectors (SectorBuffer, drive, mbrSector, 1, silent); 1.1.1.2 root 336: 1.1.1.4 root 337: return ReadSectors (SectorBuffer, drive, mbrSector, 1, silent); // Uses alternative segment 1.1.1.3 root 338: } 339: 340: 341: BiosResult GetDrivePartitions (byte drive, Partition *partitionArray, size_t partitionArrayCapacity, size_t &partitionCount, bool activeOnly, Partition *findPartitionFollowingThis, bool silent) 342: { 343: Partition *followingPartition; 344: Partition tmpPartition; 345: 346: if (findPartitionFollowingThis) 347: { 348: assert (partitionArrayCapacity == 1); 349: partitionArrayCapacity = 0xff; 350: followingPartition = partitionArray; 351: partitionArray = &tmpPartition; 352: 353: followingPartition->Drive = TC_INVALID_BIOS_DRIVE; 354: followingPartition->StartSector.LowPart = 0xFFFFffffUL; 355: } 356: 1.1.1.2 root 357: AcquireSectorBuffer(); 1.1.1.3 root 358: BiosResult result = ReadWriteMBR (false, drive, silent); 1.1.1.2 root 359: ReleaseSectorBuffer(); 1.1.1.3 root 360: 1.1.1.2 root 361: partitionCount = 0; 362: 363: MBR *mbr = (MBR *) SectorBuffer; 364: if (result != BiosResultSuccess || mbr->Signature != 0xaa55) 1.1 root 365: return result; 366: 1.1.1.2 root 367: PartitionEntryMBR mbrPartitions[4]; 368: memcpy (mbrPartitions, mbr->Partitions, sizeof (mbrPartitions)); 1.1 root 369: size_t partitionArrayPos = 0, partitionNumber; 370: 371: for (partitionNumber = 0; 1.1.1.2 root 372: partitionNumber < array_capacity (mbrPartitions) && partitionArrayPos < partitionArrayCapacity; 1.1 root 373: ++partitionNumber) 374: { 1.1.1.2 root 375: const PartitionEntryMBR &partEntry = mbrPartitions[partitionNumber]; 1.1 root 376: 377: if (partEntry.SectorCountLBA > 0) 378: { 379: Partition &partition = partitionArray[partitionArrayPos]; 380: PartitionEntryMBRToPartition (partEntry, partition); 381: 382: if (activeOnly && !partition.Active) 383: continue; 384: 385: partition.Drive = drive; 386: partition.Number = partitionNumber; 387: 388: if (partEntry.Type == 0x5 || partEntry.Type == 0xf) // Extended partition 389: { 390: if (IsLbaSupported (drive)) 391: { 392: // Find all extended partitions 393: uint64 firstExtStartLBA = partition.StartSector; 394: uint64 extStartLBA = partition.StartSector; 1.1.1.2 root 395: MBR *extMbr = (MBR *) SectorBuffer; 1.1 root 396: 397: while (partitionArrayPos < partitionArrayCapacity && 1.1.1.2 root 398: (result = ReadSectors ((byte *) extMbr, drive, extStartLBA, 1, silent)) == BiosResultSuccess 399: && extMbr->Signature == 0xaa55) 1.1 root 400: { 1.1.1.2 root 401: if (extMbr->Partitions[0].SectorCountLBA > 0) 1.1 root 402: { 1.1.1.3 root 403: Partition &logPart = partitionArray[partitionArrayPos]; 1.1.1.2 root 404: PartitionEntryMBRToPartition (extMbr->Partitions[0], logPart); 1.1 root 405: logPart.Drive = drive; 406: 407: logPart.Number = partitionNumber++; 408: logPart.Primary = false; 409: 410: logPart.StartSector.LowPart += extStartLBA.LowPart; 411: logPart.EndSector.LowPart += extStartLBA.LowPart; 1.1.1.3 root 412: 413: if (findPartitionFollowingThis) 414: { 415: if (logPart.StartSector.LowPart > findPartitionFollowingThis->EndSector.LowPart 416: && logPart.StartSector.LowPart < followingPartition->StartSector.LowPart) 417: { 418: *followingPartition = logPart; 419: } 420: } 421: else 422: ++partitionArrayPos; 1.1 root 423: } 424: 425: // Secondary extended 1.1.1.2 root 426: if (extMbr->Partitions[1].Type != 0x5 && extMbr->Partitions[1].Type == 0xf 427: || extMbr->Partitions[1].SectorCountLBA == 0) 1.1 root 428: break; 429: 1.1.1.2 root 430: extStartLBA.LowPart = extMbr->Partitions[1].StartLBA + firstExtStartLBA.LowPart; 1.1 root 431: } 432: } 433: } 434: else 435: { 436: partition.Primary = true; 1.1.1.3 root 437: 438: if (findPartitionFollowingThis) 439: { 440: if (partition.StartSector.LowPart > findPartitionFollowingThis->EndSector.LowPart 441: && partition.StartSector.LowPart < followingPartition->StartSector.LowPart) 442: { 443: *followingPartition = partition; 444: } 445: } 446: else 447: ++partitionArrayPos; 1.1 root 448: } 449: } 450: } 451: 452: partitionCount = partitionArrayPos; 453: return result; 454: } 455: 456: 1.1.1.6 ! root 457: bool GetActivePartition (byte drive) 1.1 root 458: { 1.1.1.3 root 459: size_t partCount; 460: 461: if (GetDrivePartitions (drive, &ActivePartition, 1, partCount, true) != BiosResultSuccess || partCount < 1) 462: { 463: ActivePartition.Drive = TC_INVALID_BIOS_DRIVE; 1.1.1.4 root 464: PrintError (TC_BOOT_STR_NO_BOOT_PARTITION); 1.1.1.3 root 465: return false; 466: } 1.1.1.6 ! root 467: 1.1.1.3 root 468: return true; 1.1 root 469: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.