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