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