diff options
author | Alex Ionescu <aionescu@gmail.com> | 2017-03-25 17:46:17 +0300 |
---|---|---|
committer | Alex Ionescu <aionescu@gmail.com> | 2017-03-25 17:46:17 +0300 |
commit | 64f9ae2254c10bdc984e52a34c74af7b65d662b0 (patch) | |
tree | db65e4a6b6d90281207e7085a38f4fc1eed7118c | |
parent | 9891d1048fc6e08b3d2b5929c6def43f7112698f (diff) |
Use 2MB pages. It's only a few more lines of code and avoids the perf costs of 1GB UC regions.
Also has the benefit of allowing this to run on VMWare systems now.
-rw-r--r-- | shv_x.h | 8 | ||||
-rw-r--r-- | shvvmx.c | 54 | ||||
-rw-r--r-- | vmx.h | 32 |
3 files changed, 72 insertions, 22 deletions
@@ -30,7 +30,8 @@ Environment: #define SHV_STATUS_NO_RESOURCES -2 #define SHV_STATUS_NOT_PRESENT -3 -#define _1GB (1 * 1024 * 1024 * 1024) +#define _1GB (1 * 1024 * 1024 * 1024) +#define _2MB (2 * 1024 * 1024) struct _SHV_CALLBACK_CONTEXT; @@ -85,13 +86,14 @@ typedef struct _SHV_VP_DATA DECLSPEC_ALIGN(PAGE_SIZE) UINT8 MsrBitmap[PAGE_SIZE]; DECLSPEC_ALIGN(PAGE_SIZE) VMX_EPML4E Epml4[PML4E_ENTRY_COUNT]; - DECLSPEC_ALIGN(PAGE_SIZE) VMX_HUGE_PDPTE Epdpt[PDPTE_ENTRY_COUNT]; + DECLSPEC_ALIGN(PAGE_SIZE) VMX_PDPTE Epdpt[PDPTE_ENTRY_COUNT]; + DECLSPEC_ALIGN(PAGE_SIZE) VMX_LARGE_PDE Epde[PDPTE_ENTRY_COUNT][PDE_ENTRY_COUNT]; DECLSPEC_ALIGN(PAGE_SIZE) VMX_VMCS VmxOn; DECLSPEC_ALIGN(PAGE_SIZE) VMX_VMCS Vmcs; } SHV_VP_DATA, *PSHV_VP_DATA; -C_ASSERT(sizeof(SHV_VP_DATA) == (KERNEL_STACK_SIZE + 5 * PAGE_SIZE)); +C_ASSERT(sizeof(SHV_VP_DATA) == (KERNEL_STACK_SIZE + (512 + 5) * PAGE_SIZE)); VOID _sldt ( @@ -76,7 +76,7 @@ ShvVmxMtrrInitialize ( UINT32 ShvVmxMtrrAdjustEffectiveMemoryType ( _In_ PSHV_VP_DATA VpData, - _In_ UINT64 SuperPageAddress, + _In_ UINT64 LargePageAddress, _In_ UINT32 CandidateMemoryType ) { @@ -93,11 +93,11 @@ ShvVmxMtrrAdjustEffectiveMemoryType ( if (VpData->MtrrData[i].Enabled != FALSE) { // - // Check if this super page falls within the boundary. If a single - // physical page (4KB) touches it, we need to override the entire gig. + // Check if this large page falls within the boundary. If a single + // physical page (4KB) touches it, we need to override the entire 2MB. // - if (((SuperPageAddress + _1GB) >= VpData->MtrrData[i].PhysicalAddressMin) && - (SuperPageAddress <= VpData->MtrrData[i].PhysicalAddressMax)) + if (((LargePageAddress + _2MB) >= VpData->MtrrData[i].PhysicalAddressMin) && + (LargePageAddress <= VpData->MtrrData[i].PhysicalAddressMax)) { // // Override candidate type with MTRR type @@ -118,8 +118,9 @@ ShvVmxEptInitialize ( _In_ PSHV_VP_DATA VpData ) { - UINT32 i; - VMX_HUGE_PDPTE tempEpdpte; + UINT32 i, j; + VMX_PDPTE tempEpdpte; + VMX_LARGE_PDE tempEpde; // // Fill out the EPML4E which covers the first 512GB of RAM @@ -130,12 +131,11 @@ ShvVmxEptInitialize ( VpData->Epml4[0].PageFrameNumber = ShvOsGetPhysicalAddress(&VpData->Epdpt) / PAGE_SIZE; // - // Fill out a RWX Write-back 1GB EPDPTE + // Fill out a RWX PDPTE // tempEpdpte.AsUlonglong = 0; tempEpdpte.Read = tempEpdpte.Write = tempEpdpte.Execute = 1; - tempEpdpte.Large = 1; - + // // Construct EPT identity map for every 1GB of RAM // @@ -143,12 +143,34 @@ ShvVmxEptInitialize ( for (i = 0; i < PDPTE_ENTRY_COUNT; i++) { // - // Set the page frame number (1GB-sized) and adjust the memory type + // Set the page frame number of the PDE table // - VpData->Epdpt[i].PageFrameNumber = i; - VpData->Epdpt[i].Type = ShvVmxMtrrAdjustEffectiveMemoryType(VpData, - i * _1GB, - MTRR_TYPE_WB); + VpData->Epdpt[i].PageFrameNumber = ShvOsGetPhysicalAddress(&VpData->Epde[i][0]) / PAGE_SIZE; + } + + // + // Fill out a RWX Large PDE + // + tempEpde.AsUlonglong = 0; + tempEpde.Read = tempEpde.Write = tempEpde.Execute = 1; + tempEpde.Large = 1; + + // + // Loop every 1GB of RAM (described by the PDPTE) + // + __stosq((UINT64*)VpData->Epde, tempEpde.AsUlonglong, PDPTE_ENTRY_COUNT * PDE_ENTRY_COUNT); + for (i = 0; i < PDPTE_ENTRY_COUNT; i++) + { + // + // Construct EPT identity map for every 2MB of RAM + // + for (j = 0; j < PDE_ENTRY_COUNT; j++) + { + VpData->Epde[i][j].PageFrameNumber = (i * 512) + j; + VpData->Epde[i][j].Type = ShvVmxMtrrAdjustEffectiveMemoryType(VpData, + VpData->Epde[i][j].PageFrameNumber * _2MB, + MTRR_TYPE_WB); + } } } @@ -188,7 +210,7 @@ ShvVmxEnterRootModeOnVp ( // if (((VpData->MsrData[12].QuadPart & VMX_EPT_PAGE_WALK_4_BIT) != 0) && ((VpData->MsrData[12].QuadPart & VMX_EPTP_WB_BIT) != 0) && - ((VpData->MsrData[12].QuadPart & VMX_EPT_1GB_PAGE_BIT) != 0)) + ((VpData->MsrData[12].QuadPart & VMX_EPT_2MB_PAGE_BIT) != 0)) { // // Enable EPT if these features are supported @@ -615,11 +615,37 @@ typedef struct _VMX_PDPTE }; } VMX_PDPTE, *PVMX_PDPTE; +typedef struct _VMX_LARGE_PDE +{ + union + { + struct + { + UINT64 Read : 1; + UINT64 Write : 1; + UINT64 Execute : 1; + UINT64 Type : 3; + UINT64 IgnorePat : 1; + UINT64 Large : 1; + UINT64 Accessed : 1; + UINT64 Dirty : 1; + UINT64 UserModeExecute : 1; + UINT64 SoftwareUse : 1; + UINT64 Reserved : 9; + UINT64 PageFrameNumber : 27; + UINT64 ReservedHigh : 4; + UINT64 SoftwareUseHigh : 11; + UINT64 SupressVme : 1; + }; + UINT64 AsUlonglong; + }; +} VMX_LARGE_PDE, *PVMX_LARGE_PDE; + static_assert(sizeof(VMX_EPTP) == sizeof(UINT64), "EPTP Size Mismatch"); static_assert(sizeof(VMX_EPML4E) == sizeof(UINT64), "EPML4E Size Mismatch"); static_assert(sizeof(VMX_PDPTE) == sizeof(UINT64), "EPDPTE Size Mismatch"); -#define PML4E_ENTRY_COUNT 512 -#define PDPTE_ENTRY_COUNT 512 - +#define PML4E_ENTRY_COUNT 512 +#define PDPTE_ENTRY_COUNT 512 +#define PDE_ENTRY_COUNT 512 |