├── .editorconfig ├── .gitattributes ├── .gitignore ├── Builds ├── MiniVisor.sln ├── Minivisor.doxyfile ├── Platform │ ├── EFI │ │ ├── MiniVisorDxe.inf │ │ ├── MiniVisorPkg.dec │ │ ├── MiniVisorPkg.dsc │ │ └── locate_image_base.py │ └── Windows │ │ └── DumpActiveLogs.js └── PreLinkEvent.py ├── Docs ├── Building_and_Debugging.md ├── Resources │ ├── Building_and_Testing_BootMode.jpg │ ├── Building_and_Testing_PuTTY_Configurations_for_VMware.png │ ├── Building_and_Testing_PuTTY_Exception_with_VMware.png │ ├── Building_and_Testing_PuTTY_Output_with_VMware.png │ ├── Building_and_Testing_VMwareWS_FullLogging.png │ ├── Building_and_Testing_VMwareWS_FullLogging_Sample.jpg │ ├── Building_and_Testing_VMwareWS_SelectFS.png │ ├── Building_and_Testing_VMwareWS_SerialDevice.png │ ├── Building_and_Testing_VMwareWS_Shell.png │ ├── Building_and_Testing_VMwareWS_UEFI.png │ ├── Building_and_Testing_VMwareWS_VTx.png │ ├── Readme_Showcase1.jpg │ ├── Readme_Showcase2.jpg │ ├── Readme_Showcase3.jpg │ ├── Readme_Showcase4.jpg │ ├── Testing_UEFI_on_HyperV_Serial01.png │ ├── Testing_UEFI_on_HyperV_Serial02.png │ ├── Testing_UEFI_on_HyperV_Setup01.png │ ├── Testing_UEFI_on_HyperV_Setup02.png │ ├── Testing_UEFI_on_HyperV_Setup03.png │ ├── Testing_UEFI_on_HyperV_Setup04.png │ ├── Testing_UEFI_on_HyperV_Setup05.png │ ├── Testing_UEFI_on_HyperV_Setup06.png │ ├── Testing_UEFI_on_HyperV_Setup07.png │ ├── Testing_UEFI_on_HyperV_Setup08.png │ ├── Testing_UEFI_on_HyperV_Setup09.png │ ├── Testing_UEFI_on_HyperV_Setup10.png │ ├── Testing_UEFI_on_HyperV_Setup11.png │ ├── Testing_UEFI_on_HyperV_Setup12.png │ ├── Testing_UEFI_on_HyperV_Setup13.png │ ├── Testing_UEFI_on_HyperV_Setup14.png │ ├── Testing_UEFI_on_HyperV_Setup15.png │ ├── Testing_UEFI_on_HyperV_Setup16.png │ ├── Testing_UEFI_on_HyperV_Setup17.png │ ├── Testing_UEFI_on_HyperV_Setup18.png │ ├── Testing_UEFI_on_HyperV_Setup19.png │ ├── Testing_UEFI_on_HyperV_Setup20.png │ ├── Testing_UEFI_on_HyperV_Setup21.png │ ├── Testing_UEFI_on_HyperV_Setup22.png │ ├── Testing_UEFI_on_HyperV_Setup23.png │ ├── Testing_UEFI_on_HyperV_Testing01.png │ ├── Testing_UEFI_on_HyperV_Testing02.png │ ├── Testing_UEFI_on_HyperV_Testing03.png │ └── Testing_UEFI_on_HyperV_Testing04.png └── Testing_UEFI_on_Hyper-V.md ├── Externals └── ia32-doc │ └── out │ └── ia32.h ├── LICENSE ├── README.md ├── Sources ├── Asm.asm ├── Asm.h ├── AsmCommon.inc ├── Common.h ├── ExtendedPageTables.c ├── ExtendedPageTables.h ├── HostInitialization.h ├── HostMain.c ├── HostMain.h ├── HostNesting.h ├── HostUtils.c ├── HostUtils.h ├── HostVmcall.c ├── HostVmcall.h ├── Ia32.h ├── Ia32Utils.c ├── Ia32Utils.h ├── Logger.h ├── MemoryAccess.c ├── MemoryAccess.h ├── MemoryManager.c ├── MemoryManager.h ├── MemoryType.c ├── MemoryType.h ├── MiniVisor.c ├── MiniVisor.h ├── MiniVisor.vcxproj ├── MiniVisor.vcxproj.filters ├── Platform.h ├── Platform │ ├── EFI │ │ ├── EfiAsm.asm │ │ ├── EfiAsm.h │ │ ├── EfiBitmap.c │ │ ├── EfiBitmap.h │ │ ├── EfiCommon.h │ │ ├── EfiHostInitialization.c │ │ ├── EfiHostInitialization.h │ │ ├── EfiLogger.c │ │ ├── EfiLogger.h │ │ ├── EfiPlatform.c │ │ └── EfiPlatform.h │ └── Windows │ │ ├── WinAsm.asm │ │ ├── WinAsm.h │ │ ├── WinCommon.h │ │ ├── WinHostInitialization.c │ │ ├── WinHostInitialization.h │ │ ├── WinLogger.c │ │ ├── WinLogger.h │ │ ├── WinPlatform.c │ │ └── WinPlatform.h └── Public.h └── Tests ├── CheckHvVendor ├── CheckHvVendor.sln └── CheckHvVendor │ ├── CheckHvVendor.cpp │ ├── CheckHvVendor.vcxproj │ └── CheckHvVendor.vcxproj.filters └── NmiTester ├── CpuidLoop ├── CpuidLoop.c ├── CpuidLoop.vcxproj └── CpuidLoop.vcxproj.filters ├── NmiTester.sln └── NmiTester ├── NmiTester.c ├── NmiTester.inf ├── NmiTester.vcxproj └── NmiTester.vcxproj.filters /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file how and what files are formatted with EditorConfig. The specified 2 | # formatting is applied when an user explicitly requires formatting with 3 | # [Edit] > [Advanced] > [Format Document] or makes changes in a file. 4 | # 5 | # To learn more about .editorconfig see https://aka.ms/editorconfigdocs 6 | 7 | # This is the top-level settings. EditorConfig will not look for further settings 8 | # in any parent directory that may override this settings unintentionally. 9 | root = true 10 | 11 | # All C and assembly files 12 | [*.{c,cpp,cc,cxx,h,hpp,rc,manifest,asm,nasm,s,inc}] 13 | charset = utf-8 14 | end_of_line = crlf 15 | indent_style = space 16 | indent_size = 4 17 | trim_trailing_whitespace = true 18 | insert_final_newline = true 19 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc 262 | 263 | # WPP 264 | *.mof 265 | 266 | # CppCheck 267 | *.cppcheck 268 | **/*-cppcheck-build-dir 269 | 270 | # Doxygen 271 | Doxygen/ 272 | 273 | # .lib files collected by the Pre-Link script 274 | Libs/ 275 | -------------------------------------------------------------------------------- /Builds/MiniVisor.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio Version 16 3 | VisualStudioVersion = 16.0.28729.10 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{35DE61DD-9D91-4B1A-B082-8C80ED644749}" 6 | ProjectSection(SolutionItems) = preProject 7 | ..\.editorconfig = ..\.editorconfig 8 | ..\.gitattributes = ..\.gitattributes 9 | ..\.gitignore = ..\.gitignore 10 | ..\LICENSE = ..\LICENSE 11 | PreLinkEvent.py = PreLinkEvent.py 12 | ..\README.md = ..\README.md 13 | EndProjectSection 14 | EndProject 15 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MiniVisor", "..\Sources\MiniVisor.vcxproj", "{B94B175C-8D18-47E2-800C-1AFBAAC7AC73}" 16 | EndProject 17 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Platform", "Platform", "{3C22D872-3490-4292-A646-A6DFDA461CED}" 18 | EndProject 19 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EFI", "EFI", "{278A0532-B8F9-4F76-AB0A-946AD377B07A}" 20 | ProjectSection(SolutionItems) = preProject 21 | Platform\EFI\locate_image_base.py = Platform\EFI\locate_image_base.py 22 | Platform\EFI\MiniVisorDxe.inf = Platform\EFI\MiniVisorDxe.inf 23 | Platform\EFI\MiniVisorPkg.dec = Platform\EFI\MiniVisorPkg.dec 24 | Platform\EFI\MiniVisorPkg.dsc = Platform\EFI\MiniVisorPkg.dsc 25 | EndProjectSection 26 | EndProject 27 | Global 28 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 29 | Debug|x64 = Debug|x64 30 | Release|x64 = Release|x64 31 | UEFI|x64 = UEFI|x64 32 | EndGlobalSection 33 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 34 | {B94B175C-8D18-47E2-800C-1AFBAAC7AC73}.Debug|x64.ActiveCfg = Debug|x64 35 | {B94B175C-8D18-47E2-800C-1AFBAAC7AC73}.Debug|x64.Build.0 = Debug|x64 36 | {B94B175C-8D18-47E2-800C-1AFBAAC7AC73}.Release|x64.ActiveCfg = Release|x64 37 | {B94B175C-8D18-47E2-800C-1AFBAAC7AC73}.Release|x64.Build.0 = Release|x64 38 | {B94B175C-8D18-47E2-800C-1AFBAAC7AC73}.UEFI|x64.ActiveCfg = UEFI|x64 39 | {B94B175C-8D18-47E2-800C-1AFBAAC7AC73}.UEFI|x64.Build.0 = UEFI|x64 40 | EndGlobalSection 41 | GlobalSection(SolutionProperties) = preSolution 42 | HideSolutionNode = FALSE 43 | EndGlobalSection 44 | GlobalSection(NestedProjects) = preSolution 45 | {3C22D872-3490-4292-A646-A6DFDA461CED} = {35DE61DD-9D91-4B1A-B082-8C80ED644749} 46 | {278A0532-B8F9-4F76-AB0A-946AD377B07A} = {3C22D872-3490-4292-A646-A6DFDA461CED} 47 | EndGlobalSection 48 | GlobalSection(ExtensibilityGlobals) = postSolution 49 | SolutionGuid = {FF5CF53A-DB6B-415D-9F6C-135AFA73B8FB} 50 | EndGlobalSection 51 | EndGlobal 52 | -------------------------------------------------------------------------------- /Builds/Platform/EFI/MiniVisorDxe.inf: -------------------------------------------------------------------------------- 1 | [Defines] 2 | INF_VERSION = 1.27 3 | BASE_NAME = MiniVisorDxe 4 | FILE_GUID = 431B242C-8D1B-497F-AC69-352BB4713525 5 | MODULE_TYPE = DXE_RUNTIME_DRIVER 6 | VERSION_STRING = 1.0 7 | ENTRY_POINT = DriverEntry 8 | UNLOAD_IMAGE = DriverUnload 9 | 10 | [Sources] 11 | ../../../Sources/Platform/EFI/EfiAsm.asm 12 | ../../../Sources/Platform/EFI/EfiAsm.h 13 | ../../../Sources/Platform/EFI/EfiBitmap.c 14 | ../../../Sources/Platform/EFI/EfiBitmap.h 15 | ../../../Sources/Platform/EFI/EfiCommon.h 16 | ../../../Sources/Platform/EFI/EfiHostInitialization.c 17 | ../../../Sources/Platform/EFI/EfiHostInitialization.h 18 | ../../../Sources/Platform/EFI/EfiLogger.c 19 | ../../../Sources/Platform/EFI/EfiLogger.h 20 | ../../../Sources/Platform/EFI/EfiPlatform.c 21 | ../../../Sources/Platform/EFI/EfiPlatform.h 22 | ../../../Sources/ExtendedPageTables.c 23 | ../../../Sources/ExtendedPageTables.h 24 | ../../../Sources/HostMain.c 25 | ../../../Sources/HostMain.h 26 | #../../../Sources/HostNesting.c 27 | ../../../Sources/HostNesting.h 28 | ../../../Sources/HostUtils.c 29 | ../../../Sources/HostUtils.h 30 | ../../../Sources/HostVmcall.c 31 | ../../../Sources/HostVmcall.h 32 | ../../../Sources/Logger.h 33 | ../../../Sources/MemoryAccess.c 34 | ../../../Sources/MemoryAccess.h 35 | ../../../Sources/MemoryManager.c 36 | ../../../Sources/MemoryManager.h 37 | ../../../Sources/MemoryType.c 38 | ../../../Sources/MemoryType.h 39 | ../../../Sources/MiniVisor.c 40 | ../../../Sources/MiniVisor.h 41 | ../../../Sources/Platform.h 42 | ../../../Sources/Ia32Utils.c 43 | ../../../Sources/Ia32Utils.h 44 | ../../../Sources/Ia32.h 45 | ../../../Sources/Asm.asm 46 | ../../../Sources/Asm.h 47 | ../../../Sources/Common.h 48 | ../../../Externals/ia32-doc/out/ia32.h 49 | 50 | [Packages] 51 | MdePkg/MdePkg.dec 52 | MiniVisorPkg/Builds/Platform/EFI/MiniVisorPkg.dec 53 | 54 | [LibraryClasses] 55 | UefiDriverEntryPoint 56 | UefiLib 57 | DevicePathLib 58 | SynchronizationLib 59 | MemoryAllocationLib 60 | PrintLib 61 | 62 | [Protocols] 63 | gEfiLoadedImageProtocolGuid ## CONSUMES 64 | gEfiMpServiceProtocolGuid ## CONSUMES 65 | 66 | [Guids] 67 | gEfiEventExitBootServicesGuid ## CONSUMES 68 | 69 | [Depex] 70 | TRUE 71 | 72 | [BuildOptions.common.DXE_RUNTIME_DRIVER] 73 | # Detect use of deprecated interfaces if any. 74 | MSFT:*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES 75 | 76 | # Remove DebugLib library instances (ASSERT and such) from the RELEASE binary. 77 | # https://github.com/tianocore-docs/edk2-UefiDriverWritersGuide/blob/master/31_testing_and_debugging_uefi_drivers/314_debugging_code_statements/3141_configuring_debuglib_with_edk_ii.md 78 | MSFT:RELEASE_*_*_CC_FLAGS = -D MDEPKG_NDEBUG 79 | 80 | # EDK2 default defines /ALIGN:32, which is way too small for and causes link 81 | # error. Reset to the default value. 82 | MSFT:*_*_*_DLINK_FLAGS = /ALIGN:4096 /DEBUG 83 | 84 | # By default, certain meta-data in the PE header is zeroed out to increase 85 | # compression ratio. Some of those information can be helpful for a debugger, 86 | # for example, to reconstruct stack trace. Leave it for such cases. See also, 87 | # https://edk2-docs.gitbooks.io/edk-ii-basetools-user-guides/content/GenFw.html 88 | MSFT:*_*_X64_GENFW_FLAGS = --keepexceptiontable --keepzeropending --keepoptionalheader 89 | 90 | # gcc and clang is not supported but this let us run additional code analysis. 91 | GCC:*_*_*_CC_FLAGS = -Wall -Wextra -Wno-unknown-pragmas -Wno-multichar -Wno-unused-function -Wno-unused-value -Wno-unused-parameter 92 | 93 | # Finally, note that the RELEASE build will generate excessively large binary 94 | # file. To avoid this open the Conf/tools_def.txt, locate the below line, 95 | # RELEASE_VS2019_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4281 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data 96 | # then, remove "/MERGE:.rdata=.data". 97 | -------------------------------------------------------------------------------- /Builds/Platform/EFI/MiniVisorPkg.dec: -------------------------------------------------------------------------------- 1 | [Defines] 2 | DEC_SPECIFICATION = 1.27 3 | PACKAGE_NAME = MiniVisorPkg 4 | PACKAGE_GUID = 17B17324-C05D-4F94-BE73-46D4077E3E4C 5 | PACKAGE_VERSION = 1.00 6 | 7 | [Includes] 8 | ../../../Sources 9 | ../../../Sources/Platform/EFI 10 | -------------------------------------------------------------------------------- /Builds/Platform/EFI/MiniVisorPkg.dsc: -------------------------------------------------------------------------------- 1 | [Defines] 2 | DSC_SPECIFICATION = 1.28 3 | PLATFORM_NAME = MiniVisor 4 | PLATFORM_GUID = F12E3CB1-C7C0-4EED-9E78-D144A1A09F98 5 | PLATFORM_VERSION = 1.00 6 | OUTPUT_DIRECTORY = Build/MiniVisor 7 | SUPPORTED_ARCHITECTURES = X64 8 | BUILD_TARGETS = DEBUG|RELEASE|NOOPT 9 | SKUID_IDENTIFIER = DEFAULT 10 | 11 | [LibraryClasses] 12 | RegisterFilterLib|MdePkg/Library/RegisterFilterLibNull/RegisterFilterLibNull.inf 13 | UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf 14 | PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf 15 | TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf 16 | PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf 17 | BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf 18 | BaseLib|MdePkg/Library/BaseLib/BaseLib.inf 19 | SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf 20 | CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf 21 | UefiLib|MdePkg/Library/UefiLib/UefiLib.inf 22 | UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf 23 | UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf 24 | DevicePathLib|MdePkg/Library/UefiDevicePathLibDevicePathProtocol/UefiDevicePathLibDevicePathProtocol.inf 25 | !if $(TARGET) == RELEASE 26 | DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf 27 | !else 28 | !ifdef $(DEBUG_ON_SERIAL_PORT) 29 | IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf 30 | SerialPortLib|PcAtChipsetPkg/Library/SerialIoLib/SerialIoLib.inf 31 | DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf 32 | !else 33 | DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf 34 | !endif 35 | !endif 36 | DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf 37 | 38 | [LibraryClasses.common.DXE_RUNTIME_DRIVER] 39 | PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf 40 | BaseMemoryLib|MdePkg/Library/BaseMemoryLibOptDxe/BaseMemoryLibOptDxe.inf 41 | MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf 42 | 43 | [PcdsFixedAtBuild] 44 | # Define DEBUG_ERROR | DEBUG_VERBOSE | DEBUG_INFO | DEBUG_WARN to enable 45 | # logging at those levels. Also, define DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED 46 | # and such. Assertion failure will call CpuDeadLoop. 47 | # https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-Debugging 48 | gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80400042 49 | gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x2f 50 | 51 | [Components] 52 | MiniVisorPkg/Builds/Platform/EFI/MiniVisorDxe.inf 53 | -------------------------------------------------------------------------------- /Builds/Platform/EFI/locate_image_base.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Locates the image base from the current RIP value. This can be manually invoked 4 | # from the IDA Pro during the GDB remote debug session to load symbols (a PDB file). 5 | # 6 | # Author: Satoshi Tanda 7 | current_page_base = idaapi.get_reg_val('rip') & (~0xfff) 8 | offset = 0 9 | while idc.read_dbg_word(current_page_base - offset) != 0x5a4d: 10 | offset += 0x1000 11 | 12 | image_base = current_page_base - offset 13 | print( 14 | f'Base found at 0x{image_base:02X}. To load symbols, go [File] menu >' 15 | f' Load file > PDB file..., then set,\n' 16 | f' Input file: the PDB file, for example, C:\\edk2\\MiniVisorPkg\\Builds\\x64\\UEFI\\MiniVisorDxe.pdb\n' 17 | f' Address: 0x{image_base:02X}\n' 18 | f'and hit [OK], and then, [Yes].' 19 | ) 20 | -------------------------------------------------------------------------------- /Builds/Platform/Windows/DumpActiveLogs.js: -------------------------------------------------------------------------------- 1 | /*! 2 | @file DumpActiveLogs.js 3 | 4 | @brief Implements the DumpActiveLogs function which dumps buffered log entries. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2019 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | "use strict"; 11 | 12 | function initializeScript() 13 | { 14 | return [new host.apiVersionSupport(1, 3)]; 15 | } 16 | 17 | function invokeScript() 18 | { 19 | // 20 | // Insert your script content here. This method will be called whenever the script is 21 | // invoked from a client. 22 | // 23 | // See the following for more details: 24 | // 25 | // https://aka.ms/JsDbgExt 26 | // 27 | } 28 | 29 | const log = x => host.diagnostics.debugLog(x + "\n"); 30 | const u64 = x => host.memory.readMemoryValues(x, 1, 8)[0]; 31 | const sizeof = x => host.evaluateExpression("sizeof(" + x + ")"); 32 | const str = (x) => host.memory.readString(x); 33 | const strn = (x, y) => host.memory.readString(x, y); 34 | 35 | /** 36 | * Returns an array of arrays of log entries where 0=ProcessName, 1=FunctionName, 37 | * and 2=LogMessage. 38 | * 39 | * Example: 40 | * kd> .scriptload C:\edk2\MiniVisorPkg\Builds\Platform\Windows\DumpActiveLogs.js 41 | * kd> dx Debugger.State.Scripts.DumpActiveLogs.Contents.DumpActiveLogs(),0xffff 42 | */ 43 | function DumpActiveLogs() 44 | { 45 | let addr = host.getModuleSymbolAddress("MiniVisor", "g_Logger"); 46 | let context = host.createPointerObject(u64(addr), "MiniVisor", "LOGGER_CONTEXT*"); 47 | let entriesBase = context.PairedLogBuffer.ActiveLogBuffer.LogEntries; 48 | 49 | let logs = []; 50 | host.diagnostics.debugLog("Collecting buffered log entries."); 51 | for (let offset = 0; offset < context.PairedLogBuffer.ActiveLogBuffer.NextLogOffset; /**/) 52 | { 53 | let entry = host.createPointerObject(entriesBase.address.add(offset), 54 | "MiniVisor", 55 | "_DEBUG_LOG_ENTRY*"); 56 | logs.push([ 57 | str(entry.ProcessName), 58 | str(entry.FunctionName), 59 | strn(entry.LogMessage, entry.LogMessageLength), 60 | ]); 61 | offset += sizeof("_DEBUG_LOG_ENTRY") - 1 + entry.LogMessageLength; 62 | host.diagnostics.debugLog("."); 63 | } 64 | host.diagnostics.debugLog("\n"); 65 | return logs; 66 | } 67 | -------------------------------------------------------------------------------- /Builds/PreLinkEvent.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copies the lib files created by the EDK2's build command to a single specified 4 | # locations, so that Visual Studio can easily find and link them. Invoked as 5 | # part of Pre-Link Event of the MiniVisor project. 6 | # 7 | # Author: Satoshi Tanda 8 | import os 9 | import sys 10 | import shutil 11 | 12 | def main(): 13 | path = sys.argv[1] 14 | out_dir = sys.argv[2] 15 | 16 | lib_files = [] 17 | for root, _, files in os.walk(path): 18 | for file in files: 19 | if '.lib' in file: 20 | lib_files.append(os.path.join(root, file)) 21 | 22 | if not os.path.exists(out_dir): 23 | os.mkdir(out_dir) 24 | for lib_file in lib_files: 25 | shutil.copy(lib_file, out_dir) 26 | 27 | print( 28 | 'If you see link error, rebuild the project with the EDK2 build command' 29 | ' and try again. If you still see error, try updating dependencies.\n' 30 | 'To do so, open the project properties, "Linker" > "Input", and update' 31 | ' "Additional Dependencies" with the following:' 32 | ) 33 | print(' ' + ';'.join([os.path.basename(lib_file) for lib_file in lib_files])) 34 | 35 | 36 | if __name__ == '__main__': 37 | main() 38 | -------------------------------------------------------------------------------- /Docs/Resources/Building_and_Testing_BootMode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Building_and_Testing_BootMode.jpg -------------------------------------------------------------------------------- /Docs/Resources/Building_and_Testing_PuTTY_Configurations_for_VMware.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Building_and_Testing_PuTTY_Configurations_for_VMware.png -------------------------------------------------------------------------------- /Docs/Resources/Building_and_Testing_PuTTY_Exception_with_VMware.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Building_and_Testing_PuTTY_Exception_with_VMware.png -------------------------------------------------------------------------------- /Docs/Resources/Building_and_Testing_PuTTY_Output_with_VMware.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Building_and_Testing_PuTTY_Output_with_VMware.png -------------------------------------------------------------------------------- /Docs/Resources/Building_and_Testing_VMwareWS_FullLogging.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Building_and_Testing_VMwareWS_FullLogging.png -------------------------------------------------------------------------------- /Docs/Resources/Building_and_Testing_VMwareWS_FullLogging_Sample.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Building_and_Testing_VMwareWS_FullLogging_Sample.jpg -------------------------------------------------------------------------------- /Docs/Resources/Building_and_Testing_VMwareWS_SelectFS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Building_and_Testing_VMwareWS_SelectFS.png -------------------------------------------------------------------------------- /Docs/Resources/Building_and_Testing_VMwareWS_SerialDevice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Building_and_Testing_VMwareWS_SerialDevice.png -------------------------------------------------------------------------------- /Docs/Resources/Building_and_Testing_VMwareWS_Shell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Building_and_Testing_VMwareWS_Shell.png -------------------------------------------------------------------------------- /Docs/Resources/Building_and_Testing_VMwareWS_UEFI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Building_and_Testing_VMwareWS_UEFI.png -------------------------------------------------------------------------------- /Docs/Resources/Building_and_Testing_VMwareWS_VTx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Building_and_Testing_VMwareWS_VTx.png -------------------------------------------------------------------------------- /Docs/Resources/Readme_Showcase1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Readme_Showcase1.jpg -------------------------------------------------------------------------------- /Docs/Resources/Readme_Showcase2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Readme_Showcase2.jpg -------------------------------------------------------------------------------- /Docs/Resources/Readme_Showcase3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Readme_Showcase3.jpg -------------------------------------------------------------------------------- /Docs/Resources/Readme_Showcase4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Readme_Showcase4.jpg -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Serial01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Serial01.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Serial02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Serial02.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Setup01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Setup01.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Setup02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Setup02.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Setup03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Setup03.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Setup04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Setup04.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Setup05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Setup05.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Setup06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Setup06.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Setup07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Setup07.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Setup08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Setup08.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Setup09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Setup09.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Setup10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Setup10.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Setup11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Setup11.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Setup12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Setup12.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Setup13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Setup13.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Setup14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Setup14.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Setup15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Setup15.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Setup16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Setup16.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Setup17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Setup17.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Setup18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Setup18.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Setup19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Setup19.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Setup20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Setup20.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Setup21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Setup21.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Setup22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Setup22.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Setup23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Setup23.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Testing01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Testing01.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Testing02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Testing02.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Testing03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Testing03.png -------------------------------------------------------------------------------- /Docs/Resources/Testing_UEFI_on_HyperV_Testing04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tandasat/MiniVisorPkg/4ec21d6efae00e82e70b5acfa8dcdaa94f06a63c/Docs/Resources/Testing_UEFI_on_HyperV_Testing04.png -------------------------------------------------------------------------------- /Docs/Testing_UEFI_on_Hyper-V.md: -------------------------------------------------------------------------------- 1 | Testing UEFI on Hyper-V 2 | ======================== 3 | 4 | This document provides step-by-step instructions to test the UEFI version of MiniVisor on Hyper-V. 5 | 6 | The readers are expected to be able to build MiniVisor already. If not, please go through [Building and Debugging](Building_and_Debugging.md) first. 7 | 8 | Prerequisites 9 | -------------- 10 | 11 | To follow this instruction, the reader must have a 64bit Windows 10 ISO image to set up a new virtual machine on Hyper-V. 12 | 13 | Alternatively, the reader can use an existing virtual machine as long as it has the same configurations as specified in this instructions. 14 | 15 | Overview 16 | --------- 17 | 18 | The instructions are largely divided into the following steps: 19 | 20 | 1. Setting up a new virtual machine 21 | 2. Creating a bootable virtual drive to boot into the UEFI shell 22 | 3. Testing with the virtual machine 23 | 24 | Setting up a New Virtual Machine 25 | --------------------------------- 26 | 27 | 1. From Hyper-V Manager, create a new machine. This instruction assumes the virtual machine is named as "Windows 10 UEFI". 28 | ![Testing_UEFI_on_HyperV_Setup01.png](Resources/Testing_UEFI_on_HyperV_Setup01.png) 29 | 30 | 2. Select "Generation 2". 31 | ![Testing_UEFI_on_HyperV_Setup02.png](Resources/Testing_UEFI_on_HyperV_Setup02.png) 32 | 33 | 3. Memory configuration can be anything. Click [Next]. 34 | ![Testing_UEFI_on_HyperV_Setup03.png](Resources/Testing_UEFI_on_HyperV_Setup03.png) 35 | 36 | 4. Network configuration can be anything. Click [Next]. 37 | ![Testing_UEFI_on_HyperV_Setup04.png](Resources/Testing_UEFI_on_HyperV_Setup04.png) 38 | 39 | 5. Specify the Windows 10 installation ISO file. 40 | ![Testing_UEFI_on_HyperV_Setup05.png](Resources/Testing_UEFI_on_HyperV_Setup05.png) 41 | 42 | 6. Click [Finish]. 43 | ![Testing_UEFI_on_HyperV_Setup06.png](Resources/Testing_UEFI_on_HyperV_Setup06.png) 44 | 45 | 7. Disable Secure Boot before booting the virtual machine. 46 | ![Testing_UEFI_on_HyperV_Setup07.png](Resources/Testing_UEFI_on_HyperV_Setup07.png) 47 | 48 | 8. Start the virtual machine and boot from the ISO image. 49 | ![Testing_UEFI_on_HyperV_Setup08.png](Resources/Testing_UEFI_on_HyperV_Setup08.png) 50 | 51 | 9. Complete setup. There is no special requirement for Windows installation. No Windows Update is required. 52 | 53 | 10. Shutdown the virtual machine and open the settings of it. 54 | 55 | Creating The Bootable Virtual Drive to Boot Into The UEFI Shell 56 | ---------------------------------------------------------------- 57 | 58 | 1. Add a new hard drive. 59 | ![Testing_UEFI_on_HyperV_Setup09.png](Resources/Testing_UEFI_on_HyperV_Setup09.png) 60 | 61 | 2. Click [New]. 62 | ![Testing_UEFI_on_HyperV_Setup10.png](Resources/Testing_UEFI_on_HyperV_Setup10.png) 63 | 64 | 3. The disk type can be anything. Click [Next]. 65 | ![Testing_UEFI_on_HyperV_Setup11.png](Resources/Testing_UEFI_on_HyperV_Setup11.png) 66 | 67 | 4. Give the name of the disk file. This instruction assume it is named as "FAT.vhdx". 68 | ![Testing_UEFI_on_HyperV_Setup12.png](Resources/Testing_UEFI_on_HyperV_Setup12.png) 69 | 70 | 5. Select "Create a new blank virtual hard drive" and specify the size. 1GB is big enough. 71 | ![Testing_UEFI_on_HyperV_Setup13.png](Resources/Testing_UEFI_on_HyperV_Setup13.png) 72 | 73 | 6. Click [Finish]. 74 | ![Testing_UEFI_on_HyperV_Setup14.png](Resources/Testing_UEFI_on_HyperV_Setup14.png) 75 | 76 | The settings should look like this. 77 | ![Testing_UEFI_on_HyperV_Setup15.png](Resources/Testing_UEFI_on_HyperV_Setup15.png) 78 | 79 | 7. Then, move up the new hard drive at the top of the boot order list. 80 | ![Testing_UEFI_on_HyperV_Setup16.png](Resources/Testing_UEFI_on_HyperV_Setup16.png) 81 | 82 | 8. Start PowerShell with the administrators privileges. 83 | 84 | 9. Run the follow command to mount the new drive. 85 | ``` 86 | PS> Mount-VHD -Path "C:\Users\Public\Documents\Hyper-V\Virtual hard disks\FAT.vhdx" 87 | ``` 88 | 89 | 10. Open Disk Management. 90 | ``` 91 | PS> diskmgmt.msc 92 | ``` 93 | 94 | 11. It should prompt for initialization of the disk. Select "MBR (Master Boot Record)". 95 | ![Testing_UEFI_on_HyperV_Setup17.png](Resources/Testing_UEFI_on_HyperV_Setup17.png) 96 | 97 | 12. On Disk Management, right click the new disk and select "New Simple Volume". 98 | ![Testing_UEFI_on_HyperV_Setup18.png](Resources/Testing_UEFI_on_HyperV_Setup18.png) 99 | 100 | 13. Click [Next]. 101 | ![Testing_UEFI_on_HyperV_Setup19.png](Resources/Testing_UEFI_on_HyperV_Setup19.png) 102 | 103 | 14. Click [Next]. 104 | ![Testing_UEFI_on_HyperV_Setup20.png](Resources/Testing_UEFI_on_HyperV_Setup20.png) 105 | 106 | 15. Click [Next]. This instruction assumes the drive letter D: is assigned to it. 107 | ![Testing_UEFI_on_HyperV_Setup21.png](Resources/Testing_UEFI_on_HyperV_Setup21.png) 108 | 109 | 16. Format the drive with "FAT32" file system. 110 | ![Testing_UEFI_on_HyperV_Setup22.png](Resources/Testing_UEFI_on_HyperV_Setup22.png) 111 | 112 | 17. Click [Finish]. 113 | ![Testing_UEFI_on_HyperV_Setup23.png](Resources/Testing_UEFI_on_HyperV_Setup23.png) 114 | 115 | Now, D:\ should be accessible to place files into the new hard drive. 116 | 117 | 18. Download pre-compiled the UEFI shell from the EDK2 repository ([Download](https://github.com/tianocore/edk2/raw/edk2-stable201903/ShellBinPkg/UefiShell/X64/Shell.efi)). This instruction assumes the file is downloaded as `%USERPROFILE%\Downloads\Shell.efi` 118 | 119 | 19. Deploy the UEFI shell as `Bootx64.efi`, so it can be started automatically. 120 | 121 | ``` 122 | > cd /d D:\ 123 | > mkdir EFI\Boot 124 | > copy %USERPROFILE%\Downloads\Shell.efi EFI\Boot\Bootx64.efi 125 | ``` 126 | 127 | 20. Build MiniVisor and place the compiled file into the D drive. 128 | 129 | ``` 130 | > cd /d C:\edk2 131 | > edksetup.bat 132 | > build -w -a X64 -t VS2019 -b NOOPT -p MiniVisorPkg\Builds\Platform\EFI\MiniVisorPkg.dsc 133 | > copy /y C:\edk2\Build\MiniVisor\NOOPT_VS2019\X64\MiniVisorDxe.efi D:\ 134 | ``` 135 | 136 | 22. Finally, dismount the hard drive and enable nested virtualization by running the following command on PowerShell with administrators privileges. 137 | 138 | ``` 139 | > Dismount-VHD -Path "C:\Users\Public\Documents\Hyper-V\Virtual hard disks\FAT.vhdx" 140 | > Set-VMProcessor -VMName "Windows 10 UEFI" -ExposeVirtualizationExtensions $true 141 | ``` 142 | 143 | We are going to test MiniVisor on the virtual machine next. 144 | 145 | Testing With The Virtual Machine 146 | --------------------------------- 147 | 148 | 1. Start the virtual machine. It should enter to the UEFI shell. 149 | ![Testing_UEFI_on_HyperV_Testing01.png](Resources/Testing_UEFI_on_HyperV_Testing01.png) 150 | 151 | 2. Find the file system that contains `MiniVisorDxe.efi`. In this example, it was in `fs2:`. Then load it. 152 | ``` 153 | > fs2: 154 | > load MiniVisorDxe.efi 155 | ``` 156 | ![Testing_UEFI_on_HyperV_Testing02.png](Resources/Testing_UEFI_on_HyperV_Testing02.png) 157 | 158 | 3. Then, find the file system that has the `EFI\Boot\bootx64.efi` and execute it. In this example, it was in `fs0:`. 159 | ``` 160 | > fs0: 161 | > EFI\Boot\bootx64.efi 162 | ``` 163 | ![Testing_UEFI_on_HyperV_Testing03.png](Resources/Testing_UEFI_on_HyperV_Testing03.png) 164 | 165 | This should boot Windows successfully. 166 | 167 | 4. Existence of MiniVisor can be confirmed with `CheckHvVendor.exe`. 168 | ![Testing_UEFI_on_HyperV_Testing04.png](Resources/Testing_UEFI_on_HyperV_Testing04.png) 169 | 170 | Testing Iteration 171 | ------------------ 172 | 173 | To iterate testing workflow, build the MiniVisor then run the following command on PowerShell. 174 | ``` 175 | PS> Mount-VHD -Path "C:\Users\Public\Documents\Hyper-V\Virtual hard disks\FAT.vhdx" 176 | PS> Copy-Item C:\edk2\Build\MiniVisor\NOOPT_VS2019\X64\MiniVisorDxe.efi -Destination D:\ 177 | PS> Dismount-VHD -Path "C:\Users\Public\Documents\Hyper-V\Virtual hard disks\FAT.vhdx" 178 | PS> Start-VM -Name "Windows 10 UEFI 179 | ``` 180 | 181 | This copies the newly built MiniVisorDxe.efi into the hard drive and then starts the virtual machine. 182 | 183 | Also, to automate commands in the UEFI shell, one can place a file named `startup.nsh` containing commands in the D drive to execute automatically. 184 | 185 | Serial Output 186 | -------------- 187 | 188 | Just like with VMware, serial output can be used. 189 | 190 | 1. Run the following command on PowerShell with the administrators privileges. 191 | ``` 192 | PS> Set-VMComPort -VMName "Windows 10 UEFI" -Path \\.\pipe\com_1 -Number 1 193 | ``` 194 | 195 | 2. Build MiniVisor with the `-D DEBUG_ON_SERIAL_PORT` flag. 196 | ``` 197 | > build -w -a X64 -t VS2019 -b NOOPT -p MiniVisorPkg\Builds\Platform\EFI\MiniVisorPkg.dsc -D DEBUG_ON_SERIAL_PORT 198 | ``` 199 | 200 | 3. Open serial connection for `\\.\pipe\com_1` at baudrate 115200. As an example with PuTTY, it should look like this. 201 | ![Testing_UEFI_on_HyperV_Serial01.png](Resources/Testing_UEFI_on_HyperV_Serial01.png) 202 | 203 | It should show a blank screen. 204 | 205 | 4. Once the MiniVisor is loaded, serial logs should show up on the PuTTY windows. 206 | ![Testing_UEFI_on_HyperV_Serial02.png](Resources/Testing_UEFI_on_HyperV_Serial02.png) 207 | 208 | Final Notes 209 | ------------ 210 | 211 | * Configure the virtual machine with a single processor. Multi processor system is unsupported. 212 | * This is partly because the MP protocol is not implemented on Hyper-V UEFI, but even if it were, nested virtualiation on Hyper-V does not support the wait-for-SIPI guest activity state. This is very different from any bare-metal I tested, and MiniVisor does not work on such MP systems. 213 | * For this reason, I strongly encourage everyone to test on VMware and bare-metal. Not working with MP system is like not working with pointer in the C programing language. 214 | 215 | * Debugging is not as easy as the case with QEMU+KVM or VMware due to lack of GDB debugging (ie, emulation of hardware debuggers). The authors recommend using those environment instead for this reason. 216 | 217 | * Kudos to Sinaei (@Intel80x86) for [documenting tricks to run a custome hypervisor on Hyper-V](https://rayanfam.com/topics/hypervisor-from-scratch-part-8/). 218 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Satoshi Tanda 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MiniVisor 2 | ========== 3 | 4 | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/5781c969419c47059f1aba259443fe79)](https://www.codacy.com?utm_source=github.com&utm_medium=referral&utm_content=tandasat/MiniVisorPkg&utm_campaign=Badge_Grade) 5 | 6 | This is a research hypervisor written as a UEFI and Windows driver for the educational purpose for Intel processors. 7 | 8 | This MiniVisor, as a UEFI driver, provides the ability to inspect system activities even before the operating system boots, while as a Windows driver, allows developers to debug it with familiar tools like WinDbg. 9 | 10 | Showcase 11 | --------- 12 | 13 | * Loading the hypervisor from the UEFI shell. 14 | ![Readme_Showcase1.jpg](Docs/Resources/Readme_Showcase1.jpg) 15 | 16 | * Logging boot activities and interacting with the guest. 17 | ![Readme_Showcase2.jpg](Docs/Resources/Readme_Showcase2.jpg) 18 | 19 | * Booting Ubuntu on a bare-metal. 20 | ![Readme_Showcase3.jpg](Docs/Resources/Readme_Showcase3.jpg) 21 | 22 | Motivation 23 | ----------- 24 | 25 | The goal of this project is to share an additional learning resource for writing UEFI hypervisors with the community and researchers. 26 | 27 | There are numerous open source hypervisors with small and easy-to-study implementations, but those that support booting operating systems as UEFI drivers are still not many. 28 | 29 | Given the universality of UEFI systems on the AMD64 ecosystem and the unique ability to monitor, attack and protect the system throughout operating system startup on bare-metal systems, the authors believe that having the understanding and being able to develop this type of hypervisors are valuable for research. 30 | 31 | System Requirements 32 | -------------------- 33 | 34 | Common Requirements: 35 | * Intel VT-x and EPT supported processors 36 | 37 | Requirements for the UEFI driver: 38 | * UEFI-based system 39 | * 64bit Windows 10, IoT Core, or Ubuntu to boot 40 | 41 | Requirements for the Windows driver: 42 | * 64bit Windows 10 43 | 44 | See [Building and Debugging](Docs/Building_and_Debugging.md) for testing. 45 | 46 | Advantages and Use Cases 47 | ------------------------- 48 | 49 | While this project does not implement or designed for any immediately useful features, UEFI-based hypervisors have multiple advantages over Windows driver-based ones and can implement unique features. 50 | 51 | * No need of disabling Hyper-V (Virtualization Based Security) to run the custom hypervisor 52 | * No need of enabling the test-signing mode 53 | * Zero direct indicator of existence of the hypervisor from operating system perspective 54 | * Detecting bootkit and early system modification 55 | * Implementing operating system agnostic solutions 56 | * Installing hooks during the early boot phase and letting PatchGuard to protect them 57 | ![Readme_Showcase4.jpg](Docs/Resources/Readme_Showcase4.jpg) 58 | 59 | Acknowledgments 60 | ---------------- 61 | 62 | The authors thank for creators and maintainers of the following projects: 63 | * [Bareflank](https://github.com/Bareflank/hypervisor) and [STM](https://github.com/jyao1/STM) -- for publishing UEFI-base hypervisors with the relatively small codebase. 64 | * [zpp_hypervisor](https://github.com/eyalz800/zpp_hypervisor) -- for making me realize that writing UEFI-based hypervisors is viable. 65 | * [EfiGuard](https://github.com/Mattiwatti/EfiGuard) -- for clean codebase and rich documentation for UEFI development newbies. 66 | * [hvpp](https://github.com/wbenny/hvpp) -- for few techniques required for the UEFI environment. 67 | * [ia32-doc](https://github.com/wbenny/ia32-doc) -- for saving me from defining thousands of constants and structures by hand. 68 | -------------------------------------------------------------------------------- /Sources/Asm.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file Asm.h 3 | 4 | @brief MASM-written functions. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #pragma once 11 | #include "Common.h" 12 | 13 | #if defined(MV_PLATFORM_WINDOWS) 14 | #include "Platform/Windows/WinAsm.h" 15 | #else 16 | #include "Platform/EFI/EfiAsm.h" 17 | #endif 18 | 19 | /*! 20 | @brief The entry point for the hypervisor. 21 | 22 | @details See Asm.asm. 23 | */ 24 | VOID 25 | AsmHypervisorEntryPoint ( 26 | ); 27 | 28 | /*! 29 | @brief Invalidates translations derived from EPT. 30 | 31 | @param[in] InvEptType - The type of invalidation. 32 | 33 | @param[in] InvEptDescriptor - The description of translations to invalidate. 34 | 35 | @return An appropriate VMX_RESULT value. 36 | */ 37 | VMX_RESULT 38 | AsmInvept ( 39 | _In_ INVEPT_TYPE InvEptType, 40 | _In_ CONST INVEPT_DESCRIPTOR* InvEptDescriptor 41 | ); 42 | 43 | /*! 44 | @brief Invalidates translations based on VPID. 45 | 46 | @param[in] InvVpidType - The type of invalidation. 47 | 48 | @param[in] InvVpidDescriptor - The description of translations to invalidate. 49 | 50 | @return An appropriate VMX_RESULT value. 51 | */ 52 | VMX_RESULT 53 | AsmInvvpid ( 54 | _In_ INVVPID_TYPE InvVpidType, 55 | _In_ CONST INVVPID_DESCRIPTOR* InvVpidDescriptor 56 | ); 57 | 58 | /*! 59 | @brief Reads the access rights byte of the segment. 60 | 61 | @details See: LAR-Load Access Rights Byte 62 | 63 | @param[in] SegmentSelector - The selector of the segment to read. 64 | 65 | @return The access rights byte of the segment, or 0 on failure. 66 | */ 67 | UINT32 68 | AsmLoadAccessRightsByte ( 69 | _In_ UINT16 SegmentSelector 70 | ); 71 | 72 | /*! 73 | @brief Issues hypercall. 74 | 75 | @param[in] HyperCallNumber - The hypercall number. 76 | 77 | @param[in] Parameter1 - The arbitrary 64bit parameter 1. 78 | 79 | @param[in] Parameter2 - The arbitrary 64bit parameter 2. 80 | 81 | @param[in] Parameter3 - The arbitrary 64bit parameter 3. 82 | 83 | @return The 64bit return value. Meaning is depends on HyperCallNumber. 84 | */ 85 | UINT64 86 | AsmVmxCall ( 87 | _In_ UINT64 HyperCallNumber, 88 | _In_ UINT64 Parameter1, 89 | _In_ UINT64 Parameter2, 90 | _In_ UINT64 Parameter3 91 | ); 92 | 93 | /*! 94 | @brief Returns the return address from this function. 95 | 96 | @return The return address from this function. 97 | */ 98 | UINT64 99 | AsmGetCurrentInstructionPointer ( 100 | ); 101 | 102 | /*! 103 | @brief Returns the current value of RSP. 104 | 105 | @return The current value of RSP. 106 | */ 107 | UINT64 108 | AsmGetCurrentStackPointer ( 109 | ); 110 | -------------------------------------------------------------------------------- /Sources/AsmCommon.inc: -------------------------------------------------------------------------------- 1 | ; 2 | ; @file AsmCommon.inc 3 | ; 4 | ; @brief Cross platform MASM-written marcos. 5 | ; 6 | ; @author Satoshi Tanda 7 | ; 8 | ; @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | ; 10 | 11 | ; 12 | ; @brief Saves all general purpose registers, except for RSP, to the stack. 13 | ; 14 | ; @details This macro does not alter the flag register. 15 | ; 16 | PUSHAQ macro 17 | push rax 18 | push rcx 19 | push rdx 20 | push rbx 21 | push rbp 22 | push rsi 23 | push rdi 24 | push r8 25 | push r9 26 | push r10 27 | push r11 28 | push r12 29 | push r13 30 | push r14 31 | push r15 32 | endm 33 | 34 | ; 35 | ; @brief Loads all general purpose registers, except for RSP, from the stack. 36 | ; 37 | ; @details This macro does not alter the flag register. 38 | ; 39 | POPAQ macro 40 | pop r15 41 | pop r14 42 | pop r13 43 | pop r12 44 | pop r11 45 | pop r10 46 | pop r9 47 | pop r8 48 | pop rdi 49 | pop rsi 50 | pop rbp 51 | pop rbx 52 | pop rdx 53 | pop rcx 54 | pop rax 55 | endm 56 | -------------------------------------------------------------------------------- /Sources/Common.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file Common.h 3 | 4 | @brief Common things across the project. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #pragma once 11 | #if defined(NTDDI_VERSION) 12 | #define MV_PLATFORM_WINDOWS 13 | #else 14 | #define MV_PLATFORM_EFI 15 | #endif 16 | 17 | #if defined(MV_PLATFORM_WINDOWS) 18 | #include "Platform/Windows/WinCommon.h" 19 | #else 20 | #include "Platform/EFI/EfiCommon.h" 21 | #endif 22 | 23 | #include "Ia32.h" 24 | 25 | // 26 | // The platform agnostic status type. 27 | // 28 | typedef _Return_type_success_(return >= 0) long MV_STATUS; 29 | 30 | // 31 | // Possible status values. 32 | // 33 | #define MV_STATUS_SUCCESS ((MV_STATUS)0x00000000L) 34 | #define MV_STATUS_UNSUCCESSFUL ((MV_STATUS)0xC0000001L) 35 | #define MV_STATUS_ACCESS_DENIED ((MV_STATUS)0xC0000022L) 36 | #define MV_STATUS_INSUFFICIENT_RESOURCES ((MV_STATUS)0xC000009AL) 37 | #define MV_STATUS_HV_OPERATION_FAILED ((MV_STATUS)0xC0350071L) 38 | 39 | // 40 | // The status check macro(s). 41 | // 42 | #define MV_ERROR(Status) ((UINT32)(Status) >= (UINT32)0xc0000000) 43 | 44 | // 45 | // Computes offsets from the given pointer. 46 | // 47 | #define MV_ADD2PTR(Ptr, Value) ((VOID*)((UINT8*)(Ptr) + (Value))) 48 | 49 | // 50 | // Hyper-V Hypervisor Top-Level Functional Specification (TLFS) related. 51 | // 52 | #define CPUID_HV_VENDOR_AND_MAX_FUNCTIONS ((UINT32)0x40000000) 53 | #define CPUID_HV_INTERFACE ((UINT32)0x40000001) 54 | #define CPUID_HV_MAX CPUID_HV_INTERFACE 55 | 56 | // 57 | // Indicates the invalid physical address. 58 | // 59 | #define MV_INVALID_PHYSICAL_ADDRESS ((UINT64)-1) 60 | 61 | // 62 | // Replacement of BOOLEAN for the flag to indicate whether the operation is read 63 | // or write. 64 | // 65 | typedef enum _OPERATION_TYPE 66 | { 67 | OperationRead, 68 | OperationWrite, 69 | } OPERATION_TYPE; 70 | 71 | // 72 | // The result type of Microsoft VMX-intrinsic functions. 73 | // 74 | typedef enum _VMX_RESULT 75 | { 76 | VmxResultOk = 0, //!< Operation succeeded 77 | VmxResultErrorWithStatus = 1, //!< Operation failed with extended status available 78 | VmxResultErrorWithoutStatus = 2, //!< Operation failed without status available 79 | } VMX_RESULT; 80 | -------------------------------------------------------------------------------- /Sources/ExtendedPageTables.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file ExtendedPageTables.h 3 | 4 | @brief Functions for EPT handling. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 -, Satoshi Tanda. All rights reserved. 9 | */ 10 | #pragma once 11 | #include "Common.h" 12 | 13 | /*! 14 | @brief Checks whether the EPT entry is present. 15 | 16 | @param[in] EptEntry - The pointer to the EPT entry to check. 17 | 18 | @return TRUE when the entry is present. 19 | */ 20 | #define MV_IS_EPT_ENTRY_PRESENT(EptEntry) \ 21 | (((EptEntry)->ReadAccess != FALSE) || \ 22 | ((EptEntry)->WriteAccess != FALSE) || \ 23 | ((EptEntry)->ExecuteAccess != FALSE)) 24 | 25 | /*! 26 | @brief Copies the permission of the EPT entry to the other entry. 27 | 28 | @param[out] Destination - The pointer to the EPT entry to updates its permission. 29 | 30 | @param[in] EptEntry - The pointer to the EPT entry to copy its permission from. 31 | */ 32 | #define MV_COPY_EPT_ENTRY_PERMISSIONS(Destination, EptEntry) \ 33 | (Destination)->ReadAccess = (EptEntry)->ReadAccess; \ 34 | (Destination)->WriteAccess = (EptEntry)->WriteAccess; \ 35 | (Destination)->ExecuteAccess = (EptEntry)->ExecuteAccess 36 | 37 | /*! 38 | @brief Aggregates the permission of the EPT entry to the other entry. 39 | 40 | @param[out] Destination - The pointer to the EPT entry to updates its permission. 41 | 42 | @param[in] EptEntry - The pointer to the EPT entry to aggregate its permission from. 43 | */ 44 | #define MV_AGGREGATE_EPT_ENTRY_PERMISSIONS(Destination, EptEntry) \ 45 | (Destination)->ReadAccess &= (EptEntry)->ReadAccess; \ 46 | (Destination)->WriteAccess &= (EptEntry)->WriteAccess; \ 47 | (Destination)->ExecuteAccess &= (EptEntry)->ExecuteAccess 48 | 49 | // 50 | // Holds the context specific to EPT. 51 | // 52 | typedef struct _EPT_CONTEXT 53 | { 54 | // 55 | // EPTP written to VMCS. 56 | // 57 | EPT_POINTER EptPointer; 58 | 59 | // 60 | // The virtual address of the EPT PML4. 61 | // 62 | EPT_PML4* EptPml4; 63 | } EPT_CONTEXT; 64 | 65 | /*! 66 | @brief Initializes identity-mapping EPTs. 67 | 68 | @param[in,out] EptContext - The pointer to the EPT context to initialize. 69 | 70 | @return MV_STATUS_SUCCESS on success; otherwise, an appropriate error code. 71 | */ 72 | _Must_inspect_result_ 73 | MV_STATUS 74 | InitializeExtendedPageTables ( 75 | _Inout_ EPT_CONTEXT* EptContext 76 | ); 77 | 78 | /*! 79 | @brief Cleans up the EPT context. 80 | 81 | @param[in,out] EptContext - The pointer to the EPT context to clean up. 82 | */ 83 | VOID 84 | CleanupExtendedPageTables ( 85 | _Inout_ EPT_CONTEXT* EptContext 86 | ); 87 | 88 | /*! 89 | @brief Updates the EPT PTE for the given GPA with new HPA and permissions. 90 | 91 | @param[in] EptPml4 - The pointer to the EPT PML4. 92 | 93 | @param[in] GuestPhysicalAddress - The GPA to update its EPT PTE. 94 | 95 | @param[in] HostPhysicalAddress - The pointer to the HPA to update to. If NULL 96 | is specified, the function does not change the translation. 97 | 98 | @param[in] Permissions - The pointer to the new permission to update to. If 99 | NULL is specified, the functions does not change the permissions. 100 | 101 | @return MV_STATUS_SUCCESS on success; otherwise, an appropriate error code. 102 | */ 103 | _Must_inspect_result_ 104 | MV_STATUS 105 | UpdateExtendPageTables ( 106 | _In_ EPT_PML4* EptPml4, 107 | _In_ UINT64 GuestPhysicalAddress, 108 | _In_opt_ CONST UINT64* HostPhysicalAddress, 109 | _In_opt_ CONST EPT_ENTRY* Permissions 110 | ); 111 | 112 | /*! 113 | @brief Invalidates guest-physical and combined caches. 114 | 115 | @param[in] EptPointer - The EPT pointer to invalidate associated caches. If 116 | 0 is specified, caches associated with any EPT pointers are invalidated. 117 | */ 118 | VOID 119 | InvalidateEptDerivedCache ( 120 | _In_ UINT64 EptPointer 121 | ); 122 | 123 | /*! 124 | @brief Invalidates liner and combined caches. 125 | 126 | @param[in] VirtualProcessorId - The VPID to invalidate associated caches. If 127 | 0 is specified, caches associated with any VPIDs are invalidated. 128 | */ 129 | VOID 130 | InvalidateVpidDerivedCache ( 131 | _In_ UINT16 VirtualProcessorId 132 | ); 133 | -------------------------------------------------------------------------------- /Sources/HostInitialization.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file HostInitialization.h 3 | 4 | @brief Functions for host environment initialization. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #pragma once 11 | #include "Common.h" 12 | 13 | /*! 14 | @brief Initializes the host environment. 15 | */ 16 | VOID 17 | InitializeHostEnvironment ( 18 | ); 19 | 20 | /*! 21 | @brief Returns the host CR3. 22 | 23 | @return The host CR3. 24 | */ 25 | CR3 26 | GetHostCr3 ( 27 | ); 28 | 29 | /*! 30 | @brief Returns the pointer to the host IDTR. 31 | 32 | @return The pointer to the host IDTR. 33 | */ 34 | CONST IDTR* 35 | GetHostIdtr ( 36 | ); 37 | 38 | /*! 39 | @brief Sets up the task state segment (TSS) and the TR register. 40 | 41 | @details On EFI, this functions takes a copy of the existing GDT into NewGdt, 42 | adds a new entry into it, which points to NewTss, then, updates the GDTR 43 | and TR to point to the NewGdt and the newly added entry. Those updated 44 | GDTR and TR may be used as both host and guest GDTR/TR. 45 | 46 | On Windows, this function is no-op. 47 | 48 | @param[in,out] NewTss - The pointer to buffer to be used as the task state 49 | segment. 50 | 51 | @param[out] NewGdt - The pointer to the buffet to be used as the new GDT. 52 | This will be initialized with the contents of the current GDT with the 53 | new entry for TSS. 54 | 55 | @param[in] NewGdtSize - The size of NewGdt in bytes. 56 | 57 | @param[out] OriginalGdtr - The pointer to the GDTR to receive the value before 58 | this function updates. 59 | */ 60 | VOID 61 | InitializeGdt ( 62 | _Inout_ TASK_STATE_SEGMENT_64* NewTss, 63 | _Out_writes_bytes_(NewGdtSize) SEGMENT_DESCRIPTOR_64* NewGdt, 64 | _In_ UINT64 NewGdtSize, 65 | _Out_ GDTR* OriginalGdtr 66 | ); 67 | 68 | /*! 69 | @brief Restores the GDTR to the specified value. 70 | 71 | @details On EFI, this function updates the current GDTR, however, does not 72 | restore the TR to the original value. This is because the original value 73 | is expected to be zero, which cannot write to TR anymore (causes #GP). 74 | Because of this, TR will point to an invalid entry in the restored GDT. 75 | This is an unsolvable issue unless we reuse the existing GDT instead of 76 | creating a copy, which does not work on VMware Workstation due to the 77 | physical address hosting the GDT is not modifiable. The only sane 78 | workaround would be to disallow unloading of the MiniVisor module. 79 | 80 | On Windows, this function is no-op. 81 | 82 | @param[in] OriginalGdtr - The pointer to the GDTR to restore to. 83 | */ 84 | VOID 85 | CleanupGdt ( 86 | _In_ CONST GDTR* OriginalGdtr 87 | ); 88 | 89 | /*! 90 | @brief Checks additional VMX feature availability for the platform. 91 | 92 | @return Whether sufficient VMX features are supported. 93 | */ 94 | BOOLEAN 95 | IsVmxAvailableEx ( 96 | ); 97 | -------------------------------------------------------------------------------- /Sources/HostMain.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file HostMain.h 3 | 4 | @brief Functions for VM-exit handling. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 -, Satoshi Tanda. All rights reserved. 9 | */ 10 | #pragma once 11 | #include "Common.h" 12 | -------------------------------------------------------------------------------- /Sources/HostNesting.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file HostNesting.h 3 | 4 | @brief Incomplete nesting related code. Do not study. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #pragma once 11 | #include "Common.h" 12 | #include "Ia32.h" 13 | #include "HostUtils.h" 14 | #include "ExtendedPageTables.h" 15 | 16 | typedef enum _VMX_OPERATION 17 | { 18 | VmxOperationNotInVmxOperation, 19 | VmxOperationRoot, 20 | VmxOperationNonRoot, 21 | } VMX_OPERATION; 22 | 23 | typedef enum _VMCS_LAUNCH_STATE 24 | { 25 | LaunchStateUnintialized, 26 | LaunchStateClear, 27 | LaunchStateLaunched, 28 | } VMCS_LAUNCH_STATE; 29 | 30 | typedef struct _NEXTED_VMX_CONTEXT 31 | { 32 | VMX_OPERATION VmxOperation; 33 | VMCS_LAUNCH_STATE VmcsLaunchState; 34 | 35 | // 36 | // The physical address of the VMXON region (used by L1 for L2) 37 | // 38 | UINT64 Vmxon12Pa; 39 | 40 | // 41 | // The physical addresses of VMCSs (used by L0 for L1 and L2) 42 | // 43 | UINT64 Vmcs01Pa; 44 | UINT64 Vmcs02Pa; 45 | 46 | // 47 | // Current VMCS from the point of view of the nested VMM (used by L1 for L2) 48 | // 49 | UINT64 Vmcs12Pa; 50 | 51 | // 52 | // EPT related data (used by L0 for L2) 53 | // 54 | EPT_CONTEXT Ept02Context; 55 | EPT_PML4* EptPml4_02; 56 | 57 | // 58 | // VMCS (used by L0 for L2). 59 | // 60 | DECLSPEC_ALIGN(PAGE_SIZE) VMCS Vmcs02; 61 | } NEXTED_VMX_CONTEXT; 62 | 63 | VOID 64 | HandleVmx ( 65 | _Inout_ GUEST_CONTEXT* GuestContext, 66 | _In_ UINT32 ExitReason 67 | ); 68 | 69 | VOID 70 | EmulateVmExitForL1Vmm ( 71 | _Inout_ GUEST_CONTEXT* GuestContext, 72 | _In_ UINT32 ExitReason 73 | ); 74 | 75 | BOOLEAN 76 | IsVmExitForL1 ( 77 | CONST GUEST_CONTEXT* GuestContext, 78 | VMX_VMEXIT_REASON VmExitReason 79 | ); 80 | -------------------------------------------------------------------------------- /Sources/HostUtils.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file HostUtils.h 3 | 4 | @brief Utility functions and structures for the host. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #pragma once 11 | #include "Common.h" 12 | #include "Public.h" 13 | 14 | // 15 | // 128bit XMM register (ie, equivalent to __m128 on MSVC). 16 | // 17 | typedef struct _XMM 18 | { 19 | UINT8 Value[16]; 20 | } XMM; 21 | 22 | // 23 | // Guest General Purpose Registers (GPRs) created on VM-exit from the guest 24 | // state and write back to the guest on VM-entry. 25 | // 26 | typedef struct _GUEST_REGISTERS 27 | { 28 | XMM Xmm[6]; 29 | VOID* Alignment; 30 | UINT64 R15; 31 | UINT64 R14; 32 | UINT64 R13; 33 | UINT64 R12; 34 | UINT64 R11; 35 | UINT64 R10; 36 | UINT64 R9; 37 | UINT64 R8; 38 | UINT64 Rdi; 39 | UINT64 Rsi; 40 | UINT64 Rbp; 41 | UINT64 Rbx; 42 | UINT64 Rdx; 43 | UINT64 Rcx; 44 | UINT64 Rax; 45 | } GUEST_REGISTERS; 46 | 47 | // 48 | // The guest registers that are stored in the VMCS as opposed to stack like 49 | // ones in the GUEST_REGISTERS structure. 50 | // 51 | typedef struct _VMCS_BASED_REGISTERS 52 | { 53 | UINT64 Rip; 54 | UINT64 Rsp; 55 | RFLAGS Rflags; 56 | } VMCS_BASED_REGISTERS; 57 | 58 | // 59 | // State of the guest. 60 | // 61 | typedef struct _GUEST_CONTEXT 62 | { 63 | // 64 | // Indicates that the processor should continue virtualization. FALSE of 65 | // results in disablement of hypervisor with the VMXOFF instruction. See 66 | // x64.asm. This value is used as a return value of the HandleVmExit function. 67 | // 68 | BOOLEAN ContinueVm; 69 | 70 | // 71 | // Collection of pointers passed from the kernel via the host stack. 72 | // 73 | HYPERVISOR_CONTEXT* Contexts; 74 | 75 | // 76 | // The guest states stored in hypervisor stack. 77 | // 78 | GUEST_REGISTERS* StackBasedRegisters; 79 | 80 | // 81 | // The guest states stored in the VMCS. 82 | // 83 | VMCS_BASED_REGISTERS VmcsBasedRegisters; 84 | } GUEST_CONTEXT; 85 | 86 | /*! 87 | @brief Dumps host state VMCS fields. 88 | */ 89 | VOID 90 | DumpHostState ( 91 | ); 92 | 93 | /*! 94 | @brief Dumps guest state VMCS fields. 95 | */ 96 | VOID 97 | DumpGuestState ( 98 | ); 99 | 100 | /*! 101 | @brief Dumps control VMCS fields. 102 | */ 103 | VOID 104 | DumpControl ( 105 | ); 106 | 107 | /*! 108 | @brief Writes the value to the VMCS. 109 | 110 | @param[in] Field - The VMCS field to write the value to. 111 | 112 | @param[in] FieldValue - The value to write. 113 | */ 114 | VOID 115 | VmxWrite ( 116 | _In_ VMCS_FIELD Field, 117 | _In_ UINT64 FieldValue 118 | ); 119 | 120 | /*! 121 | @brief Read a value from the VMCS. 122 | 123 | @param[in] Field - The VMCS field to read a value from. 124 | 125 | @return A value read from the VMCS. 0 is returned when a non-existent VMCS 126 | field is requested for read. 127 | */ 128 | UINT64 129 | VmxRead ( 130 | _In_ VMCS_FIELD Field 131 | ); 132 | 133 | /*! 134 | @brief Advances the guest's RIP to the address of the next instruction. This 135 | implies that the hypervisor completed emulation of the instruction. 136 | 137 | @param[in,out] GuestContext - The pointer to the guest context. 138 | */ 139 | VOID 140 | AdvanceGuestInstructionPointer ( 141 | _Inout_ GUEST_CONTEXT* GuestContext 142 | ); 143 | 144 | /*! 145 | @brief Tests whether the guest was at the CPL 0 (kernel-mode) when VM-exit 146 | happened. 147 | 148 | @return TRUE when the guest was at the CPL 0, otherwise FALSE. 149 | */ 150 | _Must_inspect_result_ 151 | BOOLEAN 152 | IsGuestInKernelMode ( 153 | ); 154 | 155 | /*! 156 | @brief Queues interrupt to occur to the VMCS. 157 | 158 | @details Generally, this interrupt fires on VM-entry and the guests runs a 159 | corresponding exception handler before executing the instruction pointed 160 | by Rip. 161 | 162 | @param[in] InterruptionType - The type of interrupt to inject. 163 | 164 | @param[in] Vector - The vector number of interrupt to inject. 165 | 166 | @param[in] DeliverErrorCode - TRUE when the interrupt should have an error 167 | code. Whether the interrupt should have an error code is defined by the 168 | Intel SDM. See comments in the EXCEPTION_VECTOR definitions for a quick 169 | reference. 170 | 171 | @param[in] ErrorCode - The error code. Not used when DeliverErrorCode is FALSE. 172 | */ 173 | VOID 174 | InjectInterruption ( 175 | _In_ INTERRUPTION_TYPE InterruptionType, 176 | _In_ EXCEPTION_VECTOR Vector, 177 | _In_ BOOLEAN DeliverErrorCode, 178 | _In_ UINT32 ErrorCode 179 | ); 180 | 181 | /*! 182 | @brief Switches the guest paging mode between 32 and 64bit modes according 183 | with CR0 and EFER. 184 | 185 | @param[in] NewGuestCr0 - The guest CR0 value to check the mode to switch to. 186 | */ 187 | VOID 188 | SwitchGuestPagingMode ( 189 | _In_ CR0 NewGuestCr0 190 | ); 191 | 192 | /*! 193 | @brief Returns the CR0 value after the FIXED0 and FIXED1 MSR values are applied 194 | for the guest. 195 | 196 | @param[in] Cr0 - The CR0 value to apply the FIXED0 and FIXED1 MSR values. 197 | 198 | @return The CR0 value where the FIXED0 and FIXED1 MSR values are applied. 199 | */ 200 | CR0 201 | AdjustGuestCr0 ( 202 | _In_ CR0 Cr0 203 | ); 204 | 205 | /*! 206 | @brief Returns the CR4 value after the FIXED0 and FIXED1 MSR values are applied 207 | for the guest. 208 | 209 | @param[in] Cr4 - The CR4 value to apply the FIXED0 and FIXED1 MSR values. 210 | 211 | @return The CR4 value where the FIXED0 and FIXED1 MSR values are applied. 212 | */ 213 | CR4 214 | AdjustGuestCr4 ( 215 | _In_ CR4 Cr4 216 | ); 217 | 218 | /*! 219 | @brief Finds the base address of the image to which the specified address belongs. 220 | 221 | @param[in] GuestContext - The pointer to the guest context. 222 | 223 | @param[in] GuestVirtualAddress - The guest virtual address to find its image 224 | base. 225 | 226 | @return The base address of the image to which GuestVirtualAddress belongs, or 227 | 0 on error. 228 | */ 229 | UINT64 230 | FindImageBase ( 231 | _In_ GUEST_CONTEXT* GuestContext, 232 | _In_ UINT64 GuestVirtualAddress 233 | ); 234 | 235 | /*! 236 | @brief Updates the MSR bitmap as specified. 237 | 238 | @param[in] Bitmaps - The pointer to the MSR bitmaps. 239 | 240 | @param[in,out] Msr - The MSR to change configurations. Must be in the range of 241 | 0x0 - 0x1fff or 0xc0000000 - 0xc0001fff. 242 | 243 | @param[in] InterOperation - The type of operation to change configurations. 244 | 245 | @param[in] Intercept - TRUE if the hypervisor should intercept the specified 246 | type of access. 247 | */ 248 | VOID 249 | UpdateMsrBitmaps ( 250 | _Inout_ MSR_BITMAPS* Bitmaps, 251 | _In_ IA32_MSR_ADDRESS Msr, 252 | _In_ OPERATION_TYPE InterOperation, 253 | _In_ BOOLEAN Intercept 254 | ); 255 | 256 | /*! 257 | @brief Enables or disables NMI window exiting. 258 | 259 | @param[in] Enable - Whether NMI window exiting should be enabled. 260 | */ 261 | VOID 262 | SetNmiWindowExiting ( 263 | _In_ BOOLEAN Enable 264 | ); 265 | -------------------------------------------------------------------------------- /Sources/HostVmcall.c: -------------------------------------------------------------------------------- 1 | /*! 2 | @file HostVmcall.c 3 | 4 | @brief Implementation of hypercall functions. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #include "HostVmcall.h" 11 | 12 | _Use_decl_annotations_ 13 | VOID 14 | HandleVmcallUninstall ( 15 | GUEST_CONTEXT* GuestContext 16 | ) 17 | { 18 | GDTR gdtr; 19 | IDTR idtr; 20 | 21 | // 22 | // This hypercall is not allowed for ring 3. 23 | // 24 | if (IsGuestInKernelMode() == FALSE) 25 | { 26 | GuestContext->StackBasedRegisters->Rax = (UINT64)MV_STATUS_ACCESS_DENIED; 27 | goto Exit; 28 | } 29 | 30 | // 31 | // On VM-exit, the processor loads registers according with the Host state 32 | // fields in the VMCS. Some registers are changed, e.g, GPRs, and some 33 | // others are changed with hard-coded values. The limits of GDTR and IDTR 34 | // are such example, and updated to 0xFFFF. When the VMRESUME instruction 35 | // is executed, this is not an issue as VM-entry reloads the proper values 36 | // from the guest state fields of the VMCS. However, it is not the case when 37 | // the VMRESUME is not called, like here. In such a case those values must 38 | // be restored with normal value manually, or PatchGuard will report 39 | // integrity violation on Windows. 40 | // 41 | // "The GDTR and IDTR limits are each set to FFFFH." 42 | // See: 27.5.2 Loading Host Segment and Descriptor-Table Registers 43 | // 44 | gdtr.BaseAddress = VmxRead(VMCS_GUEST_GDTR_BASE); 45 | gdtr.Limit = (UINT16)VmxRead(VMCS_GUEST_GDTR_LIMIT); 46 | _lgdt(&gdtr); 47 | 48 | idtr.BaseAddress = VmxRead(VMCS_GUEST_IDTR_BASE); 49 | idtr.Limit = (UINT16)VmxRead(VMCS_GUEST_IDTR_LIMIT); 50 | __lidt(&idtr); 51 | 52 | // 53 | // The host may use a different CR3 than that of the guest. This is the case 54 | // on EFI. Apply the guest one. This assumes that translation both the host 55 | // CR3 and the guest CR3 has the same translation. Otherwise, the system will 56 | // crash immediately after updating CR3. 57 | // 58 | __writecr3(VmxRead(VMCS_GUEST_CR3)); 59 | 60 | // 61 | // Save some values needed for clean up in the volatile registers. 62 | // RAX = The address of the shared processor context. This is used as a 63 | // return value of the AsmVmxCall function. 64 | // RCX = The address to continue execution after the execution of the VMXOFF 65 | // instruction. This value is needed because we have to manually 66 | // transfer execution instead of doing so automatically with the 67 | // VMRESUME instruction in this pass. 68 | // RDX = The RSP value to be restored. Same as the case of RIP, the RSP is 69 | // not automatically restored in this pass, and so, has to be updated 70 | // by the original value (not host's RSP). 71 | // Param2 = The RFLAGS value to be restored. Also same as the case of RIP and 72 | // RSP. Recall that RFLAGS is also updated automatically on VM-exit. 73 | // "RFLAGS is cleared, except bit 1, which is always set." 74 | // See: 27.5.3 Loading Host RIP, RSP, and RFLAGS 75 | // 76 | GuestContext->StackBasedRegisters->Rax = (UINT64)GuestContext->Contexts->SharedProcessorContext; 77 | GuestContext->StackBasedRegisters->Rcx = GuestContext->VmcsBasedRegisters.Rip + 78 | VmxRead(VMCS_VMEXIT_INSTRUCTION_LENGTH); 79 | GuestContext->StackBasedRegisters->Rdx = GuestContext->VmcsBasedRegisters.Rsp; 80 | GuestContext->StackBasedRegisters->R8 = GuestContext->VmcsBasedRegisters.Rflags.Flags; 81 | 82 | // 83 | // Finally, indicates that virtualization should be terminated. 84 | // 85 | GuestContext->ContinueVm = FALSE; 86 | 87 | Exit: 88 | return; 89 | } 90 | -------------------------------------------------------------------------------- /Sources/HostVmcall.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file HostVmcall.h 3 | 4 | @brief Implementation of hypercall functions. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #pragma once 11 | #include "Common.h" 12 | #include "HostUtils.h" 13 | #include "Public.h" 14 | 15 | // 16 | // The VMCALL handler type. 17 | // 18 | typedef 19 | VOID 20 | VMCALL_HANDLER ( 21 | _Inout_ GUEST_CONTEXT* GuestContext 22 | ); 23 | 24 | /*! 25 | @brief Handles hypercall for uninstalling the hypervisor. 26 | 27 | @param[in,out] GuestContext - The pointer to the guest context. 28 | */ 29 | VMCALL_HANDLER HandleVmcallUninstall; 30 | 31 | // 32 | // VMCALL handlers and mapping. 33 | // 34 | static VMCALL_HANDLER* k_VmcallHandlers[] = 35 | { 36 | NULL, 37 | HandleVmcallUninstall, 38 | }; 39 | C_ASSERT(RTL_NUMBER_OF(k_VmcallHandlers) == (MV_VMCALL_INVALID_MAX & MAXUINT32)); 40 | -------------------------------------------------------------------------------- /Sources/Ia32.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file Ia32.h 3 | 4 | @brief Intel SDM defined constants and structures. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #pragma once 11 | 12 | // 13 | // "nonstandard extension used: bit field types other than int" 14 | // 15 | #pragma warning(disable: 4214) 16 | 17 | // 18 | // "nonstandard extension used: nameless struct/union" 19 | // 20 | #pragma warning(push) 21 | #pragma warning(disable: 4201) 22 | #include 23 | #pragma warning(pop) 24 | 25 | #if !defined(CHAR_BIT) 26 | #define CHAR_BIT (8) 27 | #endif 28 | 29 | // 30 | // The entry count within the IDT. 31 | // 32 | #define IDT_ENTRY_COUNT 256 33 | 34 | // 35 | // The levels of paging structures. 36 | // 37 | #define PT_LEVEL_PML4E 4 38 | #define PT_LEVEL_PDPTE 3 39 | #define PT_LEVEL_PDE 2 40 | #define PT_LEVEL_PTE 1 41 | 42 | // 43 | // Bits useful for working with paging structures and EPTs. 44 | // 45 | #ifndef PAGE_SHIFT 46 | #define PAGE_SHIFT 12 47 | #endif 48 | #define PAGE_SHIFT_2BM 21 49 | #define PAGE_SHIFT_1GB 30 50 | #define PAGE_MASK (PAGE_SIZE - 1) 51 | 52 | // 53 | // See: 11.11.2.2 Fixed Range MTRRs 54 | // 55 | typedef union _IA32_MTRR_FIXED_RANGE_MSR 56 | { 57 | struct 58 | { 59 | UINT8 Types[8]; 60 | } u; 61 | UINT64 Flags; 62 | } IA32_MTRR_FIXED_RANGE_MSR; 63 | 64 | // 65 | // See: Table 11-10. Memory Ranges That Can Be Encoded With PAT 66 | // 67 | // Find MEMORY_TYPE_* for possible values. 68 | // 69 | typedef UINT32 IA32_MEMORY_TYPE; 70 | 71 | typedef UINT64 VMCS_FIELD; 72 | 73 | typedef SEGMENT_DESCRIPTOR_REGISTER_64 GDTR, IDTR; 74 | 75 | typedef UINT32 IA32_MSR_ADDRESS; 76 | 77 | // 78 | // See: Table 30-1. VM-Instruction Error Numbers 79 | // 80 | typedef UINT32 VMX_ERROR_NUMBER; 81 | 82 | // 83 | // The helper structure for translating the guest physical address to the 84 | // host physical address. 85 | // 86 | typedef union _ADDRESS_TRANSLATION_HELPER 87 | { 88 | // 89 | // Indexes to locate paging-structure entries corresponds to this virtual 90 | // address. 91 | // 92 | struct 93 | { 94 | UINT64 Unused : 12; //< [11:0] 95 | UINT64 Pt : 9; //< [20:12] 96 | UINT64 Pd : 9; //< [29:21] 97 | UINT64 Pdpt : 9; //< [38:30] 98 | UINT64 Pml4 : 9; //< [47:39] 99 | } AsIndex; 100 | 101 | // 102 | // The page offset for each type of pages. For example, for 4KB pages, bits 103 | // [11:0] are treated as the page offset and Mapping4Kb can be used for it. 104 | // 105 | union 106 | { 107 | UINT64 Mapping4Kb : 12; //< [11:0] 108 | UINT64 Mapping2Mb : 21; //< [20:0] 109 | UINT64 Mapping1Gb : 30; //< [29:0] 110 | } AsPageOffset; 111 | 112 | UINT64 AsUInt64; 113 | } ADDRESS_TRANSLATION_HELPER; 114 | 115 | // 116 | // See: Figure 7-11. 64-Bit TSS Format 117 | // 118 | #pragma pack(push, 1) 119 | typedef struct _TASK_STATE_SEGMENT_64 120 | { 121 | UINT32 Reserved0; 122 | UINT64 Rsp0; 123 | UINT64 Rsp1; 124 | UINT64 Rsp2; 125 | UINT64 Reserved1; 126 | UINT64 Ist[7]; 127 | UINT64 Reserved3; 128 | UINT16 Reserved4; 129 | UINT16 IoMapBaseAddress; 130 | } TASK_STATE_SEGMENT_64; 131 | C_ASSERT(sizeof(TASK_STATE_SEGMENT_64) == 104); 132 | #pragma pack(pop) 133 | 134 | // 135 | // The page-aligned, 4KB size region used as a MSR bitmap. The MSR bitmap is 136 | // used to indicate which MSR should cause VM-exit on RDMSR and WRMSR. Each 137 | // bit in this 4KB region represents ON or OFF of VM-exit, where 0 indicates 138 | // not to trigger, and 1 indicates to trigger VM-exit. This hypervisor does 139 | // not intend to handle MSR accesses and so, all bits are left as 0. It is 140 | // important that this bitmap governs VM-exit behavior only for certain sets 141 | // of MSRs. An access to any MSR that is not governed by this bitmap still 142 | // causes VM-exit unconditionally. For this reason, this hypervisor still 143 | // has RDMSR and WRMSR handling logic. 144 | // 145 | // See: 24.6.9 MSR-Bitmap Address 146 | // 147 | typedef struct _MSR_BITMAPS 148 | { 149 | UINT8 ReadBitmapLow[1024]; 150 | UINT8 ReadBitmapHigh[1024]; 151 | UINT8 WriteBitmapLow[1024]; 152 | UINT8 WriteBitmapHigh[1024]; 153 | } MSR_BITMAPS; 154 | C_ASSERT(sizeof(MSR_BITMAPS) == PAGE_SIZE); 155 | -------------------------------------------------------------------------------- /Sources/Ia32Utils.c: -------------------------------------------------------------------------------- 1 | /*! 2 | @file Ia32Utils.c 3 | 4 | @brief Utility functions that could be used by both the host and non-host. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #include "Ia32Utils.h" 11 | #include "Asm.h" 12 | #include "Logger.h" 13 | 14 | _Use_decl_annotations_ 15 | UINT64 16 | ComputeAddressFromIndexes ( 17 | UINT32 Pml4Index, 18 | UINT32 PdptIndex, 19 | UINT32 PdIndex, 20 | UINT32 PtIndex 21 | ) 22 | { 23 | ADDRESS_TRANSLATION_HELPER helper; 24 | 25 | helper.AsUInt64 = 0; 26 | helper.AsIndex.Pml4 = Pml4Index; 27 | helper.AsIndex.Pdpt = PdptIndex; 28 | helper.AsIndex.Pd = PdIndex; 29 | helper.AsIndex.Pt = PtIndex; 30 | return helper.AsUInt64; 31 | } 32 | 33 | UINT32 34 | GetSegmentAccessRight ( 35 | _In_ UINT16 SegmentSelector 36 | ) 37 | { 38 | SEGMENT_SELECTOR segmentSelector; 39 | UINT32 nativeAccessRight; 40 | VMX_SEGMENT_ACCESS_RIGHTS accessRight; 41 | 42 | segmentSelector.Flags = SegmentSelector; 43 | 44 | // 45 | // "In general, a segment register is unusable if it has been loaded with a 46 | // null selector." 47 | // See: 24.4.1 Guest Register State 48 | // 49 | if ((segmentSelector.Table == 0) && 50 | (segmentSelector.Index == 0)) 51 | { 52 | accessRight.Flags = 0; 53 | accessRight.Unusable = TRUE; 54 | goto Exit; 55 | } 56 | 57 | // 58 | // Convert the native access right to the format for VMX. Those two formats 59 | // are almost identical except that first 8 bits of the native format does 60 | // not exist in the VMX format, and that few fields are undefined in the 61 | // native format but reserved to be zero in the VMX format. 62 | // 63 | nativeAccessRight = AsmLoadAccessRightsByte(SegmentSelector); 64 | MV_ASSERT(nativeAccessRight); 65 | accessRight.Flags = (nativeAccessRight >> 8); 66 | accessRight.Reserved1 = 0; 67 | accessRight.Reserved2 = 0; 68 | accessRight.Unusable = FALSE; 69 | 70 | Exit: 71 | return accessRight.Flags; 72 | } 73 | 74 | /*! 75 | @brief Returns the segment descriptor corresponds to the SegmentSelector. 76 | 77 | @param[in] DescriptorTableBase - The address of the base of the descriptor 78 | table. 79 | 80 | @param[in] SegmentSelector - The segment selector value. 81 | 82 | @return The segment descriptor corresponds to the SegmentSelector. 83 | */ 84 | static 85 | SEGMENT_DESCRIPTOR_32* 86 | GetSegmentDescriptor ( 87 | _In_ UINT64 DescriptorTableBase, 88 | _In_ UINT16 SegmentSelector 89 | ) 90 | { 91 | SEGMENT_SELECTOR segmentSelector; 92 | SEGMENT_DESCRIPTOR_32* segmentDescriptors; 93 | 94 | // 95 | // "Selects one of 8192 descriptors in the GDT or LDT. The processor multiplies 96 | // the index value by 8 (the number of bytes in a segment descriptor) and 97 | // adds the result to the base address of the GDT or LDT (from the GDTR or 98 | // LDTR register, respectively)." 99 | // See: 3.4.2 Segment Selectors 100 | // 101 | segmentSelector.Flags = SegmentSelector; 102 | segmentDescriptors = (SEGMENT_DESCRIPTOR_32*)DescriptorTableBase; 103 | return &segmentDescriptors[segmentSelector.Index]; 104 | } 105 | 106 | /*! 107 | @brief Returns the base address of SegmentDescriptor. 108 | 109 | @param[in] SegmentDescriptor - The segment descriptor from which retrieve 110 | the base address. 111 | 112 | @return The base address of SegmentDescriptor. 113 | */ 114 | static 115 | UINT64 116 | GetSegmentBaseByDescriptor ( 117 | _In_ CONST SEGMENT_DESCRIPTOR_32* SegmentDescriptor 118 | ) 119 | { 120 | UINT64 segmentBase; 121 | UINT64 baseHigh, baseMiddle, baseLow; 122 | 123 | baseHigh = ((UINT64)SegmentDescriptor->BaseAddressHigh) << (6 * 4); 124 | baseMiddle = ((UINT64)SegmentDescriptor->BaseAddressMiddle) << (4 * 4); 125 | baseLow = SegmentDescriptor->BaseAddressLow; 126 | segmentBase = (baseHigh | baseMiddle | baseLow) & MAXUINT32; 127 | 128 | // 129 | // Few system descriptors are expanded to 16 bytes on x64. For practical 130 | // reasons, we only detect TSS descriptors (that is the System field is 131 | // cleared, and the Type field has either one of specific values). 132 | // 133 | // See: 3.5.2 Segment Descriptor Tables in IA-32e Mode 134 | // 135 | if ((SegmentDescriptor->System == 0) && 136 | ((SegmentDescriptor->Type == SEGMENT_DESCRIPTOR_TYPE_TSS_AVAILABLE) || 137 | (SegmentDescriptor->Type == SEGMENT_DESCRIPTOR_TYPE_TSS_BUSY))) 138 | { 139 | CONST SEGMENT_DESCRIPTOR_64* descriptor64; 140 | 141 | descriptor64 = (CONST SEGMENT_DESCRIPTOR_64*)SegmentDescriptor; 142 | segmentBase |= ((UINT64)descriptor64->BaseAddressUpper << 32); 143 | } 144 | return segmentBase; 145 | } 146 | 147 | UINT64 148 | GetSegmentBase ( 149 | _In_ UINT64 DescriptorTableBase, 150 | _In_ UINT16 SegmentSelector 151 | ) 152 | { 153 | UINT64 segmentBase; 154 | SEGMENT_SELECTOR segmentSelector; 155 | 156 | segmentSelector.Flags = SegmentSelector; 157 | 158 | if ((segmentSelector.Table == 0) && 159 | (segmentSelector.Index == 0)) 160 | { 161 | // 162 | // The null segment selectors technically does not point to a valid 163 | // segment descriptor, hence no valid base address either. We return 164 | // 0 for convenience, however. 165 | // 166 | // "The first entry of the GDT is not used by the processor. A segment 167 | // selector that points to this entry of the GDT (that is, a segment 168 | // selector with an index of 0 and the TI flag set to 0) is used as a 169 | // "null segment selector."". 170 | // 3.4.2 Segment Selectors 171 | // 172 | segmentBase = 0; 173 | goto Exit; 174 | } 175 | 176 | // 177 | // For practical reasons, we do not support LDT. This will not be an issue 178 | // as we are running as a SYSTEM which will not use LDT. 179 | // 180 | // "Specifies the descriptor table to use: clearing this flag selects the GDT; 181 | // setting this flag selects the current LDT." 182 | // See: 3.4.2 Segment Selectors 183 | // 184 | MV_ASSERT(segmentSelector.Table == 0); 185 | segmentBase = GetSegmentBaseByDescriptor(GetSegmentDescriptor(DescriptorTableBase, 186 | SegmentSelector)); 187 | 188 | Exit: 189 | return segmentBase; 190 | } 191 | 192 | _Use_decl_annotations_ 193 | CR0 194 | AdjustCr0 ( 195 | CR0 Cr0 196 | ) 197 | { 198 | CR0 newCr0, fixed0Cr0, fixed1Cr0; 199 | 200 | newCr0 = Cr0; 201 | fixed0Cr0.Flags = __readmsr(IA32_VMX_CR0_FIXED0); 202 | fixed1Cr0.Flags = __readmsr(IA32_VMX_CR0_FIXED1); 203 | newCr0.Flags &= fixed1Cr0.Flags; 204 | newCr0.Flags |= fixed0Cr0.Flags; 205 | return newCr0; 206 | } 207 | 208 | _Use_decl_annotations_ 209 | CR4 210 | AdjustCr4 ( 211 | CR4 Cr4 212 | ) 213 | { 214 | CR4 newCr4, fixed0Cr4, fixed1Cr4; 215 | 216 | newCr4 = Cr4; 217 | fixed0Cr4.Flags = __readmsr(IA32_VMX_CR4_FIXED0); 218 | fixed1Cr4.Flags = __readmsr(IA32_VMX_CR4_FIXED1); 219 | newCr4.Flags &= fixed1Cr4.Flags; 220 | newCr4.Flags |= fixed0Cr4.Flags; 221 | return newCr4; 222 | } 223 | 224 | _Use_decl_annotations_ 225 | BOOLEAN 226 | IsHypervisorPresent ( 227 | CONST CHAR* HyperVisorName 228 | ) 229 | { 230 | int registers[4]; // EAX, EBX, ECX, and EDX 231 | char vendorId[13]; 232 | 233 | // 234 | // When our hypervisor or ones that is compatible with the Hypervisor Top 235 | // Level Functional Specification is installed, CPUID leaf 40000000h will 236 | // return hypervisor vendor ID signature in EBX, ECX, and EDX. 237 | // 238 | __cpuid(registers, CPUID_HV_VENDOR_AND_MAX_FUNCTIONS); 239 | RtlCopyMemory(vendorId + 0, ®isters[1], sizeof(registers[1])); 240 | RtlCopyMemory(vendorId + 4, ®isters[2], sizeof(registers[2])); 241 | RtlCopyMemory(vendorId + 8, ®isters[3], sizeof(registers[3])); 242 | vendorId[12] = ANSI_NULL; 243 | 244 | return (strcmp(vendorId, HyperVisorName) == 0); 245 | } 246 | -------------------------------------------------------------------------------- /Sources/Ia32Utils.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file Ia32Utils.h 3 | 4 | @brief Utility functions that could be used by both the host and non-host. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #pragma once 11 | #include "Common.h" 12 | 13 | /*! 14 | @brief Computes the address from the four page table indexes. 15 | 16 | @param[in] Pml4Index - The index for PML4. 17 | 18 | @param[in] PdptIndex - The index for PDPT. 19 | 20 | @param[in] PdIndex - The index for PE. 21 | 22 | @param[in] PtIndex - The index for PE. 23 | 24 | @return The resulted address. 25 | */ 26 | UINT64 27 | ComputeAddressFromIndexes ( 28 | _In_ UINT32 Pml4Index, 29 | _In_ UINT32 PdptIndex, 30 | _In_ UINT32 PdIndex, 31 | _In_ UINT32 PtIndex 32 | ); 33 | 34 | /*! 35 | @brief Returns the access right of the segment specified by the SegmentSelector 36 | for VMX. 37 | 38 | @param[in] SegmentSelector - The segment selector value. 39 | 40 | @return The access right of the segment for VMX. 41 | */ 42 | UINT32 43 | GetSegmentAccessRight ( 44 | _In_ UINT16 SegmentSelector 45 | ); 46 | 47 | /*! 48 | @brief Returns the base address of the segment specified by SegmentSelector. 49 | 50 | @param[in] DescriptorTableBase - The address of the base of the descriptor 51 | table. 52 | 53 | @param[in] SegmentSelector - The segment selector which points to the 54 | segment descriptor to retrieve the base address from. 55 | 56 | @return The base address of the segment specified by SegmentSelector. 57 | */ 58 | UINT64 59 | GetSegmentBase ( 60 | _In_ UINT64 DescriptorTableBase, 61 | _In_ UINT16 SegmentSelector 62 | ); 63 | 64 | /*! 65 | @brief Returns the CR0 value after the FIXED0 and FIXED1 MSR values are applied. 66 | 67 | @param[in] Cr0 - The CR0 value to apply the FIXED0 and FIXED1 MSR values. 68 | 69 | @return The CR0 value where the FIXED0 and FIXED1 MSR values are applied. 70 | */ 71 | CR0 72 | AdjustCr0 ( 73 | _In_ CR0 Cr0 74 | ); 75 | 76 | /*! 77 | @brief Returns the CR4 value after the FIXED0 and FIXED1 MSR values are applied. 78 | 79 | @param[in] Cr4 - The CR4 value to apply the FIXED0 and FIXED1 MSR values. 80 | 81 | @return The CR4 value where the FIXED0 and FIXED1 MSR values are applied. 82 | */ 83 | CR4 84 | AdjustCr4 ( 85 | _In_ CR4 Cr4 86 | ); 87 | 88 | /*! 89 | @brief Tests whether the specified hypervisor is installed on the system. 90 | 91 | @return TRUE when a specified hypervisor is installed on the system; otherwise FALSE. 92 | */ 93 | _Must_inspect_result_ 94 | BOOLEAN 95 | IsHypervisorPresent ( 96 | _In_ CONST CHAR* HyperVisorName 97 | ); 98 | -------------------------------------------------------------------------------- /Sources/Logger.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file Logger.h 3 | 4 | @brief Declarations of functions and structures for logging. 5 | 6 | @details Strings provided for the LOG_* macros are NOT removed from the 7 | release build. If you wish so, wrap them with preprocessor and make them 8 | no-op. 9 | 10 | @author Satoshi Tanda 11 | 12 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 13 | */ 14 | #pragma once 15 | #include "Common.h" 16 | 17 | // 18 | // Logging chars and wide-chars require different format strings because of the 19 | // difference of the formatting functions. Use them like the standard's PRIx macro 20 | // family. 21 | // 22 | #if defined(MV_PLATFORM_WINDOWS) 23 | #define LOG_PRIANSI "s" 24 | #define LOG_PRIUNICODE "S" 25 | #else 26 | #define LOG_PRIANSI "a" 27 | #define LOG_PRIUNICODE "s" 28 | #endif 29 | 30 | // 31 | // Log levels. 32 | // 33 | typedef enum _LOG_LEVEL 34 | { 35 | LogLevelNone, 36 | LogLevelError, 37 | LogLevelWarning, 38 | LogLevelInfo, 39 | LogLevelDebug, 40 | LogLevelReserved, 41 | } LOG_LEVEL; 42 | 43 | /*! 44 | @brief Logs the error message without depending on the logger to be initialized. 45 | 46 | @param[in] Format - The format string. 47 | */ 48 | #define LOG_EARLY_ERROR(Format, ...) \ 49 | LogEarlyErrorMessage(Format "\n", ## __VA_ARGS__) 50 | 51 | /*! 52 | @brief Logs the error-level message. 53 | 54 | @param[in] Format - The format string. 55 | */ 56 | #define LOG_ERROR(Format, ...) \ 57 | LogMessage(LogLevelError, __FUNCTION__, (Format), ## __VA_ARGS__) 58 | 59 | /*! 60 | @brief Logs the warning-level message. 61 | 62 | @param[in] Format - The format string. 63 | */ 64 | #define LOG_WARNING(Format, ...) \ 65 | LogMessage(LogLevelWarning, __FUNCTION__, (Format), ## __VA_ARGS__) 66 | 67 | /*! 68 | @brief Logs the information-level message. 69 | 70 | @param[in] Format - The format string. 71 | */ 72 | #define LOG_INFO(Format, ...) \ 73 | LogMessage(LogLevelInfo, __FUNCTION__, (Format), ## __VA_ARGS__) 74 | 75 | /*! 76 | @brief Logs the debug-level message. 77 | 78 | @param[in] Format - The format string. 79 | */ 80 | #define LOG_DEBUG(Format, ...) \ 81 | LogMessage(LogLevelDebug, __FUNCTION__, (Format), ## __VA_ARGS__) 82 | 83 | /*! 84 | @brief Logs the log message. 85 | 86 | @param[in] Level - The level of the message. 87 | 88 | @param[in] FunctionName - The name of the function initiated this logging. 89 | 90 | @param[in] Format - The format string. 91 | */ 92 | VOID 93 | LogMessage ( 94 | _In_ LOG_LEVEL Level, 95 | _In_ CONST CHAR* FunctionName, 96 | _In_ _Printf_format_string_ CONST CHAR* Format, 97 | ... 98 | ); 99 | 100 | /*! 101 | @brief Logs the error log message immediately. 102 | 103 | @param[in] Format - The format string. 104 | */ 105 | VOID 106 | LogEarlyErrorMessage ( 107 | _In_ _Printf_format_string_ CONST CHAR* Format, 108 | ... 109 | ); 110 | -------------------------------------------------------------------------------- /Sources/MemoryAccess.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file MemoryAccess.h 3 | 4 | @brief Functions for guest virtual memory access from the hypervisor. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #pragma once 11 | #include "Common.h" 12 | #include "Ia32.h" 13 | 14 | typedef struct _MEMORY_ACCESS_CONTEXT 15 | { 16 | // 17 | // Reserved virtual address (page) for access to the guest virtual memory 18 | // from the hypervisor. 19 | // 20 | VOID* ReservedPage; 21 | 22 | // 23 | // The pointer to the PTE of the reserved page. 24 | // 25 | PTE_64* Pte; 26 | 27 | // 28 | // The address of the page table that is dynamically allocated to translate 29 | // ReservedPage with the 4KB page (and not the large page). 30 | // 31 | PTE_64* AllocatedPageTable; 32 | } MEMORY_ACCESS_CONTEXT; 33 | 34 | // 35 | // Error information can be filled by (Read|Write)GuestVirtualAddress(). 36 | // 37 | typedef struct _MEMORY_ACCESS_ERROR_INFORMATION 38 | { 39 | EXCEPTION_VECTOR ErrorType; 40 | union 41 | { 42 | struct 43 | { 44 | PAGE_FAULT_EXCEPTION ErrorCode; 45 | UINT64 FaultAddress; 46 | } PageFault; 47 | } u; 48 | } MEMORY_ACCESS_ERROR_INFORMATION; 49 | 50 | /*! 51 | @brief Initializes the memory access context. 52 | 53 | @param[out] Context - The pointer to the context to initialize. On success, 54 | the caller must clean up this context with CleanupMemoryAccess(). 55 | 56 | @param[in] HostCr3 - The host CR3. 57 | 58 | @return MV_STATUS_SUCCESS on success; otherwise, an appropriate error code. 59 | */ 60 | _IRQL_requires_max_(APC_LEVEL) 61 | _Must_inspect_result_ 62 | MV_STATUS 63 | InitializeMemoryAccess ( 64 | _Out_ MEMORY_ACCESS_CONTEXT* Context, 65 | _In_ CR3 HostCr3 66 | ); 67 | 68 | /*! 69 | @brief Cleans up the memory access context initialized with 70 | InitializeMemoryAccess(). 71 | 72 | @param[in,out] Context - The pointer to the context to clean up. 73 | */ 74 | _IRQL_requires_max_(APC_LEVEL) 75 | VOID 76 | CleanupMemoryAccess ( 77 | _Inout_ MEMORY_ACCESS_CONTEXT* Context 78 | ); 79 | 80 | /*! 81 | @brief Retrieves the physical address associated with the guest virtual 82 | address. 83 | 84 | @details This function walks through the guest paging structures and for the 85 | given virtual address and retrieves the guest physical address of it. 86 | This is equivalent to changing the current CR3 with the guest CR3 and 87 | calling GetPhysicalAddress(). This function, however, exists to avoid 88 | problems associated with CR3 update, for example, on Windows, updating 89 | the CR3 crashes the system immediately if the KVA Shadow is enabled and 90 | the guest CR3 contains the USER CR3, as it does not map our code. 91 | 92 | @param[in] Context - The pointer to the memory access context. 93 | 94 | @param[in] GuestVirtualAddress - The guest virtual address to look for its 95 | physical address. 96 | 97 | @param[out] AggregatedPagePermissions - The pointer to the paging-structure 98 | entry to receive aggregated copy of the page permissions specified in 99 | the guest paging structure entries used to translate the guest virtual 100 | address. If the guest physical address is mapped to the physical address, 101 | Write, Supervisor, and ExecuteDisable bits are updated accordingly, and 102 | the rest of bits are cleared. 103 | 104 | @return The physical address associated with the specified virtual address if 105 | exists. Otherwise, MV_INVALID_PHYSICAL_ADDRESS. 106 | */ 107 | _Must_inspect_result_ 108 | _Success_(return != MV_INVALID_PHYSICAL_ADDRESS) 109 | UINT64 110 | GetPhysicalAddressForGuest ( 111 | _In_ MEMORY_ACCESS_CONTEXT* Context, 112 | _In_ UINT64 GuestVirtualAddress, 113 | _Out_opt_ PT_ENTRY_64* AggregatedPagePermissions 114 | ); 115 | 116 | /*! 117 | @brief Reads memory from the location specified as the guest virtual address. 118 | 119 | @param[in] Context - See ReadOrWriteGuestVirtualAddress(). 120 | 121 | @param[in] KernelMode - See ReadOrWriteGuestVirtualAddress(). 122 | 123 | @param[in] GuestVirtualAddress - See ReadOrWriteGuestVirtualAddress(). 124 | 125 | @param[out] Buffer - See ReadOrWriteGuestVirtualAddress(). 126 | 127 | @param[in] BytesToRead - See ReadOrWriteGuestVirtualAddress(). 128 | 129 | @param[out] ErrorInformation - See ReadOrWriteGuestVirtualAddress(). 130 | 131 | @return See ReadOrWriteGuestVirtualAddress(). 132 | */ 133 | _Must_inspect_result_ 134 | BOOLEAN 135 | ReadGuestVirtualAddress ( 136 | _In_ MEMORY_ACCESS_CONTEXT* Context, 137 | _In_ BOOLEAN KernelMode, 138 | _In_ UINT64 GuestVirtualAddress, 139 | _Out_writes_bytes_(BytesToRead) VOID* Buffer, 140 | _In_ UINT64 BytesToRead, 141 | _Out_ MEMORY_ACCESS_ERROR_INFORMATION* ErrorInformation 142 | ); 143 | 144 | /*! 145 | @brief Write memory to the location specified as the guest virtual address. 146 | 147 | @param[in] Context - See ReadOrWriteGuestVirtualAddress(). 148 | 149 | @param[in] KernelMode - See ReadOrWriteGuestVirtualAddress(). 150 | 151 | @param[in] GuestVirtualAddress - See ReadOrWriteGuestVirtualAddress(). 152 | 153 | @param[out] Data - See ReadOrWriteGuestVirtualAddress(). 154 | 155 | @param[in] BytesToWrite - See ReadOrWriteGuestVirtualAddress(). 156 | 157 | @param[out] ErrorInformation - See ReadOrWriteGuestVirtualAddress(). 158 | 159 | @return See ReadOrWriteGuestVirtualAddress(). 160 | */ 161 | _Must_inspect_result_ 162 | BOOLEAN 163 | WriteGuestVirtualAddress ( 164 | _In_ MEMORY_ACCESS_CONTEXT* Context, 165 | _In_ BOOLEAN KernelMode, 166 | _In_ UINT64 GuestVirtualAddress, 167 | _In_reads_bytes_(BytesToWrite) CONST VOID* Data, 168 | _In_ UINT64 BytesToWrite, 169 | _Out_ MEMORY_ACCESS_ERROR_INFORMATION* ErrorInformation 170 | ); 171 | 172 | /*! 173 | @brief Maps the specified guest page number to the current address space. 174 | 175 | @param[in] Context - The pointer to the memory access context. 176 | 177 | @param[in] GuestPageNumber - The guest page number (ie, the guest virtual 178 | address without lower 12bits) to map to the host address space. 179 | 180 | @return The virtual address mapping the same physical page as specified as 181 | the page number, or NULL if the specified page number does not have 182 | a corresponding physical page. The caller must unmap the return value 183 | with UnmapGuestPage() when it is no longer needed. 184 | */ 185 | _Must_inspect_result_ 186 | VOID* 187 | MapGuestPage ( 188 | _Inout_ MEMORY_ACCESS_CONTEXT* Context, 189 | _In_ UINT64 GuestPageNumber 190 | ); 191 | 192 | /*! 193 | @brief Unmaps the address mapped with MapGuestPage(). 194 | 195 | @param[in] Context - The pointer to the memory access context. 196 | 197 | @param[in] MappedVa - The pointer returned by MapGuestPage(). 198 | */ 199 | VOID 200 | UnmapGuestPage ( 201 | _Inout_ MEMORY_ACCESS_CONTEXT* Context, 202 | _In_ VOID* MappedVa 203 | ); 204 | -------------------------------------------------------------------------------- /Sources/MemoryManager.c: -------------------------------------------------------------------------------- 1 | /*! 2 | @file MemoryManager.c 3 | 4 | @brief Functions for memory management. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #include "MemoryManager.h" 11 | #include "Platform.h" 12 | #include "Logger.h" 13 | #if defined(MV_PLATFORM_EFI) 14 | #include "Platform/EFI/EfiBitmap.h" 15 | #endif 16 | 17 | typedef struct _MEMORY_MANAGER_CONTEXT 18 | { 19 | // 20 | // Lock for concurrent access to the this memory manager instance. 21 | // 22 | SPIN_LOCK SpinLock; 23 | 24 | // 25 | // The number of pages reserved for use by the memory manager, and the 26 | // pointer to the reserved pages. 27 | // 28 | UINT32 PageCount; 29 | VOID* AllocatedPages; 30 | 31 | // 32 | // The bit index pointing to the bit found to be clear and used by the latest 33 | // allocation within AllocatedPages. The memory manager will start look for 34 | // the next clear bit from this index as optimization. 35 | // 36 | UINT32 LastUsedBitIndex; 37 | 38 | // 39 | // The bitmap header and actual bitmap buffer. The memory manager tracks 40 | // which pages within AllocatedPages are allocated for caller by setting a 41 | // bit to the corresponding offset in this bitmap. For example, if 42 | // AllocatedPages[0] to AllocatedPages[3] are allocated, bit 0-3 of the 43 | // bitmap are set. 44 | // 45 | RTL_BITMAP BitmapHeader; 46 | VOID* AllocationBitmap; 47 | 48 | // 49 | // The array of the allocated page lengths for callers. The memory manager 50 | // tracks how many pages are allocated by the single request by setting the 51 | // length in a corresponding entry in this array. For example, if the caller 52 | // requests 3 pages, and the memory manager finds 3 contiguous free pages at 53 | // AllocatedPages[0], the memory manager sets 3 to AllocationLengthMap[0]. 54 | // This is used to know the page length from the pointer on FreePages(). 55 | // 56 | UINT8* AllocationLengthMap; 57 | } MEMORY_MANAGER_CONTEXT; 58 | 59 | // 60 | // The singleton instance of the memory manager. 61 | // 62 | static MEMORY_MANAGER_CONTEXT g_MemoryManager; 63 | 64 | MV_SECTION_PAGED 65 | _Use_decl_annotations_ 66 | MV_STATUS 67 | MmInitializeMemoryManager ( 68 | UINT32 PageCount 69 | ) 70 | { 71 | MV_STATUS status; 72 | VOID* pages; 73 | UINT32 bitmapBytesCount; 74 | UINT32 bitmapPagesCount; 75 | VOID* bitmap; 76 | UINT8* lengthMap; 77 | UINT32 lengthMapBytesCount; 78 | UINT32 lengthMapPagesCount; 79 | MEMORY_MANAGER_CONTEXT* memoryManager; 80 | 81 | PAGED_CODE(); 82 | 83 | memoryManager = &g_MemoryManager; 84 | lengthMapPagesCount = 0; 85 | lengthMap = NULL; 86 | bitmapPagesCount = 0; 87 | bitmap = NULL; 88 | pages = NULL; 89 | 90 | MV_ASSERT(PageCount > 0); 91 | MV_ASSERT(memoryManager->PageCount == 0); 92 | 93 | // 94 | // Allocate the memory pool for the memory manager. This can be VERY large 95 | // memory allocation request and fail on system with little RAM. 96 | // 97 | pages = AllocateSystemMemory(PageCount); 98 | if (pages == NULL) 99 | { 100 | status = MV_STATUS_INSUFFICIENT_RESOURCES; 101 | goto Exit; 102 | } 103 | 104 | // 105 | // Computes how many bytes are required to cover the PageCount bits, 106 | // round it up to the page count (as we do not have API to allocate smaller 107 | // granularity), then allocate the bitmap. 108 | // 109 | bitmapBytesCount = (PageCount / CHAR_BIT) + 110 | ((PageCount % CHAR_BIT) != 0); 111 | bitmapPagesCount = BYTES_TO_PAGES(bitmapBytesCount); 112 | bitmap = AllocateSystemMemory(bitmapPagesCount); 113 | if (bitmap == NULL) 114 | { 115 | status = MV_STATUS_INSUFFICIENT_RESOURCES; 116 | goto Exit; 117 | } 118 | 119 | // 120 | // Compute the how many bytes are required to make the array of UINT8s 121 | // (lengths) for "PageCount" entries. Then, round it up to the page count 122 | // and allocate it. 123 | // 124 | lengthMapBytesCount = (PageCount * sizeof(UINT8)); 125 | lengthMapPagesCount = BYTES_TO_PAGES(lengthMapBytesCount); 126 | lengthMap = AllocateSystemMemory(lengthMapPagesCount); 127 | if (lengthMap == NULL) 128 | { 129 | status = MV_STATUS_INSUFFICIENT_RESOURCES; 130 | goto Exit; 131 | } 132 | 133 | // 134 | // All good. Initialize the memory manager instance. 135 | // 136 | status = MV_STATUS_SUCCESS; 137 | 138 | InitializeSystemSpinLock(&memoryManager->SpinLock); 139 | memoryManager->PageCount = PageCount; 140 | memoryManager->AllocatedPages = pages; 141 | memoryManager->LastUsedBitIndex = 0; 142 | RtlInitializeBitMap(&memoryManager->BitmapHeader, bitmap, PageCount); 143 | memoryManager->AllocationBitmap = bitmap; 144 | memoryManager->AllocationLengthMap = lengthMap; 145 | 146 | Exit: 147 | if (MV_ERROR(status)) 148 | { 149 | if (lengthMap != NULL) 150 | { 151 | FreeSystemMemory(lengthMap, lengthMapPagesCount); 152 | } 153 | if (bitmap != NULL) 154 | { 155 | FreeSystemMemory(bitmap, bitmapPagesCount); 156 | } 157 | if (pages != NULL) 158 | { 159 | FreeSystemMemory(pages, PageCount); 160 | } 161 | } 162 | return status; 163 | } 164 | 165 | MV_SECTION_PAGED 166 | _Use_decl_annotations_ 167 | VOID 168 | MmCleanupMemoryManager ( 169 | ) 170 | { 171 | UINT32 bitmapBytesCount; 172 | UINT32 bitmapPagesCount; 173 | UINT32 lengthMapBytesCount; 174 | UINT32 lengthMapPagesCount; 175 | MEMORY_MANAGER_CONTEXT* memoryManager; 176 | 177 | PAGED_CODE(); 178 | 179 | memoryManager = &g_MemoryManager; 180 | 181 | // 182 | // The memory manager must be initialized already. 183 | // 184 | MV_ASSERT(memoryManager->PageCount != 0); 185 | MV_ASSERT(memoryManager->AllocatedPages != NULL); 186 | MV_ASSERT(memoryManager->AllocationLengthMap != NULL); 187 | MV_ASSERT(memoryManager->AllocatedPages != NULL); 188 | 189 | // 190 | // All memory allocated for the callers must be freed. 191 | // 192 | MV_ASSERT(RtlAreBitsClear(&memoryManager->BitmapHeader, 193 | 0, 194 | memoryManager->PageCount) != FALSE); 195 | 196 | bitmapBytesCount = (memoryManager->PageCount / CHAR_BIT) + 197 | ((memoryManager->PageCount % CHAR_BIT) != 0); 198 | bitmapPagesCount = BYTES_TO_PAGES(bitmapBytesCount); 199 | 200 | lengthMapBytesCount = (memoryManager->PageCount * sizeof(UINT8)); 201 | lengthMapPagesCount = BYTES_TO_PAGES(lengthMapBytesCount); 202 | 203 | FreeSystemMemory(memoryManager->AllocationBitmap, 204 | bitmapPagesCount); 205 | FreeSystemMemory(memoryManager->AllocationLengthMap, 206 | lengthMapPagesCount); 207 | FreeSystemMemory(memoryManager->AllocatedPages, 208 | memoryManager->PageCount); 209 | 210 | RtlZeroMemory(memoryManager, sizeof(*memoryManager)); 211 | } 212 | 213 | _Use_decl_annotations_ 214 | VOID* 215 | MmAllocatePages ( 216 | UINT8 PageCount 217 | ) 218 | { 219 | VOID* pages; 220 | UINT32 bitIndex; 221 | MEMORY_MANAGER_CONTEXT* memoryManager; 222 | UINT8 oldIrql; 223 | 224 | memoryManager = &g_MemoryManager; 225 | 226 | // 227 | // Search the contiguous free page(s) that suffices the request. 228 | // 229 | oldIrql = AcquireSystemSpinLock(&memoryManager->SpinLock); 230 | bitIndex = RtlFindClearBitsAndSet(&memoryManager->BitmapHeader, 231 | PageCount, 232 | memoryManager->LastUsedBitIndex); 233 | ReleaseSystemSpinLock(&memoryManager->SpinLock, oldIrql); 234 | 235 | if (bitIndex == MAXUINT32) 236 | { 237 | MV_DEBUG_BREAK(); 238 | LOG_ERROR("Memory allocation failed : %lu", (UINT32)PageCount * PAGE_SIZE); 239 | pages = NULL; 240 | goto Exit; 241 | } 242 | 243 | // 244 | // Return the page(s) from the pool, and update the book keeping fields. 245 | // 246 | pages = MV_ADD2PTR(memoryManager->AllocatedPages, ((UINT64)bitIndex * PAGE_SIZE)); 247 | memoryManager->AllocationLengthMap[bitIndex] = PageCount; 248 | memoryManager->LastUsedBitIndex = bitIndex; 249 | 250 | Exit: 251 | return pages; 252 | } 253 | 254 | _Use_decl_annotations_ 255 | VOID 256 | MmFreePages ( 257 | VOID* Pages 258 | ) 259 | { 260 | UINT64 offsetInBytes; 261 | UINT32 bitIndex; 262 | MEMORY_MANAGER_CONTEXT* memoryManager; 263 | UINT8 oldIrql; 264 | UINT8 pageLength; 265 | 266 | memoryManager = &g_MemoryManager; 267 | 268 | // 269 | // The pointer must be page aligned, within the range of 270 | // [AllocatedPages, AllocatedPages + PageCount). 271 | // 272 | MV_ASSERT(Pages == PAGE_ALIGN(Pages)); 273 | MV_ASSERT((UINT64)Pages >= (UINT64)memoryManager->AllocatedPages); 274 | MV_ASSERT((UINT64)Pages < 275 | (UINT64)memoryManager->AllocatedPages + ((UINT64)memoryManager->PageCount * PAGE_SIZE)); 276 | 277 | // 278 | // Compute the bit index corresponds to the pointer requested for freeing, 279 | // and look up its length with it. The length must be more than zero, meaning 280 | // that the page allocated for the caller. 281 | // 282 | offsetInBytes = ((UINT64)Pages - (UINT64)memoryManager->AllocatedPages); 283 | bitIndex = (UINT32)(offsetInBytes / PAGE_SIZE); 284 | pageLength = memoryManager->AllocationLengthMap[bitIndex]; 285 | MV_ASSERT(pageLength > 0); 286 | 287 | // 288 | // Clears the bitmap and the length to "free" the page. 289 | // 290 | oldIrql = AcquireSystemSpinLock(&memoryManager->SpinLock); 291 | RtlClearBits(&memoryManager->BitmapHeader, bitIndex, pageLength); 292 | memoryManager->AllocationLengthMap[bitIndex] = 0; 293 | ReleaseSystemSpinLock(&memoryManager->SpinLock, oldIrql); 294 | } 295 | -------------------------------------------------------------------------------- /Sources/MemoryManager.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file MemoryManager.h 3 | 4 | @brief Functions for memory management. 5 | 6 | @details All API in this file are prefixed with Mm because naive names 7 | conflict with platform API, for example, AllocatePages and FreePages in 8 | EDK2. 9 | 10 | @author Satoshi Tanda 11 | 12 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 13 | */ 14 | #pragma once 15 | #include "Common.h" 16 | 17 | /*! 18 | @brief Allocates the requested size of memory and initialize the singleton 19 | memory manager instance with it. 20 | 21 | @param[in] PageCount - The page count to allocate for the use by the 22 | memory manager. 23 | 24 | @return MV_STATUS_SUCCESS on success; otherwise, an appropriate error code. 25 | */ 26 | _IRQL_requires_max_(PASSIVE_LEVEL) 27 | _Must_inspect_result_ 28 | MV_STATUS 29 | MmInitializeMemoryManager ( 30 | _In_ UINT32 PageCount 31 | ); 32 | 33 | /*! 34 | @brief Cleans up the memory manager. 35 | */ 36 | _IRQL_requires_max_(PASSIVE_LEVEL) 37 | VOID 38 | MmCleanupMemoryManager ( 39 | ); 40 | 41 | /*! 42 | @brief Allocates page-aligned, zero-initialized physical page backed pool. 43 | 44 | @param[in] PageCount - The page count to allocate. 45 | 46 | @return The base of allocated pointer, or NULL on failure. The caller must 47 | free the return value with FreeSystemMemory(). 48 | */ 49 | _Post_maybenull_ 50 | _Post_writable_byte_size_(PageCount * PAGE_SIZE) 51 | _Must_inspect_result_ 52 | VOID* 53 | MmAllocatePages ( 54 | _In_ UINT8 PageCount 55 | ); 56 | 57 | /*! 58 | @brief Frees the memory allocated by AllocatePages(). 59 | 60 | @param[in] Pages - The pointer to free. 61 | */ 62 | VOID 63 | MmFreePages ( 64 | _Pre_notnull_ VOID* Pages 65 | ); 66 | -------------------------------------------------------------------------------- /Sources/MemoryType.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file MemoryType.h 3 | 4 | @brief Functions for MTRR (memory type range registers) handling. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #pragma once 11 | #include "Common.h" 12 | 13 | /*! 14 | @brief Initializes the MTRR context. 15 | */ 16 | VOID 17 | InitializeMemoryTypeMapping ( 18 | ); 19 | 20 | /*! 21 | @brief Returns a memory type for the given physical address range. 22 | 23 | @param[in] PhysicalAddress - The physical address to retrieve its memory type. 24 | 25 | @param[in] RangeSize - The size of the range to check. 26 | 27 | @return The memory type for the given physical address. If the range contains 28 | more than one memory type, MEMORY_TYPE_INVALID. 29 | */ 30 | IA32_MEMORY_TYPE 31 | GetMemoryTypeForRange ( 32 | _In_ UINT64 PhysicalAddress, 33 | _In_ UINT64 RangeSize 34 | ); 35 | -------------------------------------------------------------------------------- /Sources/MiniVisor.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file MiniVisor.h 3 | 4 | @brief MiniVisor initialization. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #pragma once 11 | #include "Common.h" 12 | 13 | /*! 14 | @brief Cross platform entry point. Initializes MiniVisor. 15 | 16 | @return MV_STATUS_SUCCESS on success; otherwise, an appropriate error code. 17 | */ 18 | MV_STATUS 19 | _IRQL_requires_max_(PASSIVE_LEVEL) 20 | _Must_inspect_result_ 21 | InitializeMiniVisor ( 22 | ); 23 | 24 | /*! 25 | @brief Cross platform clean up entry callback entry point. Cleans up MiniVisor. 26 | */ 27 | _IRQL_requires_max_(PASSIVE_LEVEL) 28 | VOID 29 | CleanupMiniVisor ( 30 | ); 31 | -------------------------------------------------------------------------------- /Sources/MiniVisor.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | UEFI 14 | x64 15 | 16 | 17 | 18 | {B94B175C-8D18-47E2-800C-1AFBAAC7AC73} 19 | {dd38f7fc-d7bd-488b-9242-7d8754cde80d} 20 | v4.5 21 | 12.0 22 | Debug 23 | Win32 24 | MiniVisor 25 | $(LatestTargetPlatformVersion) 26 | 27 | 28 | 29 | Windows10 30 | true 31 | false 32 | WindowsKernelModeDriver10.0 33 | Driver 34 | WDM 35 | Desktop 36 | 37 | 38 | Application 39 | false 40 | v142 41 | NotSet 42 | false 43 | 44 | 45 | 46 | 47 | $(SolutionDir)..\..\ 48 | $(SolutionDir)..\Externals\ia32-doc\ 49 | 50 | 51 | DbgengKernelDebugger 52 | $(VC_IncludePath);$(IncludePath);$(Ia32DocDir)out; 53 | AllRules.ruleset 54 | false 55 | 56 | 57 | $(Ia32DocDir)out;$(Edk2Dir)MdePkg\Include;$(Edk2Dir)MdePkg\Include\X64 58 | $(SolutionDir)Libs 59 | .efi 60 | $(ProjectName)Dxe 61 | false 62 | 63 | 64 | 65 | SHA256 66 | 67 | 68 | 69 | 70 | Level4 71 | false 72 | Default 73 | ProgramDatabase 74 | false 75 | Disabled 76 | false 77 | false 78 | 79 | 80 | EFI Runtime 81 | true 82 | true 83 | BaseDebugPrintErrorLevelLib.lib;BaseLib.lib;BaseMemoryLibOptDxe.lib;BasePrintLib.lib;BaseSynchronizationLib.lib;BaseTimerLibNullTemplate.lib;DxePcdLib.lib;UefiBootServicesTableLib.lib;UefiDebugLibConOut.lib;UefiDevicePathLibDevicePathProtocol.lib;UefiDriverEntryPoint.lib;UefiLib.lib;UefiMemoryAllocationLib.lib;UefiRuntimeServicesTableLib.lib;MiniVisorDxe.lib 84 | _ModuleEntryPoint 85 | false 86 | false 87 | false 88 | 89 | 90 | python $(SolutionDir)PreLinkEvent.py $(Edk2Dir)Build\MiniVisor\NOOPT_VS2019\X64 $(SolutionDir)Libs 91 | 92 | 93 | copy /y $(OutDir)$(TargetName)$(TargetExt) D:\ 94 | Coping the build output to the USB drive. This is useful for compile and test interation. 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | true 104 | 105 | 106 | true 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | true 150 | 151 | 152 | true 153 | 154 | 155 | true 156 | 157 | 158 | true 159 | 160 | 161 | true 162 | 163 | 164 | true 165 | 166 | 167 | true 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | -------------------------------------------------------------------------------- /Sources/MiniVisor.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {e293d76d-1cb2-498e-865d-1408d410a323} 18 | 19 | 20 | {89b31625-554c-4a64-adb9-53d69633d23e} 21 | 22 | 23 | {0666652f-cc2f-4a3b-a0c5-0eb8b57f2ef5} 24 | 25 | 26 | {e9cab091-74b4-4aa0-b8ea-0526186a92ba} 27 | 28 | 29 | {377c4141-5e61-4508-ad18-231451501b85} 30 | 31 | 32 | {39c270e1-5eba-4499-b137-e359597058c3} 33 | 34 | 35 | 36 | 37 | Header Files 38 | 39 | 40 | Header Files 41 | 42 | 43 | Header Files 44 | 45 | 46 | Header Files 47 | 48 | 49 | Header Files 50 | 51 | 52 | Header Files 53 | 54 | 55 | Header Files 56 | 57 | 58 | Header Files 59 | 60 | 61 | Header Files 62 | 63 | 64 | Header Files 65 | 66 | 67 | Header Files 68 | 69 | 70 | Header Files 71 | 72 | 73 | Header Files 74 | 75 | 76 | Header Files\Platform\Windows 77 | 78 | 79 | Header Files\Platform\EFI 80 | 81 | 82 | Header Files\Platform\EFI 83 | 84 | 85 | Header Files\Platform\Windows 86 | 87 | 88 | Header Files 89 | 90 | 91 | Header Files\Platform\EFI 92 | 93 | 94 | Header Files\Platform\EFI 95 | 96 | 97 | Header Files\Platform\Windows 98 | 99 | 100 | Header Files\Platform\Windows 101 | 102 | 103 | Header Files\Platform\EFI 104 | 105 | 106 | Header Files\Platform\EFI 107 | 108 | 109 | Header Files\Platform\Windows 110 | 111 | 112 | Header Files 113 | 114 | 115 | Header Files 116 | 117 | 118 | Header Files 119 | 120 | 121 | 122 | 123 | Source Files 124 | 125 | 126 | Source Files 127 | 128 | 129 | Source Files 130 | 131 | 132 | Source Files 133 | 134 | 135 | Source Files 136 | 137 | 138 | Source Files 139 | 140 | 141 | Source Files 142 | 143 | 144 | Source Files\Platform\Windows 145 | 146 | 147 | Source Files\Platform\Windows 148 | 149 | 150 | Source Files\Platform\EFI 151 | 152 | 153 | Source Files\Platform\EFI 154 | 155 | 156 | Source Files\Platform\EFI 157 | 158 | 159 | Source Files\Platform\EFI 160 | 161 | 162 | Source Files\Platform\Windows 163 | 164 | 165 | Source Files 166 | 167 | 168 | Source Files 169 | 170 | 171 | 172 | 173 | Source Files 174 | 175 | 176 | Source Files\Platform\EFI 177 | 178 | 179 | Source Files\Platform\Windows 180 | 181 | 182 | 183 | 184 | Header Files 185 | 186 | 187 | -------------------------------------------------------------------------------- /Sources/Platform.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file Platform.h 3 | 4 | @brief Platform specific API. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #pragma once 11 | #include "Common.h" 12 | 13 | // 14 | // Spin lock type and state names. 15 | // 16 | #if defined(MV_PLATFORM_WINDOWS) 17 | typedef volatile LONG64 SPIN_LOCK; 18 | typedef enum _SPIN_LOCK_STATE 19 | { 20 | SpinLockReleased, 21 | SpinLockAcquired, 22 | } SPIN_LOCK_STATE; 23 | #else 24 | #include 25 | #endif 26 | 27 | /*! 28 | @brief Initializes platform specific bits. 29 | 30 | @return MV_STATUS_SUCCESS on success; otherwise, an appropriate error code. 31 | */ 32 | _IRQL_requires_max_(PASSIVE_LEVEL) 33 | _Must_inspect_result_ 34 | MV_STATUS 35 | InitializePlatform ( 36 | ); 37 | 38 | /*! 39 | @brief Cleans up platform specific bits. 40 | */ 41 | _IRQL_requires_max_(PASSIVE_LEVEL) 42 | VOID 43 | CleanupPlatform ( 44 | ); 45 | 46 | /*! 47 | @brief Stalls execution of the current processor. 48 | 49 | @details Use of this API from the host is not allowed. 50 | 51 | @param[in] Milliseconds - The time to stall in milliseconds. 52 | */ 53 | _IRQL_requires_max_(APC_LEVEL) 54 | VOID 55 | Sleep ( 56 | _In_ UINT64 Milliseconds 57 | ); 58 | 59 | /*! 60 | @brief Returns the active logical processor count. 61 | 62 | @details Use of this API from the host is not allowed. 63 | 64 | @return The active logical processor count. 65 | */ 66 | UINT32 67 | GetActiveProcessorCount ( 68 | ); 69 | 70 | /*! 71 | @brief Returns the current processor number. The BSP will return 0. 72 | 73 | @details Use of this API from the host is not allowed. 74 | 75 | @return The current processor number. 0 for BSP. 76 | */ 77 | UINT32 78 | GetCurrentProcessorNumber ( 79 | ); 80 | 81 | /*! 82 | @brief Returns the physical address of the given virtual address. 83 | 84 | @param[in] VirualAddress - The virtual address to retrieve its physical 85 | address for the current CR3. This must be non paged pool, otherwise the 86 | result is undefined. 87 | 88 | @return The physical address of the given virtual address. 89 | */ 90 | UINT64 91 | GetPhysicalAddress ( 92 | _In_ VOID* VirualAddress 93 | ); 94 | 95 | /*! 96 | @brief Returns the virtual address of the given physical address. 97 | 98 | @param[in] PhysicalAddress - The physical address to retrieve its virtual 99 | address for the current CR3. 100 | 101 | @return The virtual address of the given physical address. 102 | */ 103 | VOID* 104 | GetVirtualAddress ( 105 | _In_ UINT64 PhysicalAddress 106 | ); 107 | 108 | /*! 109 | @brief Allocates page-aligned, zero-initialized physical memory resident pages. 110 | 111 | @details Use of this API from the host is not allowed. 112 | 113 | @param[in] PageCount - The page count to allocate. 114 | 115 | @return The base of allocated pointer, or NULL on failure. The caller must 116 | free the return value with FreeSystemMemory(). 117 | */ 118 | __drv_allocatesMem(Mem) 119 | _IRQL_requires_max_(DISPATCH_LEVEL) 120 | _Post_maybenull_ 121 | _Post_writable_byte_size_(PageCount * PAGE_SIZE) 122 | _Must_inspect_result_ 123 | VOID* 124 | AllocateSystemMemory ( 125 | _In_ UINT64 PageCount 126 | ); 127 | 128 | /*! 129 | @brief Frees the memory allocated by AllocateSystemMemory(). 130 | 131 | @details Use of this API from the host is not allowed. 132 | 133 | @param[in] Pages - The pointer to free. 134 | 135 | @param[in] PageCount - Unused. 136 | */ 137 | _IRQL_requires_max_(DISPATCH_LEVEL) 138 | VOID 139 | FreeSystemMemory ( 140 | _Pre_notnull_ __drv_freesMem(Mem) VOID* Pages, 141 | _In_ UINT64 PageCount 142 | ); 143 | 144 | /*! 145 | @brief Reserves the virtual address. The returned address is not accessible. 146 | 147 | @details Use of this API from the host is not allowed. 148 | 149 | @param[in] PageCount - The page count to reserve. 150 | 151 | @return The address of reserved region on success or NULL. The caller must 152 | free this value with FreeReservedVirtualAddress(). 153 | */ 154 | _IRQL_requires_max_(APC_LEVEL) 155 | _Must_inspect_result_ 156 | VOID* 157 | ReserveVirtualAddress ( 158 | _In_ UINT64 PageCount 159 | ); 160 | 161 | /*! 162 | @brief Frees the address reserved with ReserveVirtualAddress(). 163 | 164 | @details Use of this API from the host is not allowed. 165 | 166 | @param[in] Pages - The pointer returned from ReserveVirtualAddress(). 167 | 168 | @param[in] PageCount - Unused. 169 | */ 170 | _IRQL_requires_max_(APC_LEVEL) 171 | VOID 172 | FreeReservedVirtualAddress ( 173 | _In_ VOID* Pages, 174 | _In_ UINT64 PageCount 175 | ); 176 | 177 | typedef 178 | VOID 179 | USER_PASSIVE_CALLBACK ( 180 | _Inout_ VOID* Context 181 | ); 182 | 183 | /*! 184 | @brief Executes the callback at the PASSIVE_LEVEL on each processor one by one. 185 | 186 | @details Use of this API from the host is not allowed. 187 | 188 | @param[in] Callback - The pointer to the function to execute. 189 | 190 | @param[in,out] Context - The pointer to arbitrary context data. 191 | */ 192 | _IRQL_requires_max_(APC_LEVEL) 193 | VOID 194 | RunOnAllProcessors ( 195 | _In_ USER_PASSIVE_CALLBACK* Callback, 196 | _Inout_ VOID* Context 197 | ); 198 | 199 | /*! 200 | @brief Initializes the spin lock. 201 | 202 | @param[out] SpinLock - The pointer to spin lock to initialize. 203 | */ 204 | VOID 205 | InitializeSystemSpinLock ( 206 | _Out_ SPIN_LOCK* SpinLock 207 | ); 208 | 209 | /*! 210 | @brief Acquires the spin lock. 211 | 212 | @details The custom spin lock is used because NT provided spin lock API is 213 | not compatible with Driver Verifier when they are used from hypervisor. 214 | 215 | @param[in,out] SpinLock - The pointer to the spin lock to acquire. 216 | 217 | @return The opaque previous context. 218 | */ 219 | _Requires_lock_not_held_(*SpinLock) 220 | _Acquires_lock_(*SpinLock) 221 | _IRQL_requires_max_(HIGH_LEVEL) 222 | _IRQL_saves_ 223 | _IRQL_raises_(DISPATCH_LEVEL) 224 | UINT8 225 | AcquireSystemSpinLock ( 226 | _Inout_ SPIN_LOCK* SpinLock 227 | ); 228 | 229 | /*! 230 | @brief Release the spin lock and lowers IRQL if necessary. 231 | 232 | @details The custom spin lock is used because NT provided spin lock API is 233 | not compatible with Driver Verifier when they are used from hypervisor. 234 | 235 | @param[in,out] SpinLock - The spin lock to release. 236 | 237 | @param[in] PreviousContext - The opaque previous context returned by the 238 | AcquireSpinLock function. 239 | */ 240 | _Requires_lock_held_(*SpinLock) 241 | _Releases_lock_(*SpinLock) 242 | _IRQL_requires_max_(HIGH_LEVEL) 243 | VOID 244 | ReleaseSystemSpinLock ( 245 | _Inout_ SPIN_LOCK* SpinLock, 246 | _In_ _IRQL_restores_ UINT8 PreviousContext 247 | ); 248 | -------------------------------------------------------------------------------- /Sources/Platform/EFI/EfiAsm.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; @file EfiAsm.asm 3 | ; 4 | ; @brief EFI specific MASM-written functions. 5 | ; 6 | ; @author Satoshi Tanda 7 | ; 8 | ; @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | ; 10 | include AsmCommon.inc 11 | .code 12 | 13 | extern HandleHostException : proc 14 | 15 | ; 16 | ; The index to track an interrupt number for generating AsmDefaultExceptionHandlers. 17 | ; 18 | Index = 0 19 | 20 | ; 21 | ; Generates the default exception handler code for the given interrupt/exception 22 | ; number. The generated code assumes that the interrupt/exception does not push 23 | ; error code. 24 | ; 25 | ; Index is incremented whenever this macro is used. 26 | ; 27 | INTERRUPT_HANDLER macro InterruptNumber 28 | ; 29 | ; Push dummy error code for consistent stack layout. 30 | ; 31 | push 0 32 | push InterruptNumber 33 | jmp AsmCommonExceptionHandler 34 | Index = Index + 1 35 | endm 36 | 37 | ; 38 | ; Generates the default exception handler code for the given interrupt/exception 39 | ; number. The generated code assumes that the interrupt/exception pushes error code. 40 | ; 41 | ; Index is incremented whenever this macro is used. 42 | ; 43 | INTERRUPT_HANDLER_WITH_CODE macro InterruptNumber 44 | ; 45 | ; Error code is expected to be pushed by the processor. 46 | ; 47 | nop 48 | nop 49 | push InterruptNumber 50 | jmp AsmCommonExceptionHandler 51 | Index = Index + 1 52 | endm 53 | 54 | ; 55 | ; @brief The default host exception handlers. 56 | ; 57 | ; @details This is the function containing actually 256 stub functions generated 58 | ; with the INTERRUPT_HANDLER and INTERRUPT_HANDLER_WITH_CODE macros. Each function 59 | ; works as a hendler of the corresponding interrupt/exception in the host. 60 | ; 61 | AsmDefaultExceptionHandlers proc 62 | ; 63 | ; INT0-7 64 | ; 65 | repeat 8 66 | INTERRUPT_HANDLER Index 67 | endm 68 | 69 | ; 70 | ; INT8, INT9 71 | ; 72 | INTERRUPT_HANDLER_WITH_CODE Index 73 | INTERRUPT_HANDLER Index 74 | 75 | ; 76 | ; INT10-14 77 | ; 78 | repeat 5 79 | INTERRUPT_HANDLER_WITH_CODE Index 80 | endm 81 | 82 | ; 83 | ; INT15-16 84 | ; 85 | repeat 2 86 | INTERRUPT_HANDLER Index 87 | endm 88 | 89 | ; 90 | ; INT17 91 | ; 92 | INTERRUPT_HANDLER_WITH_CODE Index 93 | 94 | ; 95 | ; INT18-255 96 | ; 97 | repeat 238 98 | INTERRUPT_HANDLER Index 99 | endm 100 | AsmDefaultExceptionHandlers endp 101 | 102 | ; 103 | ; @brief The common logic for the exception handlers. 104 | ; 105 | ; @details This function pushes register values into the stack and calls the 106 | ; high-level handler written in C. 107 | ; 108 | AsmCommonExceptionHandler proc 109 | PUSHAQ 110 | mov rcx, rsp 111 | sub rsp, 20h 112 | call HandleHostException 113 | add rsp, 20h 114 | POPAQ 115 | 116 | ; 117 | ; Remove the error code and interrupt number. 118 | ; 119 | add rsp, 10h 120 | iretq 121 | AsmCommonExceptionHandler endp 122 | 123 | end 124 | -------------------------------------------------------------------------------- /Sources/Platform/EFI/EfiAsm.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file EfiAsm.h 3 | 4 | @brief EFI specific MASM-written functions. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #pragma once 11 | #include "EfiCommon.h" 12 | 13 | /*! 14 | @brief The array of the default host exception handlers. 15 | */ 16 | VOID 17 | AsmDefaultExceptionHandlers ( 18 | ); 19 | -------------------------------------------------------------------------------- /Sources/Platform/EFI/EfiBitmap.c: -------------------------------------------------------------------------------- 1 | /*! 2 | @file EfiBitmap.c 3 | 4 | @brief EFI specific implementation of bitmap algorithm. 5 | 6 | @details Implementation of algorithm is good enough for the current use of 7 | those API but is incomplete and broken, for example, bits are NEVER 8 | reused once they are set, even after they are "cleared". 9 | 10 | For complete implementation, one can copy ReactOS's implementation if 11 | licensing the project under GPL is acceptable. hvpp by Petr Beneš has its 12 | own implementation of bitmap but is actually influenced by ReactOS 13 | implementation, and such, should be treated as GPL. 14 | 15 | @author Satoshi Tanda 16 | 17 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 18 | */ 19 | #include "EfiBitmap.h" 20 | 21 | VOID 22 | RtlInitializeBitMap ( 23 | RTL_BITMAP* BitMapHeader, 24 | UINT32* BitMapBuffer, 25 | UINT32 SizeOfBitMap 26 | ) 27 | { 28 | BitMapHeader->SizeOfBitMap = SizeOfBitMap; 29 | BitMapHeader->Buffer = BitMapBuffer; 30 | BitMapHeader->NextAvailableBitIndex = 0; 31 | BitMapHeader->SetBitCount = 0; 32 | } 33 | 34 | UINT32 35 | RtlFindClearBitsAndSet ( 36 | RTL_BITMAP* BitMapHeader, 37 | UINT32 NumberToFind, 38 | UINT32 HintIndex 39 | ) 40 | { 41 | UINT32 clearBitIndex; 42 | 43 | // 44 | // Return error if the bitmap does not have enough bits after the current 45 | // index. In other words, it never search from the index 0 because implementation 46 | // never clears bits. 47 | // 48 | if (BitMapHeader->NextAvailableBitIndex + NumberToFind > BitMapHeader->SizeOfBitMap) 49 | { 50 | clearBitIndex = MAXUINT32; 51 | goto Exit; 52 | } 53 | 54 | // 55 | // "Find" clear bits, which is just using bits from the current position. 56 | // 57 | clearBitIndex = BitMapHeader->NextAvailableBitIndex; 58 | 59 | // 60 | // "Set" requested bits, which is just moving the index further. 61 | // 62 | BitMapHeader->SetBitCount += NumberToFind; 63 | BitMapHeader->NextAvailableBitIndex += NumberToFind; 64 | 65 | Exit: 66 | return clearBitIndex; 67 | } 68 | 69 | BOOLEAN 70 | RtlAreBitsClear ( 71 | RTL_BITMAP* BitMapHeader, 72 | UINT32 StartingIndex, 73 | UINT32 Length 74 | ) 75 | { 76 | // 77 | // This implementation support checking only whether an entire bitmap is 78 | // cleared. 79 | // 80 | ASSERT(StartingIndex == 0); 81 | ASSERT(Length == BitMapHeader->SizeOfBitMap); 82 | 83 | return (BitMapHeader->SetBitCount == 0); 84 | } 85 | 86 | VOID 87 | RtlClearBits ( 88 | RTL_BITMAP* BitMapHeader, 89 | UINT32 StartingIndex, 90 | UINT32 NumberToClear 91 | ) 92 | { 93 | // 94 | // This implementation only change this counter, and never actually clear 95 | // bits and let them to be re-set. 96 | // 97 | BitMapHeader->SetBitCount -= NumberToClear; 98 | } 99 | -------------------------------------------------------------------------------- /Sources/Platform/EFI/EfiBitmap.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file EfiBitmap.h 3 | 4 | @brief EFI specific implementation of bitmap algorithm. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #pragma once 11 | #include "EfiCommon.h" 12 | 13 | typedef struct _RTL_BITMAP 14 | { 15 | UINT32 SizeOfBitMap; // Number of bits in bit map 16 | UINT32* Buffer; // Pointer to the bit map itself 17 | UINT32 NextAvailableBitIndex; // Index of the next cleared bit 18 | UINT32 SetBitCount; // Number of bits currently set 19 | } RTL_BITMAP; 20 | 21 | /*! 22 | @brief Initializes the header of a bitmap variable. 23 | 24 | @param[out] BitMapHeader - The pointer to the bitmap variable to initialize. 25 | 26 | @param[in] BitMapBuffer - The pointer to caller-allocated memory for the bitmap 27 | itself. 28 | 29 | @param[in] SizeOfBitMap - The number of bits in the bitmap. 30 | */ 31 | VOID 32 | RtlInitializeBitMap ( 33 | RTL_BITMAP* BitMapHeader, 34 | UINT32* BitMapBuffer, 35 | UINT32 SizeOfBitMap 36 | ); 37 | 38 | /*! 39 | @brief Searches for a range of clear bits of a requested size within a bitmap 40 | and sets all bits in the range when it has been located. 41 | 42 | @param[out] BitMapHeader - The pointer to the RTL_BITMAP structure that 43 | describes the bitmap. 44 | 45 | @param[in] NumberToFind - How many contiguous clear bits will satisfy this 46 | request. 47 | 48 | @param[in] HintIndex - Unused. 49 | 50 | @return The zero-based starting bit index for a clear bit range of the 51 | requested size that it set, or it returns 0xFFFFFFFF if it cannot find 52 | such a range within the given bitmap variable. 53 | */ 54 | UINT32 55 | RtlFindClearBitsAndSet ( 56 | RTL_BITMAP* BitMapHeader, 57 | UINT32 NumberToFind, 58 | UINT32 HintIndex 59 | ); 60 | 61 | /*! 62 | @brief Determines whether a given range of bits within a bitmap variable is 63 | clear. 64 | 65 | @param[in] BitMapHeader - The pointer to the RTL_BITMAP structure that 66 | describes the bitmap. 67 | 68 | @param[in] StartingIndex - The start of the bit range to be tested. 69 | 70 | @param[in] Length - How many bits to test. 71 | 72 | @return Whether a given range of bits within a bitmap variable is clear. 73 | */ 74 | BOOLEAN 75 | RtlAreBitsClear ( 76 | RTL_BITMAP* BitMapHeader, 77 | UINT32 StartingIndex, 78 | UINT32 Length 79 | ); 80 | 81 | /*! 82 | @brief Sets all bits in the specified range of bits in the bitmap to zero. 83 | 84 | @param[out] BitMapHeader - The pointer to the RTL_BITMAP structure that 85 | describes the bitmap. 86 | 87 | @param[in] StartingIndex - Unused. 88 | 89 | @param[in] NumberToClear - How many bits to clear. 90 | */ 91 | VOID 92 | RtlClearBits ( 93 | RTL_BITMAP* BitMapHeader, 94 | UINT32 StartingIndex, 95 | UINT32 NumberToClear 96 | ); 97 | -------------------------------------------------------------------------------- /Sources/Platform/EFI/EfiCommon.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file EfiCommon.h 3 | 4 | @brief EFI specific implementation of common things across the project. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #pragma once 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | // 17 | // "structure was padded due to alignment specifier" 18 | // 19 | #pragma warning(disable: 4324) 20 | 21 | 22 | /*! 23 | @brief Freezes execution of the processor by entering infinite busy loop. 24 | */ 25 | #define MV_PANIC() do { CpuDeadLoop(); } while (TRUE) 26 | #define MV_DEBUG_BREAK() 27 | #define MV_SECTION_INIT 28 | #define MV_SECTION_PAGED 29 | 30 | /*! 31 | @brief Custom ASSERT. 32 | 33 | @details This is a workaround of that the EFI standard ASSERT can cause page 34 | fault (null pointer access) when it fires in the host code. The author 35 | has not been able to find out the root cause and a fix. 36 | */ 37 | #if defined(MDEPKG_NDEBUG) 38 | #define MV_ASSERT(x) 39 | #else 40 | #define MV_ASSERT(x) \ 41 | do \ 42 | { \ 43 | if (!(x)) \ 44 | { \ 45 | LOG_ERROR("ASSERT %a(%d): %a", __FILE__, __LINE__, #x); \ 46 | MV_PANIC(); \ 47 | } \ 48 | } while (FALSE) 49 | #endif 50 | 51 | #if defined(MDEPKG_NDEBUG) 52 | #define MV_VERIFY(x) (x) 53 | #else 54 | #define MV_VERIFY(x) MV_ASSERT(x) 55 | #endif 56 | 57 | #define MV_MAX(x, y) MAX((x), (y)) 58 | #define MV_MIN(x, y) MIN((x), (y)) 59 | 60 | // 61 | // MSVC compatibility type definitions. 62 | // 63 | typedef CHAR8 CHAR; 64 | typedef CHAR16 WCHAR; 65 | #if !defined(_MSC_VER) 66 | #define __int64 long long 67 | #endif 68 | 69 | // 70 | // MSVC intrinsics. 71 | // 72 | unsigned __int64 __readcr0(void); 73 | unsigned __int64 __readcr2(void); 74 | unsigned __int64 __readcr3(void); 75 | unsigned __int64 __readcr4(void); 76 | unsigned __int64 __readcr8(void); 77 | unsigned __int64 __readdr(unsigned int); 78 | unsigned __int64 __readeflags(void); 79 | unsigned __int64 __readmsr(unsigned long); 80 | unsigned char __vmx_on(unsigned __int64 *); 81 | unsigned char __vmx_vmclear(unsigned __int64 *); 82 | unsigned char __vmx_vmlaunch(void); 83 | unsigned char __vmx_vmptrld(unsigned __int64 *); 84 | unsigned char __vmx_vmread(unsigned __int64, unsigned __int64 *); 85 | unsigned char __vmx_vmresume(void); 86 | unsigned char __vmx_vmwrite(unsigned __int64, unsigned __int64); 87 | unsigned long __segmentlimit(unsigned long); 88 | void __cpuid(int[4], int); 89 | void __cpuidex(int[4], int, int); 90 | void __debugbreak(void); 91 | void __invlpg(void *); 92 | void __lidt(void *); 93 | void __sidt(void *); 94 | void __stosq(unsigned __int64 *, unsigned __int64, unsigned __int64); 95 | void __vmx_off(void); 96 | void __vmx_vmptrst(unsigned __int64 *); 97 | void __writecr0(unsigned __int64); 98 | void __writecr2(unsigned __int64); 99 | void __writecr3(unsigned __int64); 100 | void __writecr4(unsigned __int64); 101 | void __writedr(unsigned int, unsigned __int64); 102 | void __writemsr(unsigned long, unsigned __int64); 103 | void _disable(void); 104 | void _enable(void); 105 | void _lgdt(void *); 106 | void _sgdt(void *); 107 | void _xsetbv(unsigned int, unsigned __int64); 108 | unsigned char _BitScanForward64(unsigned long *, unsigned __int64); 109 | 110 | // 111 | // Required. Otherwise, link error occurs. 112 | // 113 | #pragma intrinsic(_disable) 114 | #pragma intrinsic(_enable) 115 | 116 | // 117 | // MSVC compatibility macro definitions. 118 | // 119 | #define __drv_aliasesMem 120 | #define __drv_allocatesMem(x) 121 | #define __drv_freesMem(x) 122 | #define __drv_strictTypeMatch(x) 123 | #define _Acquires_lock_(x) 124 | #define _In_ 125 | #define _In_opt_ 126 | #define _In_range_(x, y) 127 | #define _In_reads_bytes_(x) 128 | #define _In_z_ 129 | #define _Inout_ 130 | #define _IRQL_raises_(x) 131 | #define _IRQL_requires_max_(x) 132 | #define _IRQL_restores_ 133 | #define _IRQL_saves_ 134 | #define _Must_inspect_result_ 135 | #define _Out_ 136 | #define _Out_opt_ 137 | #define _Out_writes_bytes_(x) 138 | #define _Post_maybenull_ 139 | #define _Post_writable_byte_size_(x) 140 | #define _Pre_notnull_ 141 | #define _Printf_format_string_ 142 | #define _Releases_lock_(x) 143 | #define _Requires_lock_held_(x) 144 | #define _Requires_lock_not_held_(x) 145 | #define _Return_type_success_(x) 146 | #define _Success_(x) 147 | #define _Use_decl_annotations_ 148 | #define _When_(x, y) 149 | 150 | #define ANSI_NULL ((CHAR)0) 151 | #define ANYSIZE_ARRAY (1) 152 | #define ARGUMENT_PRESENT(x) ((x) != NULL) 153 | #define BooleanFlagOn(F,SF) ((BOOLEAN)(((F) & (SF)) != 0)) 154 | #define BYTES_TO_PAGES(x) EFI_SIZE_TO_PAGES(x) 155 | #define C_ASSERT(x) STATIC_ASSERT(x, #x) 156 | #define ClearFlag(_F,_SF) ((_F) &= ~(_SF)) 157 | #define DBG_UNREFERENCED_PARAMETER(x) 158 | #define FlagOn(_F,_SF) ((_F) & (_SF)) 159 | #define KERNEL_STACK_SIZE (0x6000) 160 | #define MAXUINT16 MAX_UINT16 161 | #define MAXUINT32 MAX_UINT32 162 | #define MAXUINT64 MAX_UINT64 163 | #define MAXUINT8 MAX_UINT8 164 | #define NOTHING 165 | #define PAGE_ALIGN(Va) ((VOID*)((UINT64)(Va) & ~(PAGE_SIZE - 1))) 166 | #define PAGE_SIZE EFI_PAGE_SIZE 167 | #define PAGED_CODE() 168 | #define RTL_NUMBER_OF(x) ARRAY_SIZE(x) 169 | #define RtlCopyMemory CopyMem 170 | #define RtlZeroMemory ZeroMem 171 | #define SetFlag(_F,_SF) ((_F) |= (_SF)) 172 | #define strcmp(x, y) AsciiStrCmp((x), (y)) 173 | #define UNREFERENCED_PARAMETER(x) (void)(x) 174 | #if defined(_MSC_VER) 175 | #define DECLSPEC_ALIGN(x) __declspec(align(x)) 176 | #elif defined(__GNUC__) 177 | #define DECLSPEC_ALIGN(x) __attribute__ ((aligned(x))) 178 | #endif 179 | -------------------------------------------------------------------------------- /Sources/Platform/EFI/EfiHostInitialization.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file EfiHostInitialization.h 3 | 4 | @brief EFI specific implementation of host environment initialization. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #pragma once 11 | #include "../../HostInitialization.h" 12 | -------------------------------------------------------------------------------- /Sources/Platform/EFI/EfiLogger.c: -------------------------------------------------------------------------------- 1 | /*! 2 | @file EfiLogger.c 3 | 4 | @brief EFI specific implementation of the logger. 5 | 6 | @details Logging becomes no-op at the runtime when UefiDebugLibConOut is used, 7 | ie, -D DEBUG_ON_SERIAL_PORT is not set. See use of mPostEBS in 8 | edk2/MdePkg/Library/UefiDebugLibConOut/DebugLib.c for this behavior. 9 | 10 | @author Satoshi Tanda 11 | 12 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 13 | */ 14 | #include "EfiLogger.h" 15 | #include 16 | #include 17 | #include 18 | 19 | // 20 | // The event handle for ExitBootServices event subscription. 21 | // 22 | static EFI_EVENT g_EfiExitBootServicesEvent; 23 | 24 | // 25 | // FALSE during boot time. Once the system is transition to the run time, any 26 | // EFI API that depends on boot services directly or indirectly cannot be called. 27 | // The most significant implication is the console output cannot be used anymore. 28 | // 29 | static BOOLEAN g_AtRuntime; 30 | 31 | /*! 32 | @brief Handles the ExitBootServices notification. 33 | 34 | @details The solo purpose of this handler is to report the end of console 35 | debug output. 36 | 37 | @param[in] Event - Unused. 38 | 39 | @param[in] Context - Unused. 40 | */ 41 | static 42 | VOID 43 | EFIAPI 44 | ExitBootServicesHandler ( 45 | EFI_EVENT Event, 46 | VOID* Context 47 | ) 48 | { 49 | LOG_INFO("ExitBootServices was called. Ending console logging if used."); 50 | gBS->CloseEvent(g_EfiExitBootServicesEvent); 51 | g_AtRuntime = TRUE; 52 | } 53 | 54 | /*! 55 | @brief Registers ExitBootServices notification. 56 | 57 | @return EFI_SUCCESS on success; otherwise, an appropriate error code. 58 | */ 59 | static 60 | EFI_STATUS 61 | RegisterNotification ( 62 | ) 63 | { 64 | EFI_STATUS status; 65 | 66 | status = gBS->CreateEventEx(EVT_NOTIFY_SIGNAL, 67 | TPL_NOTIFY, 68 | ExitBootServicesHandler, 69 | NULL, 70 | &gEfiEventExitBootServicesGuid, 71 | &g_EfiExitBootServicesEvent); 72 | if (EFI_ERROR(status)) 73 | { 74 | LOG_ERROR("CreateEventEx failed : %r", status); 75 | goto Exit; 76 | } 77 | 78 | Exit: 79 | return status; 80 | } 81 | 82 | EFI_STATUS 83 | InitializeLogger ( 84 | ) 85 | { 86 | EFI_STATUS status; 87 | 88 | status = RegisterNotification(); 89 | if (EFI_ERROR(status)) 90 | { 91 | LOG_ERROR("RegisterNotifications failed : %r", status); 92 | goto Exit; 93 | } 94 | 95 | Exit: 96 | return status; 97 | } 98 | 99 | VOID 100 | CleanupLogger ( 101 | ) 102 | { 103 | if (g_AtRuntime == FALSE) 104 | { 105 | gBS->CloseEvent(g_EfiExitBootServicesEvent); 106 | } 107 | } 108 | 109 | VOID 110 | LogMessage ( 111 | LOG_LEVEL Level, 112 | CONST CHAR* FunctionName, 113 | CONST CHAR* Format, 114 | ... 115 | ) 116 | { 117 | // 118 | // Mapping from LOG_LEVEL to the EFI log level. 119 | // 120 | static CONST UINT64 debugLevelMapping[] = 121 | { 122 | 0, 123 | DEBUG_ERROR, 124 | DEBUG_WARN, 125 | DEBUG_INFO, 126 | DEBUG_VERBOSE, 127 | }; 128 | C_ASSERT(RTL_NUMBER_OF(debugLevelMapping) == LogLevelReserved); 129 | 130 | VA_LIST args; 131 | CHAR8 message[400]; 132 | 133 | VA_START(args, Format); 134 | (VOID)AsciiVSPrint(message, sizeof(message), Format, args); 135 | VA_END(args); 136 | 137 | DebugPrint(debugLevelMapping[Level], "%a: %a\n", FunctionName, message); 138 | } 139 | 140 | VOID 141 | LogEarlyErrorMessage ( 142 | CONST CHAR* Format, 143 | ... 144 | ) 145 | { 146 | VA_LIST args; 147 | 148 | VA_START(args, Format); 149 | (VOID)DebugVPrint(DEBUG_ERROR, Format, args); 150 | VA_END(args); 151 | } 152 | -------------------------------------------------------------------------------- /Sources/Platform/EFI/EfiLogger.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file EfiLogger.h 3 | 4 | @brief EFI specific implementation of the logger. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #pragma once 11 | #include "../../Logger.h" 12 | 13 | /*! 14 | @brief Initializes the global logger. 15 | 16 | @return EFI_SUCCESS on success; otherwise, an appropriate error code. 17 | */ 18 | EFI_STATUS 19 | InitializeLogger ( 20 | ); 21 | 22 | /*! 23 | @brief Clean up the logger. 24 | */ 25 | VOID 26 | CleanupLogger ( 27 | ); 28 | -------------------------------------------------------------------------------- /Sources/Platform/EFI/EfiPlatform.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file EfiPlatform.h 3 | 4 | @brief EFI specific platform API. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #pragma once 11 | #include "../../Platform.h" 12 | -------------------------------------------------------------------------------- /Sources/Platform/Windows/WinAsm.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; @file WinAsm.asm 3 | ; 4 | ; @brief Windows specific MASM-written functions. 5 | ; 6 | ; @author Satoshi Tanda 7 | ; 8 | ; @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | ; 10 | .code 11 | 12 | ; 13 | ; @brief Reads the value of LDTR. 14 | ; 15 | ; @return The value of LDTR. 16 | ; 17 | AsmReadLdtr proc 18 | sldt ax 19 | ret 20 | AsmReadLdtr endp 21 | 22 | ; 23 | ; @brief Reads the value of TR. 24 | ; 25 | ; @return The value of TR. 26 | ; 27 | AsmReadTr proc 28 | str ax 29 | ret 30 | AsmReadTr endp 31 | 32 | ; 33 | ; @brief Reads the value of ES. 34 | ; 35 | ; @return The value of ES. 36 | ; 37 | AsmReadEs proc 38 | mov ax, es 39 | ret 40 | AsmReadEs endp 41 | 42 | ; 43 | ; @brief Reads the value of CS. 44 | ; 45 | ; @return The value of CS. 46 | ; 47 | AsmReadCs proc 48 | mov ax, cs 49 | ret 50 | AsmReadCs endp 51 | 52 | ; 53 | ; @brief Reads the value of SS. 54 | ; 55 | ; @return The value of SS. 56 | ; 57 | AsmReadSs proc 58 | mov ax, ss 59 | ret 60 | AsmReadSs endp 61 | 62 | ; 63 | ; @brief Reads the value of DS. 64 | ; 65 | ; @return The value of DS. 66 | ; 67 | AsmReadDs proc 68 | mov ax, ds 69 | ret 70 | AsmReadDs endp 71 | 72 | ; 73 | ; @brief Reads the value of FS. 74 | ; 75 | ; @return The value of FS. 76 | ; 77 | AsmReadFs proc 78 | mov ax, fs 79 | ret 80 | AsmReadFs endp 81 | 82 | ; 83 | ; @brief Reads the value of GS. 84 | ; 85 | ; @return The value of GS. 86 | ; 87 | AsmReadGs proc 88 | mov ax, gs 89 | ret 90 | AsmReadGs endp 91 | 92 | ; 93 | ; @brief Writes the value to TR. 94 | ; 95 | ; @param[in] RCX - The new TR value to write. 96 | ; 97 | AsmWriteTr proc 98 | ltr cx 99 | ret 100 | AsmWriteTr endp 101 | 102 | end 103 | -------------------------------------------------------------------------------- /Sources/Platform/Windows/WinAsm.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file WinAsm.h 3 | 4 | @brief Windows specific MASM-written functions. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #pragma once 11 | #include "WinCommon.h" 12 | 13 | /*! 14 | @brief Reads the value of LDTR. 15 | 16 | @return The value of LDTR. 17 | */ 18 | UINT16 19 | AsmReadLdtr ( 20 | ); 21 | 22 | /*! 23 | @brief Reads the value of TR. 24 | 25 | @return The value of TR. 26 | */ 27 | UINT16 28 | AsmReadTr ( 29 | ); 30 | 31 | /*! 32 | @brief Reads the value of ES. 33 | 34 | @return The value of ES. 35 | */ 36 | UINT16 37 | AsmReadEs ( 38 | ); 39 | 40 | /*! 41 | @brief Reads the value of CS. 42 | 43 | @return The value of CS. 44 | */ 45 | UINT16 46 | AsmReadCs ( 47 | ); 48 | 49 | /*! 50 | @brief Reads the value of SS. 51 | 52 | @return The value of SS. 53 | */ 54 | UINT16 55 | AsmReadSs ( 56 | ); 57 | 58 | /*! 59 | @brief Reads the value of DS. 60 | 61 | @return The value of DS. 62 | */ 63 | UINT16 64 | AsmReadDs ( 65 | ); 66 | 67 | /*! 68 | @brief Reads the value of FS. 69 | 70 | @return The value of FS. 71 | */ 72 | UINT16 73 | AsmReadFs ( 74 | ); 75 | 76 | /*! 77 | @brief Reads the value of GS. 78 | 79 | @return The value of GS. 80 | */ 81 | UINT16 82 | AsmReadGs ( 83 | ); 84 | 85 | /*! 86 | @brief Writes the value to TR. 87 | 88 | @param[in] TaskSelector - The value to write to TR. 89 | */ 90 | VOID 91 | AsmWriteTr ( 92 | _In_ UINT16 TaskSelector 93 | ); 94 | -------------------------------------------------------------------------------- /Sources/Platform/Windows/WinCommon.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file WinCommon.h 3 | 4 | @brief Windows specific implementation of common things across the project. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #pragma once 11 | #include 12 | #include 13 | #include 14 | 15 | // 16 | // "Error annotation: Must succeed pool allocations are forbidden. Allocation 17 | // failures cause a system crash." 18 | // 19 | #pragma warning(disable: __WARNING_ERROR) 20 | 21 | /*! 22 | @brief Breaks into a debugger if present, and then triggers bug check. 23 | */ 24 | #define MV_PANIC() \ 25 | MV_DEBUG_BREAK(); \ 26 | __pragma(warning(push)) \ 27 | __pragma(warning(disable: __WARNING_USE_OTHER_FUNCTION)) \ 28 | KeBugCheckEx(MANUALLY_INITIATED_CRASH, 0, 0, 0, 0) \ 29 | __pragma(warning(pop)) 30 | 31 | /*! 32 | @brief Breaks into a kernel debugger if present. 33 | 34 | @details This macro is emits software breakpoint that only hits when a 35 | kernel debugger is present. This macro is useful because it does not 36 | change the current frame unlike the DbgBreakPoint function, and 37 | breakpoint by this macro can be overwritten with NOP without impacting 38 | other breakpoints. 39 | */ 40 | #define MV_DEBUG_BREAK() \ 41 | if (KD_DEBUGGER_NOT_PRESENT) \ 42 | { \ 43 | NOTHING; \ 44 | } \ 45 | else \ 46 | { \ 47 | __debugbreak(); \ 48 | } \ 49 | (VOID*)(0) 50 | 51 | // 52 | // The handy macros to specify in which section the code should be placed. 53 | // 54 | #define MV_SECTION_INIT __declspec(code_seg("INIT")) 55 | #define MV_SECTION_PAGED __declspec(code_seg("PAGE")) 56 | 57 | #define MV_ASSERT(x) NT_ASSERT(x) 58 | #define MV_VERIFY(x) NT_VERIFY(x) 59 | #define MV_MAX(x, y) max((x), (y)) 60 | #define MV_MIN(x, y) min((x), (y)) 61 | -------------------------------------------------------------------------------- /Sources/Platform/Windows/WinHostInitialization.c: -------------------------------------------------------------------------------- 1 | /*! 2 | @file WinHostInitialization.c 3 | 4 | @brief Windows specific implementation of host environment initialization. 5 | 6 | @details On Windows, no special set up is done because the host shares the 7 | System process CR3 and IDTR for ease of debugging, and other interactions 8 | with the guest as demanded. 9 | 10 | @author Satoshi Tanda 11 | 12 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 13 | */ 14 | #include "WinHostInitialization.h" 15 | 16 | // 17 | // The host CR3 and IDTR on Windows are the same as that of the System process. 18 | // This allows the host to be debugged with Windbg. 19 | // 20 | static CR3 g_HostCr3; 21 | static IDTR g_HostIdtr; 22 | 23 | VOID 24 | InitializeHostEnvironment ( 25 | ) 26 | { 27 | MV_ASSERT(PsGetCurrentProcess() == PsInitialSystemProcess); 28 | 29 | g_HostCr3.Flags = __readcr3(); 30 | __sidt(&g_HostIdtr); 31 | } 32 | 33 | CR3 34 | GetHostCr3 ( 35 | ) 36 | { 37 | return g_HostCr3; 38 | } 39 | 40 | CONST IDTR* 41 | GetHostIdtr ( 42 | ) 43 | { 44 | return &g_HostIdtr; 45 | } 46 | 47 | _Use_decl_annotations_ 48 | VOID 49 | InitializeGdt ( 50 | TASK_STATE_SEGMENT_64* NewTss, 51 | SEGMENT_DESCRIPTOR_64* NewGdt, 52 | UINT64 NewGdtSize, 53 | GDTR* OriginalGdtr 54 | ) 55 | { 56 | UNREFERENCED_PARAMETER(NewTss); 57 | UNREFERENCED_PARAMETER(NewGdt); 58 | UNREFERENCED_PARAMETER(NewGdtSize); 59 | 60 | RtlZeroMemory(OriginalGdtr, sizeof(*OriginalGdtr)); 61 | } 62 | 63 | _Use_decl_annotations_ 64 | VOID 65 | CleanupGdt ( 66 | CONST GDTR* OriginalGdtr 67 | ) 68 | { 69 | UNREFERENCED_PARAMETER(OriginalGdtr); 70 | } 71 | 72 | BOOLEAN 73 | IsVmxAvailableEx ( 74 | ) 75 | { 76 | // 77 | // Windows driver implementation does not require anything additionally. 78 | // 79 | return TRUE; 80 | } 81 | -------------------------------------------------------------------------------- /Sources/Platform/Windows/WinHostInitialization.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file WinHostInitialization.h 3 | 4 | @brief Windows specific implementation of host environment initialization. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #pragma once 11 | #include "../../HostInitialization.h" 12 | -------------------------------------------------------------------------------- /Sources/Platform/Windows/WinLogger.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file WinLogger.h 3 | 4 | @brief Windows specific implementation of the logger. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #pragma once 11 | #include "../../Logger.h" 12 | 13 | // 14 | // The handy macros to specify in which section the code should be placed. 15 | // 16 | #define LOGGER_INIT __declspec(code_seg("INIT")) 17 | #define LOGGER_PAGED __declspec(code_seg("PAGE")) 18 | 19 | // 20 | // Extended configuration flags. 21 | // 22 | typedef union _LOGGER_CONFIGURATION_FLAGS 23 | { 24 | struct 25 | { 26 | UINT32 EnableTimestamp : 1; 27 | UINT32 EnableLevel : 1; 28 | UINT32 EnableProcessorNumber : 1; 29 | UINT32 EnablePidTid : 1; 30 | UINT32 EnableProcessName : 1; 31 | UINT32 EnableFunctionName : 1; 32 | } u; 33 | 34 | UINT32 AsUInt32; 35 | } LOGGER_CONFIGURATION_FLAGS; 36 | 37 | // 38 | // The configurations of the logger to initialize. 39 | // 40 | typedef struct _LOGGER_CONFIGURATION 41 | { 42 | // 43 | // The maximum level of the log this logger will log. For example, the 44 | // information-level logs are discarded when LogLevelWarning is specified. 45 | // If LogLevelNone is set, the logger is disabled and none of logs are logged. 46 | // 47 | LOG_LEVEL Level; 48 | 49 | // 50 | // Extended configuration flags. 51 | // 52 | LOGGER_CONFIGURATION_FLAGS Flags; 53 | 54 | // 55 | // An interval to flush logs saved into log message buffer. 56 | // 57 | UINT32 FlushIntervalInMs; 58 | 59 | // 60 | // A size of log message buffer. The logger internally allocates two buffers 61 | // with this size. 62 | // 63 | SIZE_T BufferSize; 64 | 65 | // 66 | // The path to the file to save logs. The logger do not save logs into a file 67 | // when NULL is specified. 68 | // 69 | PCWSTR FilePath; 70 | } LOGGER_CONFIGURATION; 71 | 72 | /*! 73 | @brief Initializes the global logger. 74 | 75 | @param[in] Configuration - The configuration for initialization. 76 | 77 | @return STATUS_SUCCESS on success; otherwise, an appropriate error code. 78 | */ 79 | _IRQL_requires_max_(PASSIVE_LEVEL) 80 | _Must_inspect_result_ 81 | NTSTATUS 82 | InitializeLogger ( 83 | _In_ CONST LOGGER_CONFIGURATION* Configuration 84 | ); 85 | 86 | /*! 87 | @brief Clean up the logger. 88 | */ 89 | _IRQL_requires_max_(PASSIVE_LEVEL) 90 | VOID 91 | CleanupLogger ( 92 | ); 93 | -------------------------------------------------------------------------------- /Sources/Platform/Windows/WinPlatform.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file WinPlatform.h 3 | 4 | @brief Windows specific platform API. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #pragma once 11 | #include "../../Platform.h" 12 | -------------------------------------------------------------------------------- /Sources/Public.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @file Public.h 3 | 4 | @brief Interfaces to communicate with the hypervisor. 5 | 6 | @author Satoshi Tanda 7 | 8 | @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. 9 | */ 10 | #pragma once 11 | #include "Common.h" 12 | 13 | // 14 | // The VMCALL numbers our hypervisor provides. 15 | // 16 | #define MV_VMCALL_SIGNATURE_MASK (UINT64)('MinV') 17 | 18 | #define MV_VMCALL_INVALID_MIN (UINT64)((MV_VMCALL_SIGNATURE_MASK << 32) | 0) 19 | #define MV_VMCALL_UNINSTALL (UINT64)((MV_VMCALL_SIGNATURE_MASK << 32) | 1) 20 | #define MV_VMCALL_INVALID_MAX (UINT64)((MV_VMCALL_SIGNATURE_MASK << 32) | 2) 21 | 22 | // 23 | // The arbitrary collection of data passed to our hypervisor from kernel-mode 24 | // code through stack of the hypervisor. 25 | // 26 | // The structure must be 16-byte aligned so that hypervisor's stack pointer is 27 | // always 16-byte aligned and SSE instructions can be used to save XMM registers. 28 | // See Asm.asm for relevant code. 29 | // 30 | typedef struct _HYPERVISOR_CONTEXT 31 | { 32 | // 33 | // The processor number associated with this context. 0 for BSP. 34 | // 35 | UINT32 ProcessorNumber; 36 | UINT32 Padding1; 37 | 38 | // 39 | // The pointer to the MSR bitmaps that are shared across processor. 40 | // 41 | struct _MSR_BITMAPS* SharedMsrBitmaps; 42 | 43 | // 44 | // A pointer to the shared processor context. This value is not used by the 45 | // hypervisor, and the hypervisor doe not know its layout. It is stored here 46 | // so that it can be returned and freed when hypervisor is being disabled. 47 | // 48 | struct _SHARED_PROCESSOR_CONTEXT* SharedProcessorContext; 49 | 50 | // 51 | // A pointer to the EPT context. Needed to handle EPT violation VM-exit. 52 | // 53 | struct _EPT_CONTEXT* EptContext; 54 | 55 | // 56 | // A pointer to the memory access context. Used to access guest's memory. 57 | // 58 | struct _MEMORY_ACCESS_CONTEXT* MemoryAccessContext; 59 | 60 | // 61 | // The state of the nested hypervisor if any. 62 | // 63 | struct _NEXTED_VMX_CONTEXT* NestedVmxContext; 64 | } HYPERVISOR_CONTEXT; 65 | C_ASSERT((sizeof(HYPERVISOR_CONTEXT) % 0x10) == 0); 66 | -------------------------------------------------------------------------------- /Tests/CheckHvVendor/CheckHvVendor.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29709.97 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CheckHvVendor", "CheckHvVendor\CheckHvVendor.vcxproj", "{243E8ED0-58CF-4322-BB7D-D52E70352608}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {243E8ED0-58CF-4322-BB7D-D52E70352608}.Debug|x64.ActiveCfg = Debug|x64 17 | {243E8ED0-58CF-4322-BB7D-D52E70352608}.Debug|x64.Build.0 = Debug|x64 18 | {243E8ED0-58CF-4322-BB7D-D52E70352608}.Debug|x86.ActiveCfg = Debug|Win32 19 | {243E8ED0-58CF-4322-BB7D-D52E70352608}.Debug|x86.Build.0 = Debug|Win32 20 | {243E8ED0-58CF-4322-BB7D-D52E70352608}.Release|x64.ActiveCfg = Release|Win32 21 | {243E8ED0-58CF-4322-BB7D-D52E70352608}.Release|x64.Build.0 = Release|Win32 22 | {243E8ED0-58CF-4322-BB7D-D52E70352608}.Release|x86.ActiveCfg = Release|Win32 23 | {243E8ED0-58CF-4322-BB7D-D52E70352608}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {7698274F-4C44-4EDE-8DE0-FC9195A1FB39} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Tests/CheckHvVendor/CheckHvVendor/CheckHvVendor.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // This program executes CPUID(0x40000000) on all logical processors. 3 | // 4 | #include 5 | #include 6 | 7 | #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) 8 | #define WINDOWS 9 | 10 | #include 11 | #include 12 | 13 | #elif defined(__linux__) 14 | #define LINUX 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #endif 21 | 22 | static 23 | void 24 | cpuid ( 25 | int* regs, 26 | int leaf 27 | ) 28 | { 29 | #if defined(WINDOWS) 30 | __cpuid(regs, leaf); 31 | #elif defined(LINUX) 32 | __cpuid(leaf, regs[0], regs[1], regs[2], regs[3]); 33 | #endif 34 | } 35 | 36 | static 37 | unsigned long 38 | get_logical_processor_count ( 39 | ) 40 | { 41 | #if defined(WINDOWS) 42 | return GetActiveProcessorCount(ALL_PROCESSOR_GROUPS); 43 | #elif defined(LINUX) 44 | return get_nprocs(); 45 | #endif 46 | } 47 | 48 | static 49 | int 50 | get_current_processor_number ( 51 | ) 52 | { 53 | #if defined(WINDOWS) 54 | return GetCurrentProcessorNumber(); 55 | #elif defined(LINUX) 56 | return sched_getcpu(); 57 | #endif 58 | } 59 | 60 | static 61 | bool 62 | set_affinity ( 63 | int processor_number 64 | ) 65 | { 66 | #if defined(WINDOWS) 67 | return (SetProcessAffinityMask(GetCurrentProcess(), ((DWORD_PTR)1) << processor_number) != FALSE); 68 | #elif defined(LINUX) 69 | cpu_set_t mask; 70 | 71 | CPU_ZERO(&mask); 72 | CPU_SET(processor_number, &mask); 73 | return (sched_setaffinity(0, sizeof(mask), &mask) != -1); 74 | #endif 75 | } 76 | 77 | static 78 | void 79 | run_cpuid ( 80 | ) 81 | { 82 | int registers[4] = {}; // EAX, EBX, ECX, and EDX 83 | char vendorId[13]; 84 | 85 | printf("Executing CPUID(0x40000000) on CPU %d\n", get_current_processor_number()); 86 | cpuid(registers, 0x40000000); 87 | memcpy(vendorId + 0, ®isters[1], sizeof(registers[1])); 88 | memcpy(vendorId + 4, ®isters[2], sizeof(registers[2])); 89 | memcpy(vendorId + 8, ®isters[3], sizeof(registers[3])); 90 | vendorId[12] = '\0'; 91 | printf("Result: %s\n", vendorId); 92 | } 93 | 94 | 95 | static 96 | void 97 | test_cpuid_on_all_processors ( 98 | ) 99 | { 100 | unsigned long cpuCount = get_logical_processor_count(); 101 | 102 | for (unsigned long i = 0; i < cpuCount; ++i) 103 | { 104 | if (!set_affinity(i)) 105 | { 106 | printf("set_affinity failed\n"); 107 | return; 108 | } 109 | 110 | run_cpuid(); 111 | } 112 | } 113 | 114 | int 115 | main ( 116 | ) 117 | { 118 | test_cpuid_on_all_processors(); 119 | } 120 | -------------------------------------------------------------------------------- /Tests/CheckHvVendor/CheckHvVendor/CheckHvVendor.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {243E8ED0-58CF-4322-BB7D-D52E70352608} 23 | SAK 24 | SAK 25 | SAK 26 | SAK 27 | Win32Proj 28 | CheckHvVendor 29 | 10.0.18362.0 30 | 31 | 32 | 33 | Application 34 | true 35 | v141 36 | v142 37 | Unicode 38 | 39 | 40 | Application 41 | true 42 | v141 43 | v142 44 | Unicode 45 | 46 | 47 | Application 48 | false 49 | v141 50 | v142 51 | true 52 | Unicode 53 | 54 | 55 | Application 56 | false 57 | v141 58 | v142 59 | true 60 | Unicode 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | true 80 | $(VC_ReferencesPath_VC_X86)\..\onecore\x86;$(WindowsSDK_LibraryPath_x86);$(UniversalCRT_LibraryPath_x86) 81 | 82 | 83 | true 84 | $(VC_ReferencesPath_VC_X86)\..\onecore\x64;$(WindowsSDK_LibraryPath_x64);$(UniversalCRT_LibraryPath_x64) 85 | 86 | 87 | false 88 | $(VC_ReferencesPath_VC_X86)\..\onecore\x86;$(WindowsSDK_LibraryPath_x86);$(UniversalCRT_LibraryPath_x86) 89 | 90 | 91 | false 92 | $(VC_ReferencesPath_VC_X86)\..\onecore\x64;$(WindowsSDK_LibraryPath_x64);$(UniversalCRT_LibraryPath_x64) 93 | 94 | 95 | 96 | Level4 97 | Disabled 98 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 99 | true 100 | 101 | 102 | Console 103 | true 104 | onecoreuap.lib 105 | 106 | 107 | 108 | 109 | Level4 110 | Disabled 111 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 112 | true 113 | 114 | 115 | Console 116 | true 117 | onecoreuap.lib 118 | 119 | 120 | 121 | 122 | Level4 123 | MaxSpeed 124 | true 125 | true 126 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 127 | true 128 | MultiThreaded 129 | 130 | 131 | Console 132 | true 133 | true 134 | true 135 | onecoreuap.lib 136 | 137 | 138 | 139 | 140 | Level4 141 | MaxSpeed 142 | true 143 | true 144 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 145 | true 146 | MultiThreaded 147 | 148 | 149 | Console 150 | true 151 | true 152 | true 153 | onecoreuap.lib 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | -------------------------------------------------------------------------------- /Tests/CheckHvVendor/CheckHvVendor/CheckHvVendor.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Tests/NmiTester/CpuidLoop/CpuidLoop.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define CPUID_HV_VENDOR_AND_MAX_FUNCTIONS ((UINT32)0x40000000) 7 | 8 | static 9 | DWORD 10 | WINAPI 11 | ThreadEntryPoint ( 12 | PVOID Context 13 | ) 14 | { 15 | int registers[4]; 16 | 17 | while (TRUE) 18 | { 19 | __cpuid(registers, CPUID_HV_VENDOR_AND_MAX_FUNCTIONS); 20 | } 21 | return 0; 22 | } 23 | 24 | int 25 | main ( 26 | ) 27 | { 28 | DWORD processorCount; 29 | 30 | // 31 | // Spawn threads that run CPUID in the infinite loop. 32 | // 33 | processorCount = GetActiveProcessorCount(ALL_PROCESSOR_GROUPS); 34 | for (DWORD i = 0; i < processorCount; ++i) 35 | { 36 | HANDLE threadHandle; 37 | 38 | threadHandle = CreateThread(NULL, 0, ThreadEntryPoint, NULL, 0, NULL); 39 | if (threadHandle == NULL) 40 | { 41 | return EXIT_FAILURE; 42 | } 43 | CloseHandle(threadHandle); 44 | } 45 | 46 | printf("%lu CPUID loop threads started. Press the ENTER key to terminate the program.\n", 47 | processorCount); 48 | (void)getchar(); 49 | return EXIT_SUCCESS; 50 | } 51 | -------------------------------------------------------------------------------- /Tests/NmiTester/CpuidLoop/CpuidLoop.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {D6370B90-F6F4-419E-A83B-04DCB7EDFFBD} 24 | CpuidLoop 25 | 10.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v142 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v142 38 | true 39 | Unicode 40 | 41 | 42 | Application 43 | true 44 | v142 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v142 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | true 74 | 75 | 76 | true 77 | 78 | 79 | false 80 | 81 | 82 | false 83 | 84 | 85 | 86 | Level3 87 | true 88 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 89 | true 90 | 91 | 92 | Console 93 | true 94 | 95 | 96 | 97 | 98 | Level3 99 | true 100 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 101 | true 102 | 103 | 104 | Console 105 | true 106 | 107 | 108 | 109 | 110 | Level3 111 | true 112 | true 113 | true 114 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 115 | true 116 | 117 | 118 | Console 119 | true 120 | true 121 | true 122 | 123 | 124 | 125 | 126 | Level3 127 | true 128 | true 129 | true 130 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 131 | true 132 | MultiThreaded 133 | 134 | 135 | Console 136 | true 137 | true 138 | true 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /Tests/NmiTester/CpuidLoop/CpuidLoop.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /Tests/NmiTester/NmiTester.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29806.167 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NmiTester", "NmiTester\NmiTester.vcxproj", "{34ADB149-86F6-4016-A90A-BD5FCD984101}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CpuidLoop", "CpuidLoop\CpuidLoop.vcxproj", "{D6370B90-F6F4-419E-A83B-04DCB7EDFFBD}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|ARM = Debug|ARM 13 | Debug|ARM64 = Debug|ARM64 14 | Debug|x64 = Debug|x64 15 | Debug|x86 = Debug|x86 16 | Release|ARM = Release|ARM 17 | Release|ARM64 = Release|ARM64 18 | Release|x64 = Release|x64 19 | Release|x86 = Release|x86 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {34ADB149-86F6-4016-A90A-BD5FCD984101}.Debug|ARM.ActiveCfg = Debug|ARM 23 | {34ADB149-86F6-4016-A90A-BD5FCD984101}.Debug|ARM.Build.0 = Debug|ARM 24 | {34ADB149-86F6-4016-A90A-BD5FCD984101}.Debug|ARM.Deploy.0 = Debug|ARM 25 | {34ADB149-86F6-4016-A90A-BD5FCD984101}.Debug|ARM64.ActiveCfg = Debug|ARM64 26 | {34ADB149-86F6-4016-A90A-BD5FCD984101}.Debug|ARM64.Build.0 = Debug|ARM64 27 | {34ADB149-86F6-4016-A90A-BD5FCD984101}.Debug|ARM64.Deploy.0 = Debug|ARM64 28 | {34ADB149-86F6-4016-A90A-BD5FCD984101}.Debug|x64.ActiveCfg = Debug|x64 29 | {34ADB149-86F6-4016-A90A-BD5FCD984101}.Debug|x64.Build.0 = Debug|x64 30 | {34ADB149-86F6-4016-A90A-BD5FCD984101}.Debug|x64.Deploy.0 = Debug|x64 31 | {34ADB149-86F6-4016-A90A-BD5FCD984101}.Debug|x86.ActiveCfg = Debug|Win32 32 | {34ADB149-86F6-4016-A90A-BD5FCD984101}.Debug|x86.Build.0 = Debug|Win32 33 | {34ADB149-86F6-4016-A90A-BD5FCD984101}.Debug|x86.Deploy.0 = Debug|Win32 34 | {34ADB149-86F6-4016-A90A-BD5FCD984101}.Release|ARM.ActiveCfg = Release|ARM 35 | {34ADB149-86F6-4016-A90A-BD5FCD984101}.Release|ARM.Build.0 = Release|ARM 36 | {34ADB149-86F6-4016-A90A-BD5FCD984101}.Release|ARM.Deploy.0 = Release|ARM 37 | {34ADB149-86F6-4016-A90A-BD5FCD984101}.Release|ARM64.ActiveCfg = Release|ARM64 38 | {34ADB149-86F6-4016-A90A-BD5FCD984101}.Release|ARM64.Build.0 = Release|ARM64 39 | {34ADB149-86F6-4016-A90A-BD5FCD984101}.Release|ARM64.Deploy.0 = Release|ARM64 40 | {34ADB149-86F6-4016-A90A-BD5FCD984101}.Release|x64.ActiveCfg = Release|x64 41 | {34ADB149-86F6-4016-A90A-BD5FCD984101}.Release|x64.Build.0 = Release|x64 42 | {34ADB149-86F6-4016-A90A-BD5FCD984101}.Release|x64.Deploy.0 = Release|x64 43 | {34ADB149-86F6-4016-A90A-BD5FCD984101}.Release|x86.ActiveCfg = Release|Win32 44 | {34ADB149-86F6-4016-A90A-BD5FCD984101}.Release|x86.Build.0 = Release|Win32 45 | {34ADB149-86F6-4016-A90A-BD5FCD984101}.Release|x86.Deploy.0 = Release|Win32 46 | {D6370B90-F6F4-419E-A83B-04DCB7EDFFBD}.Debug|ARM.ActiveCfg = Debug|Win32 47 | {D6370B90-F6F4-419E-A83B-04DCB7EDFFBD}.Debug|ARM64.ActiveCfg = Debug|Win32 48 | {D6370B90-F6F4-419E-A83B-04DCB7EDFFBD}.Debug|x64.ActiveCfg = Debug|x64 49 | {D6370B90-F6F4-419E-A83B-04DCB7EDFFBD}.Debug|x64.Build.0 = Debug|x64 50 | {D6370B90-F6F4-419E-A83B-04DCB7EDFFBD}.Debug|x86.ActiveCfg = Debug|Win32 51 | {D6370B90-F6F4-419E-A83B-04DCB7EDFFBD}.Debug|x86.Build.0 = Debug|Win32 52 | {D6370B90-F6F4-419E-A83B-04DCB7EDFFBD}.Release|ARM.ActiveCfg = Release|Win32 53 | {D6370B90-F6F4-419E-A83B-04DCB7EDFFBD}.Release|ARM64.ActiveCfg = Release|Win32 54 | {D6370B90-F6F4-419E-A83B-04DCB7EDFFBD}.Release|x64.ActiveCfg = Release|x64 55 | {D6370B90-F6F4-419E-A83B-04DCB7EDFFBD}.Release|x64.Build.0 = Release|x64 56 | {D6370B90-F6F4-419E-A83B-04DCB7EDFFBD}.Release|x86.ActiveCfg = Release|Win32 57 | {D6370B90-F6F4-419E-A83B-04DCB7EDFFBD}.Release|x86.Build.0 = Release|Win32 58 | EndGlobalSection 59 | GlobalSection(SolutionProperties) = preSolution 60 | HideSolutionNode = FALSE 61 | EndGlobalSection 62 | GlobalSection(ExtensibilityGlobals) = postSolution 63 | SolutionGuid = {86386888-DF36-4AC3-8F2A-6CDD1F65F0FA} 64 | EndGlobalSection 65 | EndGlobal 66 | -------------------------------------------------------------------------------- /Tests/NmiTester/NmiTester/NmiTester.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | _Function_class_(NMI_CALLBACK) 5 | _IRQL_requires_same_ 6 | static 7 | BOOLEAN 8 | HandleNmi ( 9 | _In_opt_ PVOID Context, 10 | _In_ BOOLEAN Handled 11 | ) 12 | { 13 | volatile long* nmiCount; 14 | 15 | UNREFERENCED_PARAMETER(Handled); 16 | 17 | nmiCount = (long*)Context; 18 | InterlockedIncrement(nmiCount); 19 | 20 | return TRUE; 21 | } 22 | 23 | VOID 24 | static 25 | Sleep ( 26 | UINT64 Milliseconds 27 | ) 28 | { 29 | LARGE_INTEGER interval; 30 | 31 | PAGED_CODE(); 32 | 33 | interval.QuadPart = -(LONGLONG)(10000 * Milliseconds); 34 | (VOID)KeDelayExecutionThread(KernelMode, FALSE, &interval); 35 | } 36 | 37 | typedef struct _KAFFINITY_EX 38 | { 39 | USHORT Count; 40 | USHORT Size; 41 | ULONG Reserved; 42 | KAFFINITY Bitmap[20]; 43 | } KAFFINITY_EX, *PKAFFINITY_EX; 44 | 45 | typedef 46 | VOID 47 | (NTAPI*HALSENDNMI_TYPE) ( 48 | CONST KAFFINITY_EX* AffinityEx 49 | ); 50 | 51 | EXTERN_C 52 | VOID 53 | NTAPI 54 | KeInitializeAffinityEx ( 55 | KAFFINITY_EX *Affinity 56 | ); 57 | 58 | EXTERN_C 59 | VOID 60 | NTAPI 61 | KeAddProcessorAffinityEx ( 62 | KAFFINITY_EX *Affinity, 63 | ULONG ProcessorBitmask 64 | ); 65 | 66 | EXTERN_C 67 | NTSTATUS 68 | DriverEntry ( 69 | PDRIVER_OBJECT DriverObject, 70 | PUNICODE_STRING RegistryPath 71 | ) 72 | { 73 | static UNICODE_STRING halSendNmiName = RTL_CONSTANT_STRING(L"HalSendNMI"); 74 | NTSTATUS status; 75 | volatile ULONG nmiCount; 76 | PVOID registration; 77 | HALSENDNMI_TYPE halSendNMI; 78 | ULONG processorBitMask; 79 | KAFFINITY_EX affinity; 80 | ULONG processorCount; 81 | 82 | UNREFERENCED_PARAMETER(DriverObject); 83 | UNREFERENCED_PARAMETER(RegistryPath); 84 | 85 | registration = NULL; 86 | 87 | // 88 | // It makes no sense to run this test on the UP system. 89 | // 90 | processorCount = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS); 91 | if (processorCount == 1) 92 | { 93 | status = STATUS_UNSUCCESSFUL; 94 | goto Exit; 95 | } 96 | 97 | // 98 | // Register our NMI callback. 99 | // 100 | halSendNMI = (HALSENDNMI_TYPE)MmGetSystemRoutineAddress(&halSendNmiName); 101 | if (halSendNMI == NULL) 102 | { 103 | status = STATUS_PROCEDURE_NOT_FOUND; 104 | goto Exit; 105 | } 106 | 107 | nmiCount = 0; 108 | registration = KeRegisterNmiCallback(HandleNmi, (PVOID)&nmiCount); 109 | if (registration == NULL) 110 | { 111 | status = STATUS_UNSUCCESSFUL; 112 | goto Exit; 113 | } 114 | 115 | // 116 | // Send NMI to all active processors. Wait is required to minimize the 117 | // chance to refer to the counter variable before the callback is processed 118 | // on the other processors. 119 | // 120 | KeInitializeAffinityEx(&affinity); 121 | processorBitMask = 0; 122 | for (ULONG i = 0; i < processorCount; ++i) 123 | { 124 | KeAddProcessorAffinityEx(&affinity, i); 125 | } 126 | 127 | halSendNMI(&affinity); 128 | Sleep(1); 129 | 130 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, 131 | DPFLTR_ERROR_LEVEL, 132 | "NmiCount = %lu\n", 133 | nmiCount); 134 | 135 | // 136 | // Make sure the NMI occurred on the all processors. If not, probably need 137 | // more sleep. 138 | // 139 | if (nmiCount != processorCount) 140 | { 141 | status = STATUS_UNSUCCESSFUL; 142 | goto Exit; 143 | } 144 | 145 | // 146 | // Send NMI many times and see if it gets droppped. 147 | // 148 | nmiCount = 0; 149 | for (ULONG issuedNmiCount = 0; issuedNmiCount < 10000; ++issuedNmiCount) 150 | { 151 | if (nmiCount != issuedNmiCount * processorCount) 152 | { 153 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, 154 | DPFLTR_ERROR_LEVEL, 155 | "NMI dropped: %lu actual vs %lu expected\n", 156 | nmiCount, 157 | issuedNmiCount * processorCount); 158 | status = STATUS_UNSUCCESSFUL; 159 | goto Exit; 160 | } 161 | 162 | halSendNMI(&affinity); 163 | Sleep(1); 164 | 165 | if ((issuedNmiCount % 100) == 0) 166 | { 167 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, 168 | DPFLTR_ERROR_LEVEL, 169 | "Processed %lu times\n", 170 | issuedNmiCount); 171 | } 172 | } 173 | 174 | // 175 | // Good! 176 | // 177 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, 178 | DPFLTR_ERROR_LEVEL, 179 | "NMI successfully processed %lu times\n", 180 | nmiCount); 181 | 182 | status = STATUS_CANCELLED; 183 | 184 | Exit: 185 | if (registration != NULL) 186 | { 187 | NT_VERIFY(NT_SUCCESS(KeDeregisterNmiCallback(registration))); 188 | } 189 | return status; 190 | } 191 | -------------------------------------------------------------------------------- /Tests/NmiTester/NmiTester/NmiTester.inf: -------------------------------------------------------------------------------- 1 | ; 2 | ; NmiTester.inf 3 | ; 4 | 5 | [Version] 6 | Signature="$WINDOWS NT$" 7 | Class=Sample ; TODO: edit Class 8 | ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} ; TODO: edit ClassGuid 9 | Provider=%ManufacturerName% 10 | CatalogFile=NmiTester.cat 11 | DriverVer= ; TODO: set DriverVer in stampinf property pages 12 | 13 | [DestinationDirs] 14 | DefaultDestDir = 12 15 | NmiTester_Device_CoInstaller_CopyFiles = 11 16 | 17 | ; ================= Class section ===================== 18 | 19 | [ClassInstall32] 20 | Addreg=SampleClassReg 21 | 22 | [SampleClassReg] 23 | HKR,,,0,%ClassName% 24 | HKR,,Icon,,-5 25 | 26 | [SourceDisksNames] 27 | 1 = %DiskName%,,,"" 28 | 29 | [SourceDisksFiles] 30 | NmiTester.sys = 1,, 31 | WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames 32 | 33 | ;***************************************** 34 | ; Install Section 35 | ;***************************************** 36 | 37 | [Manufacturer] 38 | %ManufacturerName%=Standard,NT$ARCH$ 39 | 40 | [Standard.NT$ARCH$] 41 | %NmiTester.DeviceDesc%=NmiTester_Device, Root\NmiTester ; TODO: edit hw-id 42 | 43 | [NmiTester_Device.NT] 44 | CopyFiles=Drivers_Dir 45 | 46 | [Drivers_Dir] 47 | NmiTester.sys 48 | 49 | ;-------------- Service installation 50 | [NmiTester_Device.NT.Services] 51 | AddService = NmiTester,%SPSVCINST_ASSOCSERVICE%, NmiTester_Service_Inst 52 | 53 | ; -------------- NmiTester driver install sections 54 | [NmiTester_Service_Inst] 55 | DisplayName = %NmiTester.SVCDESC% 56 | ServiceType = 1 ; SERVICE_KERNEL_DRIVER 57 | StartType = 3 ; SERVICE_DEMAND_START 58 | ErrorControl = 1 ; SERVICE_ERROR_NORMAL 59 | ServiceBinary = %12%\NmiTester.sys 60 | 61 | ; 62 | ;--- NmiTester_Device Coinstaller installation ------ 63 | ; 64 | 65 | [NmiTester_Device.NT.CoInstallers] 66 | AddReg=NmiTester_Device_CoInstaller_AddReg 67 | CopyFiles=NmiTester_Device_CoInstaller_CopyFiles 68 | 69 | [NmiTester_Device_CoInstaller_AddReg] 70 | HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller" 71 | 72 | [NmiTester_Device_CoInstaller_CopyFiles] 73 | WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll 74 | 75 | [NmiTester_Device.NT.Wdf] 76 | KmdfService = NmiTester, NmiTester_wdfsect 77 | [NmiTester_wdfsect] 78 | KmdfLibraryVersion = $KMDFVERSION$ 79 | 80 | [Strings] 81 | SPSVCINST_ASSOCSERVICE= 0x00000002 82 | ManufacturerName="" ;TODO: Replace with your manufacturer name 83 | ClassName="Samples" ; TODO: edit ClassName 84 | DiskName = "NmiTester Installation Disk" 85 | NmiTester.DeviceDesc = "NmiTester Device" 86 | NmiTester.SVCDESC = "NmiTester Service" 87 | -------------------------------------------------------------------------------- /Tests/NmiTester/NmiTester/NmiTester.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | Debug 22 | ARM 23 | 24 | 25 | Release 26 | ARM 27 | 28 | 29 | Debug 30 | ARM64 31 | 32 | 33 | Release 34 | ARM64 35 | 36 | 37 | 38 | {34ADB149-86F6-4016-A90A-BD5FCD984101} 39 | {1bc93793-694f-48fe-9372-81e2b05556fd} 40 | v4.5 41 | 12.0 42 | Debug 43 | Win32 44 | NmiTester 45 | 46 | 47 | 48 | Windows10 49 | true 50 | WindowsKernelModeDriver10.0 51 | Driver 52 | KMDF 53 | Universal 54 | 55 | 56 | Windows10 57 | false 58 | WindowsKernelModeDriver10.0 59 | Driver 60 | KMDF 61 | Universal 62 | 63 | 64 | Windows10 65 | true 66 | WindowsKernelModeDriver10.0 67 | Driver 68 | KMDF 69 | Universal 70 | 71 | 72 | Windows10 73 | false 74 | WindowsKernelModeDriver10.0 75 | Driver 76 | KMDF 77 | Universal 78 | 79 | 80 | Windows10 81 | true 82 | WindowsKernelModeDriver10.0 83 | Driver 84 | KMDF 85 | Universal 86 | 87 | 88 | Windows10 89 | false 90 | WindowsKernelModeDriver10.0 91 | Driver 92 | KMDF 93 | Universal 94 | 95 | 96 | Windows10 97 | true 98 | WindowsKernelModeDriver10.0 99 | Driver 100 | KMDF 101 | Universal 102 | 103 | 104 | Windows10 105 | false 106 | WindowsKernelModeDriver10.0 107 | Driver 108 | KMDF 109 | Universal 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | DbgengKernelDebugger 121 | 122 | 123 | DbgengKernelDebugger 124 | 125 | 126 | DbgengKernelDebugger 127 | 128 | 129 | DbgengKernelDebugger 130 | 131 | 132 | DbgengKernelDebugger 133 | 134 | 135 | DbgengKernelDebugger 136 | 137 | 138 | DbgengKernelDebugger 139 | 140 | 141 | DbgengKernelDebugger 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | -------------------------------------------------------------------------------- /Tests/NmiTester/NmiTester/NmiTester.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {8E41214B-6785-4CFE-B992-037D68949A14} 18 | inf;inv;inx;mof;mc; 19 | 20 | 21 | 22 | 23 | Driver Files 24 | 25 | 26 | 27 | 28 | Source Files 29 | 30 | 31 | --------------------------------------------------------------------------------