Files
Andrea Allievi 0ab296f21c HyperV support v0.1
Implemented support for HyperV Root Partitions (finally)
2018-04-15 15:01:22 -07:00

97 lines
4.0 KiB
C++

/**********************************************************************
* Windows Intel Processor Trace (PT) Driver 0.5
* Filename: IntelPtXSave.cpp
* Implements the support routines for the PT XSAVE feature
* Last revision: 01/25/2017
*
* Copyright© 2017 Andrea Allievi, Richard Johnson
* TALOS Research and Intelligence Group and Microsoft Ltd
* All right reserved
**********************************************************************/
#include "stdafx.h"
#include "IntelPtXSave.h"
#include "DriverEntry.h"
#include <intrin.h>
// Check if the current processor support the XSAVE feature for Intel PT
NTSTATUS CheckPtXSaveSupport(DWORD * pdwSAreaSize, DWORD * pdwUAreaSize, DWORD * pdwPtSize) {
int cpuInfo[4] = { 0 };
// Check the presence of XSAVE Feature (chapter 13.2 of Intel Basic Architecure manual)
__cpuidex(cpuInfo, 1, 0);
if ((cpuInfo[2] & CPUID_XSAVE_MASK) != CPUID_XSAVE_MASK) return STATUS_NOT_SUPPORTED;
// Now use the Processor Extended State Enumeration Main Leaf
__cpuidex(cpuInfo, 0xD, 0);
// Check the x87 and SSE state
if ((cpuInfo[0] & (1 << 0)) == 0) return STATUS_NOT_SUPPORTED;
if ((cpuInfo[0] & (1 << 1)) == 0) return STATUS_NOT_SUPPORTED;
if (pdwUAreaSize) (*pdwUAreaSize) = cpuInfo[2];
// Now check the support of XSAVES/XRSTORS and IA32_XSS MSR
__cpuidex(cpuInfo, 0xD, 1);
if ((cpuInfo[0] & (1 << 3)) == 0) return STATUS_NOT_SUPPORTED;
// Check the opfficial PT support
if ((cpuInfo[2] & PT_XSAVE_MASK) == 0) return STATUS_NOT_SUPPORTED;
if (pdwSAreaSize) (*pdwSAreaSize) = cpuInfo[1];
// Try to get the size and position of the PT data in the EXTENDED REGION of the XSAVE area
__cpuidex(cpuInfo, 0xD, 8);
if (pdwPtSize) (*pdwPtSize) = cpuInfo[0];
ASSERT((cpuInfo[2] & (1 << 0)) == 1); // ECX Bit 00 is set if the bit n(corresponding to the sub - leaf index) is supported in the IA32_XSS MSR; it is clear if bit n is instead supported in XCR0.
// ps. Take a look at KeSaveExtendedProcessorState - RtlXSave and RtlGetEnabledExtendedFeatures
return STATUS_SUCCESS;
}
// Get the current XSAVE Area size for the enabled features in XCR0 and IA32_XSS MSR of current CPU
DWORD GetCurXSaveAreaSize() {
int cpuInfo[4] = { 0 };
// Processor Extended State Enumeration Sub - leaf(EAX = 0DH, ECX = 1)
__cpuidex(cpuInfo, 0xD, 1);
// EBX Bits 31 - 00: The size in bytes of the XSAVE area containing all states enabled by XCRO | IA32_XSS.
return (DWORD)cpuInfo[1];
}
// Save all the PT data to an XSAVE area
NTSTATUS SavePtData(PXSAVE_AREA_EX lpXSaveArea, DWORD dwSize) {
MSR_IA32_XSS_DESC xssDesc = { 0 }; // The IA32_XSS MSR descriptor
XCR0_DESC xcr0Desc = { 0 }; // The XCR0 extended register descriptor
XCR0_DESC xcr0OrgDesc = { 0 }; // The XCR0 original extended register descriptor
NTSTATUS ntStatus = STATUS_SUCCESS; // Returned NTSTATUS
ULONG_PTR cr4 = { 0 }; // Value of CR4 register (we must enable the XSAVE feature)
DWORD dwPtAreaSize = 0; // XSAVE area with Intel PT enable
if (!lpXSaveArea || !dwSize) return STATUS_INVALID_PARAMETER;
ntStatus = CheckPtXSaveSupport(NULL, NULL, &dwPtAreaSize);
if (!NT_SUCCESS(ntStatus)) return ntStatus;
// Step 1. Enable XSAVE in CR4 register
cr4 = __readcr4();
cr4 = (cr4 | OSXSAVE_CR4_MASK);
__writecr4(cr4);
// Check the XSAVE area (must be 64-BYTE aligned)
if (((ULONG_PTR)lpXSaveArea & 0x0FF) != 0)
return STATUS_INVALID_ADDRESS;
RtlZeroMemory(lpXSaveArea, dwSize);
// Set the proper bit in the MSR_IA32_XSS and in XCR0
xcr0OrgDesc.value = _xgetbv(0); // Read the original XCR0 descriptor, because otherwise we could have problem with the Windows Context Dispatcher
xcr0Desc.Bits.FpuMmx = 1;
xssDesc.Bits.IntelPt = 1;
__writemsr(MSR_IA32_XSS, xssDesc.value);
_xsetbv(0, xcr0Desc.value);
// Check the size of the XSAVE area
dwPtAreaSize = GetCurXSaveAreaSize();
if (dwSize < dwPtAreaSize) return STATUS_INVALID_BUFFER_SIZE;
// Now perform the XSAVES
DBG_BREAK();
_xsaves((LPVOID)lpXSaveArea, xssDesc.value);
// Restore old XCR0 register
_xsetbv(0, xcr0OrgDesc.value);
return STATUS_SUCCESS;
}