VeraCrypt
aboutsummaryrefslogtreecommitdiff
path: root/src/Boot/Windows
diff options
context:
space:
mode:
Diffstat (limited to 'src/Boot/Windows')
-rw-r--r--src/Boot/Windows/Bios.h28
-rw-r--r--src/Boot/Windows/Boot.vcproj242
-rw-r--r--src/Boot/Windows/BootCommon.h78
-rw-r--r--src/Boot/Windows/BootConfig.cpp90
-rw-r--r--src/Boot/Windows/BootConfig.h42
-rw-r--r--src/Boot/Windows/BootConsoleIo.cpp330
-rw-r--r--src/Boot/Windows/BootConsoleIo.h67
-rw-r--r--src/Boot/Windows/BootCrt.asm23
-rw-r--r--src/Boot/Windows/BootDebug.cpp177
-rw-r--r--src/Boot/Windows/BootDebug.h56
-rw-r--r--src/Boot/Windows/BootDefs.h188
-rw-r--r--src/Boot/Windows/BootDiskIo.cpp487
-rw-r--r--src/Boot/Windows/BootDiskIo.h116
-rw-r--r--src/Boot/Windows/BootEncryptedIo.cpp128
-rw-r--r--src/Boot/Windows/BootEncryptedIo.h18
-rw-r--r--src/Boot/Windows/BootMain.cpp1151
-rw-r--r--src/Boot/Windows/BootMain.h30
-rw-r--r--src/Boot/Windows/BootMemory.cpp82
-rw-r--r--src/Boot/Windows/BootMemory.h24
-rw-r--r--src/Boot/Windows/BootSector.asm237
-rw-r--r--src/Boot/Windows/BootStrings.h16
-rw-r--r--src/Boot/Windows/Decompressor.c436
-rw-r--r--src/Boot/Windows/IntFilter.cpp641
-rw-r--r--src/Boot/Windows/IntFilter.h16
-rw-r--r--src/Boot/Windows/Makefile184
-rw-r--r--src/Boot/Windows/Platform.cpp226
-rw-r--r--src/Boot/Windows/Platform.h112
27 files changed, 5225 insertions, 0 deletions
diff --git a/src/Boot/Windows/Bios.h b/src/Boot/Windows/Bios.h
new file mode 100644
index 00000000..bc410adb
--- /dev/null
+++ b/src/Boot/Windows/Bios.h
@@ -0,0 +1,28 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ Governed by the TrueCrypt License 3.0 the full text of which is contained in
+ the file License.txt included in TrueCrypt binary and source code distribution
+ packages.
+*/
+
+#ifndef TC_HEADER_Boot_Bios
+#define TC_HEADER_Boot_Bios
+
+#include "Platform.h"
+
+#define TC_LB_SIZE_BIT_SHIFT_DIVISOR 9
+
+#define TC_FIRST_BIOS_DRIVE 0x80
+#define TC_LAST_BIOS_DRIVE 0x8f
+#define TC_INVALID_BIOS_DRIVE (TC_FIRST_BIOS_DRIVE - 1)
+
+enum
+{
+ BiosResultSuccess = 0x00,
+ BiosResultInvalidFunction = 0x01
+};
+
+typedef byte BiosResult;
+
+#endif // TC_HEADER_Boot_Bios
diff --git a/src/Boot/Windows/Boot.vcproj b/src/Boot/Windows/Boot.vcproj
new file mode 100644
index 00000000..862f1e33
--- /dev/null
+++ b/src/Boot/Windows/Boot.vcproj
@@ -0,0 +1,242 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="Boot"
+ ProjectGUID="{8B7F059F-E4C7-4E11-88F5-EE8B8433072E}"
+ RootNamespace="Boot"
+ Keyword="MakeFileProj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="0"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ BuildCommandLine="md Release 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1&#x0D;&#x0A;&#x0D;&#x0A;md Release_AES 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=AES&#x0D;&#x0A;&#x0D;&#x0A;md Release_Serpent 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=SERPENT&#x0D;&#x0A;&#x0D;&#x0A;md Release_Twofish 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=TWOFISH&#x0D;&#x0A;&#x0D;&#x0A;md Rescue 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 RESCUE_DISK=1&#x0D;&#x0A;&#x0D;&#x0A;md Rescue_AES 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=AES RESCUE_DISK=1&#x0D;&#x0A;&#x0D;&#x0A;md Rescue_Serpent 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=SERPENT RESCUE_DISK=1&#x0D;&#x0A;&#x0D;&#x0A;md Rescue_Twofish 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=TWOFISH RESCUE_DISK=1"
+ ReBuildCommandLine="del /q /s Release &gt;NUL:&#x0D;&#x0A;md Release 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1&#x0D;&#x0A;&#x0D;&#x0A;del /q /s Release_AES &gt;NUL:&#x0D;&#x0A;md Release_AES 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=AES&#x0D;&#x0A;&#x0D;&#x0A;del /q /s Release_Serpent &gt;NUL:&#x0D;&#x0A;md Release_Serpent 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=SERPENT&#x0D;&#x0A;&#x0D;&#x0A;del /q /s Release_Twofish &gt;NUL:&#x0D;&#x0A;md Release_Twofish 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=TWOFISH&#x0D;&#x0A;&#x0D;&#x0A;del /q /s Rescue &gt;NUL:&#x0D;&#x0A;md Rescue 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 RESCUE_DISK=1&#x0D;&#x0A;&#x0D;&#x0A;del /q /s Rescue_AES &gt;NUL:&#x0D;&#x0A;md Rescue_AES 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=AES RESCUE_DISK=1&#x0D;&#x0A;&#x0D;&#x0A;del /q /s Rescue_Serpent &gt;NUL:&#x0D;&#x0A;md Rescue_Serpent 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=SERPENT RESCUE_DISK=1&#x0D;&#x0A;&#x0D;&#x0A;del /q /s Rescue_Twofish &gt;NUL:&#x0D;&#x0A;md Rescue_Twofish 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=TWOFISH RESCUE_DISK=1"
+ CleanCommandLine="del /q /s Release Release_AES Release_Serpent Release_Twofish Rescue Rescue_AES Rescue_Serpent Rescue_Twofish &gt;NUL:"
+ Output="Release\BootLoader.com"
+ PreprocessorDefinitions="WIN32;NDEBUG"
+ IncludeSearchPath="&quot;$(SolutionDir)&quot;;&quot;$(SolutionDir)\Common&quot;;&quot;$(SolutionDir)\Crypto&quot;;&quot;$(MSVC16_ROOT)\Include&quot;"
+ ForcedIncludes=""
+ AssemblySearchPath=""
+ ForcedUsingAssemblies=""
+ CompileAsManaged=""
+ />
+ </Configuration>
+ <Configuration
+ Name="Release Loader|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="0"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ BuildCommandLine="md Release 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1&#x0D;&#x0A;&#x0D;&#x0A;md Release_AES 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=AES&#x0D;&#x0A;&#x0D;&#x0A;md Release_Serpent 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=SERPENT&#x0D;&#x0A;&#x0D;&#x0A;md Release_Twofish 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=TWOFISH"
+ ReBuildCommandLine="del /q /s Release &gt;NUL:&#x0D;&#x0A;md Release 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1&#x0D;&#x0A;&#x0D;&#x0A;del /q /s Release_AES &gt;NUL:&#x0D;&#x0A;md Release_AES 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=AES&#x0D;&#x0A;&#x0D;&#x0A;del /q /s Release_Serpent &gt;NUL:&#x0D;&#x0A;md Release_Serpent 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=SERPENT&#x0D;&#x0A;&#x0D;&#x0A;del /q /s Release_Twofish &gt;NUL:&#x0D;&#x0A;md Release_Twofish 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=TWOFISH"
+ CleanCommandLine="del /q /s Release Release_AES Release_Serpent Release_Twofish &gt;NUL:"
+ Output="Release\BootLoader.com"
+ PreprocessorDefinitions="WIN32;NDEBUG"
+ IncludeSearchPath="&quot;$(SolutionDir)&quot;;&quot;$(SolutionDir)\Common&quot;;&quot;$(SolutionDir)\Crypto&quot;;&quot;$(MSVC16_ROOT)\Include&quot;"
+ ForcedIncludes=""
+ AssemblySearchPath=""
+ ForcedUsingAssemblies=""
+ CompileAsManaged=""
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\BootConfig.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\BootConsoleIo.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\BootCrt.asm"
+ >
+ </File>
+ <File
+ RelativePath=".\BootDebug.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\BootDiskIo.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\BootEncryptedIo.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\BootMain.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\BootMemory.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\BootSector.asm"
+ >
+ </File>
+ <File
+ RelativePath=".\Decompressor.c"
+ >
+ </File>
+ <File
+ RelativePath=".\IntFilter.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\Platform.cpp"
+ >
+ </File>
+ <Filter
+ Name="Common"
+ >
+ <File
+ RelativePath="..\..\Common\Crc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Common\Crypto.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Common\Endian.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Common\Pkcs5.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Common\Volumes.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Common\Xts.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Crypto"
+ >
+ <File
+ RelativePath="..\..\Crypto\Aes_hw_cpu.asm"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Crypto\AesSmall.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Crypto\AesSmall_x86.asm"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Crypto\Rmd160.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Crypto\Serpent.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Crypto\Twofish.c"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\Bios.h"
+ >
+ </File>
+ <File
+ RelativePath=".\BootCommon.h"
+ >
+ </File>
+ <File
+ RelativePath=".\BootConfig.h"
+ >
+ </File>
+ <File
+ RelativePath=".\BootConsoleIo.h"
+ >
+ </File>
+ <File
+ RelativePath=".\BootDebug.h"
+ >
+ </File>
+ <File
+ RelativePath=".\BootDefs.h"
+ >
+ </File>
+ <File
+ RelativePath=".\BootDiskIo.h"
+ >
+ </File>
+ <File
+ RelativePath=".\BootEncryptedIo.h"
+ >
+ </File>
+ <File
+ RelativePath=".\BootMain.h"
+ >
+ </File>
+ <File
+ RelativePath=".\BootMemory.h"
+ >
+ </File>
+ <File
+ RelativePath=".\BootStrings.h"
+ >
+ </File>
+ <File
+ RelativePath=".\IntFilter.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Platform.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Build Files"
+ >
+ <File
+ RelativePath=".\Makefile"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/src/Boot/Windows/BootCommon.h b/src/Boot/Windows/BootCommon.h
new file mode 100644
index 00000000..e985a9c5
--- /dev/null
+++ b/src/Boot/Windows/BootCommon.h
@@ -0,0 +1,78 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ Governed by the TrueCrypt License 3.0 the full text of which is contained in
+ the file License.txt included in TrueCrypt binary and source code distribution
+ packages.
+*/
+
+#ifndef TC_HEADER_Boot_BootCommon
+#define TC_HEADER_Boot_BootCommon
+
+#include "Common/Password.h"
+#include "BootDefs.h"
+
+// The user will be advised to upgrade the rescue disk if upgrading from the following or any previous version
+#define TC_RESCUE_DISK_UPGRADE_NOTICE_MAX_VERSION 0x060a
+
+#define TC_BOOT_LOADER_AREA_SIZE (TC_BOOT_LOADER_AREA_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS)
+
+#define TC_BOOT_VOLUME_HEADER_SECTOR (TC_BOOT_LOADER_AREA_SECTOR_COUNT - 1)
+#define TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET (TC_BOOT_VOLUME_HEADER_SECTOR * TC_SECTOR_SIZE_BIOS)
+
+#define TC_CD_BOOTSECTOR_OFFSET 0xd000
+#define TC_CD_BOOT_LOADER_SECTOR 26
+
+#define TC_ORIG_BOOT_LOADER_BACKUP_SECTOR TC_BOOT_LOADER_AREA_SECTOR_COUNT
+#define TC_ORIG_BOOT_LOADER_BACKUP_SECTOR_OFFSET (TC_ORIG_BOOT_LOADER_BACKUP_SECTOR * TC_SECTOR_SIZE_BIOS)
+
+#define TC_BOOT_LOADER_BACKUP_RESCUE_DISK_SECTOR (TC_ORIG_BOOT_LOADER_BACKUP_SECTOR + TC_BOOT_LOADER_AREA_SECTOR_COUNT)
+#define TC_BOOT_LOADER_BACKUP_RESCUE_DISK_SECTOR_OFFSET (TC_BOOT_LOADER_BACKUP_RESCUE_DISK_SECTOR * TC_SECTOR_SIZE_BIOS)
+
+#define TC_MBR_SECTOR 0
+#define TC_MAX_MBR_BOOT_CODE_SIZE 440
+
+#define TC_MAX_EXTRA_BOOT_PARTITION_SIZE (512UL * 1024UL * 1024UL)
+
+
+#pragma pack (1)
+
+typedef struct
+{
+ byte Flags;
+} BootSectorConfiguration;
+
+
+// Modifying this value can introduce incompatibility with previous versions
+#define TC_BOOT_LOADER_ARGS_OFFSET 0x10
+
+typedef struct
+{
+ // Modifying this structure can introduce incompatibility with previous versions
+ char Signature[8];
+ uint16 BootLoaderVersion;
+ uint16 CryptoInfoOffset;
+ uint16 CryptoInfoLength;
+ uint32 HeaderSaltCrc32;
+ Password BootPassword;
+ uint64 HiddenSystemPartitionStart;
+ uint64 DecoySystemPartitionStart;
+ uint32 Flags;
+ uint32 BootDriveSignature;
+
+ uint32 BootArgumentsCrc32;
+
+} BootArguments;
+
+// Modifying these values can introduce incompatibility with previous versions
+#define TC_BOOT_ARGS_FLAG_EXTRA_BOOT_PARTITION 0x1
+
+#pragma pack ()
+
+// Boot arguments signature should not be defined as a static string
+// Modifying these values can introduce incompatibility with previous versions
+#define TC_SET_BOOT_ARGUMENTS_SIGNATURE(SG) do { SG[0] = 'T'; SG[1] = 'R'; SG[2] = 'U'; SG[3] = 'E'; SG[4] = 0x11; SG[5] = 0x23; SG[6] = 0x45; SG[7] = 0x66; } while (FALSE)
+#define TC_IS_BOOT_ARGUMENTS_SIGNATURE(SG) (SG[0] == 'T' && SG[1] == 'R' && SG[2] == 'U' && SG[3] == 'E' && SG[4] == 0x11 && SG[5] == 0x23 && SG[6] == 0x45 && SG[7] == 0x66)
+
+
+#endif // TC_HEADER_Boot_BootCommon
diff --git a/src/Boot/Windows/BootConfig.cpp b/src/Boot/Windows/BootConfig.cpp
new file mode 100644
index 00000000..eeaed70a
--- /dev/null
+++ b/src/Boot/Windows/BootConfig.cpp
@@ -0,0 +1,90 @@
+/*
+ Copyright (c) 2008-2012 TrueCrypt Developers Association. All rights reserved.
+
+ Governed by the TrueCrypt License 3.0 the full text of which is contained in
+ the file License.txt included in TrueCrypt binary and source code distribution
+ packages.
+*/
+
+#include "BootConfig.h"
+
+byte BootSectorFlags;
+
+byte BootLoaderDrive;
+byte BootDrive;
+bool BootDriveGeometryValid = false;
+bool PreventNormalSystemBoot = false;
+bool PreventBootMenu = false;
+char CustomUserMessage[TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH + 1];
+uint32 OuterVolumeBackupHeaderCrc;
+
+bool BootStarted = false;
+
+DriveGeometry BootDriveGeometry;
+
+CRYPTO_INFO *BootCryptoInfo;
+Partition EncryptedVirtualPartition;
+
+Partition ActivePartition;
+Partition PartitionFollowingActive;
+bool ExtraBootPartitionPresent = false;
+uint64 HiddenVolumeStartUnitNo;
+uint64 HiddenVolumeStartSector;
+
+#ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+
+void ReadBootSectorUserConfiguration ()
+{
+ byte userConfig;
+
+ AcquireSectorBuffer();
+
+ if (ReadWriteMBR (false, BootLoaderDrive, true) != BiosResultSuccess)
+ goto ret;
+
+ userConfig = SectorBuffer[TC_BOOT_SECTOR_USER_CONFIG_OFFSET];
+
+#ifdef TC_WINDOWS_BOOT_AES
+ EnableHwEncryption (!(userConfig & TC_BOOT_USER_CFG_FLAG_DISABLE_HW_ENCRYPTION));
+#endif
+
+ PreventBootMenu = (userConfig & TC_BOOT_USER_CFG_FLAG_DISABLE_ESC);
+
+ memcpy (CustomUserMessage, SectorBuffer + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET, TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH);
+ CustomUserMessage[TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH] = 0;
+
+ if (userConfig & TC_BOOT_USER_CFG_FLAG_SILENT_MODE)
+ {
+ if (CustomUserMessage[0])
+ {
+ InitVideoMode();
+ Print (CustomUserMessage);
+ }
+
+ DisableScreenOutput();
+ }
+
+ OuterVolumeBackupHeaderCrc = *(uint32 *) (SectorBuffer + TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET);
+
+ret:
+ ReleaseSectorBuffer();
+}
+
+
+BiosResult UpdateBootSectorConfiguration (byte drive)
+{
+ AcquireSectorBuffer();
+
+ BiosResult result = ReadWriteMBR (false, drive);
+ if (result != BiosResultSuccess)
+ goto ret;
+
+ SectorBuffer[TC_BOOT_SECTOR_CONFIG_OFFSET] = BootSectorFlags;
+ result = ReadWriteMBR (true, drive);
+
+ret:
+ ReleaseSectorBuffer();
+ return result;
+}
+
+#endif // !TC_WINDOWS_BOOT_RESCUE_DISK_MODE
diff --git a/src/Boot/Windows/BootConfig.h b/src/Boot/Windows/BootConfig.h
new file mode 100644
index 00000000..5fe591fe
--- /dev/null
+++ b/src/Boot/Windows/BootConfig.h
@@ -0,0 +1,42 @@
+/*
+ Copyright (c) 2008-2009 TrueCrypt Developers Association. All rights reserved.
+
+ Governed by the TrueCrypt License 3.0 the full text of which is contained in
+ the file License.txt included in TrueCrypt binary and source code distribution
+ packages.
+*/
+
+#ifndef TC_HEADER_Boot_BootConfig
+#define TC_HEADER_Boot_BootConfig
+
+#include "Crypto.h"
+#include "Platform.h"
+#include "BootDiskIo.h"
+
+extern byte BootSectorFlags;
+
+extern byte BootLoaderDrive;
+extern byte BootDrive;
+extern bool BootDriveGeometryValid;
+extern DriveGeometry BootDriveGeometry;
+extern bool PreventNormalSystemBoot;
+extern bool PreventBootMenu;
+extern char CustomUserMessage[TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH + 1];
+extern uint32 OuterVolumeBackupHeaderCrc;
+
+extern bool BootStarted;
+
+extern CRYPTO_INFO *BootCryptoInfo;
+extern Partition EncryptedVirtualPartition;
+
+extern Partition ActivePartition;
+extern Partition PartitionFollowingActive;
+extern bool ExtraBootPartitionPresent;
+extern uint64 HiddenVolumeStartUnitNo;
+extern uint64 HiddenVolumeStartSector;
+
+
+void ReadBootSectorUserConfiguration ();
+BiosResult UpdateBootSectorConfiguration (byte drive);
+
+#endif // TC_HEADER_Boot_BootConfig
diff --git a/src/Boot/Windows/BootConsoleIo.cpp b/src/Boot/Windows/BootConsoleIo.cpp
new file mode 100644
index 00000000..6558018f
--- /dev/null
+++ b/src/Boot/Windows/BootConsoleIo.cpp
@@ -0,0 +1,330 @@
+/*
+ Copyright (c) 2008-2009 TrueCrypt Developers Association. All rights reserved.
+
+ Governed by the TrueCrypt License 3.0 the full text of which is contained in
+ the file License.txt included in TrueCrypt binary and source code distribution
+ packages.
+*/
+
+#include "Platform.h"
+#include "Bios.h"
+#include "BootConsoleIo.h"
+#include "BootDebug.h"
+#include "BootStrings.h"
+
+
+static int ScreenOutputDisabled = 0;
+
+void DisableScreenOutput ()
+{
+ ++ScreenOutputDisabled;
+}
+
+
+void EnableScreenOutput ()
+{
+ --ScreenOutputDisabled;
+}
+
+
+void PrintChar (char c)
+{
+#ifdef TC_BOOT_TRACING_ENABLED
+ WriteDebugPort (c);
+#endif
+
+ if (ScreenOutputDisabled)
+ return;
+
+ __asm
+ {
+ mov bx, 7
+ mov al, c
+ mov ah, 0xe
+ int 0x10
+ }
+}
+
+
+void PrintCharAtCursor (char c)
+{
+ if (ScreenOutputDisabled)
+ return;
+
+ __asm
+ {
+ mov bx, 7
+ mov al, c
+ mov cx, 1
+ mov ah, 0xa
+ int 0x10
+ }
+}
+
+
+void Print (const char *str)
+{
+ char c;
+ while (c = *str++)
+ PrintChar (c);
+}
+
+
+void Print (uint32 number)
+{
+ char str[12];
+ int pos = 0;
+ while (number >= 10)
+ {
+ str[pos++] = (char) (number % 10) + '0';
+ number /= 10;
+ }
+ str[pos] = (char) (number % 10) + '0';
+
+ while (pos >= 0)
+ PrintChar (str[pos--]);
+}
+
+
+void Print (const uint64 &number)
+{
+ if (number.HighPart == 0)
+ Print (number.LowPart);
+ else
+ PrintHex (number);
+}
+
+
+void PrintHex (byte b)
+{
+ PrintChar (((b >> 4) >= 0xA ? 'A' - 0xA : '0') + (b >> 4));
+ PrintChar (((b & 0xF) >= 0xA ? 'A' - 0xA : '0') + (b & 0xF));
+}
+
+
+void PrintHex (uint16 data)
+{
+ PrintHex (byte (data >> 8));
+ PrintHex (byte (data));
+}
+
+
+void PrintHex (uint32 data)
+{
+ PrintHex (uint16 (data >> 16));
+ PrintHex (uint16 (data));
+}
+
+
+void PrintHex (const uint64 &data)
+{
+ PrintHex (data.HighPart);
+ PrintHex (data.LowPart);
+}
+
+void PrintRepeatedChar (char c, int n)
+{
+ while (n-- > 0)
+ PrintChar (c);
+}
+
+
+void PrintEndl ()
+{
+ Print ("\r\n");
+}
+
+
+void PrintEndl (int cnt)
+{
+ while (cnt-- > 0)
+ PrintEndl ();
+}
+
+
+void Beep ()
+{
+ PrintChar (7);
+}
+
+
+void InitVideoMode ()
+{
+ if (ScreenOutputDisabled)
+ return;
+
+ __asm
+ {
+ // Text mode 80x25
+ mov ax, 3
+ int 0x10
+
+ // Page 0
+ mov ax, 0x500
+ int 0x10
+ }
+}
+
+
+void ClearScreen ()
+{
+ if (ScreenOutputDisabled)
+ return;
+
+ __asm
+ {
+ // White text on black
+ mov bh, 7
+ xor cx, cx
+ mov dx, 0x184f
+ mov ax, 0x600
+ int 0x10
+
+ // Cursor at 0,0
+ xor bh, bh
+ xor dx, dx
+ mov ah, 2
+ int 0x10
+ }
+}
+
+
+void PrintBackspace ()
+{
+ PrintChar (TC_BIOS_CHAR_BACKSPACE);
+ PrintCharAtCursor (' ');
+}
+
+
+void PrintError (const char *message)
+{
+ Print (TC_BOOT_STR_ERROR);
+ Print (message);
+ PrintEndl();
+ Beep();
+}
+
+
+void PrintErrorNoEndl (const char *message)
+{
+ Print (TC_BOOT_STR_ERROR);
+ Print (message);
+ Beep();
+}
+
+
+byte GetShiftFlags ()
+{
+ byte flags;
+ __asm
+ {
+ mov ah, 2
+ int 0x16
+ mov flags, al
+ }
+
+ return flags;
+}
+
+
+byte GetKeyboardChar ()
+{
+ return GetKeyboardChar (nullptr);
+}
+
+
+byte GetKeyboardChar (byte *scanCode)
+{
+ // Work around potential BIOS bugs (Windows boot manager polls the keystroke buffer)
+ while (!IsKeyboardCharAvailable());
+
+ byte asciiCode;
+ byte scan;
+ __asm
+ {
+ mov ah, 0
+ int 0x16
+ mov asciiCode, al
+ mov scan, ah
+ }
+
+ if (scanCode)
+ *scanCode = scan;
+
+ return asciiCode;
+}
+
+
+bool IsKeyboardCharAvailable ()
+{
+ bool available = false;
+ __asm
+ {
+ mov ah, 1
+ int 0x16
+ jz not_avail
+ mov available, true
+ not_avail:
+ }
+
+ return available;
+}
+
+
+bool EscKeyPressed ()
+{
+ if (IsKeyboardCharAvailable ())
+ {
+ byte keyScanCode;
+ GetKeyboardChar (&keyScanCode);
+ return keyScanCode == TC_BIOS_KEY_ESC;
+ }
+
+ return false;
+}
+
+
+void ClearBiosKeystrokeBuffer ()
+{
+ __asm
+ {
+ push es
+ xor ax, ax
+ mov es, ax
+ mov di, 0x41e
+ mov cx, 32
+ cld
+ rep stosb
+ pop es
+ }
+}
+
+
+bool IsPrintable (char c)
+{
+ return c >= ' ' && c <= '~';
+}
+
+
+int GetString (char *buffer, size_t bufferSize)
+{
+ byte c;
+ byte scanCode;
+ size_t pos = 0;
+
+ while (pos < bufferSize)
+ {
+ c = GetKeyboardChar (&scanCode);
+
+ if (scanCode == TC_BIOS_KEY_ENTER)
+ break;
+
+ if (scanCode == TC_BIOS_KEY_ESC)
+ return 0;
+
+ buffer[pos++] = c;
+ PrintChar (IsPrintable (c) ? c : ' ');
+ }
+
+ return pos;
+}
diff --git a/src/Boot/Windows/BootConsoleIo.h b/src/Boot/Windows/BootConsoleIo.h
new file mode 100644
index 00000000..daf86633
--- /dev/null
+++ b/src/Boot/Windows/BootConsoleIo.h
@@ -0,0 +1,67 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ Governed by the TrueCrypt License 3.0 the full text of which is contained in
+ the file License.txt included in TrueCrypt binary and source code distribution
+ packages.
+*/
+
+#ifndef TC_HEADER_Boot_BootConsoleIo
+#define TC_HEADER_Boot_BootConsoleIo
+
+#include "Platform.h"
+
+#define TC_DEBUG_PORT 0
+
+#define TC_BIOS_KEY_ESC 1
+#define TC_BIOS_KEY_BACKSPACE 14
+#define TC_BIOS_KEY_ENTER 28
+#define TC_BIOS_KEY_F1 0x3b
+#define TC_BIOS_KEY_F2 0x3c
+#define TC_BIOS_KEY_F3 0x3d
+#define TC_BIOS_KEY_F4 0x3e
+#define TC_BIOS_KEY_F5 0x3f
+#define TC_BIOS_KEY_F6 0x40
+#define TC_BIOS_KEY_F7 0x41
+#define TC_BIOS_KEY_F8 0x42
+#define TC_BIOS_KEY_F9 0x43
+#define TC_BIOS_KEY_F10 0x44
+
+#define TC_BIOS_SHIFTMASK_CAPSLOCK (1 << 6)
+#define TC_BIOS_SHIFTMASK_LSHIFT (1 << 1)
+#define TC_BIOS_SHIFTMASK_RSHIFT (1 << 0)
+
+#define TC_BIOS_CHAR_BACKSPACE 8
+
+#define TC_BIOS_MAX_CHARS_PER_LINE 80
+
+void Beep ();
+void ClearBiosKeystrokeBuffer ();
+void ClearScreen ();
+void DisableScreenOutput ();
+void EnableScreenOutput ();
+bool EscKeyPressed ();
+byte GetKeyboardChar ();
+byte GetKeyboardChar (byte *scanCode);
+byte GetShiftFlags ();
+int GetString (char *buffer, size_t bufferSize);
+void InitVideoMode ();
+bool IsKeyboardCharAvailable ();
+bool IsPrintable (char c);
+void Print (const char *str);
+void Print (uint32 number);
+void Print (const uint64 &number);
+void PrintBackspace ();
+void PrintChar (char c);
+void PrintCharAtCursor (char c);
+void PrintEndl ();
+void PrintEndl (int cnt);
+void PrintRepeatedChar (char c, int n);
+void PrintError (const char *message);
+void PrintErrorNoEndl (const char *message);
+void PrintHex (byte b);
+void PrintHex (uint16 data);
+void PrintHex (uint32 data);
+void PrintHex (const uint64 &data);
+
+#endif // TC_HEADER_Boot_BootConsoleIo
diff --git a/src/Boot/Windows/BootCrt.asm b/src/Boot/Windows/BootCrt.asm
new file mode 100644
index 00000000..9087ad70
--- /dev/null
+++ b/src/Boot/Windows/BootCrt.asm
@@ -0,0 +1,23 @@
+;
+; Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+;
+; Governed by the TrueCrypt License 3.0 the full text of which is contained in
+; the file License.txt included in TrueCrypt binary and source code distribution
+; packages.
+;
+
+.MODEL tiny, C
+.386
+
+INCLUDE BootDefs.i
+
+EXTERNDEF main:NEAR
+
+_TEXT SEGMENT
+ORG TC_COM_EXECUTABLE_OFFSET
+
+start:
+ jmp main
+
+_TEXT ENDS
+END start
diff --git a/src/Boot/Windows/BootDebug.cpp b/src/Boot/Windows/BootDebug.cpp
new file mode 100644
index 00000000..e422767a
--- /dev/null
+++ b/src/Boot/Windows/BootDebug.cpp
@@ -0,0 +1,177 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ Governed by the TrueCrypt License 3.0 the full text of which is contained in
+ the file License.txt included in TrueCrypt binary and source code distribution
+ packages.
+*/
+
+#include "Platform.h"
+#include "Bios.h"
+#include "BootConsoleIo.h"
+#include "BootDefs.h"
+#include "BootDiskIo.h"
+#include "BootDebug.h"
+
+
+#ifdef TC_BOOT_TRACING_ENABLED
+
+void InitDebugPort ()
+{
+ __asm
+ {
+ mov dx, TC_DEBUG_PORT
+ mov ah, 1
+ int 0x17
+ mov dx, TC_DEBUG_PORT
+ mov ah, 0xe2
+ int 0x17
+ }
+}
+
+
+void WriteDebugPort (byte dataByte)
+{
+ __asm
+ {
+ mov al, dataByte
+ mov dx, TC_DEBUG_PORT
+ mov ah, 0
+ int 0x17
+ }
+}
+
+#endif // TC_BOOT_TRACING_ENABLED
+
+
+#ifdef TC_BOOT_DEBUG_ENABLED
+
+extern "C" void PrintDebug (uint32 debugVal)
+{
+ Print (debugVal);
+ PrintEndl();
+}
+
+
+void PrintVal (const char *message, const uint32 value, bool newLine, bool hex)
+{
+ Print (message);
+ Print (": ");
+
+ if (hex)
+ PrintHex (value);
+ else
+ Print (value);
+
+ if (newLine)
+ PrintEndl();
+}
+
+
+void PrintVal (const char *message, const uint64 &value, bool newLine, bool hex)
+{
+ Print (message);
+ Print (": ");
+ PrintHex (value);
+ if (newLine)
+ PrintEndl();
+}
+
+
+void PrintHexDump (byte *mem, size_t size, uint16 *memSegment)
+{
+ const size_t width = 16;
+ for (size_t pos = 0; pos < size; )
+ {
+ for (int pass = 1; pass <= 2; ++pass)
+ {
+ size_t i;
+ for (i = 0; i < width && pos < size; ++i)
+ {
+ byte dataByte;
+ if (memSegment)
+ {
+ __asm
+ {
+ push es
+ mov si, ss:memSegment
+ mov es, ss:[si]
+ mov si, ss:mem
+ add si, pos
+ mov al, es:[si]
+ mov dataByte, al
+ pop es
+ }
+ pos++;
+ }
+ else
+ dataByte = mem[pos++];
+
+ if (pass == 1)
+ {
+ PrintHex (dataByte);
+ PrintChar (' ');
+ }
+ else
+ PrintChar (IsPrintable (dataByte) ? dataByte : '.');
+ }
+
+ if (pass == 1)
+ {
+ pos -= i;
+ PrintChar (' ');
+ }
+ }
+
+ PrintEndl ();
+ }
+}
+
+
+void PrintHexDump (uint16 memSegment, uint16 memOffset, size_t size)
+{
+ PrintHexDump ((byte *) memOffset, size, &memSegment);
+}
+
+#endif // TC_BOOT_DEBUG_ENABLED
+
+
+#ifdef TC_BOOT_STACK_CHECKING_ENABLED
+
+extern "C" char end[];
+
+static void PrintStackInfo ()
+{
+ uint16 spReg;
+ __asm mov spReg, sp
+
+ Print ("Stack: "); Print (TC_BOOT_LOADER_STACK_TOP - spReg);
+ Print ("/"); Print (TC_BOOT_LOADER_STACK_TOP - (uint16) end);
+}
+
+
+void CheckStack ()
+{
+ uint16 spReg;
+ __asm mov spReg, sp
+
+ if (*(uint32 *) end != 0x12345678UL || spReg < (uint16) end)
+ {
+ __asm cli
+ __asm mov sp, TC_BOOT_LOADER_STACK_TOP
+
+ PrintError ("Stack overflow");
+ TC_THROW_FATAL_EXCEPTION;
+ }
+}
+
+
+void InitStackChecker ()
+{
+ *(uint32 *) end = 0x12345678UL;
+
+ PrintStackInfo();
+ PrintEndl();
+}
+
+#endif // TC_BOOT_STACK_CHECKING_ENABLED
diff --git a/src/Boot/Windows/BootDebug.h b/src/Boot/Windows/BootDebug.h
new file mode 100644
index 00000000..1f7b3aac
--- /dev/null
+++ b/src/Boot/Windows/BootDebug.h
@@ -0,0 +1,56 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ Governed by the TrueCrypt License 3.0 the full text of which is contained in
+ the file License.txt included in TrueCrypt binary and source code distribution
+ packages.
+*/
+
+#ifndef TC_HEADER_Boot_BootDebug
+#define TC_HEADER_Boot_BootDebug
+
+#include "Platform.h"
+#include "BootConsoleIo.h"
+
+#if 0
+# define TC_BOOT_DEBUG_ENABLED
+#endif
+
+#if 0 || defined (TC_BOOT_DEBUG_ENABLED)
+# define TC_BOOT_STACK_CHECKING_ENABLED
+ extern "C" void CheckStack ();
+#else
+# define CheckStack()
+#endif
+
+#if 0
+# define TC_BOOT_TRACING_ENABLED
+# if 1
+# define TC_TRACE_INT13
+# endif
+# if 0
+# define TC_TRACE_INT15
+# endif
+#endif
+
+#ifdef TC_BOOT_DEBUG_ENABLED
+# define trace_point do { Print(__FILE__); PrintChar (':'); Print (TC_TO_STRING (__LINE__)); PrintEndl(); } while (false)
+# define trace_val(VAL) PrintVal (#VAL, VAL);
+# define trace_hex(VAL) do { Print (#VAL), PrintChar (':'); PrintHex (VAL); PrintEndl(); } while (false)
+# define assert(COND) do { if (!(COND)) { trace_point; __asm jmp $ } } while (false)
+#else
+# define trace_point
+# define trace_val(VAL)
+# define trace_hex(VAL)
+# define assert(COND)
+#endif
+
+void InitDebugPort ();
+void InitStackChecker ();
+void WriteDebugPort (byte dataByte);
+void PrintHexDump (byte *mem, size_t size, uint16 *memSegment = nullptr);
+void PrintHexDump (uint16 memSegment, uint16 memOffset, size_t size);
+void PrintVal (const char *message, const uint32 value, bool newLine = true, bool hex = false);
+void PrintVal (const char *message, const uint64 &value, bool newLine = true, bool hex = false);
+
+#endif // TC_HEADER_Boot_BootDebug
diff --git a/src/Boot/Windows/BootDefs.h b/src/Boot/Windows/BootDefs.h
new file mode 100644
index 00000000..efb9b5f9
--- /dev/null
+++ b/src/Boot/Windows/BootDefs.h
@@ -0,0 +1,188 @@
+/*
+ Copyright (c) 2008-2009 TrueCrypt Developers Association. All rights reserved.
+
+ Governed by the TrueCrypt License 3.0 the full text of which is contained in
+ the file License.txt included in TrueCrypt binary and source code distribution
+ packages.
+*/
+
+#ifndef TC_HEADER_Boot_BootDefs
+#define TC_HEADER_Boot_BootDefs
+
+// Total memory required (CODE + DATA + BSS + STACK + 0x100) in KBytes - determined from linker map.
+#define TC__BOOT_MEMORY_REQUIRED 42
+
+#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE
+# undef TC__BOOT_MEMORY_REQUIRED
+
+# ifdef TC_WINDOWS_BOOT_AES
+# ifdef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+# define TC__BOOT_MEMORY_REQUIRED 30
+# else
+# define TC__BOOT_MEMORY_REQUIRED 28
+# endif
+# elif defined (TC_WINDOWS_BOOT_SERPENT)
+# define TC__BOOT_MEMORY_REQUIRED 32
+# elif defined (TC_WINDOWS_BOOT_TWOFISH)
+# define TC__BOOT_MEMORY_REQUIRED 40
+# endif
+
+#if 0
+# undef TC__BOOT_MEMORY_REQUIRED
+# define TC__BOOT_MEMORY_REQUIRED 60
+#endif
+
+#endif
+
+// Modifying this value can introduce incompatibility with previous versions
+#define TC__BOOT_LOADER_SEGMENT TC_HEX (9000) // Some buggy BIOS routines fail if CS bits 0-10 are not zero
+
+#if TC__BOOT_MEMORY_REQUIRED <= 32
+# define TC__BOOT_LOADER_SEGMENT_LOW (TC__BOOT_LOADER_SEGMENT - 32 * 1024 / 16)
+#else
+# define TC__BOOT_LOADER_SEGMENT_LOW (TC__BOOT_LOADER_SEGMENT - 64 * 1024 / 16)
+#endif
+
+#define TC__COM_EXECUTABLE_OFFSET TC_HEX (100)
+
+#define TC__BOOT_LOADER_LOWMEM_SEGMENT TC_HEX (2000)
+#define TC__BOOT_LOADER_BUFFER_SEGMENT TC_HEX (4000)
+#define TC__BOOT_LOADER_ALT_SEGMENT TC_HEX (6000)
+
+#define TC__BOOT_LOADER_STACK_TOP (TC_BOOT_MEMORY_REQUIRED * TC_UNSIGNED (1024) - 4)
+
+#define TC__LB_SIZE 512
+#define TC__BOOT_LOADER_AREA_SECTOR_COUNT 63
+
+#define TC__BOOT_SECTOR_VERSION_OFFSET 430
+#define TC__BOOT_SECTOR_LOADER_LENGTH_OFFSET 432
+#define TC__BOOT_SECTOR_LOADER_CHECKSUM_OFFSET 434
+#define TC__BOOT_SECTOR_USER_CONFIG_OFFSET 438
+#define TC__BOOT_SECTOR_CONFIG_OFFSET 439 // The last byte that is reserved for the boot loader
+
+#define TC__BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH 24
+#define TC__BOOT_SECTOR_USER_MESSAGE_OFFSET (TC__BOOT_SECTOR_VERSION_OFFSET - TC__BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH)
+
+#define TC__BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_SIZE 4
+#define TC__BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET (TC__BOOT_SECTOR_USER_MESSAGE_OFFSET - TC__BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_SIZE)
+
+#define TC__BOOT_LOADER_DECOMPRESSOR_START_SECTOR 2
+#define TC__BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT 4
+#define TC__BOOT_LOADER_DECOMPRESSOR_MEMORY_SIZE 32768
+#define TC__BOOT_LOADER_COMPRESSED_BUFFER_OFFSET (TC_COM_EXECUTABLE_OFFSET + 3072)
+
+#define TC__BOOT_LOADER_START_SECTOR (TC_BOOT_LOADER_DECOMPRESSOR_START_SECTOR + TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT)
+#define TC__MAX_BOOT_LOADER_SECTOR_COUNT (TC_BOOT_LOADER_AREA_SECTOR_COUNT - TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT - 2)
+#define TC__MAX_BOOT_LOADER_DECOMPRESSED_SIZE ((TC_BOOT_LOADER_AREA_SECTOR_COUNT - 2) * TC_LB_SIZE)
+
+#define TC__BOOT_LOADER_BACKUP_SECTOR_COUNT 30
+
+#define TC__GZIP_HEADER_SIZE 10
+
+#define TC__BOOT_CFG_FLAG_AREA_SIZE 1 // In bytes
+
+// If you add more flags, revise TC__BOOT_CFG_FLAG_AREA_SIZE
+#define TC__BOOT_CFG_FLAG_BACKUP_LOADER_AVAILABLE TC_HEX (02)
+#define TC__BOOT_CFG_FLAG_WINDOWS_VISTA_OR_LATER TC_HEX (04)
+#define TC__BOOT_CFG_FLAG_RESCUE_DISABLE_HW_ENCRYPTION TC_HEX (10)
+#define TC__BOOT_CFG_FLAG_RESCUE_DISK_ORIG_SYS_LOADER TC_HEX (20)
+#define TC__BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE (TC_HEX (40) + TC_HEX (80))
+
+// Modifying the following values can introduce incompatibility with previous versions
+#define TC__BOOT_USER_CFG_FLAG_SILENT_MODE TC_HEX (01)
+#define TC__BOOT_USER_CFG_FLAG_DISABLE_ESC TC_HEX (02)
+#define TC__BOOT_USER_CFG_FLAG_DISABLE_HW_ENCRYPTION TC_HEX (04)
+
+// The following items are treated as a 2-bit value (apply TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE to obtain the value)
+#define TC__HIDDEN_OS_CREATION_PHASE_NONE 0
+#define TC__HIDDEN_OS_CREATION_PHASE_CLONING TC_HEX (40) // The boot loader is to copy the content of the system partition to the hidden volume
+#define TC__HIDDEN_OS_CREATION_PHASE_WIPING TC_HEX (80) // The boot loader has successfully copied the content of the system partition to the hidden volume. The original OS is to be wiped now.
+#define TC__HIDDEN_OS_CREATION_PHASE_WIPED (TC_HEX (40) + TC_HEX (80)) // The original OS has been wiped. The user is required to install a new OS (decoy OS) on the system partition now.
+
+
+#ifdef TC_ASM_PREPROCESS
+
+#define TC_HEX(N) 0##N##h
+#define TC_UNSIGNED(N) N
+
+TC_BOOT_MEMORY_REQUIRED = TC__BOOT_MEMORY_REQUIRED
+TC_BOOT_LOADER_SEGMENT = TC__BOOT_LOADER_SEGMENT
+TC_BOOT_LOADER_SEGMENT_LOW = TC__BOOT_LOADER_SEGMENT_LOW
+TC_COM_EXECUTABLE_OFFSET = TC__COM_EXECUTABLE_OFFSET
+TC_BOOT_LOADER_LOWMEM_SEGMENT = TC__BOOT_LOADER_LOWMEM_SEGMENT
+TC_BOOT_LOADER_BUFFER_SEGMENT = TC__BOOT_LOADER_BUFFER_SEGMENT
+TC_BOOT_LOADER_ALT_SEGMENT = TC__BOOT_LOADER_ALT_SEGMENT
+TC_BOOT_LOADER_STACK_TOP = TC__BOOT_LOADER_STACK_TOP
+TC_LB_SIZE = TC__LB_SIZE
+TC_BOOT_LOADER_AREA_SECTOR_COUNT = TC__BOOT_LOADER_AREA_SECTOR_COUNT
+TC_BOOT_SECTOR_LOADER_LENGTH_OFFSET = TC__BOOT_SECTOR_LOADER_LENGTH_OFFSET
+TC_BOOT_SECTOR_LOADER_CHECKSUM_OFFSET = TC__BOOT_SECTOR_LOADER_CHECKSUM_OFFSET
+TC_BOOT_SECTOR_CONFIG_OFFSET = TC__BOOT_SECTOR_CONFIG_OFFSET
+TC_BOOT_SECTOR_USER_CONFIG_OFFSET = TC__BOOT_SECTOR_USER_CONFIG_OFFSET
+TC_BOOT_LOADER_DECOMPRESSOR_START_SECTOR = TC__BOOT_LOADER_DECOMPRESSOR_START_SECTOR
+TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT = TC__BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT
+TC_BOOT_LOADER_DECOMPRESSOR_MEMORY_SIZE = TC__BOOT_LOADER_DECOMPRESSOR_MEMORY_SIZE
+TC_BOOT_LOADER_COMPRESSED_BUFFER_OFFSET = TC__BOOT_LOADER_COMPRESSED_BUFFER_OFFSET
+TC_BOOT_LOADER_START_SECTOR = TC__BOOT_LOADER_START_SECTOR
+TC_MAX_BOOT_LOADER_SECTOR_COUNT = TC__MAX_BOOT_LOADER_SECTOR_COUNT
+TC_MAX_BOOT_LOADER_DECOMPRESSED_SIZE = TC__MAX_BOOT_LOADER_DECOMPRESSED_SIZE
+TC_BOOT_LOADER_BACKUP_SECTOR_COUNT = TC__BOOT_LOADER_BACKUP_SECTOR_COUNT
+TC_GZIP_HEADER_SIZE = TC__GZIP_HEADER_SIZE
+TC_BOOT_CFG_FLAG_AREA_SIZE = TC__BOOT_CFG_FLAG_AREA_SIZE
+TC_BOOT_CFG_FLAG_BACKUP_LOADER_AVAILABLE = TC__BOOT_CFG_FLAG_BACKUP_LOADER_AVAILABLE
+TC_BOOT_CFG_FLAG_WINDOWS_VISTA_OR_LATER = TC__BOOT_CFG_FLAG_WINDOWS_VISTA_OR_LATER
+TC_BOOT_CFG_FLAG_RESCUE_DISK_ORIG_SYS_LOADER = TC__BOOT_CFG_FLAG_RESCUE_DISK_ORIG_SYS_LOADER
+TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE = TC__BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE
+TC_BOOT_USER_CFG_FLAG_SILENT_MODE = TC__BOOT_USER_CFG_FLAG_SILENT_MODE
+TC_HIDDEN_OS_CREATION_PHASE_NONE = TC__HIDDEN_OS_CREATION_PHASE_NONE
+TC_HIDDEN_OS_CREATION_PHASE_CLONING = TC__HIDDEN_OS_CREATION_PHASE_CLONING
+TC_HIDDEN_OS_CREATION_PHASE_WIPING = TC__HIDDEN_OS_CREATION_PHASE_WIPING
+TC_HIDDEN_OS_CREATION_PHASE_WIPED = TC__HIDDEN_OS_CREATION_PHASE_WIPED
+
+#else // TC_ASM_PREPROCESS
+
+#define TC_HEX(N) 0x##N
+#define TC_UNSIGNED(N) N##U
+
+#define TC_BOOT_MEMORY_REQUIRED TC__BOOT_MEMORY_REQUIRED
+#define TC_BOOT_LOADER_SEGMENT TC__BOOT_LOADER_SEGMENT
+#define TC_COM_EXECUTABLE_OFFSET TC__COM_EXECUTABLE_OFFSET
+#define TC_BOOT_LOADER_LOWMEM_SEGMENT TC__BOOT_LOADER_LOWMEM_SEGMENT
+#define TC_BOOT_LOADER_BUFFER_SEGMENT TC__BOOT_LOADER_BUFFER_SEGMENT
+#define TC_BOOT_LOADER_ALT_SEGMENT TC__BOOT_LOADER_ALT_SEGMENT
+#define TC_BOOT_LOADER_STACK_TOP (TC__BOOT_LOADER_STACK_TOP)
+#define TC_BOOT_LOADER_AREA_SECTOR_COUNT TC__BOOT_LOADER_AREA_SECTOR_COUNT
+#define TC_BOOT_SECTOR_USER_MESSAGE_OFFSET TC__BOOT_SECTOR_USER_MESSAGE_OFFSET
+#define TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_SIZE TC__BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_SIZE
+#define TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET TC__BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET
+#define TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH TC__BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH
+#define TC_BOOT_SECTOR_VERSION_OFFSET TC__BOOT_SECTOR_VERSION_OFFSET
+#define TC_BOOT_SECTOR_LOADER_LENGTH_OFFSET TC__BOOT_SECTOR_LOADER_LENGTH_OFFSET
+#define TC_BOOT_SECTOR_LOADER_CHECKSUM_OFFSET TC__BOOT_SECTOR_LOADER_CHECKSUM_OFFSET
+#define TC_BOOT_LOADER_DECOMPRESSOR_START_SECTOR TC__BOOT_LOADER_DECOMPRESSOR_START_SECTOR
+#define TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT TC__BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT
+#define TC_BOOT_SECTOR_CONFIG_OFFSET TC__BOOT_SECTOR_CONFIG_OFFSET
+#define TC_BOOT_SECTOR_USER_CONFIG_OFFSET TC__BOOT_SECTOR_USER_CONFIG_OFFSET
+#define TC_BOOT_LOADER_START_SECTOR TC__BOOT_LOADER_START_SECTOR
+#define TC_LB_SIZE TC__LB_SIZE
+#define TC_MAX_BOOT_LOADER_SECTOR_COUNT TC__MAX_BOOT_LOADER_SECTOR_COUNT
+#define TC_MAX_BOOT_LOADER_DECOMPRESSED_SIZE TC__MAX_BOOT_LOADER_DECOMPRESSED_SIZE
+#define TC_BOOT_LOADER_BACKUP_SECTOR_COUNT TC__BOOT_LOADER_BACKUP_SECTOR_COUNT
+#define TC_GZIP_HEADER_SIZE TC__GZIP_HEADER_SIZE
+#define TC_BOOT_CFG_FLAG_AREA_SIZE TC__BOOT_CFG_FLAG_AREA_SIZE
+#define TC_BOOT_CFG_FLAG_BACKUP_LOADER_AVAILABLE TC__BOOT_CFG_FLAG_BACKUP_LOADER_AVAILABLE
+#define TC_BOOT_CFG_FLAG_WINDOWS_VISTA_OR_LATER TC__BOOT_CFG_FLAG_WINDOWS_VISTA_OR_LATER
+#define TC_BOOT_CFG_FLAG_RESCUE_DISK_ORIG_SYS_LOADER TC__BOOT_CFG_FLAG_RESCUE_DISK_ORIG_SYS_LOADER
+#define TC_BOOT_CFG_FLAG_RESCUE_DISABLE_HW_ENCRYPTION TC__BOOT_CFG_FLAG_RESCUE_DISABLE_HW_ENCRYPTION
+#define TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE TC__BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE
+#define TC_BOOT_USER_CFG_FLAG_SILENT_MODE TC__BOOT_USER_CFG_FLAG_SILENT_MODE
+#define TC_BOOT_USER_CFG_FLAG_DISABLE_ESC TC__BOOT_USER_CFG_FLAG_DISABLE_ESC
+#define TC_BOOT_USER_CFG_FLAG_DISABLE_HW_ENCRYPTION TC__BOOT_USER_CFG_FLAG_DISABLE_HW_ENCRYPTION
+#define TC_HIDDEN_OS_CREATION_PHASE_NONE TC__HIDDEN_OS_CREATION_PHASE_NONE
+#define TC_HIDDEN_OS_CREATION_PHASE_CLONING TC__HIDDEN_OS_CREATION_PHASE_CLONING
+#define TC_HIDDEN_OS_CREATION_PHASE_WIPING TC__HIDDEN_OS_CREATION_PHASE_WIPING
+#define TC_HIDDEN_OS_CREATION_PHASE_WIPED TC__HIDDEN_OS_CREATION_PHASE_WIPED
+
+#endif // TC_ASM_PREPROCESS
+
+#endif // TC_HEADER_Boot_BootDefs
diff --git a/src/Boot/Windows/BootDiskIo.cpp b/src/Boot/Windows/BootDiskIo.cpp
new file mode 100644
index 00000000..84e888e0
--- /dev/null
+++ b/src/Boot/Windows/BootDiskIo.cpp
@@ -0,0 +1,487 @@
+/*
+ Copyright (c) 2008-2011 TrueCrypt Developers Association. All rights reserved.
+
+ Governed by the TrueCrypt License 3.0 the full text of which is contained in
+ the file License.txt included in TrueCrypt binary and source code distribution
+ packages.
+*/
+
+#include "Bios.h"
+#include "BootConsoleIo.h"
+#include "BootConfig.h"
+#include "BootDebug.h"
+#include "BootDefs.h"
+#include "BootDiskIo.h"
+#include "BootStrings.h"
+
+
+byte SectorBuffer[TC_LB_SIZE];
+
+#ifdef TC_BOOT_DEBUG_ENABLED
+static bool SectorBufferInUse = false;
+
+void AcquireSectorBuffer ()
+{
+ if (SectorBufferInUse)
+ TC_THROW_FATAL_EXCEPTION;
+
+ SectorBufferInUse = true;
+}
+
+
+void ReleaseSectorBuffer ()
+{
+ SectorBufferInUse = false;
+}
+
+#endif
+
+
+bool IsLbaSupported (byte drive)
+{
+ static byte CachedDrive = TC_INVALID_BIOS_DRIVE;
+ static bool CachedStatus;
+ uint16 result = 0;
+
+ if (CachedDrive == drive)
+ goto ret;
+
+ __asm
+ {
+ mov bx, 0x55aa
+ mov dl, drive
+ mov ah, 0x41
+ int 0x13
+ jc err
+ mov result, bx
+ err:
+ }
+
+ CachedDrive = drive;
+ CachedStatus = (result == 0xaa55);
+ret:
+ return CachedStatus;
+}
+
+
+void PrintDiskError (BiosResult error, bool write, byte drive, const uint64 *sector, const ChsAddress *chs)
+{
+ PrintEndl();
+ Print (write ? "Write" : "Read"); Print (" error:");
+ Print (error);
+ Print (" Drive:");
+ Print (drive ^ 0x80);
+
+ if (sector)
+ {
+ Print (" Sector:");
+ Print (*sector);
+ }
+
+ if (chs)
+ {
+ Print (" CHS:");
+ Print (*chs);
+ }
+
+ PrintEndl();
+ Beep();
+}
+
+
+void Print (const ChsAddress &chs)
+{
+ Print (chs.Cylinder);
+ PrintChar ('/');
+ Print (chs.Head);
+ PrintChar ('/');
+ Print (chs.Sector);
+}
+
+
+void PrintSectorCountInMB (const uint64 &sectorCount)
+{
+ Print (sectorCount >> (TC_LB_SIZE_BIT_SHIFT_DIVISOR + 2)); Print (" MB ");
+}
+
+
+BiosResult ReadWriteSectors (bool write, uint16 bufferSegment, uint16 bufferOffset, byte drive, const ChsAddress &chs, byte sectorCount, bool silent)
+{
+ CheckStack();
+
+ byte cylinderLow = (byte) chs.Cylinder;
+ byte sector = chs.Sector;
+ sector |= byte (chs.Cylinder >> 2) & 0xc0;
+ byte function = write ? 0x03 : 0x02;
+
+ BiosResult result;
+ byte tryCount = TC_MAX_BIOS_DISK_IO_RETRIES;
+
+ do
+ {
+ result = BiosResultSuccess;
+
+ __asm
+ {
+ push es
+ mov ax, bufferSegment
+ mov es, ax
+ mov bx, bufferOffset
+ mov dl, drive
+ mov ch, cylinderLow
+ mov si, chs
+ mov dh, [si].Head
+ mov cl, sector
+ mov al, sectorCount
+ mov ah, function
+ int 0x13
+ jnc ok // If CF=0, ignore AH to prevent issues caused by potential bugs in BIOSes
+ mov result, ah
+ ok:
+ pop es
+ }
+
+ if (result == BiosResultEccCorrected)
+ result = BiosResultSuccess;
+
+ // Some BIOSes report I/O errors prematurely in some cases
+ } while (result != BiosResultSuccess && --tryCount != 0);
+
+ if (!silent && result != BiosResultSuccess)
+ PrintDiskError (result, write, drive, nullptr, &chs);
+
+ return result;
+}
+
+
+BiosResult ReadWriteSectors (bool write, byte *buffer, byte drive, const ChsAddress &chs, byte sectorCount, bool silent)
+{
+ uint16 codeSeg;
+ __asm mov codeSeg, cs
+ return ReadWriteSectors (write, codeSeg, (uint16) buffer, drive, chs, sectorCount, silent);
+}
+
+
+BiosResult ReadSectors (byte *buffer, byte drive, const ChsAddress &chs, byte sectorCount, bool silent)
+{
+ return ReadWriteSectors (false, buffer, drive, chs, sectorCount, silent);
+}
+
+
+BiosResult WriteSectors (byte *buffer, byte drive, const ChsAddress &chs, byte sectorCount, bool silent)
+{
+ return ReadWriteSectors (true, buffer, drive, chs, sectorCount, silent);
+}
+
+
+static BiosResult ReadWriteSectors (bool write, BiosLbaPacket &dapPacket, byte drive, const uint64 &sector, uint16 sectorCount, bool silent)
+{
+ CheckStack();
+
+ if (!IsLbaSupported (drive))
+ {
+ DriveGeometry geometry;
+
+ BiosResult result = GetDriveGeometry (drive, geometry, silent);
+ if (result != BiosResultSuccess)
+ return result;
+
+ ChsAddress chs;
+ LbaToChs (geometry, sector, chs);
+ return ReadWriteSectors (write, (uint16) (dapPacket.Buffer >> 16), (uint16) dapPacket.Buffer, drive, chs, sectorCount, silent);
+ }
+
+ dapPacket.Size = sizeof (dapPacket);
+ dapPacket.Reserved = 0;
+ dapPacket.SectorCount = sectorCount;
+ dapPacket.Sector = sector;
+
+ byte function = write ? 0x43 : 0x42;
+
+ BiosResult result;
+ byte tryCount = TC_MAX_BIOS_DISK_IO_RETRIES;
+
+ do
+ {
+ result = BiosResultSuccess;
+
+ __asm
+ {
+ mov bx, 0x55aa
+ mov dl, drive
+ mov si, [dapPacket]
+ mov ah, function
+ xor al, al
+ int 0x13
+ jnc ok // If CF=0, ignore AH to prevent issues caused by potential bugs in BIOSes
+ mov result, ah
+ ok:
+ }
+
+ if (result == BiosResultEccCorrected)
+ result = BiosResultSuccess;
+
+ // Some BIOSes report I/O errors prematurely in some cases
+ } while (result != BiosResultSuccess && --tryCount != 0);
+
+ if (!silent && result != BiosResultSuccess)
+ PrintDiskError (result, write, drive, &sector);
+
+ return result;
+}
+
+
+static BiosResult ReadWriteSectors (bool write, byte *buffer, byte drive, const uint64 &sector, uint16 sectorCount, bool silent)
+{
+ BiosLbaPacket dapPacket;
+ dapPacket.Buffer = (uint32) buffer;
+ return ReadWriteSectors (write, dapPacket, drive, sector, sectorCount, silent);
+}
+
+
+BiosResult ReadWriteSectors (bool write, uint16 bufferSegment, uint16 bufferOffset, byte drive, const uint64 &sector, uint16 sectorCount, bool silent)
+{
+ BiosLbaPacket dapPacket;
+ dapPacket.Buffer = ((uint32) bufferSegment << 16) | bufferOffset;
+ return ReadWriteSectors (write, dapPacket, drive, sector, sectorCount, silent);
+}
+
+BiosResult ReadSectors (uint16 bufferSegment, uint16 bufferOffset, byte drive, const uint64 &sector, uint16 sectorCount, bool silent)
+{
+ return ReadWriteSectors (false, bufferSegment, bufferOffset, drive, sector, sectorCount, silent);
+}
+
+
+BiosResult ReadSectors (byte *buffer, byte drive, const uint64 &sector, uint16 sectorCount, bool silent)
+{
+ BiosResult result;
+ uint16 codeSeg;
+ __asm mov codeSeg, cs
+
+ result = ReadSectors (BootStarted ? codeSeg : TC_BOOT_LOADER_ALT_SEGMENT, (uint16) buffer, drive, sector, sectorCount, silent);
+
+ // Alternative segment is used to prevent memory corruption caused by buggy BIOSes
+ if (!BootStarted)
+ CopyMemory (TC_BOOT_LOADER_ALT_SEGMENT, (uint16) buffer, buffer, sectorCount * TC_LB_SIZE);
+
+ return result;
+}
+
+
+BiosResult WriteSectors (byte *buffer, byte drive, const uint64 &sector, uint16 sectorCount, bool silent)
+{
+ return ReadWriteSectors (true, buffer, drive, sector, sectorCount, silent);
+}
+
+
+BiosResult GetDriveGeometry (byte drive, DriveGeometry &geometry, bool silent)
+{
+ CheckStack();
+
+ byte maxCylinderLow, maxHead, maxSector;
+ BiosResult result;
+ __asm
+ {
+ push es
+ mov dl, drive
+ mov ah, 0x08
+ int 0x13
+
+ mov result, ah
+ mov maxCylinderLow, ch
+ mov maxSector, cl
+ mov maxHead, dh
+ pop es
+ }
+
+ if (result == BiosResultSuccess)
+ {
+ geometry.Cylinders = (maxCylinderLow | (uint16 (maxSector & 0xc0) << 2)) + 1;
+ geometry.Heads = maxHead + 1;
+ geometry.Sectors = maxSector & ~0xc0;
+ }
+ else if (!silent)
+ {
+ Print ("Drive ");
+ Print (drive ^ 0x80);
+ Print (" not found: ");
+ PrintErrorNoEndl ("");
+ Print (result);
+ PrintEndl();
+ }
+
+ return result;
+}
+
+
+void ChsToLba (const DriveGeometry &geometry, const ChsAddress &chs, uint64 &lba)
+{
+ lba.HighPart = 0;
+ lba.LowPart = (uint32 (chs.Cylinder) * geometry.Heads + chs.Head) * geometry.Sectors + chs.Sector - 1;
+}
+
+
+void LbaToChs (const DriveGeometry &geometry, const uint64 &lba, ChsAddress &chs)
+{
+ chs.Sector = (byte) ((lba.LowPart % geometry.Sectors) + 1);
+ uint32 ch = lba.LowPart / geometry.Sectors;
+ chs.Head = (byte) (ch % geometry.Heads);
+ chs.Cylinder = (uint16) (ch / geometry.Heads);
+}
+
+
+void PartitionEntryMBRToPartition (const PartitionEntryMBR &partEntry, Partition &partition)
+{
+ partition.Active = partEntry.BootIndicator == 0x80;
+ partition.EndSector.HighPart = 0;
+ partition.EndSector.LowPart = partEntry.StartLBA + partEntry.SectorCountLBA - 1;
+ partition.SectorCount.HighPart = 0;
+ partition.SectorCount.LowPart = partEntry.SectorCountLBA;
+ partition.StartSector.HighPart = 0;
+ partition.StartSector.LowPart = partEntry.StartLBA;
+ partition.Type = partEntry.Type;
+}
+
+
+BiosResult ReadWriteMBR (bool write, byte drive, bool silent)
+{
+ uint64 mbrSector;
+ mbrSector.HighPart = 0;
+ mbrSector.LowPart = 0;
+
+ if (write)
+ return WriteSectors (SectorBuffer, drive, mbrSector, 1, silent);
+
+ return ReadSectors (SectorBuffer, drive, mbrSector, 1, silent); // Uses alternative segment
+}
+
+
+BiosResult GetDrivePartitions (byte drive, Partition *partitionArray, size_t partitionArrayCapacity, size_t &partitionCount, bool activeOnly, Partition *findPartitionFollowingThis, bool silent)
+{
+ Partition *followingPartition;
+ Partition tmpPartition;
+
+ if (findPartitionFollowingThis)
+ {
+ assert (partitionArrayCapacity == 1);
+ partitionArrayCapacity = 0xff;
+ followingPartition = partitionArray;
+ partitionArray = &tmpPartition;
+
+ followingPartition->Drive = TC_INVALID_BIOS_DRIVE;
+ followingPartition->StartSector.LowPart = 0xFFFFffffUL;
+ }
+
+ AcquireSectorBuffer();
+ BiosResult result = ReadWriteMBR (false, drive, silent);
+ ReleaseSectorBuffer();
+
+ partitionCount = 0;
+
+ MBR *mbr = (MBR *) SectorBuffer;
+ if (result != BiosResultSuccess || mbr->Signature != 0xaa55)
+ return result;
+
+ PartitionEntryMBR mbrPartitions[4];
+ memcpy (mbrPartitions, mbr->Partitions, sizeof (mbrPartitions));
+ size_t partitionArrayPos = 0, partitionNumber;
+
+ for (partitionNumber = 0;
+ partitionNumber < array_capacity (mbrPartitions) && partitionArrayPos < partitionArrayCapacity;
+ ++partitionNumber)
+ {
+ const PartitionEntryMBR &partEntry = mbrPartitions[partitionNumber];
+
+ if (partEntry.SectorCountLBA > 0)
+ {
+ Partition &partition = partitionArray[partitionArrayPos];
+ PartitionEntryMBRToPartition (partEntry, partition);
+
+ if (activeOnly && !partition.Active)
+ continue;
+
+ partition.Drive = drive;
+ partition.Number = partitionArrayPos;
+
+ if (partEntry.Type == 0x5 || partEntry.Type == 0xf) // Extended partition
+ {
+ if (IsLbaSupported (drive))
+ {
+ // Find all extended partitions
+ uint64 firstExtStartLBA = partition.StartSector;
+ uint64 extStartLBA = partition.StartSector;
+ MBR *extMbr = (MBR *) SectorBuffer;
+
+ while (partitionArrayPos < partitionArrayCapacity &&
+ (result = ReadSectors ((byte *) extMbr, drive, extStartLBA, 1, silent)) == BiosResultSuccess
+ && extMbr->Signature == 0xaa55)
+ {
+ if (extMbr->Partitions[0].SectorCountLBA > 0)
+ {
+ Partition &logPart = partitionArray[partitionArrayPos];
+ PartitionEntryMBRToPartition (extMbr->Partitions[0], logPart);
+ logPart.Drive = drive;
+
+ logPart.Number = partitionArrayPos;
+ logPart.Primary = false;
+
+ logPart.StartSector.LowPart += extStartLBA.LowPart;
+ logPart.EndSector.LowPart += extStartLBA.LowPart;
+
+ if (findPartitionFollowingThis)
+ {
+ if (logPart.StartSector.LowPart > findPartitionFollowingThis->EndSector.LowPart
+ && logPart.StartSector.LowPart < followingPartition->StartSector.LowPart)
+ {
+ *followingPartition = logPart;
+ }
+ }
+ else
+ ++partitionArrayPos;
+ }
+
+ // Secondary extended
+ if (extMbr->Partitions[1].Type != 0x5 && extMbr->Partitions[1].Type == 0xf
+ || extMbr->Partitions[1].SectorCountLBA == 0)
+ break;
+
+ extStartLBA.LowPart = extMbr->Partitions[1].StartLBA + firstExtStartLBA.LowPart;
+ }
+ }
+ }
+ else
+ {
+ partition.Primary = true;
+
+ if (findPartitionFollowingThis)
+ {
+ if (partition.StartSector.LowPart > findPartitionFollowingThis->EndSector.LowPart
+ && partition.StartSector.LowPart < followingPartition->StartSector.LowPart)
+ {
+ *followingPartition = partition;
+ }
+ }
+ else
+ ++partitionArrayPos;
+ }
+ }
+ }
+
+ partitionCount = partitionArrayPos;
+ return result;
+}
+
+
+bool GetActivePartition (byte drive)
+{
+ size_t partCount;
+
+ if (GetDrivePartitions (drive, &ActivePartition, 1, partCount, true) != BiosResultSuccess || partCount < 1)
+ {
+ ActivePartition.Drive = TC_INVALID_BIOS_DRIVE;
+ PrintError (TC_BOOT_STR_NO_BOOT_PARTITION);
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/Boot/Windows/BootDiskIo.h b/src/Boot/Windows/BootDiskIo.h
new file mode 100644
index 00000000..cc84c018
--- /dev/null
+++ b/src/Boot/Windows/BootDiskIo.h
@@ -0,0 +1,116 @@
+/*
+ Copyright (c) 2008-2011 TrueCrypt Developers Association. All rights reserved.
+
+ Governed by the TrueCrypt License 3.0 the full text of which is contained in
+ the file License.txt included in TrueCrypt binary and source code distribution
+ packages.
+*/
+
+#ifndef TC_HEADER_Boot_BootDiskIo
+#define TC_HEADER_Boot_BootDiskIo
+
+#include "Bios.h"
+#include "BootDebug.h"
+#include "BootDefs.h"
+
+#define TC_MAX_BIOS_DISK_IO_RETRIES 5
+
+enum
+{
+ BiosResultEccCorrected = 0x11
+};
+
+#pragma pack(1)
+
+struct PartitionEntryMBR
+{
+ byte BootIndicator;
+
+ byte StartHead;
+ byte StartCylSector;
+ byte StartCylinder;
+
+ byte Type;
+
+ byte EndHead;
+ byte EndSector;
+ byte EndCylinder;
+
+ uint32 StartLBA;
+ uint32 SectorCountLBA;
+};
+
+struct MBR
+{
+ byte Code[446];
+ PartitionEntryMBR Partitions[4];
+ uint16 Signature;
+};
+
+struct BiosLbaPacket
+{
+ byte Size;
+ byte Reserved;
+ uint16 SectorCount;
+ uint32 Buffer;
+ uint64 Sector;
+};
+
+#pragma pack()
+
+
+struct ChsAddress
+{
+ uint16 Cylinder;
+ byte Head;
+ byte Sector;
+};
+
+struct Partition
+{
+ byte Number;
+ byte Drive;
+ bool Active;
+ uint64 EndSector;
+ bool Primary;
+ uint64 SectorCount;
+ uint64 StartSector;
+ byte Type;
+};
+
+struct DriveGeometry
+{
+ uint16 Cylinders;
+ byte Heads;
+ byte Sectors;
+};
+
+
+#ifdef TC_BOOT_DEBUG_ENABLED
+void AcquireSectorBuffer ();
+void ReleaseSectorBuffer ();
+#else
+# define AcquireSectorBuffer()
+# define ReleaseSectorBuffer()
+#endif
+
+void ChsToLba (const DriveGeometry &geometry, const ChsAddress &chs, uint64 &lba);
+bool GetActivePartition (byte drive);
+BiosResult GetDriveGeometry (byte drive, DriveGeometry &geometry, bool silent = false);
+BiosResult GetDrivePartitions (byte drive, Partition *partitionArray, size_t partitionArrayCapacity, size_t &partitionCount, bool activeOnly = false, Partition *findPartitionFollowingThis = nullptr, bool silent = false);
+bool IsLbaSupported (byte drive);
+void LbaToChs (const DriveGeometry &geometry, const uint64 &lba, ChsAddress &chs);
+void Print (const ChsAddress &chs);
+void PrintDiskError (BiosResult error, bool write, byte drive, const uint64 *sector, const ChsAddress *chs = nullptr);
+void PrintSectorCountInMB (const uint64 &sectorCount);
+BiosResult ReadWriteMBR (bool write, byte drive, bool silent = false);
+BiosResult ReadSectors (uint16 bufferSegment, uint16 bufferOffset, byte drive, const uint64 &sector, uint16 sectorCount, bool silent = false);
+BiosResult ReadSectors (byte *buffer, byte drive, const uint64 &sector, uint16 sectorCount, bool silent = false);
+BiosResult ReadSectors (byte *buffer, byte drive, const ChsAddress &chs, byte sectorCount, bool silent = false);
+BiosResult ReadWriteSectors (bool write, uint16 bufferSegment, uint16 bufferOffset, byte drive, const uint64 &sector, uint16 sectorCount, bool silent);
+BiosResult WriteSectors (byte *buffer, byte drive, const uint64 &sector, uint16 sectorCount, bool silent = false);
+BiosResult WriteSectors (byte *buffer, byte drive, const ChsAddress &chs, byte sectorCount, bool silent = false);
+
+extern byte SectorBuffer[TC_LB_SIZE];
+
+#endif // TC_HEADER_Boot_BootDiskIo
diff --git a/src/Boot/Windows/BootEncryptedIo.cpp b/src/Boot/Windows/BootEncryptedIo.cpp
new file mode 100644
index 00000000..ff048991
--- /dev/null
+++ b/src/Boot/Windows/BootEncryptedIo.cpp
@@ -0,0 +1,128 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ Governed by the TrueCrypt License 3.0 the full text of which is contained in
+ the file License.txt included in TrueCrypt binary and source code distribution
+ packages.
+*/
+
+#include "Crypto.h"
+#include "Platform.h"
+#include "BootConfig.h"
+#include "BootDebug.h"
+#include "BootDefs.h"
+#include "BootDiskIo.h"
+#include "BootEncryptedIo.h"
+
+
+BiosResult ReadEncryptedSectors (uint16 destSegment, uint16 destOffset, byte drive, uint64 sector, uint16 sectorCount)
+{
+ BiosResult result;
+ bool decrypt = true;
+
+ if (BootCryptoInfo->hiddenVolume)
+ {
+ if (ReadWritePartiallyCoversEncryptedArea (sector, sectorCount))
+ return BiosResultInvalidFunction;
+
+ if (sector >= EncryptedVirtualPartition.StartSector && sector <= EncryptedVirtualPartition.EndSector)
+ {
+ // Remap the request to the hidden volume
+ sector -= EncryptedVirtualPartition.StartSector;
+ sector += HiddenVolumeStartSector;
+ }
+ else
+ decrypt = false;
+ }
+
+ result = ReadSectors (destSegment, destOffset, drive, sector, sectorCount);
+
+ if (result != BiosResultSuccess || !decrypt)
+ return result;
+
+ if (BootCryptoInfo->hiddenVolume)
+ {
+ // Convert sector number to data unit number of the hidden volume
+ sector -= HiddenVolumeStartSector;
+ sector += HiddenVolumeStartUnitNo;
+ }
+
+ if (drive == EncryptedVirtualPartition.Drive)
+ {
+ while (sectorCount-- > 0)
+ {
+ if (BootCryptoInfo->hiddenVolume
+ || (sector >= EncryptedVirtualPartition.StartSector && sector <= EncryptedVirtualPartition.EndSector))
+ {
+ AcquireSectorBuffer();
+ CopyMemory (destSegment, destOffset, SectorBuffer, TC_LB_SIZE);
+
+ DecryptDataUnits (SectorBuffer, &sector, 1, BootCryptoInfo);
+
+ CopyMemory (SectorBuffer, destSegment, destOffset, TC_LB_SIZE);
+ ReleaseSectorBuffer();
+ }
+
+ ++sector;
+ destOffset += TC_LB_SIZE;
+ }
+ }
+
+ return result;
+}
+
+
+BiosResult WriteEncryptedSectors (uint16 sourceSegment, uint16 sourceOffset, byte drive, uint64 sector, uint16 sectorCount)
+{
+ BiosResult result;
+ AcquireSectorBuffer();
+ uint64 dataUnitNo;
+ uint64 writeOffset;
+
+ dataUnitNo = sector;
+ writeOffset.HighPart = 0;
+ writeOffset.LowPart = 0;
+
+ if (BootCryptoInfo->hiddenVolume)
+ {
+ if (ReadWritePartiallyCoversEncryptedArea (sector, sectorCount))
+ return BiosResultInvalidFunction;
+
+ // Remap the request to the hidden volume
+ writeOffset = HiddenVolumeStartSector;
+ writeOffset -= EncryptedVirtualPartition.StartSector;
+ dataUnitNo -= EncryptedVirtualPartition.StartSector;
+ dataUnitNo += HiddenVolumeStartUnitNo;
+ }
+
+ while (sectorCount-- > 0)
+ {
+ CopyMemory (sourceSegment, sourceOffset, SectorBuffer, TC_LB_SIZE);
+
+ if (drive == EncryptedVirtualPartition.Drive && sector >= EncryptedVirtualPartition.StartSector && sector <= EncryptedVirtualPartition.EndSector)
+ {
+ EncryptDataUnits (SectorBuffer, &dataUnitNo, 1, BootCryptoInfo);
+ }
+
+ result = WriteSectors (SectorBuffer, drive, sector + writeOffset, 1);
+
+ if (result != BiosResultSuccess)
+ break;
+
+ ++sector;
+ ++dataUnitNo;
+ sourceOffset += TC_LB_SIZE;
+ }
+
+ ReleaseSectorBuffer();
+ return result;
+}
+
+
+static bool ReadWritePartiallyCoversEncryptedArea (const uint64 &sector, uint16 sectorCount)
+{
+ uint64 readWriteEnd = sector + --sectorCount;
+
+ return ((sector < EncryptedVirtualPartition.StartSector && readWriteEnd >= EncryptedVirtualPartition.StartSector)
+ || (sector >= EncryptedVirtualPartition.StartSector && readWriteEnd > EncryptedVirtualPartition.EndSector));
+}
diff --git a/src/Boot/Windows/BootEncryptedIo.h b/src/Boot/Windows/BootEncryptedIo.h
new file mode 100644
index 00000000..14cf182d
--- /dev/null
+++ b/src/Boot/Windows/BootEncryptedIo.h
@@ -0,0 +1,18 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ Governed by the TrueCrypt License 3.0 the full text of which is contained in
+ the file License.txt included in TrueCrypt binary and source code distribution
+ packages.
+*/
+
+#ifndef TC_HEADER_Boot_BootEncryptionIo
+#define TC_HEADER_Boot_BootEncryptionIo
+
+#include "Platform.h"
+
+BiosResult ReadEncryptedSectors (uint16 destSegment, uint16 destOffset, byte drive, uint64 sector, uint16 sectorCount);
+BiosResult WriteEncryptedSectors (uint16 sourceSegment, uint16 sourceOffset, byte drive, uint64 sector, uint16 sectorCount);
+static bool ReadWritePartiallyCoversEncryptedArea (const uint64 &sector, uint16 sectorCount);
+
+#endif // TC_HEADER_Boot_BootEncryptionIo
diff --git a/src/Boot/Windows/BootMain.cpp b/src/Boot/Windows/BootMain.cpp
new file mode 100644
index 00000000..5d4b942c
--- /dev/null
+++ b/src/Boot/Windows/BootMain.cpp
@@ -0,0 +1,1151 @@
+/*
+ Copyright (c) 2008-2011 TrueCrypt Developers Association. All rights reserved.
+
+ Governed by the TrueCrypt License 3.0 the full text of which is contained in
+ the file License.txt included in TrueCrypt binary and source code distribution
+ packages.
+*/
+
+#include "Crc.h"
+#include "Crypto.h"
+#include "Password.h"
+#include "Volumes.h"
+
+#include "Platform.h"
+#include "Bios.h"
+#include "BootConfig.h"
+#include "BootMain.h"
+#include "BootDefs.h"
+#include "BootCommon.h"
+#include "BootConsoleIo.h"
+#include "BootDebug.h"
+#include "BootDiskIo.h"
+#include "BootEncryptedIo.h"
+#include "BootMemory.h"
+#include "BootStrings.h"
+#include "IntFilter.h"
+
+
+static void InitScreen ()
+{
+ ClearScreen();
+
+ const char *title =
+#ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+ " TrueCrypt Boot Loader "
+#else
+ " TrueCrypt Rescue Disk "
+#endif
+ VERSION_STRING "\r\n";
+
+ Print (title);
+
+ PrintRepeatedChar ('\xDC', TC_BIOS_MAX_CHARS_PER_LINE);
+
+#ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+ if (CustomUserMessage[0])
+ {
+ PrintEndl();
+ Print (CustomUserMessage);
+ }
+#endif
+
+ PrintEndl (2);
+}
+
+
+static void PrintMainMenu ()
+{
+ if (PreventBootMenu)
+ return;
+
+ Print (" Keyboard Controls:\r\n");
+ Print (" [Esc] ");
+
+#ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+
+ Print ((BootSectorFlags & TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE) != TC_HIDDEN_OS_CREATION_PHASE_NONE
+ ? "Boot Non-Hidden System (Boot Manager)"
+ : "Skip Authentication (Boot Manager)");
+
+#else // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+
+ Print ("Skip Authentication (Boot Manager)");
+ Print ("\r\n [F8] "); Print ("Repair Options");
+
+#endif // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+
+ PrintEndl (3);
+}
+
+
+static bool IsMenuKey (byte scanCode)
+{
+#ifdef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+ return scanCode == TC_MENU_KEY_REPAIR;
+#else
+ return false;
+#endif
+}
+
+
+static bool AskYesNo (const char *message)
+{
+ Print (message);
+ Print ("? (y/n): ");
+ while (true)
+ {
+ switch (GetKeyboardChar())
+ {
+ case 'y':
+ case 'Y':
+ case 'z':
+ case 'Z':
+ Print ("y\r\n");
+ return true;
+
+ case 'n':
+ case 'N':
+ Print ("n\r\n");
+ return false;
+
+ default:
+ Beep();
+ }
+ }
+}
+
+
+static int AskSelection (const char *options[], size_t optionCount)
+{
+ for (int i = 0; i < optionCount; ++i)
+ {
+ Print ("["); Print (i + 1); Print ("] ");
+ Print (options[i]);
+ PrintEndl();
+ }
+ Print ("[Esc] Cancel\r\n\r\n");
+
+ Print ("To select, press 1-9: ");
+
+ char str;
+
+ while (true)
+ {
+ if (GetString (&str, 1) == 0)
+ return 0;
+
+ if (str >= '1' && str <= optionCount + '0')
+ return str - '0';
+
+ Beep();
+ PrintBackspace();
+ }
+}
+
+
+static byte AskPassword (Password &password)
+{
+ size_t pos = 0;
+ byte scanCode;
+ byte asciiCode;
+
+ Print ("Enter password");
+ Print (PreventNormalSystemBoot ? " for hidden system:\r\n" : ": ");
+
+ while (true)
+ {
+ asciiCode = GetKeyboardChar (&scanCode);
+
+ switch (scanCode)
+ {
+ case TC_BIOS_KEY_ENTER:
+ ClearBiosKeystrokeBuffer();
+ PrintEndl();
+
+ password.Length = pos;
+ return scanCode;
+
+ case TC_BIOS_KEY_BACKSPACE:
+ if (pos > 0)
+ {
+ if (pos < MAX_PASSWORD)
+ PrintBackspace();
+ else
+ PrintCharAtCursor (' ');
+
+ --pos;
+ }
+ continue;
+
+ default:
+ if (scanCode == TC_BIOS_KEY_ESC || IsMenuKey (scanCode))
+ {
+ burn (password.Text, sizeof (password.Text));
+ ClearBiosKeystrokeBuffer();
+
+ PrintEndl();
+ return scanCode;
+ }
+ }
+
+ if (!IsPrintable (asciiCode) || pos == MAX_PASSWORD)
+ {
+ Beep();
+ continue;
+ }
+
+ password.Text[pos++] = asciiCode;
+ if (pos < MAX_PASSWORD)
+ PrintChar ('*');
+ else
+ PrintCharAtCursor ('*');
+ }
+}
+
+
+static void ExecuteBootSector (byte drive, byte *sectorBuffer)
+{
+ Print ("Booting...\r\n");
+ CopyMemory (sectorBuffer, 0x0000, 0x7c00, TC_LB_SIZE);
+
+ BootStarted = true;
+
+ uint32 addr = 0x7c00;
+ __asm
+ {
+ cli
+ mov dl, drive // Boot drive
+ mov dh, 0
+ xor ax, ax
+ mov si, ax
+ mov ds, ax
+ mov es, ax
+ mov ss, ax
+ mov sp, 0x7c00
+ sti
+
+ jmp cs:addr
+ }
+}
+
+
+static bool OpenVolume (byte drive, Password &password, CRYPTO_INFO **cryptoInfo, uint32 *headerSaltCrc32, bool skipNormal, bool skipHidden)
+{
+ int volumeType;
+ bool hiddenVolume;
+ uint64 headerSec;
+
+ AcquireSectorBuffer();
+
+ for (volumeType = 1; volumeType <= 2; ++volumeType)
+ {
+ hiddenVolume = (volumeType == 2);
+
+ if (hiddenVolume)
+ {
+ if (skipHidden || PartitionFollowingActive.Drive != drive || PartitionFollowingActive.SectorCount <= ActivePartition.SectorCount)
+ continue;
+
+ headerSec = PartitionFollowingActive.StartSector + TC_HIDDEN_VOLUME_HEADER_OFFSET / TC_LB_SIZE;
+ }
+ else
+ {
+ if (skipNormal)
+ continue;
+
+ headerSec.HighPart = 0;
+ headerSec.LowPart = TC_BOOT_VOLUME_HEADER_SECTOR;
+ }
+
+ if (ReadSectors (SectorBuffer, drive, headerSec, 1) != BiosResultSuccess)
+ continue;
+
+ if (ReadVolumeHeader (!hiddenVolume, (char *) SectorBuffer, &password, cryptoInfo, nullptr) == ERR_SUCCESS)
+ {
+ // Prevent opening a non-system hidden volume
+ if (hiddenVolume && !((*cryptoInfo)->HeaderFlags & TC_HEADER_FLAG_ENCRYPTED_SYSTEM))
+ {
+ crypto_close (*cryptoInfo);
+ continue;
+ }
+
+ if (headerSaltCrc32)
+ *headerSaltCrc32 = GetCrc32 (SectorBuffer, PKCS5_SALT_SIZE);
+
+ break;
+ }
+ }
+
+ ReleaseSectorBuffer();
+ return volumeType != 3;
+}
+
+
+static bool CheckMemoryRequirements ()
+{
+ uint16 codeSeg;
+ __asm mov codeSeg, cs
+ if (codeSeg == TC_BOOT_LOADER_LOWMEM_SEGMENT)
+ {
+ PrintErrorNoEndl ("BIOS reserved too much memory: ");
+
+ uint16 memFree;
+ __asm
+ {
+ push es
+ xor ax, ax
+ mov es, ax
+ mov ax, es:[0x413]
+ mov memFree, ax
+ pop es
+ }
+
+ Print (memFree);
+ PrintEndl();
+ Print (TC_BOOT_STR_UPGRADE_BIOS);
+
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool MountVolume (byte drive, byte &exitKey, bool skipNormal, bool skipHidden)
+{
+ BootArguments *bootArguments = (BootArguments *) TC_BOOT_LOADER_ARGS_OFFSET;
+ int incorrectPasswordCount = 0;
+
+ EraseMemory (bootArguments, sizeof (*bootArguments));
+
+ // Open volume header
+ while (true)
+ {
+ exitKey = AskPassword (bootArguments->BootPassword);
+
+ if (exitKey != TC_BIOS_KEY_ENTER)
+ return false;
+
+ if (OpenVolume (BootDrive, bootArguments->BootPassword, &BootCryptoInfo, &bootArguments->HeaderSaltCrc32, skipNormal, skipHidden))
+ break;
+
+ if (GetShiftFlags() & TC_BIOS_SHIFTMASK_CAPSLOCK)
+ Print ("Warning: Caps Lock is on.\r\n");
+
+ Print ("Incorrect password.\r\n\r\n");
+
+ if (++incorrectPasswordCount == 4)
+ {
+#ifdef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+ Print ("If you are sure the password is correct, the key data may be damaged.\r\n"
+ "If so, use 'Repair Options' > 'Restore key data'.\r\n\r\n");
+#else
+ Print ("If you are sure the password is correct, the key data may be damaged. Boot your\r\n"
+ "TrueCrypt Rescue Disk and select 'Repair Options' > 'Restore key data'.\r\n\r\n");
+#endif
+ }
+ }
+
+ // Setup boot arguments
+ bootArguments->BootLoaderVersion = VERSION_NUM;
+ bootArguments->CryptoInfoOffset = (uint16) BootCryptoInfo;
+ bootArguments->CryptoInfoLength = sizeof (*BootCryptoInfo);
+
+ if (BootCryptoInfo->hiddenVolume)
+ bootArguments->HiddenSystemPartitionStart = PartitionFollowingActive.StartSector << TC_LB_SIZE_BIT_SHIFT_DIVISOR;
+
+ if (ExtraBootPartitionPresent)
+ bootArguments->Flags |= TC_BOOT_ARGS_FLAG_EXTRA_BOOT_PARTITION;
+
+ TC_SET_BOOT_ARGUMENTS_SIGNATURE (bootArguments->Signature);
+
+ // Setup virtual encrypted partition
+ if (BootCryptoInfo->EncryptedAreaLength.HighPart != 0 || BootCryptoInfo->EncryptedAreaLength.LowPart != 0)
+ {
+ EncryptedVirtualPartition.Drive = BootDrive;
+
+ EncryptedVirtualPartition.StartSector = BootCryptoInfo->EncryptedAreaStart >> TC_LB_SIZE_BIT_SHIFT_DIVISOR;
+
+ HiddenVolumeStartUnitNo = EncryptedVirtualPartition.StartSector;
+ HiddenVolumeStartSector = PartitionFollowingActive.StartSector;
+ HiddenVolumeStartSector += EncryptedVirtualPartition.StartSector;
+
+ EncryptedVirtualPartition.SectorCount = BootCryptoInfo->EncryptedAreaLength >> TC_LB_SIZE_BIT_SHIFT_DIVISOR;
+
+ EncryptedVirtualPartition.EndSector = EncryptedVirtualPartition.SectorCount - 1;
+ EncryptedVirtualPartition.EndSector += EncryptedVirtualPartition.StartSector;
+ }
+ else
+ {
+ // Drive not encrypted
+ EncryptedVirtualPartition.Drive = TC_INVALID_BIOS_DRIVE;
+ }
+
+ return true;
+}
+
+
+static bool GetSystemPartitions (byte drive)
+{
+ size_t partCount;
+
+ if (!GetActivePartition (drive))
+ return false;
+
+ // Find partition following the active one
+ GetDrivePartitions (drive, &PartitionFollowingActive, 1, partCount, false, &ActivePartition);
+
+ // If there is an extra boot partition, use the partitions following it.
+ // The real boot partition is determined in BootEncryptedDrive().
+ if (ActivePartition.SectorCount.HighPart == 0 && ActivePartition.SectorCount.LowPart <= TC_MAX_EXTRA_BOOT_PARTITION_SIZE / TC_LB_SIZE
+ && PartitionFollowingActive.Drive != TC_INVALID_BIOS_DRIVE)
+ {
+ ExtraBootPartitionPresent = true;
+
+ ActivePartition = PartitionFollowingActive;
+ GetDrivePartitions (drive, &PartitionFollowingActive, 1, partCount, false, &ActivePartition);
+ }
+
+ return true;
+}
+
+
+static byte BootEncryptedDrive ()
+{
+ BootArguments *bootArguments = (BootArguments *) TC_BOOT_LOADER_ARGS_OFFSET;
+ byte exitKey;
+ BootCryptoInfo = NULL;
+
+ if (!GetSystemPartitions (BootDrive))
+ goto err;
+
+ if (!MountVolume (BootDrive, exitKey, PreventNormalSystemBoot, false))
+ return exitKey;
+
+ if (!CheckMemoryRequirements ())
+ goto err;
+
+ if (BootCryptoInfo->hiddenVolume)
+ {
+ EncryptedVirtualPartition = ActivePartition;
+ bootArguments->DecoySystemPartitionStart = ActivePartition.StartSector << TC_LB_SIZE_BIT_SHIFT_DIVISOR;
+ }
+
+ if (ExtraBootPartitionPresent && !GetActivePartition (BootDrive))
+ goto err;
+
+ if (ReadWriteMBR (false, ActivePartition.Drive) != BiosResultSuccess)
+ goto err;
+
+ bootArguments->BootDriveSignature = *(uint32 *) (SectorBuffer + 0x1b8);
+
+ if (!InstallInterruptFilters())
+ goto err;
+
+ bootArguments->BootArgumentsCrc32 = GetCrc32 ((byte *) bootArguments, (byte *) &bootArguments->BootArgumentsCrc32 - (byte *) bootArguments);
+
+ while (true)
+ {
+ // Execute boot sector of the active partition
+ if (ReadSectors (SectorBuffer, ActivePartition.Drive, ActivePartition.StartSector, 1) == BiosResultSuccess)
+ {
+ if (*(uint16 *) (SectorBuffer + 510) != 0xaa55)
+ {
+ PrintError (TC_BOOT_STR_NO_BOOT_PARTITION);
+ GetKeyboardChar();
+ }
+
+ ExecuteBootSector (ActivePartition.Drive, SectorBuffer);
+ }
+
+ GetKeyboardChar();
+ }
+
+err:
+ if (BootCryptoInfo)
+ {
+ crypto_close (BootCryptoInfo);
+ BootCryptoInfo = NULL;
+ }
+
+ EncryptedVirtualPartition.Drive = TC_INVALID_BIOS_DRIVE;
+ EraseMemory ((void *) TC_BOOT_LOADER_ARGS_OFFSET, sizeof (BootArguments));
+
+ byte scanCode;
+ GetKeyboardChar (&scanCode);
+ return scanCode;
+}
+
+
+static void BootMenu ()
+{
+ BiosResult result;
+ Partition partitions[16];
+ Partition bootablePartitions[9];
+ size_t partitionCount;
+ size_t bootablePartitionCount = 0;
+
+ for (byte drive = TC_FIRST_BIOS_DRIVE; drive <= TC_LAST_BIOS_DRIVE; ++drive)
+ {
+ if (GetDrivePartitions (drive, partitions, array_capacity (partitions), partitionCount, false, nullptr, true) == BiosResultSuccess)
+ {
+ for (size_t i = 0; i < partitionCount; ++i)
+ {
+ const Partition &partition = partitions[i];
+ result = ReadSectors (SectorBuffer, drive, partition.StartSector, 1);
+
+ if (result == BiosResultSuccess && *(uint16 *) (SectorBuffer + TC_LB_SIZE - 2) == 0xaa55)
+ {
+ // Windows writes boot loader on all NTFS/FAT filesytems it creates and, therefore,
+ // NTFS/FAT partitions must have the boot indicator set to be considered bootable.
+ if (!partition.Active
+ && (*(uint32 *) (SectorBuffer + 3) == 0x5346544e // 'NTFS'
+ || *(uint32 *) (SectorBuffer + 3) == 0x41465845 && SectorBuffer[7] == 'T' // 'exFAT'
+ || *(uint16 *) (SectorBuffer + 54) == 0x4146 && SectorBuffer[56] == 'T' // 'FAT'
+ || *(uint16 *) (SectorBuffer + 82) == 0x4146 && SectorBuffer[84] == 'T'))
+ {
+ continue;
+ }
+
+ // Bootable sector found
+ if (bootablePartitionCount < array_capacity (bootablePartitions))
+ bootablePartitions[bootablePartitionCount++] = partition;
+ }
+ }
+ }
+ }
+
+ if (bootablePartitionCount < 1)
+ {
+ PrintError (TC_BOOT_STR_NO_BOOT_PARTITION);
+ GetKeyboardChar();
+ return;
+ }
+
+ char partChar;
+ while (true)
+ {
+ InitScreen();
+ Print ("Bootable Partitions:\r\n");
+ PrintRepeatedChar ('\xC4', 20);
+ Print ("\r\n");
+
+ for (size_t i = 0; i < bootablePartitionCount; ++i)
+ {
+ const Partition &partition = bootablePartitions[i];
+ Print ("["); Print (i + 1); Print ("] ");
+ Print ("Drive: "); Print (partition.Drive - TC_FIRST_BIOS_DRIVE);
+ Print (", Partition: "); Print (partition.Number + 1);
+ Print (", Size: "); PrintSectorCountInMB (partition.SectorCount); PrintEndl();
+ }
+
+ if (bootablePartitionCount == 1)
+ {
+ // There's only one bootable partition so we'll boot it directly instead of showing boot manager
+ partChar = '1';
+ }
+ else
+ {
+ Print ("[Esc] Cancel\r\n\r\n");
+ Print ("Press 1-9 to select partition: ");
+
+ if (GetString (&partChar, 1) == 0)
+ return;
+
+ PrintEndl();
+
+ if (partChar < '1' || partChar > '0' + bootablePartitionCount)
+ {
+ Beep();
+ continue;
+ }
+ }
+
+ const Partition &partition = bootablePartitions[partChar - '0' - 1];
+
+ if (ReadSectors (SectorBuffer, partition.Drive, partition.StartSector, 1) == BiosResultSuccess)
+ {
+ ExecuteBootSector (partition.Drive, SectorBuffer);
+ }
+ }
+}
+
+
+#ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+
+static bool CopySystemPartitionToHiddenVolume (byte drive, byte &exitKey)
+{
+ bool status = false;
+
+ uint64 sectorsRemaining;
+ uint64 sectorOffset;
+ sectorOffset.LowPart = 0;
+ sectorOffset.HighPart = 0;
+
+ int fragmentSectorCount = 0x7f; // Maximum safe value supported by BIOS
+ int statCount;
+
+ if (!CheckMemoryRequirements ())
+ goto err;
+
+ if (!GetSystemPartitions (drive))
+ goto err;
+
+ if (PartitionFollowingActive.Drive == TC_INVALID_BIOS_DRIVE)
+ TC_THROW_FATAL_EXCEPTION;
+
+ // Check if BIOS can read the last sector of the hidden system
+ AcquireSectorBuffer();
+
+ if (ReadSectors (SectorBuffer, PartitionFollowingActive.Drive, PartitionFollowingActive.EndSector - (TC_VOLUME_HEADER_GROUP_SIZE / TC_LB_SIZE - 2), 1) != BiosResultSuccess
+ || GetCrc32 (SectorBuffer, sizeof (SectorBuffer)) != OuterVolumeBackupHeaderCrc)
+ {
+ PrintErrorNoEndl ("Your BIOS does not support large drives");
+ Print (IsLbaSupported (PartitionFollowingActive.Drive) ? " due to a bug" : "\r\n- Enable LBA in BIOS");
+ PrintEndl();
+ Print (TC_BOOT_STR_UPGRADE_BIOS);
+
+ ReleaseSectorBuffer();
+ goto err;
+ }
+
+ ReleaseSectorBuffer();
+
+ if (!MountVolume (drive, exitKey, true, false))
+ return false;
+
+ sectorsRemaining = EncryptedVirtualPartition.SectorCount;
+
+ if (!(sectorsRemaining == ActivePartition.SectorCount))
+ TC_THROW_FATAL_EXCEPTION;
+
+ InitScreen();
+ Print ("\r\nCopying system to hidden volume. To abort, press Esc.\r\n\r\n");
+
+ while (sectorsRemaining.HighPart != 0 || sectorsRemaining.LowPart != 0)
+ {
+ if (EscKeyPressed())
+ {
+ Print ("\rIf aborted, copying will have to start from the beginning (if attempted again).\r\n");
+ if (AskYesNo ("Abort"))
+ break;
+ }
+
+ if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart < fragmentSectorCount)
+ fragmentSectorCount = (int) sectorsRemaining.LowPart;
+
+ if (ReadWriteSectors (false, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, ActivePartition.StartSector + sectorOffset, fragmentSectorCount, false) != BiosResultSuccess)
+ {
+ Print ("To fix bad sectors: 1) Terminate 2) Encrypt and decrypt sys partition 3) Retry\r\n");
+ crypto_close (BootCryptoInfo);
+ goto err;
+ }
+
+ AcquireSectorBuffer();
+
+ for (int i = 0; i < fragmentSectorCount; ++i)
+ {
+ CopyMemory (TC_BOOT_LOADER_BUFFER_SEGMENT, i * TC_LB_SIZE, SectorBuffer, TC_LB_SIZE);
+
+ uint64 s = HiddenVolumeStartUnitNo + sectorOffset + i;
+ EncryptDataUnits (SectorBuffer, &s, 1, BootCryptoInfo);
+
+ CopyMemory (SectorBuffer, TC_BOOT_LOADER_BUFFER_SEGMENT, i * TC_LB_SIZE, TC_LB_SIZE);
+ }
+
+ ReleaseSectorBuffer();
+
+ if (ReadWriteSectors (true, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, HiddenVolumeStartSector + sectorOffset, fragmentSectorCount, false) != BiosResultSuccess)
+ {
+ crypto_close (BootCryptoInfo);
+ goto err;
+ }
+
+ sectorsRemaining = sectorsRemaining - fragmentSectorCount;
+ sectorOffset = sectorOffset + fragmentSectorCount;
+
+ if (!(statCount++ & 0xf))
+ {
+ Print ("\rRemaining: ");
+ PrintSectorCountInMB (sectorsRemaining);
+ }
+ }
+
+ crypto_close (BootCryptoInfo);
+
+ if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart == 0)
+ {
+ status = true;
+ Print ("\rCopying completed.");
+ }
+
+ PrintEndl (2);
+ goto ret;
+
+err:
+ exitKey = TC_BIOS_KEY_ESC;
+ GetKeyboardChar();
+
+ret:
+ EraseMemory ((void *) TC_BOOT_LOADER_ARGS_OFFSET, sizeof (BootArguments));
+ return status;
+}
+
+
+#else // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+
+
+static void DecryptDrive (byte drive)
+{
+ byte exitKey;
+ if (!MountVolume (drive, exitKey, false, true))
+ return;
+
+ BootArguments *bootArguments = (BootArguments *) TC_BOOT_LOADER_ARGS_OFFSET;
+
+ bool headerUpdateRequired = false;
+ uint64 sectorsRemaining = EncryptedVirtualPartition.EndSector + 1 - EncryptedVirtualPartition.StartSector;
+ uint64 sector = EncryptedVirtualPartition.EndSector + 1;
+
+ int fragmentSectorCount = 0x7f; // Maximum safe value supported by BIOS
+ int statCount;
+
+ bool skipBadSectors = false;
+
+ Print ("\r\nUse only if Windows cannot start. Decryption under Windows is much faster\r\n"
+ "(in TrueCrypt, select 'System' > 'Permanently Decrypt').\r\n\r\n");
+
+ if (!AskYesNo ("Decrypt now"))
+ {
+ crypto_close (BootCryptoInfo);
+ goto ret;
+ }
+
+ if (EncryptedVirtualPartition.Drive == TC_INVALID_BIOS_DRIVE)
+ {
+ // Drive already decrypted
+ sectorsRemaining.HighPart = 0;
+ sectorsRemaining.LowPart = 0;
+ }
+ else
+ {
+ Print ("\r\nTo safely interrupt and defer decryption, press Esc.\r\n"
+ "WARNING: You can turn off power only after you press Esc.\r\n\r\n");
+ }
+
+ while (sectorsRemaining.HighPart != 0 || sectorsRemaining.LowPart != 0)
+ {
+ if (EscKeyPressed())
+ break;
+
+ if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart < fragmentSectorCount)
+ fragmentSectorCount = (int) sectorsRemaining.LowPart;
+
+ sector = sector - fragmentSectorCount;
+
+ if (!(statCount++ & 0xf))
+ {
+ Print ("\rRemaining: ");
+ PrintSectorCountInMB (sectorsRemaining);
+ }
+
+ if (ReadWriteSectors (false, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, sector, fragmentSectorCount, skipBadSectors) == BiosResultSuccess)
+ {
+ AcquireSectorBuffer();
+
+ for (int i = 0; i < fragmentSectorCount; ++i)
+ {
+ CopyMemory (TC_BOOT_LOADER_BUFFER_SEGMENT, i * TC_LB_SIZE, SectorBuffer, TC_LB_SIZE);
+
+ uint64 s = sector + i;
+ DecryptDataUnits (SectorBuffer, &s, 1, BootCryptoInfo);
+
+ CopyMemory (SectorBuffer, TC_BOOT_LOADER_BUFFER_SEGMENT, i * TC_LB_SIZE, TC_LB_SIZE);
+ }
+
+ ReleaseSectorBuffer();
+
+ if (ReadWriteSectors (true, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, sector, fragmentSectorCount, skipBadSectors) != BiosResultSuccess && !skipBadSectors)
+ goto askBadSectorSkip;
+ }
+ else if (!skipBadSectors)
+ goto askBadSectorSkip;
+
+ sectorsRemaining = sectorsRemaining - fragmentSectorCount;
+ headerUpdateRequired = true;
+ continue;
+
+askBadSectorSkip:
+ if (!AskYesNo ("Skip all bad sectors"))
+ break;
+
+ skipBadSectors = true;
+ sector = sector + fragmentSectorCount;
+ fragmentSectorCount = 1;
+ }
+
+ crypto_close (BootCryptoInfo);
+
+ if (headerUpdateRequired)
+ {
+ AcquireSectorBuffer();
+ uint64 headerSector;
+ headerSector.HighPart = 0;
+ headerSector.LowPart = TC_BOOT_VOLUME_HEADER_SECTOR;
+
+ // Update encrypted area size in volume header
+
+ CRYPTO_INFO *headerCryptoInfo = crypto_open();
+ while (ReadSectors (SectorBuffer, drive, headerSector, 1) != BiosResultSuccess);
+
+ if (ReadVolumeHeader (TRUE, (char *) SectorBuffer, &bootArguments->BootPassword, NULL, headerCryptoInfo) == 0)
+ {
+ DecryptBuffer (SectorBuffer + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, headerCryptoInfo);
+
+ uint64 encryptedAreaLength = sectorsRemaining << TC_LB_SIZE_BIT_SHIFT_DIVISOR;
+
+ for (int i = 7; i >= 0; --i)
+ {
+ SectorBuffer[TC_HEADER_OFFSET_ENCRYPTED_AREA_LENGTH + i] = (byte) encryptedAreaLength.LowPart;
+ encryptedAreaLength = encryptedAreaLength >> 8;
+ }
+
+ uint32 headerCrc32 = GetCrc32 (SectorBuffer + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC);
+
+ for (i = 3; i >= 0; --i)
+ {
+ SectorBuffer[TC_HEADER_OFFSET_HEADER_CRC + i] = (byte) headerCrc32;
+ headerCrc32 >>= 8;
+ }
+
+ EncryptBuffer (SectorBuffer + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, headerCryptoInfo);
+ }
+
+ crypto_close (headerCryptoInfo);
+
+ while (WriteSectors (SectorBuffer, drive, headerSector, 1) != BiosResultSuccess);
+ ReleaseSectorBuffer();
+ }
+
+ if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart == 0)
+ Print ("\rDrive decrypted.\r\n");
+ else
+ Print ("\r\nDecryption deferred.\r\n");
+
+ GetKeyboardChar();
+ret:
+ EraseMemory (bootArguments, sizeof (*bootArguments));
+}
+
+
+static void RepairMenu ()
+{
+ DriveGeometry bootLoaderDriveGeometry;
+
+ if (GetDriveGeometry (BootLoaderDrive, bootLoaderDriveGeometry, true) != BiosResultSuccess)
+ {
+ // Some BIOSes may fail to get the geometry of an emulated floppy drive
+ bootLoaderDriveGeometry.Cylinders = 80;
+ bootLoaderDriveGeometry.Heads = 2;
+ bootLoaderDriveGeometry.Sectors = 18;
+ }
+
+ while (true)
+ {
+ InitScreen();
+ Print ("Available "); Print ("Repair Options"); Print (":\r\n");
+ PrintRepeatedChar ('\xC4', 25);
+ PrintEndl();
+
+ enum
+ {
+ RestoreNone = 0,
+ DecryptVolume,
+ RestoreTrueCryptLoader,
+ RestoreVolumeHeader,
+ RestoreOriginalSystemLoader
+ };
+
+ static const char *options[] = { "Permanently decrypt system partition/drive", "Restore TrueCrypt Boot Loader", "Restore key data (volume header)", "Restore original system loader" };
+
+ int selection = AskSelection (options,
+ (BootSectorFlags & TC_BOOT_CFG_FLAG_RESCUE_DISK_ORIG_SYS_LOADER) ? array_capacity (options) : array_capacity (options) - 1);
+
+ PrintEndl();
+
+ switch (selection)
+ {
+ case RestoreNone:
+ return;
+
+ case DecryptVolume:
+ DecryptDrive (BootDrive);
+ continue;
+
+ case RestoreOriginalSystemLoader:
+ if (!AskYesNo ("Is the system partition/drive decrypted"))
+ {
+ Print ("Please decrypt it first.\r\n");
+ GetKeyboardChar();
+ continue;
+ }
+ break;
+ }
+
+ bool writeConfirmed = false;
+ BiosResult result;
+
+ uint64 sector;
+ sector.HighPart = 0;
+ ChsAddress chs;
+
+ byte mbrPartTable[TC_LB_SIZE - TC_MAX_MBR_BOOT_CODE_SIZE];
+ AcquireSectorBuffer();
+
+ for (int i = (selection == RestoreVolumeHeader ? TC_BOOT_VOLUME_HEADER_SECTOR : TC_MBR_SECTOR);
+ i < TC_BOOT_LOADER_AREA_SECTOR_COUNT; ++i)
+ {
+ sector.LowPart = i;
+
+ if (selection == RestoreOriginalSystemLoader)
+ sector.LowPart += TC_ORIG_BOOT_LOADER_BACKUP_SECTOR;
+ else if (selection == RestoreTrueCryptLoader)
+ sector.LowPart += TC_BOOT_LOADER_BACKUP_RESCUE_DISK_SECTOR;
+
+ // The backup medium may be a floppy-emulated bootable CD. The emulation may fail if LBA addressing is used.
+ // Therefore, only CHS addressing can be used.
+ LbaToChs (bootLoaderDriveGeometry, sector, chs);
+ sector.LowPart = i;
+
+ if (i == TC_MBR_SECTOR)
+ {
+ // Read current partition table
+ result = ReadSectors (SectorBuffer, TC_FIRST_BIOS_DRIVE, sector, 1);
+ if (result != BiosResultSuccess)
+ goto err;
+
+ memcpy (mbrPartTable, SectorBuffer + TC_MAX_MBR_BOOT_CODE_SIZE, sizeof (mbrPartTable));
+ }
+
+ result = ReadSectors (SectorBuffer, BootLoaderDrive, chs, 1);
+ if (result != BiosResultSuccess)
+ goto err;
+
+ if (i == TC_MBR_SECTOR)
+ {
+ // Preserve current partition table
+ memcpy (SectorBuffer + TC_MAX_MBR_BOOT_CODE_SIZE, mbrPartTable, sizeof (mbrPartTable));
+ }
+
+ // Volume header
+ if (i == TC_BOOT_VOLUME_HEADER_SECTOR)
+ {
+ if (selection == RestoreTrueCryptLoader)
+ continue;
+
+ if (selection == RestoreVolumeHeader)
+ {
+ while (true)
+ {
+ bool validHeaderPresent = false;
+ uint32 masterKeyScheduleCrc;
+
+ Password password;
+ byte exitKey = AskPassword (password);
+
+ if (exitKey != TC_BIOS_KEY_ENTER)
+ goto abort;
+
+ CRYPTO_INFO *cryptoInfo;
+
+ CopyMemory (SectorBuffer, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, TC_LB_SIZE);
+ ReleaseSectorBuffer();
+
+ // Restore volume header only if the current one cannot be used
+ if (OpenVolume (TC_FIRST_BIOS_DRIVE, password, &cryptoInfo, nullptr, false, true))
+ {
+ validHeaderPresent = true;
+ masterKeyScheduleCrc = GetCrc32 (cryptoInfo->ks, sizeof (cryptoInfo->ks));
+ crypto_close (cryptoInfo);
+ }
+
+ AcquireSectorBuffer();
+ CopyMemory (TC_BOOT_LOADER_BUFFER_SEGMENT, 0, SectorBuffer, TC_LB_SIZE);
+
+ if (ReadVolumeHeader (TRUE, (char *) SectorBuffer, &password, &cryptoInfo, nullptr) == 0)
+ {
+ if (validHeaderPresent)
+ {
+ if (masterKeyScheduleCrc == GetCrc32 (cryptoInfo->ks, sizeof (cryptoInfo->ks)))
+ {
+ Print ("Original header preserved.\r\n");
+ goto err;
+ }
+
+ Print ("WARNING: Drive 0 contains a valid header!\r\n");
+ }
+
+ crypto_close (cryptoInfo);
+ break;
+ }
+
+ Print ("Incorrect password.\r\n\r\n");
+ }
+ }
+ }
+
+ if (!writeConfirmed && !AskYesNo ("Modify drive 0"))
+ goto abort;
+ writeConfirmed = true;
+
+ if (WriteSectors (SectorBuffer, TC_FIRST_BIOS_DRIVE, sector, 1) != BiosResultSuccess)
+ goto err;
+ }
+done:
+ switch (selection)
+ {
+ case RestoreTrueCryptLoader:
+ Print ("TrueCrypt Boot Loader");
+ break;
+
+ case RestoreVolumeHeader:
+ Print ("Header");
+ break;
+
+ case RestoreOriginalSystemLoader:
+ Print ("System loader");
+ break;
+ }
+ Print (" restored.\r\n");
+
+err: GetKeyboardChar();
+abort: ReleaseSectorBuffer();
+ }
+}
+
+#endif // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+
+
+#ifndef DEBUG
+extern "C" void _acrtused () { } // Required by linker
+#endif
+
+
+void main ()
+{
+ __asm mov BootLoaderDrive, dl
+ __asm mov BootSectorFlags, dh
+
+#ifdef TC_BOOT_TRACING_ENABLED
+ InitDebugPort();
+#endif
+
+#ifdef TC_BOOT_STACK_CHECKING_ENABLED
+ InitStackChecker();
+#endif
+
+#ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+ ReadBootSectorUserConfiguration();
+#elif defined (TC_WINDOWS_BOOT_AES)
+ EnableHwEncryption (!(BootSectorFlags & TC_BOOT_CFG_FLAG_RESCUE_DISABLE_HW_ENCRYPTION));
+#endif
+
+ InitVideoMode();
+ InitScreen();
+
+ // Determine boot drive
+ BootDrive = BootLoaderDrive;
+ if (BootDrive < TC_FIRST_BIOS_DRIVE)
+ BootDrive = TC_FIRST_BIOS_DRIVE;
+
+ // Query boot drive geometry
+ if (GetDriveGeometry (BootDrive, BootDriveGeometry) != BiosResultSuccess)
+ {
+ BootDrive = TC_FIRST_BIOS_DRIVE;
+ if (GetDriveGeometry (BootDrive, BootDriveGeometry) != BiosResultSuccess)
+ {
+#ifdef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+ Print ("- Connect system drive to (SATA) port 1\r\n");
+#endif
+ GetKeyboardChar();
+ }
+ else
+ BootDriveGeometryValid = true;
+ }
+ else
+ BootDriveGeometryValid = true;
+
+#ifdef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+
+ // Check whether the user is not using the Rescue Disk to create a hidden system
+
+ if (ReadWriteMBR (false, BootDrive, true) == BiosResultSuccess
+ && *(uint32 *) (SectorBuffer + 6) == 0x65757254
+ && *(uint32 *) (SectorBuffer + 10) == 0x70797243
+ && (SectorBuffer[TC_BOOT_SECTOR_CONFIG_OFFSET] & TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE) != TC_HIDDEN_OS_CREATION_PHASE_NONE)
+ {
+ PrintError ("It appears you are creating a hidden OS.");
+ if (AskYesNo ("Is this correct"))
+ {
+ Print ("Please remove the Rescue Disk from the drive and restart.");
+ while (true);
+ }
+ }
+
+#endif // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+
+
+ // Main menu
+
+ while (true)
+ {
+ byte exitKey;
+ InitScreen();
+
+#ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+
+ // Hidden system setup
+ byte hiddenSystemCreationPhase = BootSectorFlags & TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE;
+
+ if (hiddenSystemCreationPhase != TC_HIDDEN_OS_CREATION_PHASE_NONE)
+ {
+ PreventNormalSystemBoot = true;
+ PrintMainMenu();
+
+ if (hiddenSystemCreationPhase == TC_HIDDEN_OS_CREATION_PHASE_CLONING)
+ {
+ if (CopySystemPartitionToHiddenVolume (BootDrive, exitKey))
+ {
+ BootSectorFlags = (BootSectorFlags & ~TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE) | TC_HIDDEN_OS_CREATION_PHASE_WIPING;
+ UpdateBootSectorConfiguration (BootLoaderDrive);
+ }
+ else if (exitKey == TC_BIOS_KEY_ESC)
+ goto bootMenu;
+ else
+ continue;
+ }
+ }
+ else
+ PrintMainMenu();
+
+ exitKey = BootEncryptedDrive();
+
+#else // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+
+ PrintMainMenu();
+ exitKey = BootEncryptedDrive();
+
+ if (exitKey == TC_MENU_KEY_REPAIR)
+ {
+ RepairMenu();
+ continue;
+ }
+
+#endif // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+
+bootMenu:
+ if (!PreventBootMenu)
+ BootMenu();
+ }
+}
diff --git a/src/Boot/Windows/BootMain.h b/src/Boot/Windows/BootMain.h
new file mode 100644
index 00000000..2cb4af87
--- /dev/null
+++ b/src/Boot/Windows/BootMain.h
@@ -0,0 +1,30 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ Governed by the TrueCrypt License 3.0 the full text of which is contained in
+ the file License.txt included in TrueCrypt binary and source code distribution
+ packages.
+*/
+
+#ifndef TC_HEADER_Boot_BootMain
+#define TC_HEADER_Boot_BootMain
+
+#include "TCdefs.h"
+#include "Platform.h"
+
+static byte AskPassword (Password &password);
+static int AskSelection (const char *options[], size_t optionCount);
+static bool AskYesNo (const char *message);
+static byte BootEncryptedDrive ();
+static void BootMenu ();
+static void ExecuteBootSector (byte drive, byte *sectorBuffer);
+static void InitScreen ();
+static bool IsMenuKey (byte scanCode);
+static bool MountVolume (byte drive, byte &exitKey);
+static bool OpenVolume (byte drive, Password &password, CRYPTO_INFO **cryptoInfo, uint32 *headerSaltCrc32 = nullptr, bool skipNormal = false, bool skipHidden = false);
+static void PrintMainMenu ();
+static void RepairMenu ();
+
+#define TC_MENU_KEY_REPAIR TC_BIOS_KEY_F8
+
+#endif // TC_HEADER_Boot_BootMain
diff --git a/src/Boot/Windows/BootMemory.cpp b/src/Boot/Windows/BootMemory.cpp
new file mode 100644
index 00000000..c9e11328
--- /dev/null
+++ b/src/Boot/Windows/BootMemory.cpp
@@ -0,0 +1,82 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ Governed by the TrueCrypt License 3.0 the full text of which is contained in
+ the file License.txt included in TrueCrypt binary and source code distribution
+ packages.
+*/
+
+#include "BootDefs.h"
+#include "BootMemory.h"
+
+static uint32 MemoryMapContValue;
+
+static bool GetMemoryMapEntry (BiosMemoryMapEntry &entry)
+{
+ static const uint32 function = 0x0000E820UL;
+ static const uint32 magic = 0x534D4150UL;
+ static const uint32 bufferSize = sizeof (BiosMemoryMapEntry);
+
+ bool carry = false;
+ uint32 resultMagic;
+ uint32 resultSize;
+
+ __asm
+ {
+ push es
+
+ lea di, function
+ TC_ASM_MOV_EAX_DI
+ lea di, MemoryMapContValue
+ TC_ASM_MOV_EBX_DI
+ lea di, bufferSize
+ TC_ASM_MOV_ECX_DI
+ lea di, magic
+ TC_ASM_MOV_EDX_DI
+ lea di, MemoryMapContValue
+ TC_ASM_MOV_DI_ECX
+
+ // Use alternative segment to prevent memory corruption caused by buggy BIOSes
+ push TC_BOOT_LOADER_ALT_SEGMENT
+ pop es
+ mov di, 0
+
+ int 0x15
+ jnc no_carry
+ mov carry, true
+ no_carry:
+
+ lea di, resultMagic
+ TC_ASM_MOV_DI_EAX
+ lea di, MemoryMapContValue
+ TC_ASM_MOV_DI_EBX
+ lea di, resultSize
+ TC_ASM_MOV_DI_ECX
+
+ pop es
+ }
+
+ CopyMemory (TC_BOOT_LOADER_ALT_SEGMENT, 0, &entry, sizeof (entry));
+
+ // BIOS may set CF at the end of the list
+ if (carry)
+ MemoryMapContValue = 0;
+
+ return resultMagic == magic && resultSize == bufferSize;
+}
+
+
+bool GetFirstBiosMemoryMapEntry (BiosMemoryMapEntry &entry)
+{
+ MemoryMapContValue = 0;
+ return GetMemoryMapEntry (entry);
+}
+
+
+bool GetNextBiosMemoryMapEntry (BiosMemoryMapEntry &entry)
+{
+ if (MemoryMapContValue == 0)
+ return false;
+
+ return GetMemoryMapEntry (entry);
+}
diff --git a/src/Boot/Windows/BootMemory.h b/src/Boot/Windows/BootMemory.h
new file mode 100644
index 00000000..06b53655
--- /dev/null
+++ b/src/Boot/Windows/BootMemory.h
@@ -0,0 +1,24 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ Governed by the TrueCrypt License 3.0 the full text of which is contained in
+ the file License.txt included in TrueCrypt binary and source code distribution
+ packages.
+*/
+
+#include "Platform.h"
+#include "Bios.h"
+
+#pragma pack(1)
+
+struct BiosMemoryMapEntry
+{
+ uint64 BaseAddress;
+ uint64 Length;
+ uint32 Type;
+};
+
+#pragma pack()
+
+bool GetFirstBiosMemoryMapEntry (BiosMemoryMapEntry &entry);
+bool GetNextBiosMemoryMapEntry (BiosMemoryMapEntry &entry);
diff --git a/src/Boot/Windows/BootSector.asm b/src/Boot/Windows/BootSector.asm
new file mode 100644
index 00000000..582505b4
--- /dev/null
+++ b/src/Boot/Windows/BootSector.asm
@@ -0,0 +1,237 @@
+;
+; Copyright (c) 2008-2009 TrueCrypt Developers Association. All rights reserved.
+;
+; Governed by the TrueCrypt License 3.0 the full text of which is contained in
+; the file License.txt included in TrueCrypt binary and source code distribution
+; packages.
+;
+
+.MODEL tiny
+.386
+_TEXT SEGMENT USE16
+
+INCLUDE BootDefs.i
+
+ORG 7C00h ; Standard boot sector offset
+
+start:
+ ; BIOS executes boot sector from 0:7C00 or 7C0:0000 (default CD boot loader address).
+ ; Far jump to the next instruction sets IP to the standard offset 7C00.
+ db 0EAh ; jmp 0:main
+ dw main, 0
+
+loader_name_msg:
+ db ' TrueCrypt Boot Loader', 13, 10, 0
+
+main:
+ cli
+ xor ax, ax
+ mov ds, ax
+ mov ss, ax
+ mov sp, 7C00h
+ sti
+
+ ; Display boot loader name
+ test byte ptr [start + TC_BOOT_SECTOR_USER_CONFIG_OFFSET], TC_BOOT_USER_CFG_FLAG_SILENT_MODE
+ jnz skip_loader_name_msg
+
+ lea si, loader_name_msg
+ call print
+skip_loader_name_msg:
+
+ ; Determine boot loader segment
+ mov ax, TC_BOOT_LOADER_SEGMENT
+
+ ; Check available memory
+ cmp word ptr [ds:413h], TC_BOOT_LOADER_SEGMENT / 1024 * 16 + TC_BOOT_MEMORY_REQUIRED
+ jge memory_ok
+
+ mov ax, TC_BOOT_LOADER_SEGMENT_LOW
+
+ cmp word ptr [ds:413h], TC_BOOT_LOADER_SEGMENT_LOW / 1024 * 16 + TC_BOOT_MEMORY_REQUIRED
+ jge memory_ok
+
+ ; Insufficient memory
+ mov ax, TC_BOOT_LOADER_LOWMEM_SEGMENT
+
+memory_ok:
+ mov es, ax
+
+ ; Clear BSS section
+ xor al, al
+ mov di, TC_COM_EXECUTABLE_OFFSET
+ mov cx, TC_BOOT_MEMORY_REQUIRED * 1024 - TC_COM_EXECUTABLE_OFFSET - 1
+ cld
+ rep stosb
+
+ mov ax, es
+ sub ax, TC_BOOT_LOADER_DECOMPRESSOR_MEMORY_SIZE / 16 ; Decompressor segment
+ mov es, ax
+
+ ; Load decompressor
+ mov cl, TC_BOOT_LOADER_DECOMPRESSOR_START_SECTOR
+retry_backup:
+ mov al, TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT
+ mov bx, TC_COM_EXECUTABLE_OFFSET
+ call read_sectors
+
+ ; Decompressor checksum
+ xor ebx, ebx
+ mov si, TC_COM_EXECUTABLE_OFFSET
+ mov cx, TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT * TC_LB_SIZE
+ call checksum
+ push ebx
+
+ ; Load compressed boot loader
+ mov bx, TC_BOOT_LOADER_COMPRESSED_BUFFER_OFFSET
+ mov cl, TC_BOOT_LOADER_START_SECTOR
+ mov al, TC_MAX_BOOT_LOADER_SECTOR_COUNT
+
+ test backup_loader_used, 1
+ jz non_backup
+ mov al, TC_BOOT_LOADER_BACKUP_SECTOR_COUNT - TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT
+ mov cl, TC_BOOT_LOADER_START_SECTOR + TC_BOOT_LOADER_BACKUP_SECTOR_COUNT
+
+non_backup:
+ call read_sectors
+
+ ; Boot loader checksum
+ pop ebx
+ mov si, TC_BOOT_LOADER_COMPRESSED_BUFFER_OFFSET
+ mov cx, word ptr [start + TC_BOOT_SECTOR_LOADER_LENGTH_OFFSET]
+ call checksum
+
+ ; Verify checksum
+ cmp ebx, dword ptr [start + TC_BOOT_SECTOR_LOADER_CHECKSUM_OFFSET]
+ je checksum_ok
+
+ ; Checksum incorrect - try using backup if available
+ test backup_loader_used, 1
+ jnz loader_damaged
+
+ mov backup_loader_used, 1
+ mov cl, TC_BOOT_LOADER_DECOMPRESSOR_START_SECTOR + TC_BOOT_LOADER_BACKUP_SECTOR_COUNT
+
+ test TC_BOOT_CFG_FLAG_BACKUP_LOADER_AVAILABLE, byte ptr [start + TC_BOOT_SECTOR_CONFIG_OFFSET]
+ jnz retry_backup
+
+loader_damaged:
+ lea si, loader_damaged_msg
+ call print
+ lea si, loader_name_msg
+ call print
+ jmp $
+checksum_ok:
+
+ ; Set up decompressor segment
+ mov ax, es
+ mov ds, ax
+ cli
+ mov ss, ax
+ mov sp, TC_BOOT_LOADER_DECOMPRESSOR_MEMORY_SIZE
+ sti
+
+ push dx
+
+ ; Decompress boot loader
+ push TC_BOOT_LOADER_COMPRESSED_BUFFER_OFFSET + TC_GZIP_HEADER_SIZE ; Compressed data
+ push TC_MAX_BOOT_LOADER_DECOMPRESSED_SIZE ; Output buffer size
+ push TC_BOOT_LOADER_DECOMPRESSOR_MEMORY_SIZE + TC_COM_EXECUTABLE_OFFSET ; Output buffer
+
+ push cs
+ push decompressor_ret
+ push es
+ push TC_COM_EXECUTABLE_OFFSET
+ retf
+decompressor_ret:
+
+ add sp, 6
+ pop dx
+
+ ; Restore boot sector segment
+ push cs
+ pop ds
+
+ ; Check decompression result
+ test ax, ax
+ jz decompression_ok
+
+ lea si, loader_damaged_msg
+ call print
+ jmp $
+decompression_ok:
+
+ ; DH = boot sector flags
+ mov dh, byte ptr [start + TC_BOOT_SECTOR_CONFIG_OFFSET]
+
+ ; Set up boot loader segment
+ mov ax, es
+ add ax, TC_BOOT_LOADER_DECOMPRESSOR_MEMORY_SIZE / 16
+ mov es, ax
+ mov ds, ax
+ cli
+ mov ss, ax
+ mov sp, TC_BOOT_LOADER_STACK_TOP
+ sti
+
+ ; Execute boot loader
+ push es
+ push TC_COM_EXECUTABLE_OFFSET
+ retf
+
+ ; Print string
+print:
+ xor bx, bx
+ mov ah, 0eh
+ cld
+
+@@: lodsb
+ test al, al
+ jz print_end
+
+ int 10h
+ jmp @B
+
+print_end:
+ ret
+
+ ; Read sectors of the first cylinder
+read_sectors:
+ mov ch, 0 ; Cylinder
+ mov dh, 0 ; Head
+ ; DL = drive number passed from BIOS
+ mov ah, 2
+ int 13h
+ jnc read_ok
+
+ lea si, disk_error_msg
+ call print
+read_ok:
+ ret
+
+ ; Calculate checksum
+checksum:
+ push ds
+ push es
+ pop ds
+ xor eax, eax
+ cld
+
+@@: lodsb
+ add ebx, eax
+ rol ebx, 1
+ loop @B
+
+ pop ds
+ ret
+
+backup_loader_used db 0
+
+disk_error_msg db 'Disk error', 13, 10, 7, 0
+loader_damaged_msg db 7, 'Loader damaged! Use Rescue Disk: Repair Options > Restore', 0
+
+ORG 7C00h + 510
+ dw 0AA55h ; Boot sector signature
+
+_TEXT ENDS
+END start
diff --git a/src/Boot/Windows/BootStrings.h b/src/Boot/Windows/BootStrings.h
new file mode 100644
index 00000000..8b6bbbd9
--- /dev/null
+++ b/src/Boot/Windows/BootStrings.h
@@ -0,0 +1,16 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ Governed by the TrueCrypt License 3.0 the full text of which is contained in
+ the file License.txt included in TrueCrypt binary and source code distribution
+ packages.
+*/
+
+#ifndef TC_HEADER_Boot_BootStrings
+#define TC_HEADER_Boot_BootStrings
+
+#define TC_BOOT_STR_ERROR "Error: "
+#define TC_BOOT_STR_NO_BOOT_PARTITION "No bootable partition found"
+#define TC_BOOT_STR_UPGRADE_BIOS "- Upgrade BIOS\r\n- Use a different motherboard model/brand\r\n"
+
+#endif // TC_HEADER_Boot_BootStrings
diff --git a/src/Boot/Windows/Decompressor.c b/src/Boot/Windows/Decompressor.c
new file mode 100644
index 00000000..efdbed91
--- /dev/null
+++ b/src/Boot/Windows/Decompressor.c
@@ -0,0 +1,436 @@
+/*
+ puff.c
+ Copyright (C) 2002-2004 Mark Adler, all rights reserved
+ version 1.8, 9 Jan 2004
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the author be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Mark Adler madler@alumni.caltech.edu
+*/
+
+/* Adapted for TrueCrypt */
+
+
+#define local static /* for local function definitions */
+#define NIL ((unsigned char *)0) /* for no output option */
+
+/*
+ * Maximums for allocations and loops. It is not useful to change these --
+ * they are fixed by the deflate format.
+ */
+#define MAXBITS 15 /* maximum bits in a code */
+#define MAXLCODES 286 /* maximum number of literal/length codes */
+#define MAXDCODES 30 /* maximum number of distance codes */
+#define MAXCODES (MAXLCODES+MAXDCODES) /* maximum codes lengths to read */
+#define FIXLCODES 288 /* number of fixed literal/length codes */
+
+/* input and output state */
+struct state {
+ /* output state */
+ unsigned char *out; /* output buffer */
+ unsigned int outlen; /* available space at out */
+ unsigned int outcnt; /* bytes written to out so far */
+
+ /* input state */
+ unsigned char *in; /* input buffer */
+ unsigned int incnt; /* bytes read so far */
+ int bitbuf; /* bit buffer */
+ int bitcnt; /* number of bits in bit buffer */
+};
+
+
+local int bits(struct state *s, int need)
+{
+ long val; /* bit accumulator (can use up to 20 bits) */
+
+ /* load at least need bits into val */
+ val = s->bitbuf;
+ while (s->bitcnt < need) {
+ val |= (long)(s->in[s->incnt++]) << s->bitcnt; /* load eight bits */
+ s->bitcnt += 8;
+ }
+
+ /* drop need bits and update buffer, always zero to seven bits left */
+ s->bitbuf = (int)(val >> need);
+ s->bitcnt -= need;
+
+ /* return need bits, zeroing the bits above that */
+ return (int)(val & ((1L << need) - 1));
+}
+
+
+local int stored(struct state *s)
+{
+ unsigned len; /* length of stored block */
+
+ /* discard leftover bits from current byte (assumes s->bitcnt < 8) */
+ s->bitbuf = 0;
+ s->bitcnt = 0;
+
+ /* get length and check against its one's complement */
+ len = s->in[s->incnt++];
+ len |= s->in[s->incnt++] << 8;
+ if (s->in[s->incnt++] != (~len & 0xff) ||
+ s->in[s->incnt++] != ((~len >> 8) & 0xff))
+ return -2; /* didn't match complement! */
+
+ /* copy len bytes from in to out */
+ if (s->out != NIL) {
+ if (s->outcnt + len > s->outlen)
+ return 1; /* not enough output space */
+ while (len--)
+ s->out[s->outcnt++] = s->in[s->incnt++];
+ }
+ else { /* just scanning */
+ s->outcnt += len;
+ s->incnt += len;
+ }
+
+ /* done with a valid stored block */
+ return 0;
+}
+
+
+struct huffman {
+ short *count; /* number of symbols of each length */
+ short *symbol; /* canonically ordered symbols */
+};
+
+
+#ifdef SLOW
+local int decode(struct state *s, struct huffman *h)
+{
+ int len; /* current number of bits in code */
+ int code; /* len bits being decoded */
+ int first; /* first code of length len */
+ int count; /* number of codes of length len */
+ int index; /* index of first code of length len in symbol table */
+
+ code = first = index = 0;
+ for (len = 1; len <= MAXBITS; len++) {
+ code |= bits(s, 1); /* get next bit */
+ count = h->count[len];
+ if (code < first + count) /* if length len, return symbol */
+ return h->symbol[index + (code - first)];
+ index += count; /* else update for next length */
+ first += count;
+ first <<= 1;
+ code <<= 1;
+ }
+ return -9; /* ran out of codes */
+}
+
+/*
+ * A faster version of decode() for real applications of this code. It's not
+ * as readable, but it makes puff() twice as fast. And it only makes the code
+ * a few percent larger.
+ */
+#else /* !SLOW */
+local int decode(struct state *s, struct huffman *h)
+{
+ int len; /* current number of bits in code */
+ int code; /* len bits being decoded */
+ int first; /* first code of length len */
+ int count; /* number of codes of length len */
+ int index; /* index of first code of length len in symbol table */
+ int bitbuf; /* bits from stream */
+ int left; /* bits left in next or left to process */
+ short *next; /* next number of codes */
+
+ bitbuf = s->bitbuf;
+ left = s->bitcnt;
+ code = first = index = 0;
+ len = 1;
+ next = h->count + 1;
+ while (1) {
+ while (left--) {
+ code |= bitbuf & 1;
+ bitbuf >>= 1;
+ count = *next++;
+ if (code < first + count) { /* if length len, return symbol */
+ s->bitbuf = bitbuf;
+ s->bitcnt = (s->bitcnt - len) & 7;
+ return h->symbol[index + (code - first)];
+ }
+ index += count; /* else update for next length */
+ first += count;
+ first <<= 1;
+ code <<= 1;
+ len++;
+ }
+ left = (MAXBITS+1) - len;
+ if (left == 0) break;
+ bitbuf = s->in[s->incnt++];
+ if (left > 8) left = 8;
+ }
+ return -9; /* ran out of codes */
+}
+#endif /* SLOW */
+
+
+local int construct(struct huffman *h, short *length, int n)
+{
+ int symbol; /* current symbol when stepping through length[] */
+ int len; /* current length when stepping through h->count[] */
+ int left; /* number of possible codes left of current length */
+ short offs[MAXBITS+1]; /* offsets in symbol table for each length */
+
+ /* count number of codes of each length */
+ for (len = 0; len <= MAXBITS; len++)
+ h->count[len] = 0;
+ for (symbol = 0; symbol < n; symbol++)
+ (h->count[length[symbol]])++; /* assumes lengths are within bounds */
+ if (h->count[0] == n) /* no codes! */
+ return 0; /* complete, but decode() will fail */
+
+ /* check for an over-subscribed or incomplete set of lengths */
+ left = 1; /* one possible code of zero length */
+ for (len = 1; len <= MAXBITS; len++) {
+ left <<= 1; /* one more bit, double codes left */
+ left -= h->count[len]; /* deduct count from possible codes */
+ if (left < 0) return left; /* over-subscribed--return negative */
+ } /* left > 0 means incomplete */
+
+ /* generate offsets into symbol table for each length for sorting */
+ offs[1] = 0;
+ for (len = 1; len < MAXBITS; len++)
+ offs[len + 1] = offs[len] + h->count[len];
+
+ /*
+ * put symbols in table sorted by length, by symbol order within each
+ * length
+ */
+ for (symbol = 0; symbol < n; symbol++)
+ if (length[symbol] != 0)
+ h->symbol[offs[length[symbol]]++] = symbol;
+
+ /* return zero for complete set, positive for incomplete set */
+ return left;
+}
+
+
+local int codes(struct state *s,
+ struct huffman *lencode,
+ struct huffman *distcode)
+{
+ int symbol; /* decoded symbol */
+ int len; /* length for copy */
+ unsigned dist; /* distance for copy */
+ static const short lens[29] = { /* Size base for length codes 257..285 */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258};
+ static const short lext[29] = { /* Extra bits for length codes 257..285 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0};
+ static const short dists[30] = { /* Offset base for distance codes 0..29 */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577};
+ static const short dext[30] = { /* Extra bits for distance codes 0..29 */
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13};
+
+ /* decode literals and length/distance pairs */
+ do {
+ symbol = decode(s, lencode);
+ if (symbol < 0) return symbol; /* invalid symbol */
+ if (symbol < 256) { /* literal: symbol is the byte */
+ /* write out the literal */
+ if (s->out != NIL) {
+ if (s->outcnt == s->outlen) return 1;
+ s->out[s->outcnt] = symbol;
+ }
+ s->outcnt++;
+ }
+ else if (symbol > 256) { /* length */
+ /* get and compute length */
+ symbol -= 257;
+ if (symbol >= 29) return -9; /* invalid fixed code */
+ len = lens[symbol] + bits(s, lext[symbol]);
+
+ /* get and check distance */
+ symbol = decode(s, distcode);
+ if (symbol < 0) return symbol; /* invalid symbol */
+ dist = dists[symbol] + bits(s, dext[symbol]);
+ if (dist > s->outcnt)
+ return -10; /* distance too far back */
+
+ /* copy length bytes from distance bytes back */
+ if (s->out != NIL) {
+ if (s->outcnt + len > s->outlen) return 1;
+ while (len--) {
+ s->out[s->outcnt] = s->out[s->outcnt - dist];
+ s->outcnt++;
+ }
+ }
+ else
+ s->outcnt += len;
+ }
+ } while (symbol != 256); /* end of block symbol */
+
+ /* done with a valid fixed or dynamic block */
+ return 0;
+}
+
+
+local int fixed(struct state *s)
+{
+ static int virgin = 1;
+ static short lencnt[MAXBITS+1], lensym[FIXLCODES];
+ static short distcnt[MAXBITS+1], distsym[MAXDCODES];
+ static struct huffman lencode = {lencnt, lensym};
+ static struct huffman distcode = {distcnt, distsym};
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ int symbol;
+ short lengths[FIXLCODES];
+
+ /* literal/length table */
+ for (symbol = 0; symbol < 144; symbol++)
+ lengths[symbol] = 8;
+ for (; symbol < 256; symbol++)
+ lengths[symbol] = 9;
+ for (; symbol < 280; symbol++)
+ lengths[symbol] = 7;
+ for (; symbol < FIXLCODES; symbol++)
+ lengths[symbol] = 8;
+ construct(&lencode, lengths, FIXLCODES);
+
+ /* distance table */
+ for (symbol = 0; symbol < MAXDCODES; symbol++)
+ lengths[symbol] = 5;
+ construct(&distcode, lengths, MAXDCODES);
+
+ /* do this just once */
+ virgin = 0;
+ }
+
+ /* decode data until end-of-block code */
+ return codes(s, &lencode, &distcode);
+}
+
+
+local int dynamic(struct state *s)
+{
+ int nlen, ndist, ncode; /* number of lengths in descriptor */
+ int index; /* index of lengths[] */
+ int err; /* construct() return value */
+ short lengths[MAXCODES]; /* descriptor code lengths */
+ short lencnt[MAXBITS+1], lensym[MAXLCODES]; /* lencode memory */
+ short distcnt[MAXBITS+1], distsym[MAXDCODES]; /* distcode memory */
+ struct huffman lencode = {lencnt, lensym}; /* length code */
+ struct huffman distcode = {distcnt, distsym}; /* distance code */
+ static const short order[19] = /* permutation of code length codes */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ /* get number of lengths in each table, check lengths */
+ nlen = bits(s, 5) + 257;
+ ndist = bits(s, 5) + 1;
+ ncode = bits(s, 4) + 4;
+ if (nlen > MAXLCODES || ndist > MAXDCODES)
+ return -3; /* bad counts */
+
+ /* read code length code lengths (really), missing lengths are zero */
+ for (index = 0; index < ncode; index++)
+ lengths[order[index]] = bits(s, 3);
+ for (; index < 19; index++)
+ lengths[order[index]] = 0;
+
+ /* build huffman table for code lengths codes (use lencode temporarily) */
+ err = construct(&lencode, lengths, 19);
+ if (err != 0) return -4; /* require complete code set here */
+
+ /* read length/literal and distance code length tables */
+ index = 0;
+ while (index < nlen + ndist) {
+ int symbol; /* decoded value */
+ int len; /* last length to repeat */
+
+ symbol = decode(s, &lencode);
+ if (symbol < 16) /* length in 0..15 */
+ lengths[index++] = symbol;
+ else { /* repeat instruction */
+ len = 0; /* assume repeating zeros */
+ if (symbol == 16) { /* repeat last length 3..6 times */
+ if (index == 0) return -5; /* no last length! */
+ len = lengths[index - 1]; /* last length */
+ symbol = 3 + bits(s, 2);
+ }
+ else if (symbol == 17) /* repeat zero 3..10 times */
+ symbol = 3 + bits(s, 3);
+ else /* == 18, repeat zero 11..138 times */
+ symbol = 11 + bits(s, 7);
+ if (index + symbol > nlen + ndist)
+ return -6; /* too many lengths! */
+ while (symbol--) /* repeat last or zero symbol times */
+ lengths[index++] = len;
+ }
+ }
+
+ /* build huffman table for literal/length codes */
+ err = construct(&lencode, lengths, nlen);
+ if (err < 0 || (err > 0 && nlen - lencode.count[0] != 1))
+ return -7; /* only allow incomplete codes if just one code */
+
+ /* build huffman table for distance codes */
+ err = construct(&distcode, lengths + nlen, ndist);
+ if (err < 0 || (err > 0 && ndist - distcode.count[0] != 1))
+ return -8; /* only allow incomplete codes if just one code */
+
+ /* decode data until end-of-block code */
+ return codes(s, &lencode, &distcode);
+}
+
+
+void _acrtused () { }
+
+// Decompress deflated data
+int far main (
+ unsigned char *dest, /* pointer to destination pointer */
+ unsigned int destlen, /* amount of output space */
+ unsigned char *source) /* pointer to source data pointer */
+{
+ struct state s; /* input/output state */
+ int last, type; /* block information */
+ int err; /* return value */
+
+ /* initialize output state */
+ s.out = dest;
+ s.outlen = destlen; /* ignored if dest is NIL */
+ s.outcnt = 0;
+
+ /* initialize input state */
+ s.in = source;
+ s.incnt = 0;
+ s.bitbuf = 0;
+ s.bitcnt = 0;
+
+ /* process blocks until last block or error */
+ do {
+ last = bits(&s, 1); /* one if last block */
+ type = bits(&s, 2); /* block type 0..3 */
+ err = type == 0 ? stored(&s) :
+ (type == 1 ? fixed(&s) :
+ (type == 2 ? dynamic(&s) :
+ -1)); /* type == 3, invalid */
+ if (err != 0) break; /* return with error */
+ } while (!last);
+
+ return err;
+}
diff --git a/src/Boot/Windows/IntFilter.cpp b/src/Boot/Windows/IntFilter.cpp
new file mode 100644
index 00000000..cd0ea574
--- /dev/null
+++ b/src/Boot/Windows/IntFilter.cpp
@@ -0,0 +1,641 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ Governed by the TrueCrypt License 3.0 the full text of which is contained in
+ the file License.txt included in TrueCrypt binary and source code distribution
+ packages.
+*/
+
+#include "Platform.h"
+#include "BootMemory.h"
+#include "BootConfig.h"
+#include "BootConsoleIo.h"
+#include "BootDebug.h"
+#include "BootDefs.h"
+#include "BootDiskIo.h"
+#include "BootEncryptedIo.h"
+#include "BootStrings.h"
+#include "IntFilter.h"
+
+static uint32 OriginalInt13Handler;
+static uint32 OriginalInt15Handler;
+
+static Registers IntRegisters;
+
+
+bool Int13Filter ()
+{
+ CheckStack();
+
+ Registers regs;
+ memcpy (&regs, &IntRegisters, sizeof (regs));
+ __asm sti
+
+ static int ReEntryCount = -1;
+ ++ReEntryCount;
+
+ byte function = (byte) (regs.AX >> 8);
+
+#ifdef TC_TRACE_INT13
+ DisableScreenOutput();
+
+ PrintHex (function);
+
+ Print (" EN:"); Print (ReEntryCount);
+ Print (" SS:"); PrintHex (regs.SS);
+
+ uint16 spdbg;
+ __asm mov spdbg, sp
+ PrintChar (' ');
+ PrintHex (spdbg);
+ PrintChar ('<'); PrintHex (TC_BOOT_LOADER_STACK_TOP);
+
+#endif
+
+ bool passOriginalRequest = true;
+
+ switch (function)
+ {
+ case 0x2: // Read sectors
+ case 0x3: // Write sectors
+ {
+ byte drive = (byte) regs.DX;
+
+ ChsAddress chs;
+ chs.Cylinder = ((regs.CX << 2) & 0x300) | (regs.CX >> 8);
+ chs.Head = regs.DX >> 8;
+ chs.Sector = regs.CX & 0x3f;
+
+ byte sectorCount = (byte) regs.AX;
+
+#ifdef TC_TRACE_INT13
+ PrintVal (": Drive", drive - TC_FIRST_BIOS_DRIVE, false);
+ Print (" Chs: "); Print (chs);
+#endif
+
+ uint64 sector;
+ if (drive == BootDrive)
+ {
+ if (!BootDriveGeometryValid)
+ TC_THROW_FATAL_EXCEPTION;
+
+ ChsToLba (BootDriveGeometry, chs, sector);
+#ifdef TC_TRACE_INT13
+ PrintVal (" Sec", sector.LowPart, false);
+#endif
+ }
+
+#ifdef TC_TRACE_INT13
+ PrintVal (" Count", sectorCount, false);
+ Print (" Buf: "); PrintHex (regs.ES); PrintChar (':'); PrintHex (regs.BX);
+ PrintEndl();
+#endif
+
+ if (ReEntryCount == 0 && drive == EncryptedVirtualPartition.Drive)
+ {
+ BiosResult result;
+
+ if (function == 0x3)
+ result = WriteEncryptedSectors (regs.ES, regs.BX, drive, sector, sectorCount);
+ else
+ result = ReadEncryptedSectors (regs.ES, regs.BX, drive, sector, sectorCount);
+
+ __asm cli
+
+ memcpy (&IntRegisters, &regs, sizeof (regs));
+ IntRegisters.AX = (uint16) result << 8;
+
+ if (result == BiosResultSuccess)
+ {
+ IntRegisters.AX |= sectorCount;
+ IntRegisters.Flags &= ~TC_X86_CARRY_FLAG;
+ }
+ else
+ IntRegisters.Flags |= TC_X86_CARRY_FLAG;
+
+ passOriginalRequest = false;
+ }
+ }
+ break;
+
+ case 0x42: // Read sectors LBA
+ case 0x43: // Write sectors LBA
+ {
+ byte drive = (byte) regs.DX;
+
+ BiosLbaPacket lba;
+ CopyMemory (regs.DS, regs.SI, (byte *) &lba, sizeof (lba));
+
+#ifdef TC_TRACE_INT13
+ PrintVal (": Drive", drive - TC_FIRST_BIOS_DRIVE, false);
+ PrintVal (" Sec", lba.Sector.LowPart, false);
+ PrintVal (" Count", lba.SectorCount, false);
+ PrintVal (" Buf", lba.Buffer, false, true);
+ PrintEndl();
+#endif
+
+ if (ReEntryCount == 0 && drive == EncryptedVirtualPartition.Drive)
+ {
+ BiosResult result;
+
+ uint16 segment = (uint16) (lba.Buffer >> 16);
+ uint16 offset = (uint16) lba.Buffer;
+
+ if (function == 0x43)
+ result = WriteEncryptedSectors (segment, offset, drive, lba.Sector, lba.SectorCount);
+ else
+ result = ReadEncryptedSectors (segment, offset, drive, lba.Sector, lba.SectorCount);
+
+ __asm cli
+
+ memcpy (&IntRegisters, &regs, sizeof (regs));
+ IntRegisters.AX = (IntRegisters.AX & 0xff) | ((uint16) result << 8);
+
+ if (result == BiosResultSuccess)
+ IntRegisters.Flags &= ~TC_X86_CARRY_FLAG;
+ else
+ IntRegisters.Flags |= TC_X86_CARRY_FLAG;
+
+ passOriginalRequest = false;
+ }
+ }
+ break;
+
+ default:
+#ifdef TC_TRACE_INT13
+ PrintEndl();
+#endif
+ break;
+ }
+
+#ifdef TC_TRACE_INT13
+ EnableScreenOutput();
+#endif
+ --ReEntryCount;
+
+ return passOriginalRequest;
+}
+
+
+#define TC_MAX_MEMORY_MAP_SIZE 80
+
+BiosMemoryMapEntry BiosMemoryMap[TC_MAX_MEMORY_MAP_SIZE];
+static size_t BiosMemoryMapSize;
+
+
+static void CreateBootLoaderMemoryMapEntry (BiosMemoryMapEntry *newMapEntry, uint32 bootLoaderStart)
+{
+ newMapEntry->Type = 0x2;
+ newMapEntry->BaseAddress.HighPart = 0;
+ newMapEntry->BaseAddress.LowPart = bootLoaderStart;
+ newMapEntry->Length.HighPart = 0;
+ newMapEntry->Length.LowPart = TC_BOOT_MEMORY_REQUIRED * 1024UL;
+}
+
+
+static bool CreateNewBiosMemoryMap ()
+{
+ // Create a new BIOS memory map presenting the memory area of the loader as reserved
+
+ BiosMemoryMapSize = 0;
+ BiosMemoryMapEntry entry;
+ BiosMemoryMapEntry *newMapEntry = BiosMemoryMap;
+
+ const BiosMemoryMapEntry *mapEnd = BiosMemoryMap + TC_MAX_MEMORY_MAP_SIZE;
+
+ uint64 bootLoaderStart;
+ bootLoaderStart.HighPart = 0;
+
+ uint16 codeSeg;
+ __asm mov codeSeg, cs
+ bootLoaderStart.LowPart = GetLinearAddress (codeSeg, 0);
+
+ uint64 bootLoaderEnd;
+ bootLoaderEnd.HighPart = 0;
+ bootLoaderEnd.LowPart = bootLoaderStart.LowPart + TC_BOOT_MEMORY_REQUIRED * 1024UL;
+
+ bool loaderEntryInserted = false;
+
+ if (GetFirstBiosMemoryMapEntry (entry))
+ {
+ do
+ {
+ uint64 entryEnd = entry.BaseAddress + entry.Length;
+
+ if (entry.Type == 0x1 && RegionsIntersect (bootLoaderStart, TC_BOOT_MEMORY_REQUIRED * 1024UL, entry.BaseAddress, entryEnd - 1))
+ {
+ // Free map entry covers the boot loader area
+
+ if (entry.BaseAddress < bootLoaderStart)
+ {
+ // Create free entry below the boot loader area
+ if (newMapEntry >= mapEnd)
+ goto mapOverflow;
+
+ *newMapEntry = entry;
+ newMapEntry->Length = bootLoaderStart - entry.BaseAddress;
+ ++newMapEntry;
+ }
+
+ if (!loaderEntryInserted)
+ {
+ // Create reserved entry for the boot loader if it has not been done yet
+ if (newMapEntry >= mapEnd)
+ goto mapOverflow;
+
+ CreateBootLoaderMemoryMapEntry (newMapEntry, bootLoaderStart.LowPart);
+ ++newMapEntry;
+ loaderEntryInserted = true;
+ }
+
+ if (bootLoaderEnd < entryEnd)
+ {
+ // Create free entry above the boot loader area
+ if (newMapEntry >= mapEnd)
+ goto mapOverflow;
+
+ newMapEntry->Type = 0x1;
+ newMapEntry->BaseAddress = bootLoaderEnd;
+ newMapEntry->Length = entryEnd - bootLoaderEnd;
+ ++newMapEntry;
+ }
+ }
+ else
+ {
+ if (newMapEntry >= mapEnd)
+ goto mapOverflow;
+
+ if (!loaderEntryInserted && entry.BaseAddress > bootLoaderStart)
+ {
+ // Create reserved entry for the boot loader if it has not been done yet
+ CreateBootLoaderMemoryMapEntry (newMapEntry, bootLoaderStart.LowPart);
+ ++newMapEntry;
+ loaderEntryInserted = true;
+ }
+
+ // Copy map entry
+ *newMapEntry++ = entry;
+ }
+
+ } while (GetNextBiosMemoryMapEntry (entry));
+ }
+
+ BiosMemoryMapSize = newMapEntry - BiosMemoryMap;
+ return true;
+
+mapOverflow:
+ size_t overSize = 0;
+ while (GetNextBiosMemoryMapEntry (entry))
+ {
+ ++overSize;
+ }
+
+ PrintErrorNoEndl ("MMP:");
+ Print (overSize);
+ PrintEndl();
+
+ return false;
+}
+
+
+bool Int15Filter ()
+{
+ CheckStack();
+
+#ifdef TC_TRACE_INT15
+ DisableScreenOutput();
+
+ Print ("15-");
+ PrintHex (IntRegisters.AX);
+
+ Print (" SS:"); PrintHex (IntRegisters.SS);
+
+ uint16 spdbg;
+ __asm mov spdbg, sp
+ PrintChar (' ');
+ PrintHex (spdbg);
+ PrintChar ('<'); PrintHex (TC_BOOT_LOADER_STACK_TOP);
+
+ Print (" EAX:"); PrintHex (IntRegisters.EAX);
+ Print (" EBX:"); PrintHex (IntRegisters.EBX);
+ Print (" ECX:"); PrintHex (IntRegisters.ECX);
+ Print (" EDX:"); PrintHex (IntRegisters.EDX);
+ Print (" DI:"); PrintHex (IntRegisters.DI);
+ PrintEndl();
+
+#endif
+
+ if (IntRegisters.EBX >= BiosMemoryMapSize)
+ {
+ IntRegisters.Flags |= TC_X86_CARRY_FLAG;
+ IntRegisters.EBX = 0;
+ IntRegisters.AX = -1;
+ }
+ else
+ {
+ CopyMemory ((byte *) &BiosMemoryMap[IntRegisters.EBX], IntRegisters.ES, IntRegisters.DI, sizeof (BiosMemoryMap[0]));
+
+ IntRegisters.Flags &= ~TC_X86_CARRY_FLAG;
+ IntRegisters.EAX = 0x534D4150UL;
+
+ ++IntRegisters.EBX;
+ if (IntRegisters.EBX >= BiosMemoryMapSize)
+ IntRegisters.EBX = 0;
+
+ IntRegisters.ECX = sizeof (BiosMemoryMap[0]);
+ }
+
+ if (IntRegisters.EBX == 0 && !(BootSectorFlags & TC_BOOT_CFG_FLAG_WINDOWS_VISTA_OR_LATER))
+ {
+ // Uninstall filter when the modified map has been issued three times to prevent
+ // problems with hardware drivers on some notebooks running Windows XP.
+
+ static int CompleteMapIssueCount = 0;
+ if (++CompleteMapIssueCount >= 3)
+ {
+ __asm
+ {
+ cli
+ push es
+
+ lea si, OriginalInt15Handler
+ xor ax, ax
+ mov es, ax
+ mov di, 0x15 * 4
+
+ mov ax, [si]
+ mov es:[di], ax
+ mov ax, [si + 2]
+ mov es:[di + 2], ax
+
+ pop es
+ sti
+ }
+ }
+ }
+
+#ifdef TC_TRACE_INT15
+ BiosMemoryMapEntry entry;
+ CopyMemory (IntRegisters.ES, IntRegisters.DI, (byte *) &entry, sizeof (entry));
+ PrintHex (entry.Type); PrintChar (' ');
+ PrintHex (entry.BaseAddress); PrintChar (' ');
+ PrintHex (entry.Length); PrintChar (' ');
+ PrintHex (entry.BaseAddress + entry.Length); PrintEndl();
+
+ Print ("EAX:"); PrintHex (IntRegisters.EAX);
+ Print (" EBX:"); PrintHex (IntRegisters.EBX);
+ Print (" ECX:"); PrintHex (IntRegisters.ECX);
+ Print (" EDX:"); PrintHex (IntRegisters.EDX);
+ Print (" DI:"); PrintHex (IntRegisters.DI);
+ Print (" FL:"); PrintHex (IntRegisters.Flags);
+ PrintEndl (2);
+#endif
+
+#ifdef TC_TRACE_INT15
+ EnableScreenOutput();
+#endif
+ return false;
+}
+
+
+void IntFilterEntry ()
+{
+ // No automatic variables should be used in this scope as SS may change
+ static uint16 OrigStackPointer;
+ static uint16 OrigStackSegment;
+
+ __asm
+ {
+ pushf
+ pushad
+
+ cli
+ mov cs:IntRegisters.DI, di
+
+ lea di, cs:IntRegisters.EAX
+ TC_ASM_EMIT4 (66,2E,89,05) // mov [cs:di], eax
+ lea di, cs:IntRegisters.EBX
+ TC_ASM_EMIT4 (66,2E,89,1D) // mov [cs:di], ebx
+ lea di, cs:IntRegisters.ECX
+ TC_ASM_EMIT4 (66,2E,89,0D) // mov [cs:di], ecx
+ lea di, cs:IntRegisters.EDX
+ TC_ASM_EMIT4 (66,2E,89,15) // mov [cs:di], edx
+
+ mov ax, [bp + 8]
+ mov cs:IntRegisters.Flags, ax
+
+ mov cs:IntRegisters.SI, si
+ mov si, [bp + 2] // Int number
+
+ mov cs:IntRegisters.DS, ds
+ mov cs:IntRegisters.ES, es
+ mov cs:IntRegisters.SS, ss
+
+ // Compiler assumes SS == DS - use our stack if this condition is not met
+ mov ax, ss
+ mov bx, cs
+ cmp ax, bx
+ jz stack_ok
+
+ mov cs:OrigStackPointer, sp
+ mov cs:OrigStackSegment, ss
+ mov ax, cs
+ mov ss, ax
+ mov sp, TC_BOOT_LOADER_STACK_TOP
+
+ stack_ok:
+ // DS = CS
+ push ds
+ push es
+ mov ax, cs
+ mov ds, ax
+ mov es, ax
+
+ push si // Int number
+
+ // Filter request
+ cmp si, 0x15
+ je filter15
+ cmp si, 0x13
+ jne $
+
+ call Int13Filter
+ jmp s0
+
+ filter15:
+ call Int15Filter
+
+ s0:
+ pop si // Int number
+ pop es
+ pop ds
+
+ // Restore original SS:SP if our stack is empty
+ cli
+ mov bx, TC_BOOT_LOADER_STACK_TOP
+ cmp bx, sp
+ jnz stack_in_use
+
+ mov ss, cs:OrigStackSegment
+ mov sp, cs:OrigStackPointer
+ stack_in_use:
+
+ test ax, ax // passOriginalRequest
+ jnz pass_request
+
+ // Return results of filtered request
+ popad
+ popf
+ mov ax, cs:IntRegisters.Flags
+ mov [bp + 8], ax
+ leave
+
+ lea di, cs:IntRegisters.EAX
+ TC_ASM_EMIT4 (66,2E,8B,05) // mov eax, [cs:di]
+ lea di, cs:IntRegisters.EBX
+ TC_ASM_EMIT4 (66,2E,8B,1D) // mov ebx, [cs:di]
+ lea di, cs:IntRegisters.ECX
+ TC_ASM_EMIT4 (66,2E,8B,0D) // mov ecx, [cs:di]
+ lea di, cs:IntRegisters.EDX
+ TC_ASM_EMIT4 (66,2E,8B,15) // mov edx, [cs:di]
+
+ mov di, cs:IntRegisters.DI
+ mov si, cs:IntRegisters.SI
+ mov es, cs:IntRegisters.ES
+ mov ds, cs:IntRegisters.DS
+
+ sti
+ add sp, 2
+ iret
+
+ // Pass original request
+ pass_request:
+ sti
+ cmp si, 0x15
+ je pass15
+ cmp si, 0x13
+ jne $
+
+ popad
+ popf
+ leave
+ add sp, 2
+ jmp cs:OriginalInt13Handler
+
+ pass15:
+ popad
+ popf
+ leave
+ add sp, 2
+ jmp cs:OriginalInt15Handler
+ }
+}
+
+
+void Int13FilterEntry ()
+{
+ __asm
+ {
+ leave
+ push 0x13
+ jmp IntFilterEntry
+ }
+}
+
+
+static void Int15FilterEntry ()
+{
+ __asm
+ {
+ pushf
+ cmp ax, 0xe820 // Get system memory map
+ je filter
+
+ popf
+ leave
+ jmp cs:OriginalInt15Handler
+
+ filter:
+ leave
+ push 0x15
+ jmp IntFilterEntry
+ }
+}
+
+
+bool InstallInterruptFilters ()
+{
+
+#ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+
+ // If the filters have already been installed, it usually indicates stack corruption
+ // and a consequent reentry of this routine without a system reset.
+
+ uint32 currentInt13Handler;
+ CopyMemory (0, 0x13 * 4, &currentInt13Handler, sizeof (currentInt13Handler));
+
+ if (currentInt13Handler == (uint32) Int13FilterEntry)
+ {
+ PrintError ("Memory corrupted");
+ Print (TC_BOOT_STR_UPGRADE_BIOS);
+
+ GetKeyboardChar();
+ return true;
+ }
+
+#endif
+
+ if (!CreateNewBiosMemoryMap())
+ return false;
+
+ __asm
+ {
+ cli
+ push es
+
+ // Save original INT 13 handler
+ xor ax, ax
+ mov es, ax
+
+ mov si, 0x13 * 4
+ lea di, OriginalInt13Handler
+
+ mov ax, es:[si]
+ mov [di], ax
+ mov ax, es:[si + 2]
+ mov [di + 2], ax
+
+ // Install INT 13 filter
+ lea ax, Int13FilterEntry
+ mov es:[si], ax
+ mov es:[si + 2], cs
+
+ // Save original INT 15 handler
+ mov si, 0x15 * 4
+ lea di, OriginalInt15Handler
+
+ mov ax, es:[si]
+ mov [di], ax
+ mov ax, es:[si + 2]
+ mov [di + 2], ax
+
+ // Install INT 15 filter
+ lea ax, Int15FilterEntry
+ mov es:[si], ax
+ mov es:[si + 2], cs
+
+ // If the BIOS does not support system memory map (INT15 0xe820),
+ // set amount of available memory to CS:0000 - 0:0000
+ cmp BiosMemoryMapSize, 1
+ jg mem_map_ok
+ mov ax, cs
+ shr ax, 10 - 4 // CS * 16 / 1024
+ mov es:[0x413], ax // = KBytes available
+ mem_map_ok:
+
+ pop es
+ sti
+ }
+
+ return true;
+}
diff --git a/src/Boot/Windows/IntFilter.h b/src/Boot/Windows/IntFilter.h
new file mode 100644
index 00000000..b2e5c5d8
--- /dev/null
+++ b/src/Boot/Windows/IntFilter.h
@@ -0,0 +1,16 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ Governed by the TrueCrypt License 3.0 the full text of which is contained in
+ the file License.txt included in TrueCrypt binary and source code distribution
+ packages.
+*/
+
+#ifndef TC_HEADER_Boot_IntFilter
+#define TC_HEADER_Boot_IntFilter
+
+#include "Platform.h"
+
+bool InstallInterruptFilters ();
+
+#endif TC_HEADER_Boot_IntFilter
diff --git a/src/Boot/Windows/Makefile b/src/Boot/Windows/Makefile
new file mode 100644
index 00000000..737fbe5f
--- /dev/null
+++ b/src/Boot/Windows/Makefile
@@ -0,0 +1,184 @@
+#
+# Copyright (c) 2008-2010 TrueCrypt Developers Association. All rights reserved.
+#
+# Governed by the TrueCrypt License 3.0 the full text of which is contained in
+# the file License.txt included in TrueCrypt binary and source code distribution
+# packages.
+#
+
+PROJ = BootLoader
+.SILENT:
+
+!ifndef MSVC16_ROOT
+!error Environment variable MSVC16_ROOT must point to the installation directory of MS Visual C++ 1.5
+!endif
+
+ENVPATH = $(PATH)
+
+CC = $(MSVC16_ROOT)\bin\cl.exe
+LD = $(MSVC16_ROOT)\bin\link.exe
+
+AFLAGS = /nologo /omf
+
+CFLAGS = /nologo /W3 /Fc /I "$(MSVC16_ROOT)\Include" /I"..\..\.." /I"..\..\..\Common" /I"..\..\..\Crypto"
+CFLAGS = $(CFLAGS) /D __int8=char /D __int16=int /D __int32=long /D BOOL=char /D FALSE=0 /D TRUE=1
+CFLAGS = $(CFLAGS) /D LITTLE_ENDIAN=1234 /D BYTE_ORDER=1234 /D TC_WINDOWS_BOOT /D TC_MINIMIZE_CODE_SIZE /D TC_NO_COMPILER_INT64
+CFLAGS = $(CFLAGS) /D malloc=malloc_NA
+
+LFLAGS = /NOLOGO /ONERROR:NOEXE /NOI /BATCH
+
+OBJDIR = Release
+
+!ifdef RESCUE_DISK
+OBJDIR = Rescue
+CFLAGS = $(CFLAGS) /D TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+!endif
+
+!ifdef SINGLE_CIPHER
+OBJDIR = $(OBJDIR)_$(SINGLE_CIPHER)
+CFLAGS = $(CFLAGS) /D TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE /D TC_WINDOWS_BOOT_$(SINGLE_CIPHER)
+!endif
+
+OUTDIR = $(OBJDIR)
+TARGETEXT = com
+TARGETS = $(OUTDIR)\BootDefs.i $(OUTDIR)\BootSector.bin $(OUTDIR)\Decompressor.com
+CFLAGS = $(CFLAGS) /AT /Zl /f- /G3 /Oe /Os /Ob1 /OV0 /Gs /Gf /Gy /D NDEBUG
+LFLAGS = $(LFLAGS) /NOD /NOE /TINY
+OBJS = $(OUTDIR)\BootCrt.obj
+LIBS = slibce
+
+!if 1
+SRCDIR = ..
+!else
+SRCDIR = $(MAKEDIR)
+!endif
+
+TARGETS = $(TARGETS) $(OUTDIR)\$(PROJ).$(TARGETEXT)
+
+OBJS = $(OBJS) $(OUTDIR)\BootConfig.obj
+OBJS = $(OBJS) $(OUTDIR)\BootConsoleIo.obj
+OBJS = $(OBJS) $(OUTDIR)\BootDebug.obj
+OBJS = $(OBJS) $(OUTDIR)\BootDiskIo.obj
+OBJS = $(OBJS) $(OUTDIR)\BootEncryptedIo.obj
+OBJS = $(OBJS) $(OUTDIR)\BootMain.obj
+OBJS = $(OBJS) $(OUTDIR)\BootMemory.obj
+OBJS = $(OBJS) $(OUTDIR)\IntFilter.obj
+OBJS = $(OBJS) $(OUTDIR)\Platform.obj
+
+OBJS = $(OBJS) $(OUTDIR)\Crc.obj
+OBJS = $(OBJS) $(OUTDIR)\Crypto.obj
+OBJS = $(OBJS) $(OUTDIR)\Endian.obj
+OBJS = $(OBJS) $(OUTDIR)\Pkcs5.obj
+OBJS = $(OBJS) $(OUTDIR)\Volumes.obj
+OBJS = $(OBJS) $(OUTDIR)\Xts.obj
+
+OBJS = $(OBJS) $(OUTDIR)\Rmd160.obj
+
+!if !DEFINED (SINGLE_CIPHER)
+OBJS = $(OBJS) $(OUTDIR)\AesSmall.obj
+!else if "$(SINGLE_CIPHER)" == "AES"
+OBJS = $(OBJS) $(OUTDIR)\Aes_hw_cpu.obj
+OBJS = $(OBJS) $(OUTDIR)\AesSmall_x86.obj
+OBJS = $(OBJS) $(OUTDIR)\Aestab.obj
+!endif
+
+!if !DEFINED (SINGLE_CIPHER) || "$(SINGLE_CIPHER)" == "SERPENT"
+OBJS = $(OBJS) $(OUTDIR)\Serpent.obj
+!endif
+
+!if !DEFINED (SINGLE_CIPHER) || "$(SINGLE_CIPHER)" == "TWOFISH"
+OBJS = $(OBJS) $(OUTDIR)\Twofish.obj
+!endif
+
+
+all: env $(TARGETS)
+
+env:
+ set INCLUDE=.
+ set LIB=.
+ set LIBPATH=.
+
+clean:
+ -del /q /s $(OBJDIR) >NUL:
+
+
+.asm{$(OUTDIR)}.obj:
+ cd $(OBJDIR)
+ $(AS) $(AFLAGS) /c "$(SRCDIR)\$<"
+ cd ..
+
+{..\..\Crypto}.asm{$(OUTDIR)}.obj:
+ cd $(OBJDIR)
+ echo $(<F)
+ nasm.exe -Xvc -f obj -Ox -o "$(<B).obj" -l "$(<B).lst" "$(SRCDIR)\$<"
+ cd ..
+
+{..\..\Crypto}.c{$(OUTDIR)}.obj:
+ cd $(OBJDIR)
+ set PATH=.
+ $(CC) $(CFLAGS) /c "$(SRCDIR)\$<"
+ set PATH=$(ENVPATH)
+ cd ..
+
+{..\..\Common}.c{$(OUTDIR)}.obj:
+ cd $(OBJDIR)
+ set PATH=.
+ $(CC) $(CFLAGS) /c "$(SRCDIR)\$<"
+ set PATH=$(ENVPATH)
+ cd ..
+
+.c{$(OUTDIR)}.obj:
+ cd $(OBJDIR)
+ set PATH=.
+ $(CC) $(CFLAGS) /c "$(SRCDIR)\$<"
+ set PATH=$(ENVPATH)
+ cd ..
+
+.cpp{$(OUTDIR)}.obj:
+ cd $(OBJDIR)
+ set PATH=.
+ $(CC) $(CFLAGS) /c "$(SRCDIR)\$<"
+ set PATH=$(ENVPATH)
+ cd ..
+
+$(OUTDIR)\BootDefs.i: BootDefs.h
+ cd $(OBJDIR)
+ set PATH=.
+ $(CC) $(CFLAGS) /D TC_ASM_PREPROCESS /P /EP "$(SRCDIR)\BootDefs.h"
+ set PATH=$(ENVPATH)
+ cd ..
+
+$(OUTDIR)\BootSector.bin: $(OUTDIR)\BootSector.obj
+ cd $(OBJDIR)
+ $(LD) $(LFLAGS) BootSector.obj,BootSector.bin,,,, >NUL:
+ -dd.exe conv=notrunc bs=512 if=BootSector.bin of=$(PROJ).flp 2>NUL:
+ cd ..
+
+$(OUTDIR)\Decompressor.com: $(OUTDIR)\BootCrt.obj $(OUTDIR)\Decompressor.obj
+ cd $(OBJDIR)
+ $(LD) $(LFLAGS) BootCrt.obj Decompressor.obj,Decompressor.com,Decompressor.map,$(MSVC16_ROOT)\lib\+slibce,,
+ -dd.exe conv=notrunc,sync bs=512 seek=1 if=Decompressor.com of=$(PROJ).flp 2>NUL:
+ cd ..
+
+$(OUTDIR)\$(PROJ).$(TARGETEXT): $(OBJS)
+ @echo Linking...
+ cd $(OBJDIR)
+
+ echo >NUL: @<<$(PROJ).crf2
+
+$(PROJ).$(TARGETEXT)
+$(PROJ).map
+$(MSVC16_ROOT)\lib\+
+$(LIBS)
+;
+<<
+ del $(PROJ).crf >NUL: 2>NUL:
+ for %F in ($(**F)) do @echo %F + >>$(PROJ).crf
+ type $(PROJ).crf2 >>$(PROJ).crf
+
+ $(LD) $(LFLAGS) @$(PROJ).crf
+ del $(PROJ).crf $(PROJ).crf2
+
+ gzip.exe -c -n --best $(PROJ).$(TARGETEXT) >$(PROJ).$(TARGETEXT).gz
+ -dd.exe conv=notrunc,sync bs=512 seek=5 if=$(PROJ).$(TARGETEXT).gz of=$(PROJ).flp 2>NUL:
+ cd ..
diff --git a/src/Boot/Windows/Platform.cpp b/src/Boot/Windows/Platform.cpp
new file mode 100644
index 00000000..7894bf02
--- /dev/null
+++ b/src/Boot/Windows/Platform.cpp
@@ -0,0 +1,226 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ Governed by the TrueCrypt License 3.0 the full text of which is contained in
+ the file License.txt included in TrueCrypt binary and source code distribution
+ packages.
+*/
+
+#include "Platform.h"
+#include "BootConsoleIo.h"
+
+
+uint64 operator+ (const uint64 &a, const uint64 &b)
+{
+ int carry = 0;
+ uint64 r;
+
+ r.LowPart = a.LowPart + b.LowPart;
+ __asm
+ {
+ jnc nocarry
+ mov carry, 1
+ nocarry:
+ }
+
+ r.HighPart = a.HighPart + b.HighPart + carry;
+
+ return r;
+}
+
+uint64 operator+ (const uint64 &a, uint32 b)
+{
+ uint64 b64;
+ b64.HighPart = 0;
+ b64.LowPart = b;
+ return a + b64;
+}
+
+uint64 &operator+= (uint64 &a, const uint64 &b)
+{
+ return a = a + b;
+}
+
+uint64 operator- (const uint64 &a, const uint64 &b)
+{
+ int carry = 0;
+ uint64 r;
+
+ r.LowPart = a.LowPart - b.LowPart;
+ __asm
+ {
+ jnc nocarry
+ mov carry, 1
+ nocarry:
+ }
+
+ r.HighPart = a.HighPart - b.HighPart - carry;
+
+ return r;
+}
+
+uint64 operator- (const uint64 &a, uint32 b)
+{
+ uint64 b64;
+ b64.HighPart = 0;
+ b64.LowPart = b;
+ return a - b64;
+}
+
+uint64 &operator-= (uint64 &a, const uint64 &b)
+{
+ return a = a - b;
+}
+
+uint64 operator>> (const uint64 &a, int shiftCount)
+{
+ uint64 r = a;
+
+ while (shiftCount--)
+ {
+ r.LowPart >>= 1;
+
+ if ((byte) r.HighPart & 1)
+ r.LowPart |= 0x80000000UL;
+
+ r.HighPart >>= 1;
+ }
+
+ return r;
+}
+
+uint64 operator<< (const uint64 &a, int shiftCount)
+{
+ uint64 r = a;
+
+ while (shiftCount--)
+ r += r;
+
+ return r;
+}
+
+uint64 &operator++ (uint64 &a)
+{
+ uint64 b;
+ b.HighPart = 0;
+ b.LowPart = 1;
+
+ return a += b;
+}
+
+bool operator== (const uint64 &a, const uint64 &b)
+{
+ return a.HighPart == b.HighPart && a.LowPart == b.LowPart;
+}
+
+bool operator> (const uint64 &a, const uint64 &b)
+{
+ return (a.HighPart > b.HighPart) || (a.HighPart == b.HighPart && a.LowPart > b.LowPart);
+}
+
+bool operator< (const uint64 &a, const uint64 &b)
+{
+ return (a.HighPart < b.HighPart) || (a.HighPart == b.HighPart && a.LowPart < b.LowPart);
+}
+
+bool operator>= (const uint64 &a, const uint64 &b)
+{
+ return a > b || a == b;
+}
+
+bool operator<= (const uint64 &a, const uint64 &b)
+{
+ return a < b || a == b;
+}
+
+bool TestInt64 ()
+{
+ uint64 a, b, c;
+ a.HighPart = 0x00112233UL;
+ a.LowPart = 0xabcd1234UL;
+
+ b.HighPart = 0x00ffeeddUL;
+ b.LowPart = 0xffffFFFFUL;
+
+ a += b;
+ a -= b;
+
+ ++a;
+
+ b = b + (uint32) 1UL;
+
+ c = (a - ((a + b) >> 32) - (uint32) 1UL);
+ if (c.HighPart != 0x112233UL || c.LowPart != 0xAABC0123UL)
+ return false;
+
+ c = c << 9;
+ return c.HighPart == 0x22446755UL && c.LowPart == 0x78024600UL;
+}
+
+
+void CopyMemory (void *source, uint16 destSegment, uint16 destOffset, uint16 blockSize)
+{
+ __asm
+ {
+ push es
+ mov si, ss:source
+ mov es, ss:destSegment
+ mov di, ss:destOffset
+ mov cx, ss:blockSize
+ cld
+ rep movsb
+ pop es
+ }
+}
+
+
+void CopyMemory (uint16 sourceSegment, uint16 sourceOffset, void *destination, uint16 blockSize)
+{
+ __asm
+ {
+ push ds
+ push es
+ mov ax, ds
+ mov es, ax
+ mov di, ss:destination
+ mov si, ss:sourceOffset
+ mov cx, ss:blockSize
+ mov ds, ss:sourceSegment
+ cld
+ rep movsb
+ pop es
+ pop ds
+ }
+}
+
+
+void EraseMemory (void *memory, int size)
+{
+ memset (memory, 0, size);
+}
+
+
+uint32 GetLinearAddress (uint16 segment, uint16 offset)
+{
+ return (uint32 (segment) << 4) + offset;
+}
+
+
+bool RegionsIntersect (const uint64 &start1, uint32 length1, const uint64 &start2, const uint64 &end2)
+{
+ uint64 end1 = start1 + length1 - 1UL;
+ uint64 intersectEnd = (end1 <= end2) ? end1 : end2;
+
+ uint64 intersectStart = (start1 >= start2) ? start1 : start2;
+ if (intersectStart > intersectEnd)
+ return false;
+
+ return (intersectEnd + 1UL - intersectStart).LowPart != 0;
+}
+
+
+void ThrowFatalException (int line)
+{
+ PrintChar ('#'); Print (line);
+ while (1);
+}
diff --git a/src/Boot/Windows/Platform.h b/src/Boot/Windows/Platform.h
new file mode 100644
index 00000000..9c923d5e
--- /dev/null
+++ b/src/Boot/Windows/Platform.h
@@ -0,0 +1,112 @@
+/*
+ Copyright (c) 2008-2009 TrueCrypt Developers Association. All rights reserved.
+
+ Governed by the TrueCrypt License 3.0 the full text of which is contained in
+ the file License.txt included in TrueCrypt binary and source code distribution
+ packages.
+*/
+
+#ifndef TC_HEADER_Boot_Platform
+#define TC_HEADER_Boot_Platform
+
+#pragma warning (disable: 4018 4102 4704 4769)
+
+#include "TCdefs.h"
+#include <memory.h>
+
+typedef char bool;
+#define false 0
+#define true 1
+
+#define nullptr 0
+#define NULL 0
+
+typedef UINT64_STRUCT uint64;
+
+#define array_capacity(arr) (sizeof (arr) / sizeof ((arr)[0]))
+
+#define TC_TO_STRING2(n) #n
+#define TC_TO_STRING(n) TC_TO_STRING2(n)
+
+
+#define TC_X86_CARRY_FLAG 0x1
+
+#define TC_ASM_EMIT(A,B) __asm _emit 0x##A __asm _emit 0x##B
+#define TC_ASM_EMIT3(A,B,C) __asm _emit 0x##A __asm _emit 0x##B __asm _emit 0x##C
+#define TC_ASM_EMIT4(A,B,C,D) __asm _emit 0x##A __asm _emit 0x##B __asm _emit 0x##C __asm _emit 0x##D
+
+#define TC_ASM_MOV_EAX_DI TC_ASM_EMIT3 (66, 8B, 05)
+#define TC_ASM_MOV_EBX_DI TC_ASM_EMIT3 (66, 8B, 1D)
+#define TC_ASM_MOV_ECX_DI TC_ASM_EMIT3 (66, 8B, 0D)
+#define TC_ASM_MOV_EDX_DI TC_ASM_EMIT3 (66, 8B, 15)
+
+#define TC_ASM_MOV_DI_EAX TC_ASM_EMIT3 (66, 89, 05)
+#define TC_ASM_MOV_DI_EBX TC_ASM_EMIT3 (66, 89, 1D)
+#define TC_ASM_MOV_DI_ECX TC_ASM_EMIT3 (66, 89, 0D)
+#define TC_ASM_MOV_DI_EDX TC_ASM_EMIT3 (66, 89, 15)
+
+
+#pragma pack(1)
+
+struct Registers
+{
+ uint16 Flags;
+
+ union
+ {
+ uint32 EAX;
+ struct { uint16 AX; uint16 EAXH; };
+ };
+
+ union
+ {
+ uint32 EBX;
+ struct { uint16 BX; uint16 EBXH; };
+ };
+
+ union
+ {
+ uint32 ECX;
+ struct { uint16 CX; uint16 ECXH; };
+ };
+
+ union
+ {
+ uint32 EDX;
+ struct { uint16 DX; uint16 EDXH; };
+ };
+
+ uint16 DI;
+ uint16 SI;
+ uint16 DS;
+ uint16 ES;
+ uint16 SS;
+};
+
+#pragma pack()
+
+
+uint64 operator+ (const uint64 &a, const uint64 &b);
+uint64 operator+ (const uint64 &a, uint32 b);
+uint64 &operator+= (uint64 &a, const uint64 &b);
+uint64 operator- (const uint64 &a, const uint64 &b);
+uint64 operator- (const uint64 &a, uint32 b);
+uint64 &operator-= (uint64 &a, const uint64 &b);
+uint64 operator>> (const uint64 &a, int shiftCount);
+uint64 operator<< (const uint64 &a, int shiftCount);
+uint64 &operator++ (uint64 &a);
+bool operator== (const uint64 &a, const uint64 &b);
+bool operator> (const uint64 &a, const uint64 &b);
+bool operator< (const uint64 &a, const uint64 &b);
+bool operator>= (const uint64 &a, const uint64 &b);
+bool operator<= (const uint64 &a, const uint64 &b);
+
+void CopyMemory (void *source, uint16 destSegment, uint16 destOffset, uint16 blockSize);
+void CopyMemory (uint16 sourceSegment, uint16 sourceOffset, void *destination, uint16 blockSize);
+extern "C" void EraseMemory (void *memory, int size);
+uint32 GetLinearAddress (uint16 segment, uint16 offset);
+bool RegionsIntersect (const uint64 &start1, uint32 length1, const uint64 &start2, const uint64 &end2);
+bool TestInt64 ();
+extern "C" void ThrowFatalException (int line);
+
+#endif // TC_HEADER_Boot_Platform