|
|
1.1 root 1: /*
1.1.1.7 root 2: Copyright (c) 2008-2009 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.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.