|
|
1.1 root 1: /*
2: Copyright (c) 2008 TrueCrypt Foundation. All rights reserved.
3:
1.1.1.3 ! root 4: Governed by the TrueCrypt License 2.5 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"
15:
16:
1.1.1.2 root 17: byte SectorBuffer[TC_LB_SIZE];
18:
19: #ifdef TC_BOOT_DEBUG_ENABLED
20: static bool SectorBufferInUse = false;
21:
22: void AcquireSectorBuffer ()
23: {
24: if (SectorBufferInUse)
25: TC_THROW_FATAL_EXCEPTION;
26:
27: SectorBufferInUse = true;
28: }
29:
30:
31: void ReleaseSectorBuffer ()
32: {
33: SectorBufferInUse = false;
34: }
35:
36: #endif
37:
38:
1.1 root 39: bool IsLbaSupported (byte drive)
40: {
1.1.1.3 ! root 41: static byte CachedDrive = TC_INVALID_BIOS_DRIVE;
! 42: static bool CachedStatus;
1.1 root 43: uint16 result = 0;
1.1.1.3 ! root 44:
! 45: if (CachedDrive == drive)
! 46: goto ret;
! 47:
1.1 root 48: __asm
49: {
50: mov bx, 0x55aa
51: mov dl, drive
52: mov ah, 0x41
53: int 0x13
54: jc err
55: mov result, bx
56: err:
57: }
58:
1.1.1.3 ! root 59: CachedDrive = drive;
! 60: CachedStatus = (result == 0xaa55);
! 61: ret:
! 62: return CachedStatus;
1.1 root 63: }
64:
65:
66: void PrintDiskError (BiosResult error, bool write, byte drive, const uint64 *sector, const ChsAddress *chs)
67: {
68: PrintEndl();
69: Print (write ? "Write" : "Read"); Print (" error:");
1.1.1.3 ! root 70: Print (error);
1.1 root 71: Print (" Drive:");
72: Print (drive < TC_FIRST_BIOS_DRIVE ? drive : drive - TC_FIRST_BIOS_DRIVE);
73:
74: if (sector)
75: {
76: Print (" Sector:");
77: Print (*sector);
78: }
79:
80: if (chs)
81: {
82: Print (" CHS:");
83: Print (*chs);
84: }
85:
86: PrintEndl();
87: Beep();
88: }
89:
90:
91: void Print (const ChsAddress &chs)
92: {
93: Print (chs.Cylinder);
94: PrintChar ('/');
95: Print (chs.Head);
96: PrintChar ('/');
97: Print (chs.Sector);
98: }
99:
100:
1.1.1.3 ! root 101: void PrintSectorCountInMB (const uint64 §orCount)
! 102: {
! 103: Print (sectorCount >> (TC_LB_SIZE_BIT_SHIFT_DIVISOR + 2)); Print (" MB ");
! 104: }
! 105:
! 106:
1.1.1.2 root 107: BiosResult ReadWriteSectors (bool write, uint16 bufferSegment, uint16 bufferOffset, byte drive, const ChsAddress &chs, byte sectorCount, bool silent)
1.1 root 108: {
1.1.1.2 root 109: CheckStack();
110:
1.1 root 111: byte cylinderLow = (byte) chs.Cylinder;
112: byte sector = chs.Sector;
113: sector |= byte (chs.Cylinder >> 2) & 0xc0;
114: byte function = write ? 0x03 : 0x02;
1.1.1.2 root 115:
1.1 root 116: BiosResult result;
117: __asm
118: {
119: push es
1.1.1.2 root 120: mov ax, bufferSegment
1.1 root 121: mov es, ax
1.1.1.2 root 122: mov bx, bufferOffset
123: mov dl, drive
124: mov ch, cylinderLow
1.1 root 125: mov si, chs
1.1.1.2 root 126: mov dh, [si].Head
127: mov cl, sector
128: mov al, sectorCount
1.1 root 129: mov ah, function
130: int 0x13
131: mov result, ah
132: pop es
133: }
134:
135: if (result == BiosResultEccCorrected)
136: result = BiosResultSuccess;
137:
138: if (!silent && result != BiosResultSuccess)
139: PrintDiskError (result, write, drive, nullptr, &chs);
140:
141: return result;
142: }
143:
144:
1.1.1.2 root 145: BiosResult ReadWriteSectors (bool write, byte *buffer, byte drive, const ChsAddress &chs, byte sectorCount, bool silent)
146: {
147: uint16 codeSeg;
148: __asm mov codeSeg, cs
1.1.1.3 ! root 149: return ReadWriteSectors (write, codeSeg, (uint16) buffer, drive, chs, sectorCount, silent);
1.1.1.2 root 150: }
151:
152:
1.1 root 153: BiosResult ReadSectors (byte *buffer, byte drive, const ChsAddress &chs, byte sectorCount, bool silent)
154: {
155: return ReadWriteSectors (false, buffer, drive, chs, sectorCount, silent);
156: }
157:
158:
159: BiosResult WriteSectors (byte *buffer, byte drive, const ChsAddress &chs, byte sectorCount, bool silent)
160: {
161: return ReadWriteSectors (true, buffer, drive, chs, sectorCount, silent);
162: }
163:
164:
165: static BiosResult ReadWriteSectors (bool write, BiosLbaPacket &dapPacket, byte drive, const uint64 §or, uint16 sectorCount, bool silent)
166: {
1.1.1.2 root 167: CheckStack();
168:
1.1 root 169: dapPacket.Size = sizeof (dapPacket);
170: dapPacket.Reserved = 0;
171: dapPacket.SectorCount = sectorCount;
172: dapPacket.Sector = sector;
173:
174: byte function = write ? 0x43 : 0x42;
175:
176: BiosResult result;
177: __asm
178: {
179: mov bx, 0x55aa
180: mov dl, drive
181: mov si, [dapPacket]
182: mov ah, function
183: xor al, al
184: int 0x13
185: mov result, ah
186: }
187:
188: if (result == BiosResultEccCorrected)
189: result = BiosResultSuccess;
190:
191: if (!silent && result != BiosResultSuccess)
192: PrintDiskError (result, write, drive, §or);
193:
194: return result;
195: }
196:
197:
198: static BiosResult ReadWriteSectors (bool write, byte *buffer, byte drive, const uint64 §or, uint16 sectorCount, bool silent)
199: {
200: BiosLbaPacket dapPacket;
201: dapPacket.Buffer = (uint32) buffer;
202: return ReadWriteSectors (write, dapPacket, drive, sector, sectorCount, silent);
203: }
204:
205:
206: BiosResult ReadWriteSectors (bool write, uint16 bufferSegment, uint16 bufferOffset, byte drive, const uint64 §or, uint16 sectorCount, bool silent)
207: {
208: BiosLbaPacket dapPacket;
209: dapPacket.Buffer = ((uint32) bufferSegment << 16) | bufferOffset;
210: return ReadWriteSectors (write, dapPacket, drive, sector, sectorCount, silent);
211: }
212:
213:
1.1.1.2 root 214: BiosResult ReadSectors (uint16 bufferSegment, uint16 bufferOffset, byte drive, const uint64 §or, uint16 sectorCount, bool silent)
1.1 root 215: {
216: if (IsLbaSupported (drive))
1.1.1.2 root 217: return ReadWriteSectors (false, bufferSegment, bufferOffset, drive, sector, sectorCount, silent);
1.1 root 218:
219: DriveGeometry geometry;
220:
221: BiosResult result = GetDriveGeometry (drive, geometry, silent);
222: if (result != BiosResultSuccess)
223: return result;
224:
225: ChsAddress chs;
226: LbaToChs (geometry, sector, chs);
1.1.1.2 root 227: return ReadWriteSectors (false, bufferSegment, bufferOffset, drive, chs, sectorCount, silent);
228: }
229:
230:
231: BiosResult ReadSectors (byte *buffer, byte drive, const uint64 §or, uint16 sectorCount, bool silent)
232: {
233: uint16 codeSeg;
234: __asm mov codeSeg, cs
235: return ReadSectors (codeSeg, (uint16) buffer, drive, sector, sectorCount, silent);
1.1 root 236: }
237:
238:
239: BiosResult WriteSectors (byte *buffer, byte drive, const uint64 §or, uint16 sectorCount, bool silent)
240: {
241: return ReadWriteSectors (true, buffer, drive, sector, sectorCount, silent);
242: }
243:
244:
245: BiosResult GetDriveGeometry (byte drive, DriveGeometry &geometry, bool silent)
246: {
1.1.1.2 root 247: CheckStack();
248:
1.1 root 249: byte maxCylinderLow, maxHead, maxSector;
250: BiosResult result;
251: __asm
252: {
253: push es
254: mov dl, drive
255: mov ah, 0x08
256: int 0x13
257:
258: mov result, ah
259: jc err
260: mov maxCylinderLow, ch
261: mov maxSector, cl
262: mov maxHead, dh
263: err:
264: pop es
265: }
266:
267: if (result == BiosResultSuccess)
268: {
269: geometry.Cylinders = (maxCylinderLow | (uint16 (maxSector & 0xc0) << 2)) + 1;
270: geometry.Heads = maxHead + 1;
271: geometry.Sectors = maxSector & ~0xc0;
272: }
273: else if (!silent)
274: {
275: PrintError ("Cannot get geometry of drive ", true, false);
276: Print (drive);
277: PrintEndl();
278: }
279:
280: return result;
281: }
282:
283:
284: void ChsToLba (const DriveGeometry &geometry, const ChsAddress &chs, uint64 &lba)
285: {
286: lba.HighPart = 0;
287: lba.LowPart = (uint32 (chs.Cylinder) * geometry.Heads + chs.Head) * geometry.Sectors + chs.Sector - 1;
288: }
289:
290:
291: void LbaToChs (const DriveGeometry &geometry, const uint64 &lba, ChsAddress &chs)
292: {
293: chs.Sector = (lba.LowPart % geometry.Sectors) + 1;
294: uint32 ch = lba.LowPart / geometry.Sectors;
295: chs.Head = ch % geometry.Heads;
296: chs.Cylinder = ch / geometry.Heads;
297: }
298:
299:
300: void PartitionEntryMBRToPartition (const PartitionEntryMBR &partEntry, Partition &partition)
301: {
302: partition.Active = partEntry.BootIndicator == 0x80;
303: partition.EndSector.HighPart = 0;
304: partition.EndSector.LowPart = partEntry.StartLBA + partEntry.SectorCountLBA - 1;
305: partition.SectorCount.HighPart = 0;
306: partition.SectorCount.LowPart = partEntry.SectorCountLBA;
307: partition.StartSector.HighPart = 0;
308: partition.StartSector.LowPart = partEntry.StartLBA;
309: partition.Type = partEntry.Type;
310: }
311:
312:
1.1.1.3 ! root 313: BiosResult ReadWriteMBR (bool write, byte drive, bool silent)
1.1 root 314: {
1.1.1.2 root 315: ChsAddress chs;
316: chs.Cylinder = 0;
317: chs.Head = 0;
318: chs.Sector = 1;
319:
1.1.1.3 ! root 320: return ReadWriteSectors (write, SectorBuffer, drive, chs, 1, silent);
! 321: }
! 322:
! 323:
! 324: BiosResult GetDrivePartitions (byte drive, Partition *partitionArray, size_t partitionArrayCapacity, size_t &partitionCount, bool activeOnly, Partition *findPartitionFollowingThis, bool silent)
! 325: {
! 326: Partition *followingPartition;
! 327: Partition tmpPartition;
! 328:
! 329: if (findPartitionFollowingThis)
! 330: {
! 331: assert (partitionArrayCapacity == 1);
! 332: partitionArrayCapacity = 0xff;
! 333: followingPartition = partitionArray;
! 334: partitionArray = &tmpPartition;
! 335:
! 336: followingPartition->Drive = TC_INVALID_BIOS_DRIVE;
! 337: followingPartition->StartSector.LowPart = 0xFFFFffffUL;
! 338: }
! 339:
1.1.1.2 root 340: AcquireSectorBuffer();
1.1.1.3 ! root 341: BiosResult result = ReadWriteMBR (false, drive, silent);
1.1.1.2 root 342: ReleaseSectorBuffer();
1.1.1.3 ! root 343:
1.1.1.2 root 344: partitionCount = 0;
345:
346: MBR *mbr = (MBR *) SectorBuffer;
347: if (result != BiosResultSuccess || mbr->Signature != 0xaa55)
1.1 root 348: return result;
349:
1.1.1.2 root 350: PartitionEntryMBR mbrPartitions[4];
351: memcpy (mbrPartitions, mbr->Partitions, sizeof (mbrPartitions));
1.1 root 352: size_t partitionArrayPos = 0, partitionNumber;
353:
354: for (partitionNumber = 0;
1.1.1.2 root 355: partitionNumber < array_capacity (mbrPartitions) && partitionArrayPos < partitionArrayCapacity;
1.1 root 356: ++partitionNumber)
357: {
1.1.1.2 root 358: const PartitionEntryMBR &partEntry = mbrPartitions[partitionNumber];
1.1 root 359:
360: if (partEntry.SectorCountLBA > 0)
361: {
362: Partition &partition = partitionArray[partitionArrayPos];
363: PartitionEntryMBRToPartition (partEntry, partition);
364:
365: if (activeOnly && !partition.Active)
366: continue;
367:
368: partition.Drive = drive;
369: partition.Number = partitionNumber;
370:
371: if (partEntry.Type == 0x5 || partEntry.Type == 0xf) // Extended partition
372: {
373: if (IsLbaSupported (drive))
374: {
375: // Find all extended partitions
376: uint64 firstExtStartLBA = partition.StartSector;
377: uint64 extStartLBA = partition.StartSector;
1.1.1.2 root 378: MBR *extMbr = (MBR *) SectorBuffer;
1.1 root 379:
380: while (partitionArrayPos < partitionArrayCapacity &&
1.1.1.2 root 381: (result = ReadSectors ((byte *) extMbr, drive, extStartLBA, 1, silent)) == BiosResultSuccess
382: && extMbr->Signature == 0xaa55)
1.1 root 383: {
1.1.1.2 root 384: if (extMbr->Partitions[0].SectorCountLBA > 0)
1.1 root 385: {
1.1.1.3 ! root 386: Partition &logPart = partitionArray[partitionArrayPos];
1.1.1.2 root 387: PartitionEntryMBRToPartition (extMbr->Partitions[0], logPart);
1.1 root 388: logPart.Drive = drive;
389:
390: logPart.Number = partitionNumber++;
391: logPart.Primary = false;
392:
393: logPart.StartSector.LowPart += extStartLBA.LowPart;
394: logPart.EndSector.LowPart += extStartLBA.LowPart;
1.1.1.3 ! root 395:
! 396: if (findPartitionFollowingThis)
! 397: {
! 398: if (logPart.StartSector.LowPart > findPartitionFollowingThis->EndSector.LowPart
! 399: && logPart.StartSector.LowPart < followingPartition->StartSector.LowPart)
! 400: {
! 401: *followingPartition = logPart;
! 402: }
! 403: }
! 404: else
! 405: ++partitionArrayPos;
1.1 root 406: }
407:
408: // Secondary extended
1.1.1.2 root 409: if (extMbr->Partitions[1].Type != 0x5 && extMbr->Partitions[1].Type == 0xf
410: || extMbr->Partitions[1].SectorCountLBA == 0)
1.1 root 411: break;
412:
1.1.1.2 root 413: extStartLBA.LowPart = extMbr->Partitions[1].StartLBA + firstExtStartLBA.LowPart;
1.1 root 414: }
415: }
416: }
417: else
418: {
419: partition.Primary = true;
1.1.1.3 ! root 420:
! 421: if (findPartitionFollowingThis)
! 422: {
! 423: if (partition.StartSector.LowPart > findPartitionFollowingThis->EndSector.LowPart
! 424: && partition.StartSector.LowPart < followingPartition->StartSector.LowPart)
! 425: {
! 426: *followingPartition = partition;
! 427: }
! 428: }
! 429: else
! 430: ++partitionArrayPos;
1.1 root 431: }
432: }
433: }
434:
435: partitionCount = partitionArrayPos;
436: return result;
437: }
438:
439:
1.1.1.3 ! root 440: bool GetActiveAndFollowingPartition (byte drive)
1.1 root 441: {
1.1.1.3 ! root 442: size_t partCount;
! 443:
! 444: // Find active partition
! 445: if (GetDrivePartitions (drive, &ActivePartition, 1, partCount, true) != BiosResultSuccess || partCount < 1)
! 446: {
! 447: ActivePartition.Drive = TC_INVALID_BIOS_DRIVE;
! 448: PrintError ("No bootable partition found");
! 449: return false;
! 450: }
! 451:
! 452: // Find partition following the active one
! 453: GetDrivePartitions (drive, &PartitionFollowingActive, 1, partCount, false, &ActivePartition);
! 454:
! 455: return true;
1.1 root 456: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.