|
|
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;
1.1.1.10! root 404: partition.Number = partitionArrayPos;
1.1 root 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:
1.1.1.10! root 425: logPart.Number = partitionArrayPos;
1.1 root 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.