DRNG::DRNG(void) { int info[4]; if (_drng_support != DRNG_SUPPORT_UNKNOWN) return; _drng_support= DRNG_SUPPORT_NONE; // Check our feature support __cpuid(info, 0); if ( memcmp(&(info[1]), "Genu", 4) || memcmp(&(info[3]), "ineI", 4) || memcmp(&(info[2]), "ntel", 4) ) return; __cpuidex(info, 1, 0); if ( ((UINT) info[2]) & (1<<30) ) _drng_support|= DRNG_SUPPORT_RDRAND; #ifdef COMPILER_HAS_RDSEED_SUPPORT __cpuidex(info, 7, 0); if ( ((UINT) info[1]) & (1<<18) ) _drng_support|= DRNG_SUPPORT_RDSEED; #endif }
/// @todo docs void init_cpuinfo(cpuinfo::impl& info) { int registers[4]; /// According to the msvc docs eax, ebx, ecx and edx are /// stored (in that order) in the array passed to the __cpuid /// function. // The register information per input can be extracted from here: // http://en.wikipedia.org/wiki/CPUID // CPUID should be called with EAX=0 first, as this will return the // maximum supported EAX input value for future calls __cpuid(registers, 0); uint32_t maximum_eax = registers[0]; // Set registers for basic flag extraction, eax=1 // All CPUs should support index=1 if (maximum_eax >= 1U) { __cpuid(registers, 1); extract_x86_flags(info, registers[2], registers[3]); } // Set registers for extended flags extraction, eax=7 and ecx=0 // This operation is not supported on older CPUs, so it should be skipped // to avoid incorrect results if (maximum_eax >= 7U) { __cpuidex(registers, 7, 0); extract_x86_extended_flags(info, registers[1]); } }
static unsigned init_caps(void) { unsigned int caps = 0; union { struct { unsigned int eax, ebx, ecx, edx; }; int data[4]; } regs = {0}; __cpuid(regs.data, 0); unsigned int max = regs.eax; if (max >= 1) { __cpuid(regs.data, 0); if (regs.edx & (1 << 26)) { caps |= CPU_CAP_SSE2; } if (regs.ecx & (1 << 19)) { caps |= CPU_CAP_SSE4_1; } } if (max >= 7) { __cpuidex(regs.data, 7, 0); if (regs.ebx & (1 << 5)) { caps |= CPU_CAP_AVX2; } } return caps; }
_Use_decl_annotations_ bool EptIsEptAvailable() { PAGED_CODE(); int regs[4] = {}; __cpuidex(regs, 0x80000008, 0); Cpuid80000008Eax cpuidEax = {static_cast<ULONG32>(regs[0])}; HYPERPLATFORM_LOG_DEBUG("Physical Address Range = %d bits", cpuidEax.fields.physical_address_bits); // No processors supporting the Intel 64 architecture support more than 48 // physical-address bits if (cpuidEax.fields.physical_address_bits > 48) { return false; } // page walk length is 4 steps // extended page tables can be laid out in write-back memory // INVEPT instruction with all possible types is supported Ia32VmxEptVpidCapMsr vpid = {UtilReadMsr64(Msr::kIa32VmxEptVpidCap)}; if (!vpid.fields.support_page_walk_length4 || !vpid.fields.support_write_back_memory_type || !vpid.fields.support_invept || !vpid.fields.support_single_context_invept || !vpid.fields.support_all_context_invept) { return false; } return true; }
VOID ShvVpUninitialize ( _In_ PSHV_VP_DATA VpData ) { INT dummy[4]; UNREFERENCED_PARAMETER(VpData); // // Send the magic shutdown instruction sequence // __cpuidex(dummy, 0x41414141, 0x42424242); // // The processor will return here after the hypervisor issues a VMXOFF // instruction and restores the CPU context to this location. Unfortunately // because this is done with RtlRestoreContext which returns using "iretq", // this causes the processor to remove the RPL bits off the segments. As // the x64 kernel does not expect kernel-mode code to chang ethe value of // any segments, this results in the DS and ES segments being stuck 0x20, // and the FS segment being stuck at 0x50, until the next context switch. // // If the DPC happened to have interrupted either the idle thread or system // thread, that's perfectly fine (albeit unusual). If the DPC interrupted a // 64-bit long-mode thread, that's also fine. However if the DPC interrupts // a thread in compatibility-mode, running as part of WoW64, it will hit a // GPF instantenously and crash. // // Thus, set the segments to their correct value, one more time, as a fix. // ShvVmxCleanup(KGDT64_R3_DATA | RPL_MASK, KGDT64_R3_CMTEB | RPL_MASK); }
// __asm__ blocks are only checked for inline functions that end up being // emitted, so call functions with __asm__ blocks to make sure their inline // assembly parses. void f() { __movsb(0, 0, 0); __movsd(0, 0, 0); __movsw(0, 0, 0); __stosd(0, 0, 0); __stosw(0, 0, 0); #ifdef _M_X64 __movsq(0, 0, 0); __stosq(0, 0, 0); #endif int info[4]; __cpuid(info, 0); __cpuidex(info, 0, 0); _xgetbv(0); __halt(); __nop(); __readmsr(0); // FIXME: Call these in 64-bit too once the intrinsics have been fixed to // work there, PR19301 #ifndef _M_X64 __readcr3(); __writecr3(0); #endif #ifdef _M_ARM __dmb(_ARM_BARRIER_ISHST); #endif }
static inline void get_cpuid2(int *array, int info_type, int ecx) { #if defined(_MSC_VER) __cpuidex(array, info_type, ecx); #else __cpuid_count(info_type, ecx, array[0], array[1], array[2], array[3]); #endif }
inline void cpuidex(register_type pRegisters[4], int function, int subfunction) { #if defined(BOOST_SIMD_CPUID_HEADER) __cpuid_count ( function, subfunction , pRegisters[eax], pRegisters[ebx], pRegisters[ecx], pRegisters[edx] ); #else __cpuidex(pRegisters, function, subfunction); #endif }
/* I hate this. */ BOOL cpuid(uint32_t *_eax, uint32_t *_ebx, uint32_t *_ecx, uint32_t *_edx) { uint32_t regs[4]; __cpuidex(regs, *_eax, *_ecx); *_eax = regs[0]; *_ebx = regs[1]; *_ecx = regs[2]; *_edx = regs[3]; return TRUE; }
String GetProcessorInfo() { char brand[0x40] = {}; int cpui[4] = { -1 }; __cpuidex(cpui, 0x80000002, 0); //unsigned int blocks = cpui[0]; for (int i = 0; i <= 2; ++i) { __cpuidex(cpui, 0x80000002 + i, 0); *reinterpret_cast<int*>(brand + i * 16) = cpui[0]; *reinterpret_cast<int*>(brand + 4 + i * 16) = cpui[1]; *reinterpret_cast<int*>(brand + 8 + i * 16) = cpui[2]; *reinterpret_cast<int*>(brand + 12 + i * 16) = cpui[3]; } return String(brand, 0x40); }
static bool internal_cpuid(int32_t out[4], int32_t x) { #if defined __GNUC__ __cpuid_count(x, 0, out[0], out[1], out[2], out[3]); return true; #endif #if defined _MSC_VER __cpuidex(out, x, 0); return true; #endif return false; }
void init_functions () { int out [4]; __cpuid (out, 1); BOOL sse42 = (out [2] & (1 << 20)) != 0; BOOL sse41 = (out [2] & (1 << 19)) != 0; BOOL fma = (out [2] & (1 << 12)) != 0; BOOL avx = (out [2] & (1 << 28)) != 0; BOOL osxsave = (out [2] & (1 << 29)) != 0; __cpuidex (out, 7, 0); BOOL avx2 = (out [1] & 0x20) != 0; int i = 0; funcs [i] = calculate_float; method_names [i] = "float"; if (full_mode) i++; if (sse42) { funcs [i] = calculate_sse_float; method_names [i] = "float SSE"; if (full_mode) i++; } if (osxsave && avx) { funcs [i] = calculate_avx_float; method_names [i] = "float AVX"; if (full_mode) i++; } if (osxsave && avx && avx2) { funcs [i] = calculate_avx2_float; method_names [i] = "float AVX2"; if (full_mode) i++; } if (osxsave && avx && avx2 && fma) { funcs [i] = calculate_fma_float; method_names [i] = "float FMA"; if (full_mode) i++; } if (!full_mode) i++; funcs [i] = calculate_double; method_names [i] = "double"; if (full_mode) i++; if (sse42) { funcs [i] = calculate_sse_double; method_names [i] = "double SSE"; if (full_mode) i++; } if (osxsave && avx) { funcs [i] = calculate_avx_double; method_names [i] = "double AVX"; if (full_mode) i++; } if (osxsave && avx && avx2) { funcs [i] = calculate_avx2_double; method_names [i] = "double AVX2"; if (full_mode) i++; } if (osxsave && avx && avx2 && fma) { funcs [i] = calculate_fma_double; method_names [i] = "double FMA"; if (full_mode) i++; } if (!full_mode) i++; func_count = i; func_index = 0; calculate_func = funcs [func_index]; }
CPUInfo __stdcall cpuidex(int InfoType, int ECXValue) { int results[4]; __cpuidex(results, InfoType, ECXValue); CPUInfo i; i.Part1 = results[0]; i.Part2 = results[1]; i.Part3 = results[2]; i.Part4 = results[3]; return i; }
void fe_hw_x86_cpuidex(uint32_t leaf, uint32_t subleaf, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) { #if (defined(__GNUC__) || defined(__clang__)) __cpuid_count(leaf, subleaf, eax, ebx, ecx, edx); #elif defined(_MSC_VER) int regs[4]; __cpuidex(regs, leaf, subleaf); *eax = regs[0]; *ebx = regs[1]; *ecx = regs[2]; *edx = regs[3]; #else #error "No cpuid intrinsic for this target !" #endif }
VOID ShvVmxHandleCpuid ( _In_ PSHV_VP_STATE VpState ) { INT cpu_info[4]; // // Check for the magic CPUID sequence, and check that it is is coming from // Ring 0. Technically we could also check the RIP and see if this falls // in the expected function, but we may want to allow a sepaarate "unload" // driver or code at some point. // if ((VpState->VpRegs->Rax == 0x41414141) && (VpState->VpRegs->Rcx == 0x42424242) && ((ShvVmxRead(GUEST_CS_SELECTOR) & RPL_MASK) == DPL_SYSTEM)) { VpState->ExitVm = TRUE; return; } // // Otherwise, issue the CPUID to the logical processor based on the indexes // on the VP's GPRs. // __cpuidex(cpu_info, (INT)VpState->VpRegs->Rax, (INT)VpState->VpRegs->Rcx); // // Check if this was CPUID 1h, which is the features request. // if (VpState->VpRegs->Rax == 1) { // // Set the Hypervisor Present-bit in RCX, which Intel and AMD have both // reserved for this indication. // cpu_info[2] |= 0x80000000; } // // Copy the values from the logical processor registers into the VP GPRs. // VpState->VpRegs->Rax = cpu_info[0]; VpState->VpRegs->Rbx = cpu_info[1]; VpState->VpRegs->Rcx = cpu_info[2]; VpState->VpRegs->Rdx = cpu_info[3]; }
CCpuAccel() { int info[4]; __cpuid(info, 0x00000000); int Basic = info[0]; __cpuid(info, 0x00000001); if (info[3] & 0x00800000) m_Supported |= ACCEL_MMX; if (info[3] & 0x02000000) m_Supported |= ACCEL_SSE; if (info[3] & 0x04000000) m_Supported |= ACCEL_SSE2; if (info[2] & 0x00000001) m_Supported |= ACCEL_SSE3; if (info[2] & 0x00000200) m_Supported |= ACCEL_SSSE3; if (info[2] & 0x00080000) m_Supported |= ACCEL_SSE4_1; if (info[2] & 0x00100000) m_Supported |= ACCEL_SSE4_2; if (info[2] & 0x10000000) m_Supported |= ACCEL_AVX; if (Basic >= 7) { __cpuidex(info, 7, 0); if (info[1] & 0x00000020) m_Supported |= ACCEL_AVX2; } bool fAVX = false; if (::IsProcessorFeaturePresent(PF_XSAVE_ENABLED)) { GetEnabledXStateFeatures_Ptr pGetEnabledXStateFeatures = (GetEnabledXStateFeatures_Ptr) ::GetProcAddress(::GetModuleHandle(TEXT("kernel32.dll")), "GetEnabledXStateFeatures"); if (pGetEnabledXStateFeatures && (pGetEnabledXStateFeatures() & XSTATE_MASK_AVX)) { fAVX = true; } } if (!fAVX) m_Supported &= ~(ACCEL_AVX | ACCEL_AVX2); m_Enabled = m_Supported; }
void X86CpuUtil::callCpuId(uint32_t inEax, uint32_t inEcx, X86CpuId* outResult) { #ifdef _MSC_VER // 2009-02-05: Thanks to Mike Tajmajer for supporting VC7.1 compiler. // ASMJIT_HOST_X64 is here only for readibility, only VS2005 can compile 64-bit code. # if _MSC_VER >= 1400 || defined(ASMJIT_HOST_X64) // Done by intrinsics. __cpuidex(reinterpret_cast<int*>(outResult->i), inEax, inEcx); # else // _MSC_VER < 1400 uint32_t cpuid_eax = inEax; uint32_t cpuid_ecx = inCax; uint32_t* cpuid_out = outResult->i; __asm { mov eax, cpuid_eax mov ecx, cpuid_ecx mov edi, cpuid_out cpuid mov dword ptr[edi + 0], eax mov dword ptr[edi + 4], ebx mov dword ptr[edi + 8], ecx mov dword ptr[edi + 12], edx } # endif // _MSC_VER < 1400 #elif defined(__GNUC__) // Note, patched to preserve ebx/rbx register which is used by GCC. # if defined(ASMJIT_HOST_X86) # define __myCpuId(inEax, inEcx, outEax, outEbx, outEcx, outEdx) \ asm ("mov %%ebx, %%edi\n" \ "cpuid\n" \ "xchg %%edi, %%ebx\n" \ : "=a" (outEax), "=D" (outEbx), "=c" (outEcx), "=d" (outEdx) : "a" (inEax), "c" (inEcx)) # else # define __myCpuId(inEax, inEcx, outEax, outEbx, outEcx, outEdx) \ asm ("mov %%rbx, %%rdi\n" \ "cpuid\n" \ "xchg %%rdi, %%rbx\n" \ : "=a" (outEax), "=D" (outEbx), "=c" (outEcx), "=d" (outEdx) : "a" (inEax), "c" (inEcx)) # endif __myCpuId(inEax, inEcx, outResult->eax, outResult->ebx, outResult->ecx, outResult->edx); #endif // COMPILER }
// CPUID _Use_decl_annotations_ static void VmmpHandleCpuid( GuestContext *guest_context) { HYPERPLATFORM_PERFORMANCE_MEASURE_THIS_SCOPE(); unsigned int cpu_info[4] = {}; const auto function_id = static_cast<int>(guest_context->gp_regs->ax); const auto sub_function_id = static_cast<int>(guest_context->gp_regs->cx); if (function_id == 0 && sub_function_id == kHyperPlatformVmmBackdoorCode) { // Say "Pong by VMM!" when the back-door code was given guest_context->gp_regs->bx = 'gnoP'; guest_context->gp_regs->dx = ' yb '; guest_context->gp_regs->cx = '!MMV'; } else { __cpuidex(reinterpret_cast<int *>(cpu_info), function_id, sub_function_id); guest_context->gp_regs->ax = cpu_info[0]; guest_context->gp_regs->bx = cpu_info[1]; guest_context->gp_regs->cx = cpu_info[2]; guest_context->gp_regs->dx = cpu_info[3]; } VmmpAdjustGuestInstructionPointer(guest_context->ip); }
InstructionSet_Internal() : nIds_{ 0 }, nExIds_{ 0 }, isIntel_{ false }, isAMD_{ false }, f_1_ECX_{ 0 }, f_1_EDX_{ 0 }, f_7_EBX_{ 0 }, f_7_ECX_{ 0 }, f_81_ECX_{ 0 }, f_81_EDX_{ 0 }, data_{}, extdata_{} { //int cpuInfo[4] = {-1}; std::array<int, 4> cpui; // Calling __cpuid with 0x0 as the function_id argument // gets the number of the highest valid function ID. __cpuid(cpui.data(), 0); nIds_ = cpui[0]; for (int i = 0; i <= nIds_; ++i) { __cpuidex(cpui.data(), i, 0); data_.push_back(cpui); } // Capture vendor string char vendor[0x20]; memset(vendor, 0, sizeof(vendor)); *reinterpret_cast<int*>(vendor) = data_[0][1]; *reinterpret_cast<int*>(vendor + 4) = data_[0][3]; *reinterpret_cast<int*>(vendor + 8) = data_[0][2]; vendor_ = vendor; if (vendor_ == "GenuineIntel") { isIntel_ = true; } else if (vendor_ == "AuthenticAMD") { isAMD_ = true; } // load bitset with flags for function 0x00000001 if (nIds_ >= 1) { f_1_ECX_ = data_[1][2]; f_1_EDX_ = data_[1][3]; } // load bitset with flags for function 0x00000007 if (nIds_ >= 7) { f_7_EBX_ = data_[7][1]; f_7_ECX_ = data_[7][2]; } // Calling __cpuid with 0x80000000 as the function_id argument // gets the number of the highest valid extended ID. __cpuid(cpui.data(), 0x80000000); nExIds_ = cpui[0]; char brand[0x40]; memset(brand, 0, sizeof(brand)); for (int i = 0x80000000; i <= nExIds_; ++i) { __cpuidex(cpui.data(), i, 0); extdata_.push_back(cpui); } // load bitset with flags for function 0x80000001 if (nExIds_ >= 0x80000001) { f_81_ECX_ = extdata_[1][2]; f_81_EDX_ = extdata_[1][3]; } // Interpret CPU brand string if reported if (nExIds_ >= 0x80000004) { memcpy(brand, extdata_[2].data(), sizeof(cpui)); memcpy(brand + 16, extdata_[3].data(), sizeof(cpui)); memcpy(brand + 32, extdata_[4].data(), sizeof(cpui)); brand_ = brand; } };
int CALLBACK WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { s_gameFuncs = LoadGameFuncs(); assert(s_gameFuncs.valid); ImGuiIO& io = ImGui::GetIO(); //io.MemAllocFn = memory::malloc; //io.MemFreeFn = memory::free; //_crtBreakAlloc = 4015; s_queue = new util::ThreadSafeQueue<WindowEvent>(); g_LogInfo(SL_BUILD_DATE); // Log CPU features { #if 0 struct CPUInfo { union { int i[4]; }; } info = { 0 }; // Get number of functions __cpuid(info.i, 0); int nIds_ = info.i[0]; // Dump info std::vector<CPUInfo> data; for (int i = 0; i <= nIds_; ++i) { __cpuidex(info.i, i, 0); data.push_back(info); } // Vendor if(data.size() >= 0) { char vendor[13] = {0}; memcpy(vendor + 0, data[0].i + 1, 4); memcpy(vendor + 4, data[0].i + 3, 4); memcpy(vendor + 8, data[0].i + 2, 4); g_LogInfo("CPU Vendor: " + std::string(vendor)); } #endif // http://stackoverflow.com/questions/850774/how-to-determine-the-hardware-cpu-and-ram-on-a-machine int CPUInfo[4] = { 0 }; char CPUBrandString[0x40]; // Get the information associated with each extended ID. __cpuid(CPUInfo, 0x80000000); int nExIds = CPUInfo[0]; for (int i = 0x80000000; i <= nExIds; i++) { __cpuid(CPUInfo, i); // Interpret CPU brand string if (i == 0x80000002) memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo)); else if (i == 0x80000003) memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo)); else if (i == 0x80000004) memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo)); } //string includes manufacturer, model and clockspeed std::string brand(CPUBrandString); g_LogInfo(brand.substr(brand.find_first_not_of(" "))); SYSTEM_INFO sysInfo; GetSystemInfo(&sysInfo); g_LogInfo("Logical processors: " + std::to_string(sysInfo.dwNumberOfProcessors)); MEMORYSTATUSEX statex; statex.dwLength = sizeof (statex); GlobalMemoryStatusEx(&statex); g_LogInfo("Total System Memory: " + std::to_string(statex.ullTotalPhys/1024/1024) + " MB"); } auto className = L"StarlightClassName"; WNDCLASSEXW wndClass = { 0 }; wndClass.cbSize = sizeof(WNDCLASSEXW); wndClass.style = CS_CLASSDC; wndClass.lpfnWndProc = WndProc; wndClass.hInstance = GetModuleHandleW(nullptr); wndClass.hCursor = LoadCursorW(nullptr, IDC_ARROW); wndClass.lpszClassName = className; RegisterClassExW(&wndClass); // Get desktop rectangle RECT desktopRect; GetClientRect(GetDesktopWindow(), &desktopRect); // Get window rectangle RECT windowRect = { 0, 0, 800, 600 }; // TODO: Config file? AdjustWindowRect(&windowRect, WS_OVERLAPPEDWINDOW, FALSE); // Calculate window dimensions LONG windowWidth = windowRect.right - windowRect.left; LONG windowHeight = windowRect.bottom - windowRect.top; LONG x = desktopRect.right / 2 - windowWidth / 2; LONG y = desktopRect.bottom / 2 - windowHeight / 2; #ifdef _DEBUG // Move the screen to the right monitor on JOTARO wchar_t computerName[MAX_COMPUTERNAME_LENGTH + 1]; DWORD dwSize = sizeof(computerName); GetComputerNameW(computerName, &dwSize); if (wcscmp(computerName, L"JOTARO") == 0) { x += 1920; } #endif s_config.Load(); s_hwnd = CreateWindowExW( 0L, className, L"Starlight", WS_OVERLAPPEDWINDOW, x, y, windowWidth, windowHeight, nullptr, nullptr, GetModuleHandleW(nullptr), nullptr ); // Show the window ShowWindow(s_hwnd, SW_MAXIMIZE); UpdateWindow(s_hwnd); // Create thread s_running.store(true); unsigned int threadID; HANDLE thread = (HANDLE) _beginthreadex(nullptr, 0, MyThreadFunction, nullptr, 0, &threadID); if (!thread) { // Error creating thread return 1; } // Watch Lua directory hDirectoryChange = FindFirstChangeNotification(L"../starlight/", TRUE, FILE_NOTIFY_CHANGE_LAST_WRITE); if (!hDirectoryChange) { g_LogInfo("Error creating directory change notification handle: Lua reload on save will not work."); } // Message loop MSG msg; while (s_running.load() && GetMessageW(&msg, nullptr, 0, 0)) { TranslateMessage(&msg); DispatchMessageW(&msg); } WaitForSingleObject(thread, INFINITE); CloseHandle(thread); if (hDirectoryChange) { if (!FindCloseChangeNotification(hDirectoryChange)) { g_LogInfo("Failed to close directory change notification handle."); } } s_gameFuncs.DestroyLogger(); io.Fonts->Clear(); s_config.Save(); delete s_queue; UnregisterClassW(className, GetModuleHandleW(nullptr)); _CrtDumpMemoryLeaks(); return 0; }
void dbt_cpuid(int eax, int ecx, struct cpuid_t *cpuid) { int cpuinfo[4]; __cpuidex(cpuinfo, eax, ecx); cpuid->eax = cpuinfo[0]; cpuid->ebx = cpuinfo[1]; cpuid->ecx = cpuinfo[2]; cpuid->edx = cpuinfo[3]; /* Mangle cpu feature bits, omit unsupported features */ if (eax == 0x01) { /* Feature information */ cpuid->edx &= (0 | FEATURE_FPU | FEATURE_VME | FEATURE_DE | FEATURE_PSE | FEATURE_TSC | FEATURE_MSR | FEATURE_PAE | FEATURE_MCE | FEATURE_CX8 | FEATURE_APIC //| FEATURE_SEP | FEATURE_MTRR | FEATURE_PGE | FEATURE_MCA | FEATURE_CMOV | FEATURE_PAT | FEATURE_PSE_36 | FEATURE_PSN | FEATURE_CLFSH | FEATURE_DS | FEATURE_ACPI | FEATURE_MMX | FEATURE_FXSR | FEATURE_SSE | FEATURE_SSE2 | FEATURE_SS | FEATURE_HTT | FEATURE_TM | FEATURE_IA64 | FEATURE_PBE ); cpuid->ecx &= (0 | FEATURE_SSE3 //| FEATURE_PCLMULQDQ | FEATURE_DTES64 | FEATURE_MONITOR | FEATURE_DS_CPL | FEATURE_VMX | FEATURE_SMX | FEATURE_EST | FEATURE_TM2 | FEATURE_SSSE3 | FEATURE_CNXT_ID //| FEATURE_FMA //| FEATURE_CMPXCHG16B | FEATURE_XTPR | FEATURE_PDCM | FEATURE_PCID | FEATURE_DCA | FEATURE_SSE41 | FEATURE_SSE42 | FEATURE_X2APIC | FEATURE_MOVBE | FEATURE_POPCNT | FEATURE_TSC_DEADLINE //| FEATURE_AES //| FEATURE_XSAVE //| FEATURE_OSXSAVE //| FEATURE_AVX //| FEATURE_F16C //| FEATURE_RDRAND | FEATURE_HYPERVISOR ); } else if (eax == 0x80000001) { /* Extended function */ cpuid->edx &= (0 | FEATURE_SYSCALL | FEATURE_NX //| FEATURE_MMXEXT //| FEATURE_FXSR_OPT | FEATURE_GPAGE //| FEATURE_RDTSCP | FEATURE_64 //| FEATURE_3DNOWEXT //| FEATURE_3DNOW ); /* AMD extensions */ cpuid->ecx &= (0 | FEATURE_LAHF //| FEATURE_CMP_LEGACY //| FEATURE_SVM //| FEATURE_EXTAPIC //| FEATURE_CR8_LEGACY //| FEATURE_ABM //| FEATURE_SSE4A //| FEATURE_MISALIGNSSE //| FEATURE_3DNOWPREFETCH //| FEATURE_OSVW //| FEATURE_IBS //| FEATURE_XOP //| FEATURE_SKINIT //| FEATURE_WDT //| FEATURE_LWP //| FEATURE_FMA4 //| FEATURE_TCE //| FEATURE_NODEID_MSR //| FEATURE_TBM //| FEATURE_TOPOEXT //| FEATURE_PERFCTR_CORE //| FEATURE_PERFCTR_NB //| FEATURE_BPEXT //| FEATURE_PERFCTR_L2 ); } else if (eax == 0x07) { /* Structured extended feature flags */ if (ecx == 0x00) { cpuid->eax = 0; cpuid->ebx &= (0 //| FEATURE_FSGSBASE | FEATURE_TSC_ADJUST //| FEATURE_BMI1 //| FEATURE_HLE //| FEATURE_AVX2 | FEATURE_SMEP //| FEATURE_BMI2 | FEATURE_ERMS //| FEATURE_INVPCID //| FEATURE_RTM //| FEATURE_MPX //| FEATURE_AVX512F //| FEATURE_RDSEED //| FEATURE_ADX //| FEATURE_SMAP //| FEATURE_CLFLUSHOPT //| FEATURE_AVX512PF //| FEATURE_AVX512ER //| FEATURE_AVX512CD ); cpuid->ecx = 0; cpuid->edx = 0; } else cpuid->eax = cpuid->ebx = cpuid->ecx = cpuid->edx = 0; } }
static void cpuid(int32_t out[4], int32_t x) { __cpuidex(out,x,0); }
NTSTATUS DriverDeviceControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { NTSTATUS Status = STATUS_UNSUCCESSFUL; PIO_STACK_LOCATION IrpSp; ULONG IOControlCode = 0; ULONG dwBytesWritten = 0; PCHAR pInBuf = NULL, pOutBuf = NULL; unsigned int _cpu_thread_id = 0; unsigned int new_cpu_thread_id = 0; ULONG _num_active_cpus = 0; KAFFINITY _kaffinity = 0; UINT32 core_id = 0; // // Get the current IRP stack location of this request // IrpSp = IoGetCurrentIrpStackLocation (Irp); IOControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode; DbgPrint( "[chipsec] >>>>>>>>>> IOCTL >>>>>>>>>>\n" ); DbgPrint( "[chipsec] DeviceObject = 0x%x IOCTL = 0x%x\n", DeviceObject, IOControlCode ); DbgPrint( "[chipsec] InputBufferLength = 0x%x, OutputBufferLength = 0x%x\n", IrpSp->Parameters.DeviceIoControl.InputBufferLength, IrpSp->Parameters.DeviceIoControl.OutputBufferLength ); // // CPU thread ID // _num_active_cpus = KeQueryActiveProcessorCount( NULL ); _kaffinity = KeQueryActiveProcessors(); _cpu_thread_id = KeGetCurrentProcessorNumber(); DbgPrint( "[chipsec] Active CPU threads : %d (KeNumberProcessors = %d)\n", _num_active_cpus, KeNumberProcessors ); DbgPrint( "[chipsec] Active CPU mask (KAFFINITY): 0x%08X\n", _kaffinity ); DbgPrint( "[chipsec] Current CPU thread : %d\n", _cpu_thread_id ); // // Switch on the IOCTL code that is being requested by the user. If the // operation is a valid one for this device do the needful. // Irp -> IoStatus.Information = 0; switch( IOControlCode ) { case READ_PCI_CFG_REGISTER: { DWORD val; BYTE size = 0; WORD bdf[4]; BYTE bus = 0, dev = 0, fun = 0, off = 0; DbgPrint( "[chipsec] > READ_PCI_CFG_REGISTER\n" ); RtlCopyBytes( bdf,Irp->AssociatedIrp.SystemBuffer, 4*sizeof(WORD) ); RtlCopyBytes( &size, (BYTE*)Irp->AssociatedIrp.SystemBuffer + 4*sizeof(WORD), sizeof(BYTE) ); bus = (UINT8)bdf[0]; dev = (UINT8)bdf[1]; fun = (UINT8)bdf[2]; off = (UINT8)bdf[3]; if( 1 != size && 2 != size && 4 != size) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } val = ReadPCICfg( bus, dev, fun, off, size ); IrpSp->Parameters.Read.Length = size; RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (VOID*)&val, size ); DbgPrint( "[chipsec][READ_PCI_CFG_REGISTER] B/D/F: %#04x/%#04x/%#04x, OFFSET: %#04x, value = %#010x (size = 0x%x)\n", bus, dev, fun, off, val, size ); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } case WRITE_PCI_CFG_REGISTER: { DWORD val = 0; WORD bdf[6]; BYTE bus = 0, dev = 0, fun = 0, off = 0; BYTE size = 0; DbgPrint( "[chipsec] > WRITE_PCI_CFG_REGISTER\n" ); RtlCopyBytes( bdf, Irp->AssociatedIrp.SystemBuffer, 6 * sizeof(WORD) ); bus = (UINT8)bdf[0]; dev = (UINT8)bdf[1]; fun = (UINT8)bdf[2]; off = (UINT8)bdf[3]; RtlCopyBytes( &size, (BYTE*)Irp->AssociatedIrp.SystemBuffer + 6*sizeof(WORD), sizeof(BYTE) ); val = ((DWORD)bdf[5] << 16) | bdf[4]; DbgPrint( "[chipsec][WRITE_PCI_CFG_REGISTER] B/D/F: %#02x/%#02x/%#02x, OFFSET: %#02x, value = %#010x (size = %#02x)\n", bus, dev, fun, off, val, size ); WritePCICfg( bus, dev, fun, off, size, val ); Status = STATUS_SUCCESS; break; } case IOCTL_READ_PHYSMEM: { UINT32 len = 0; PVOID virt_addr; PHYSICAL_ADDRESS phys_addr = { 0x0, 0x0 }; DbgPrint( "[chipsec] > IOCTL_READ_PHYSMEM\n" ); if( !Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength < 3*sizeof(UINT32)) { DbgPrint( "[chipsec][IOCTL_READ_PHYSMEM] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; phys_addr.HighPart = ((UINT32*)pInBuf)[0]; phys_addr.LowPart = ((UINT32*)pInBuf)[1]; len = ((UINT32*)pInBuf)[2]; if( !len ) len = 4; if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength < len ) { DbgPrint( "[chipsec][IOCTL_READ_PHYSMEM] ERROR: STATUS_BUFFER_TOO_SMALL\n" ); Status = STATUS_BUFFER_TOO_SMALL; break; } __try { Status = _read_phys_mem( phys_addr, len, pOutBuf ); } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); DbgPrint( "[chipsec][IOCTL_READ_PHYSMEM] ERROR: exception code 0x%X\n", Status ); break; } if( NT_SUCCESS(Status) ) { DbgPrint( "[chipsec][IOCTL_READ_PHYSMEM] Contents:\n" ); _dump_buffer( (unsigned char *)pOutBuf, min(len,0x100) ); dwBytesWritten = len; } break; } case IOCTL_WRITE_PHYSMEM: { UINT32 len = 0; PVOID virt_addr = 0; PHYSICAL_ADDRESS phys_addr = { 0x0, 0x0 }; DbgPrint( "[chipsec] > IOCTL_WRITE_PHYSMEM\n" ); if( Irp->AssociatedIrp.SystemBuffer ) { pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < 3*sizeof(UINT32) ) { DbgPrint( "[chipsec][IOCTL_WRITE_PHYSMEM] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } phys_addr.HighPart = ((UINT32*)pInBuf)[0]; phys_addr.LowPart = ((UINT32*)pInBuf)[1]; len = ((UINT32*)pInBuf)[2]; ((UINT32*)pInBuf) += 3; if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < len + 3*sizeof(UINT32) ) { DbgPrint( "[chipsec][IOCTL_WRITE_PHYSMEM] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } DbgPrint( "[chipsec][IOCTL_WRITE_PHYSMEM] Writing contents:\n" ); _dump_buffer( (unsigned char *)pInBuf, min(len,0x100) ); __try { Status = _write_phys_mem( phys_addr, len, pInBuf ); } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); DbgPrint( "[chipsec][IOCTL_WRITE_PHYSMEM] ERROR: exception code 0x%X\n", Status ); break; } break; } } case IOCTL_ALLOC_PHYSMEM: { SIZE_T NumberOfBytes = 0; PVOID va = 0; PHYSICAL_ADDRESS HighestAcceptableAddress = { 0xFFFFFFFF, 0xFFFFFFFF }; DbgPrint( "[chipsec] > IOCTL_ALLOC_PHYSMEM\n" ); pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; if( !pInBuf || IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(UINT64) + sizeof(UINT32)) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &HighestAcceptableAddress.QuadPart, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(UINT64) ); RtlCopyBytes( &NumberOfBytes, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(UINT64), sizeof(UINT32) ); DbgPrint( "[chipsec] Allocating: NumberOfBytes = 0x%X, PhysAddr = 0x%I64x", NumberOfBytes, HighestAcceptableAddress.QuadPart ); va = MmAllocateContiguousMemory( NumberOfBytes, HighestAcceptableAddress ); if( !va ) { DbgPrint( "[chipsec] ERROR: STATUS_UNSUCCESSFUL - could not allocate memory\n" ); Status = STATUS_UNSUCCESSFUL; } else if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength < 2*sizeof(UINT64) ) { DbgPrint( "[chipsec] ERROR: STATUS_BUFFER_TOO_SMALL - should be at least 2*UINT64\n" ); Status = STATUS_BUFFER_TOO_SMALL; } else { PHYSICAL_ADDRESS pa = MmGetPhysicalAddress( va ); DbgPrint( "[chipsec] Allocated Buffer: VirtAddr = 0x%I64x, PhysAddr = 0x%I64x\n", (UINT64)va, pa.QuadPart ); ((UINT64*)pOutBuf)[0] = (UINT64)va; ((UINT64*)pOutBuf)[1] = pa.QuadPart; IrpSp->Parameters.Read.Length = 2*sizeof(UINT64); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; } break; } case IOCTL_FREE_PHYSMEM: { UINT64 va = 0x0; pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; DbgPrint( "[chipsec] > IOCTL_FREE_PHYSMEM\n" ); if( !Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof(UINT64)) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &va, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(UINT64) ); DbgPrint( "[chipsec][IOCTL_FREE_PHYSMEM] Virtual address of the memory being freed: 0x%I64X\n", va ); MmFreeContiguousMemory( (PVOID)va ); IrpSp->Parameters.Read.Length = 0; dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } case IOCTL_GET_PHYSADDR: { UINT64 va = 0x0; PHYSICAL_ADDRESS pa = { 0x0, 0x0 }; pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; DbgPrint( "[chipsec] > IOCTL_GET_PHYSADDR\n" ); if( !Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof(UINT64)) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(UINT64)) { DbgPrint( "[chipsec] ERROR: STATUS_BUFFER_TOO_SMALL\n" ); Status = STATUS_BUFFER_TOO_SMALL; break; } RtlCopyBytes( &va, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(UINT64) ); pa = MmGetPhysicalAddress( (PVOID)va ); DbgPrint( "[chipsec][IOCTL_GET_PHYSADDR] Traslated virtual address 0x%I64X to physical: 0x%I64X\n", va, pa.QuadPart, pa.LowPart); RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (void*)&pa, sizeof(UINT64) ); IrpSp->Parameters.Read.Length = sizeof(UINT64); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } case IOCTL_MAP_IO_SPACE: { PVOID va = 0x0; PHYSICAL_ADDRESS pa = { 0x0, 0x0 }; unsigned int len = 0; unsigned int cache_type = 0; pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; DbgPrint( "[chipsec] > IOCTL_MAP_IO_SPACE\n" ); if( !Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength != 3*8) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(UINT64)) { DbgPrint( "[chipsec] ERROR: STATUS_BUFFER_TOO_SMALL\n" ); Status = STATUS_BUFFER_TOO_SMALL; break; } RtlCopyBytes( &pa, (BYTE*)Irp->AssociatedIrp.SystemBuffer + 0x00, 0x8 ); RtlCopyBytes( &len, (BYTE*)Irp->AssociatedIrp.SystemBuffer + 0x08, 0x4 ); RtlCopyBytes( &cache_type, (BYTE*)Irp->AssociatedIrp.SystemBuffer + 0x10, 0x4 ); va = MmMapIoSpace(pa, len, cache_type); DbgPrint( "[chipsec][IOCTL_MAP_IO_SPACE] Mapping physical address 0x%016llX to virtual 0x%016llX\n", pa, va); RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (void*)&va, sizeof(va) ); IrpSp->Parameters.Read.Length = sizeof(va); dwBytesWritten = sizeof(va); Status = STATUS_SUCCESS; break; } case IOCTL_LOAD_UCODE_PATCH: { PVOID ucode_buf = NULL; UINT64 ucode_start = 0; UINT16 ucode_size = 0; UINT32 _eax = 0, _edx = 0; int CPUInfo[4] = {-1}; DbgPrint("[chipsec] > IOCTL_LOAD_UCODE_UPDATE\n" ); if( !Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(BYTE) + sizeof(UINT16) ) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER (input buffer size < 3)\n" ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &new_cpu_thread_id, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(BYTE) ); if( new_cpu_thread_id >= _num_active_cpus ) new_cpu_thread_id = 0; KeSetSystemAffinityThread( (KAFFINITY)(1 << new_cpu_thread_id) ); DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] Changed CPU thread to %d\n", KeGetCurrentProcessorNumber() ); RtlCopyBytes( &ucode_size, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(BYTE), sizeof(UINT16) ); DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] Ucode update size = 0x%X\n", ucode_size ); if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < ucode_size + sizeof(BYTE) + sizeof(UINT16) ) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER (input buffer size < ucode_size + 3)\n" ); Status = STATUS_INVALID_PARAMETER; break; } ucode_buf = ExAllocatePoolWithTag( NonPagedPool, ucode_size, 0x3184 ); if( !ucode_buf ) { DbgPrint( "[chipsec] ERROR: couldn't allocate pool for ucode binary\n" ); break; } RtlCopyBytes( ucode_buf, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(BYTE) + sizeof(UINT16), ucode_size ); ucode_start = (UINT64)ucode_buf; DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] ucode update address = 0x%p (eax = 0x%08X, edx = 0x%08X)\n", ucode_start, (UINT32)(ucode_start & 0xFFFFFFFF), (UINT32)((ucode_start >> 32) & 0xFFFFFFFF) ); DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] ucode update contents:\n" ); _dump_buffer( (unsigned char *)ucode_buf, min(ucode_size,0x100) ); // -- // -- trigger CPU ucode patch update // -- pInBuf points to the beginning of ucode update binary // -- _wrmsr( MSR_IA32_BIOS_UPDT_TRIG, (UINT32)((ucode_start >> 32) & 0xFFFFFFFF), (UINT32)(ucode_start & 0xFFFFFFFF) ); ExFreePoolWithTag( ucode_buf, 0x3184 ); // -- // -- check if patch was loaded // -- // -- need to clear IA32_BIOS_SIGN_ID MSR first // -- CPUID will deposit an update ID value in 64-bit MSR at address MSR_IA32_BIOS_SIGN_ID // -- read IA32_BIOS_SIGN_ID MSR to check patch ID != 0 // -- DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] checking ucode update was loaded..\n" ); DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] clear IA32_BIOS_SIGN_ID, CPUID EAX=1, read back IA32_BIOS_SIGN_ID\n" ); _wrmsr( MSR_IA32_BIOS_SIGN_ID, 0, 0 ); __cpuid(CPUInfo, 1); _rdmsr( MSR_IA32_BIOS_SIGN_ID, &_eax, &_edx ); DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] RDMSR( IA32_BIOS_SIGN_ID=0x8b ) = 0x%08x%08x\n", _edx, _eax ); if( 0 != _edx ) DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] Microcode update loaded (ID != 0)\n" ); else DbgPrint( "[chipsec] ERROR: Microcode update failed\n" ); Status = STATUS_SUCCESS; break; } case IOCTL_WRMSR: { UINT32 msrData[3]; UINT32 _eax = 0, _edx = 0; unsigned int _msr_addr; DbgPrint("[chipsec] > IOCTL_WRMSR\n"); pInBuf = Irp->AssociatedIrp.SystemBuffer; if( !pInBuf ) { DbgPrint( "[chipsec][IOCTL_WRMSR] ERROR: NO data provided\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(BYTE) + 3*sizeof(UINT32) ) { DbgPrint( "[chipsec][IOCTL_WRMSR] ERROR: STATUS_INVALID_PARAMETER (input buffer size < sizeof(BYTE) + 3*sizeof(UINT32))\n" ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &new_cpu_thread_id, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(BYTE) ); if( new_cpu_thread_id >= _num_active_cpus ) new_cpu_thread_id = 0; KeSetSystemAffinityThread( (KAFFINITY)(1 << new_cpu_thread_id) ); DbgPrint( "[chipsec][IOCTL_WRMSR] Changed CPU thread to %d\n", KeGetCurrentProcessorNumber() ); RtlCopyBytes( msrData, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(BYTE), 3 * sizeof(UINT32) ); _msr_addr = msrData[0]; _eax = msrData[1]; _edx = msrData[2]; DbgPrint( "[chipsec][IOCTL_WRMSR] WRMSR( 0x%x ) <-- 0x%08x%08x\n", _msr_addr, _edx, _eax ); // -- // -- write MSR // -- __try { _wrmsr( _msr_addr, _edx, _eax ); } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); DbgPrint( "[chipsec][IOCTL_WRMSR] ERROR: exception code 0x%X\n", Status ); break; } // -- // -- read MSR to check if it was written // -- // _rdmsr( _msr_addr, &_eax, &_edx ); // DbgPrint( "[chipsec][IOCTL_WRMSR] RDMSR( 0x%x ) --> 0x%08x%08x\n", _msr_addr, _edx, _eax ); Status = STATUS_SUCCESS; break; } case IOCTL_RDMSR: { UINT32 msrData[1]; UINT32 _eax = 0; UINT32 _edx = 0; UINT32 _msr_addr = 0; DbgPrint("[chipsec] > IOCTL_RDMSR\n"); pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; if( !pInBuf ) { DbgPrint( "[chipsec] ERROR: No input provided\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(BYTE) + sizeof(UINT32) ) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER - input buffer size < sizeof(BYTE) + sizeof(UINT32)\n" ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &new_cpu_thread_id, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(BYTE) ); if( new_cpu_thread_id >= _num_active_cpus ) new_cpu_thread_id = 0; KeSetSystemAffinityThread( (KAFFINITY)(1 << new_cpu_thread_id) ); DbgPrint( "[chipsec][IOCTL_RDMSR] Changed CPU thread to %d\n", KeGetCurrentProcessorNumber() ); RtlCopyBytes( msrData, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(BYTE), sizeof(UINT32) ); _msr_addr = msrData[0]; __try { _rdmsr( _msr_addr, &_eax, &_edx ); } __except( EXCEPTION_EXECUTE_HANDLER ) { Status = GetExceptionCode(); DbgPrint( "[chipsec][IOCTL_RDMSR] ERROR: exception code 0x%X\n", Status ); break; } DbgPrint( "[chipsec][IOCTL_RDMSR] RDMSR( 0x%x ) --> 0x%08x%08x\n", _msr_addr, _edx, _eax ); if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength >= 2*sizeof(UINT32) ) { IrpSp->Parameters.Read.Length = 2*sizeof(UINT32); RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (VOID*)&_eax, sizeof(UINT32) ); RtlCopyBytes( ((UINT8*)Irp->AssociatedIrp.SystemBuffer) + sizeof(UINT32), (VOID*)&_edx, sizeof(UINT32) ); dwBytesWritten = 2*sizeof(UINT32); Status = STATUS_SUCCESS; } else { DbgPrint( "[chipsec] ERROR: STATUS_BUFFER_TOO_SMALL - should be at least 2 UINT32\n" ); Status = STATUS_BUFFER_TOO_SMALL; } break; } case READ_IO_PORT: { DWORD value; BYTE size = 0; WORD io_port; DbgPrint( "[chipsec] > READ_IO_PORT\n" ); RtlCopyBytes( &io_port, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(WORD) ); RtlCopyBytes( &size, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(WORD), sizeof(BYTE) ); if( 1 != size && 2 != size && 4 != size) { DbgPrint( "[chipsec][READ_IO_PORT] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } __try { value = ReadIOPort( io_port, size ); } __except( EXCEPTION_EXECUTE_HANDLER ) { Status = GetExceptionCode(); DbgPrint( "[chipsec][READ_IO_PORT] ERROR: exception code 0x%X\n", Status ); break; } IrpSp->Parameters.Read.Length = size; RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (VOID*)&value, size ); DbgPrint( "[chipsec][READ_IO_PORT] I/O Port %#04x, value = %#010x (size = %#02x)\n", io_port, value, size ); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } case WRITE_IO_PORT: { DWORD value = 0; WORD io_port = 0; BYTE size = 0; DbgPrint( "[chipsec] > WRITE_IO_PORT\n" ); RtlCopyBytes( &io_port, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(WORD) ); RtlCopyBytes( &value, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(WORD), sizeof(DWORD) ); RtlCopyBytes( &size, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(WORD) + sizeof(DWORD), sizeof(BYTE) ); DbgPrint( "[chipsec][WRITE_IO_PORT] I/O Port %#04x, value = %#010x (size = %#02x)\n", io_port, value, size ); __try { WriteIOPort( value, io_port, size ); } __except( EXCEPTION_EXECUTE_HANDLER ) { Status = GetExceptionCode(); DbgPrint( "[chipsec][WRITE_IO_PORT] ERROR: exception code 0x%X\n", Status ); break; } Status = STATUS_SUCCESS; break; } case GET_CPU_DESCRIPTOR_TABLE: { BYTE dt_code = 0; DESCRIPTOR_TABLE_RECORD dtr; PDESCRIPTOR_TABLE_RECORD pdtr = &dtr; PHYSICAL_ADDRESS dt_pa; DbgPrint( "[chipsec] > GET_CPU_DESCRIPTOR_TABLE\n" ); RtlCopyBytes( &new_cpu_thread_id, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(BYTE) ); if( new_cpu_thread_id >= _num_active_cpus ) new_cpu_thread_id = 0; KeSetSystemAffinityThread( (KAFFINITY)(1 << new_cpu_thread_id) ); DbgPrint( "[chipsec][GET_CPU_DESCRIPTOR_TABLE] Changed CPU thread to %d\n", KeGetCurrentProcessorNumber() ); RtlCopyBytes( &dt_code, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(BYTE), sizeof(BYTE) ); DbgPrint( "[chipsec][GET_CPU_DESCRIPTOR_TABLE] Descriptor table: %x\n", dt_code ); switch( dt_code ) { case CPU_DT_CODE_GDTR: { _store_gdtr( (void*)pdtr ); break; } case CPU_DT_CODE_LDTR: { _store_ldtr( (void*)pdtr ); break; } case CPU_DT_CODE_IDTR: default: { _store_idtr( (void*)pdtr ); break; } } DbgPrint( "[chipsec][GET_CPU_DESCRIPTOR_TABLE] Descriptor table register contents:\n" ); _dump_buffer( (unsigned char *)pdtr, sizeof(DESCRIPTOR_TABLE_RECORD) ); DbgPrint( "[chipsec][GET_CPU_DESCRIPTOR_TABLE] IDTR: Limit = 0x%04x, Base = 0x%I64x\n", dtr.limit, dtr.base ); dt_pa = MmGetPhysicalAddress( (PVOID)dtr.base ); DbgPrint( "[chipsec][GET_CPU_DESCRIPTOR_TABLE] Descriptor table PA: 0x%I64X (0x%08X_%08X)\n", dt_pa.QuadPart, dt_pa.HighPart, dt_pa.LowPart ); IrpSp->Parameters.Read.Length = sizeof(DESCRIPTOR_TABLE_RECORD) + sizeof(dt_pa.QuadPart); RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (void*)pdtr, sizeof(DESCRIPTOR_TABLE_RECORD) ); RtlCopyBytes( (UINT8*)Irp->AssociatedIrp.SystemBuffer + sizeof(DESCRIPTOR_TABLE_RECORD), (VOID*)&dt_pa.QuadPart, sizeof(dt_pa.QuadPart) ); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } case IOCTL_SWSMI: { CPU_REG_TYPE gprs[6] = {0}; CPU_REG_TYPE _rax = 0, _rbx = 0, _rcx = 0, _rdx = 0, _rsi = 0, _rdi = 0; unsigned int _smi_code_data = 0; DbgPrint("[chipsec] > IOCTL_SWSMI\n"); pInBuf = Irp->AssociatedIrp.SystemBuffer; if( !pInBuf ) { DbgPrint( "[chipsec] ERROR: NO data provided\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(UINT16) + sizeof(gprs) ) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER (input buffer size < sizeof(UINT16) + sizeof(gprs))\n" ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &_smi_code_data, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(UINT16) ); RtlCopyBytes( gprs, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(UINT16), sizeof(gprs) ); _rax = gprs[ 0 ]; _rbx = gprs[ 1 ]; _rcx = gprs[ 2 ]; _rdx = gprs[ 3 ]; _rsi = gprs[ 4 ]; _rdi = gprs[ 5 ]; DbgPrint( "[chipsec][IOCTL_SWSMI] SW SMI to ports 0x%X-0x%X <- 0x%04X\n", 0xB2, 0xB3, _smi_code_data ); DbgPrint( " RAX = 0x%I64x\n", _rax ); DbgPrint( " RBX = 0x%I64x\n", _rbx ); DbgPrint( " RCX = 0x%I64x\n", _rcx ); DbgPrint( " RDX = 0x%I64x\n", _rdx ); DbgPrint( " RSI = 0x%I64x\n", _rsi ); DbgPrint( " RDI = 0x%I64x\n", _rdi ); // -- // -- send SMI using port 0xB2 // -- __try { _swsmi( _smi_code_data, _rax, _rbx, _rcx, _rdx, _rsi, _rdi ); } __except( EXCEPTION_EXECUTE_HANDLER ) { Status = GetExceptionCode(); break; } Status = STATUS_SUCCESS; break; } case IOCTL_CPUID: { DWORD CPUInfo[4] = {-1}; DWORD gprs[2] = {0}; DWORD _rax = 0, _rcx = 0; //CPU_REG_TYPE gprs[6]; //CPU_REG_TYPE _rax = 0, _rbx = 0, _rcx = 0, _rdx = 0, _rsi = 0, _rdi = 0; DbgPrint("[chipsec] > IOCTL_CPUID\n"); pInBuf = Irp->AssociatedIrp.SystemBuffer; if( !pInBuf ) { DbgPrint( "[chipsec] ERROR: NO data provided\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(gprs) ) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER (input buffer size < %d)\n", sizeof(gprs) ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( gprs, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(gprs) ); _rax = gprs[ 0 ]; _rcx = gprs[ 1 ]; DbgPrint( "[chipsec][IOCTL_CPUID] CPUID:\n" ); DbgPrint( " EAX = 0x%08X\n", _rax ); DbgPrint( " ECX = 0x%08X\n", _rcx ); __cpuidex( CPUInfo, _rax, _rcx ); DbgPrint( "[chipsec][IOCTL_CPUID] CPUID returned:\n" ); DbgPrint( " EAX = 0x%08X\n", CPUInfo[0] ); DbgPrint( " EBX = 0x%08X\n", CPUInfo[1] ); DbgPrint( " ECX = 0x%08X\n", CPUInfo[2] ); DbgPrint( " EDX = 0x%08X\n", CPUInfo[3] ); IrpSp->Parameters.Read.Length = sizeof(CPUInfo); RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (void*)CPUInfo, sizeof(CPUInfo) ); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } case IOCTL_WRCR: { UINT64 val64 = 0; CPU_REG_TYPE value = 0; WORD cr_reg = 0; DbgPrint( "[chipsec] > WRITE_CR\n" ); if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < (sizeof(cr_reg) + sizeof(val64) + sizeof(BYTE))) { Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &cr_reg, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(cr_reg) ); RtlCopyBytes( &val64, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(cr_reg), sizeof(val64) ); new_cpu_thread_id = *((BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(cr_reg) + sizeof(val64)); if( new_cpu_thread_id >= _num_active_cpus ) { // new_cpu_thread_id = 0; Status = STATUS_INVALID_PARAMETER; break; } KeSetSystemAffinityThread( (KAFFINITY)(1 << new_cpu_thread_id) ); value = (CPU_REG_TYPE)val64; DbgPrint( "[chipsec][WRITE_CR] CR Reg %#04x, value = %#010x \n", cr_reg, value ); switch (cr_reg) { case 0: WriteCR0(value); Status = STATUS_SUCCESS; break; case 2: WriteCR2(value); Status = STATUS_SUCCESS; break; case 3: WriteCR3(value); Status = STATUS_SUCCESS; break; case 4: WriteCR4(value); Status = STATUS_SUCCESS; break; case 8: #if defined(_M_AMD64) WriteCR8(value); Status = STATUS_SUCCESS; break; #endif default: Status = STATUS_INVALID_PARAMETER; break; } if( !NT_SUCCESS(Status) ) { break; } dwBytesWritten = 0; Status = STATUS_SUCCESS; break; } case IOCTL_RDCR: { UINT64 val64 = 0; CPU_REG_TYPE value = 0; WORD cr_reg = 0; DbgPrint( "[chipsec] > READ_CR\n" ); if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < (sizeof(cr_reg)+sizeof(BYTE)) || IrpSp->Parameters.DeviceIoControl.OutputBufferLength < (sizeof(val64)) ) { Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &cr_reg, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(cr_reg) ); new_cpu_thread_id = *((BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(cr_reg)); if( new_cpu_thread_id >= _num_active_cpus ) { // new_cpu_thread_id = 0; Status = STATUS_INVALID_PARAMETER; break; } KeSetSystemAffinityThread( (KAFFINITY)(1 << new_cpu_thread_id) ); switch (cr_reg) { case 0: value = ReadCR0(); Status = STATUS_SUCCESS; break; case 2: value = ReadCR2(); Status = STATUS_SUCCESS; break; case 3: value = ReadCR3(); Status = STATUS_SUCCESS; break; case 4: value = ReadCR4(); Status = STATUS_SUCCESS; break; case 8: #if defined(_M_AMD64) value = ReadCR8(); Status = STATUS_SUCCESS; break; #endif default: Status = STATUS_INVALID_PARAMETER; break; } if( !NT_SUCCESS(Status) ) { break; } val64 = value; RtlCopyBytes( (BYTE*)Irp->AssociatedIrp.SystemBuffer, &val64, sizeof(val64) ); dwBytesWritten = sizeof(val64); DbgPrint( "[chipsec][READ_CR] CR Reg %#04x, value = %#010x \n", cr_reg, value ); Status = STATUS_SUCCESS; break; } case IOCTL_HYPERCALL: { CPU_REG_TYPE regs[11] = {0}; CPU_REG_TYPE result = 0; DbgPrint("[chipsec] > IOCTL_HYPERCALL\n"); pInBuf = Irp->AssociatedIrp.SystemBuffer; if( !Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof(regs)) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(result)) { DbgPrint( "[chipsec] ERROR: STATUS_BUFFER_TOO_SMALL\n" ); Status = STATUS_BUFFER_TOO_SMALL; break; } RtlCopyBytes( regs, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(regs) ); DbgPrint( "[chipsec][IOCTL_HYPERCALL] HYPERCALL:\n" ); #if defined(_M_AMD64) DbgPrint( " RCX = 0x%016llX RDX = 0x%016llX\n", regs[0], regs[1] ); DbgPrint( " R8 = 0x%016llX R9 = 0x%016llX\n", regs[2], regs[3] ); DbgPrint( " R10 = 0x%016llX R11 = 0x%016llX\n", regs[4], regs[5] ); DbgPrint( " RAX = 0x%016llX RBX = 0x%016llX\n", regs[6], regs[7] ); DbgPrint( " RDI = 0x%016llX RSI = 0x%016llX\n", regs[8], regs[9] ); #endif #if defined(_M_IX86) DbgPrint( " EAX = 0x%08X EBX = 0x%08X ECX = 0x%08X\n", regs[6], regs[7], regs[0] ); DbgPrint( " EDX = 0x%08X ESI = 0x%08X EDI = 0x%08X\n", regs[1], regs[8], regs[9] ); #endif DbgPrint( " XMM0-XMM5 buffer VA = 0x%016llX\n", regs[9] ); __try { result = hypercall(regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6], regs[7], regs[8], regs[9], regs[10], &hypercall_page); } __except( EXCEPTION_EXECUTE_HANDLER ) { Status = GetExceptionCode(); DbgPrint( "[chipsec][IOCTL_HYPERCALL] ERROR: exception code 0x%X\n", Status ); break; } DbgPrint( "[chipsec][IOCTL_HYPERCALL] returned: 0x%016llX\n", result); IrpSp->Parameters.Read.Length = sizeof(result); RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (void*)&result, sizeof(result) ); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } default: DbgPrint( "[chipsec] ERROR: invalid IOCTL\n"); Status = STATUS_NOT_IMPLEMENTED; break; } // -- switch
inline CPUIDInfo cpuid(std::uint32_t eax) { CPUIDInfo info; __cpuidex((int*)&info.data[0], eax, 0); return info; }
void VCIntrinsicCPUIDPolicy::CPUIDExtended( CPUIDSubleafResult & Registers, uint32_t Leaf, uint32_t Subleaf ) noexcept { static_assert( sizeof( uint32_t ) == sizeof( int ), "VC's intrinsic requires an int for the registers" ); __cpuidex( reinterpret_cast< int * >( & Registers ), Leaf, Subleaf ); }
// Allocates structures for virtualization, initializes VMCS and virtualizes // the current processor _Use_decl_annotations_ static void VmpInitializeVm( ULONG_PTR guest_stack_pointer, ULONG_PTR guest_instruction_pointer, void *context) { PAGED_CODE(); const auto shared_data = reinterpret_cast<SharedProcessorData *>(context); if (!shared_data) { return; } // Allocate related structures const auto processor_data = reinterpret_cast<ProcessorData *>(ExAllocatePoolWithTag( NonPagedPool, sizeof(ProcessorData), kHyperPlatformCommonPoolTag)); if (!processor_data) { return; } RtlZeroMemory(processor_data, sizeof(ProcessorData)); processor_data->shared_data = shared_data; InterlockedIncrement(&processor_data->shared_data->reference_count); // Set up EPT processor_data->ept_data = EptInitialization(); if (!processor_data->ept_data) { goto ReturnFalse; } // Check if XSAVE/XRSTOR are available and save an instruction mask for all // supported user state components processor_data->xsave_inst_mask = RtlGetEnabledExtendedFeatures(static_cast<ULONG64>(-1)); HYPERPLATFORM_LOG_DEBUG("xsave_inst_mask = %p", processor_data->xsave_inst_mask); if (processor_data->xsave_inst_mask) { // Allocate a large enough XSAVE area to store all supported user state // components. A size is round-up to multiple of the page size so that the // address fulfills a requirement of 64K alignment. // // See: ENUMERATION OF CPU SUPPORT FOR XSAVE INSTRUCTIONS AND XSAVESUPPORTED // FEATURES int cpu_info[4] = {}; __cpuidex(cpu_info, 0xd, 0); const auto xsave_area_size = ROUND_TO_PAGES(cpu_info[2]); // ecx processor_data->xsave_area = ExAllocatePoolWithTag( NonPagedPool, xsave_area_size, kHyperPlatformCommonPoolTag); if (!processor_data->xsave_area) { goto ReturnFalse; } RtlZeroMemory(processor_data->xsave_area, xsave_area_size); } else { // Use FXSAVE/FXRSTOR instead. int cpu_info[4] = {}; __cpuid(cpu_info, 1); const CpuFeaturesEcx cpu_features_ecx = {static_cast<ULONG32>(cpu_info[2])}; const CpuFeaturesEdx cpu_features_edx = {static_cast<ULONG32>(cpu_info[3])}; if (cpu_features_ecx.fields.avx) { HYPERPLATFORM_LOG_ERROR("A processor supports AVX but not XSAVE/XRSTOR."); goto ReturnFalse; } if (!cpu_features_edx.fields.fxsr) { HYPERPLATFORM_LOG_ERROR("A processor does not support FXSAVE/FXRSTOR."); goto ReturnFalse; } } // Allocate other processor data fields processor_data->vmm_stack_limit = UtilAllocateContiguousMemory(KERNEL_STACK_SIZE); if (!processor_data->vmm_stack_limit) { goto ReturnFalse; } RtlZeroMemory(processor_data->vmm_stack_limit, KERNEL_STACK_SIZE); processor_data->vmcs_region = reinterpret_cast<VmControlStructure *>(ExAllocatePoolWithTag( NonPagedPool, kVmxMaxVmcsSize, kHyperPlatformCommonPoolTag)); if (!processor_data->vmcs_region) { goto ReturnFalse; } RtlZeroMemory(processor_data->vmcs_region, kVmxMaxVmcsSize); processor_data->vmxon_region = reinterpret_cast<VmControlStructure *>(ExAllocatePoolWithTag( NonPagedPool, kVmxMaxVmcsSize, kHyperPlatformCommonPoolTag)); if (!processor_data->vmxon_region) { goto ReturnFalse; } RtlZeroMemory(processor_data->vmxon_region, kVmxMaxVmcsSize); // Initialize stack memory for VMM like this: // // (High) // +------------------+ <- vmm_stack_region_base (eg, AED37000) // | processor_data | // +------------------+ <- vmm_stack_data (eg, AED36FFC) // | MAXULONG_PTR | // +------------------+ <- vmm_stack_base (initial SP)(eg, AED36FF8) // | | v // | (VMM Stack) | v (grow) // | | v // +------------------+ <- vmm_stack_limit (eg, AED34000) // (Low) const auto vmm_stack_region_base = reinterpret_cast<ULONG_PTR>(processor_data->vmm_stack_limit) + KERNEL_STACK_SIZE; const auto vmm_stack_data = vmm_stack_region_base - sizeof(void *); const auto vmm_stack_base = vmm_stack_data - sizeof(void *); HYPERPLATFORM_LOG_DEBUG("vmm_stack_limit = %p", processor_data->vmm_stack_limit); HYPERPLATFORM_LOG_DEBUG("vmm_stack_region_base = %p", vmm_stack_region_base); HYPERPLATFORM_LOG_DEBUG("vmm_stack_data = %p", vmm_stack_data); HYPERPLATFORM_LOG_DEBUG("vmm_stack_base = %p", vmm_stack_base); HYPERPLATFORM_LOG_DEBUG("processor_data = %p stored at %p", processor_data, vmm_stack_data); HYPERPLATFORM_LOG_DEBUG("guest_stack_pointer = %p", guest_stack_pointer); HYPERPLATFORM_LOG_DEBUG("guest_inst_pointer = %p", guest_instruction_pointer); *reinterpret_cast<ULONG_PTR *>(vmm_stack_base) = MAXULONG_PTR; *reinterpret_cast<ProcessorData **>(vmm_stack_data) = processor_data; // Set up VMCS if (!VmpEnterVmxMode(processor_data)) { goto ReturnFalse; } if (!VmpInitializeVmcs(processor_data)) { goto ReturnFalseWithVmxOff; } if (!VmpSetupVmcs(processor_data, guest_stack_pointer, guest_instruction_pointer, vmm_stack_base)) { goto ReturnFalseWithVmxOff; } // Do virtualize the processor VmpLaunchVm(); // Here is not be executed with successful vmlaunch. Instead, the context // jumps to an address specified by guest_instruction_pointer. ReturnFalseWithVmxOff:; __vmx_off(); ReturnFalse:; VmpFreeProcessorData(processor_data); }
static inline void cpuid(unsigned func, unsigned subfunc, unsigned cpuinfo[4]) { __cpuidex(cpuinfo, func, subfunc); }
inline static void cpuid (int output[4], int aa, int cc = 0) { __cpuidex(output, aa, cc); }
extern "C" __declspec(dllexport) BOOLEAN hasSSE2() { // Misc. bool HW_MMX; bool HW_x64; bool HW_ABM; // Advanced Bit Manipulation bool HW_RDRAND; bool HW_BMI1; bool HW_BMI2; bool HW_ADX; bool HW_PREFETCHWT1; // SIMD: 128-bit bool HW_SSE; bool HW_SSE2; bool HW_SSE3; bool HW_SSSE3; bool HW_SSE41; bool HW_SSE42; bool HW_SSE4a; bool HW_AES; bool HW_SHA; // SIMD: 256-bit bool HW_AVX; bool HW_XOP; bool HW_FMA3; bool HW_FMA4; bool HW_AVX2; // SIMD: 512-bit bool HW_AVX512F; // AVX512 Foundation bool HW_AVX512CD; // AVX512 Conflict Detection bool HW_AVX512PF; // AVX512 Prefetch bool HW_AVX512ER; // AVX512 Exponential + Reciprocal bool HW_AVX512VL; // AVX512 Vector Length Extensions bool HW_AVX512BW; // AVX512 Byte + Word bool HW_AVX512DQ; // AVX512 Doubleword + Quadword bool HW_AVX512IFMA; // AVX512 Integer 52-bit Fused Multiply-Add bool HW_AVX512VBMI; // AVX512 Vector Byte Manipulation Instructions int info[4]; __cpuidex(info, 0, 0); int nIds = info[0]; __cpuidex(info, 0x80000000, 0); unsigned nExIds = info[0]; // Detect Features if (nIds >= 0x00000001) { __cpuidex(info, 0x00000001, 0); HW_MMX = (info[3] & ((int)1 << 23)) != 0; HW_SSE = (info[3] & ((int)1 << 25)) != 0; HW_SSE2 = (info[3] & ((int)1 << 26)) != 0; HW_SSE3 = (info[2] & ((int)1 << 0)) != 0; HW_SSSE3 = (info[2] & ((int)1 << 9)) != 0; HW_SSE41 = (info[2] & ((int)1 << 19)) != 0; HW_SSE42 = (info[2] & ((int)1 << 20)) != 0; HW_AES = (info[2] & ((int)1 << 25)) != 0; HW_AVX = (info[2] & ((int)1 << 28)) != 0; HW_FMA3 = (info[2] & ((int)1 << 12)) != 0; HW_RDRAND = (info[2] & ((int)1 << 30)) != 0; } if (nIds >= 0x00000007) { __cpuidex(info, 0x00000007,0); HW_AVX2 = (info[1] & ((int)1 << 5)) != 0; HW_BMI1 = (info[1] & ((int)1 << 3)) != 0; HW_BMI2 = (info[1] & ((int)1 << 8)) != 0; HW_ADX = (info[1] & ((int)1 << 19)) != 0; HW_SHA = (info[1] & ((int)1 << 29)) != 0; HW_PREFETCHWT1 = (info[2] & ((int)1 << 0)) != 0; HW_AVX512F = (info[1] & ((int)1 << 16)) != 0; HW_AVX512CD = (info[1] & ((int)1 << 28)) != 0; HW_AVX512PF = (info[1] & ((int)1 << 26)) != 0; HW_AVX512ER = (info[1] & ((int)1 << 27)) != 0; HW_AVX512VL = (info[1] & ((int)1 << 31)) != 0; HW_AVX512BW = (info[1] & ((int)1 << 30)) != 0; HW_AVX512DQ = (info[1] & ((int)1 << 17)) != 0; HW_AVX512IFMA = (info[1] & ((int)1 << 21)) != 0; HW_AVX512VBMI = (info[2] & ((int)1 << 1)) != 0; } if (nExIds >= 0x80000001) { __cpuidex(info, 0x80000001,0); HW_x64 = (info[3] & ((int)1 << 29)) != 0; HW_ABM = (info[2] & ((int)1 << 5)) != 0; HW_SSE4a = (info[2] & ((int)1 << 6)) != 0; HW_FMA4 = (info[2] & ((int)1 << 16)) != 0; HW_XOP = (info[2] & ((int)1 << 11)) != 0; } return (BOOLEAN)HW_SSE2; }
CpuDetect::CpuDetect() : m_mmx(false), m_sse(false), m_sse2(false), m_sse3(false), m_ssse3(false), m_sse41(false), m_sse42(false), m_aes(false), m_avx(false), m_fma3(false), m_rdrand(false), m_avx2(false), m_bmi1(false), m_bmi2(false), m_adx(false), m_sha(false), m_prefetchwt1(false), m_avx512f(false), m_avx512cd(false), m_avx512pf(false), m_avx512er(false), m_avx512vl(false), m_avx512bw(false), m_avx512dq(false), m_avx512ifma(false), m_avx512vbmi(false), m_x64(false), m_abm(false), m_sse4a(false), m_fma4(false), m_hop(false) { int cpuInfo[4]; __cpuidex(cpuInfo, 0, 0); int nIds = cpuInfo[0]; __cpuidex(cpuInfo, 0x80000000, 0); unsigned nExIds = cpuInfo[0]; if (nIds >= 0x00000001) { __cpuidex(cpuInfo, 1, 0); m_mmx = (cpuInfo[3] & ((int)1 << 23)) != 0; m_sse = (cpuInfo[3] & ((int)1 << 25)) != 0; m_sse2 = (cpuInfo[3] & ((int)1 << 26)) != 0; m_sse3 = (cpuInfo[2] & ((int)1 << 0)) != 0; m_ssse3 = (cpuInfo[2] & ((int)1 << 9)) != 0; m_sse41 = (cpuInfo[2] & ((int)1 << 19)) != 0; m_sse42 = (cpuInfo[2] & ((int)1 << 20)) != 0; m_aes = (cpuInfo[2] & ((int)1 << 25)) != 0; m_avx = (cpuInfo[2] & ((int)1 << 28)) != 0; m_fma3 = (cpuInfo[2] & ((int)1 << 12)) != 0; m_rdrand = (cpuInfo[2] & ((int)1 << 30)) != 0; } if (nIds >= 0x00000007) { __cpuidex(cpuInfo, 0x00000007, 0); m_avx2 = (cpuInfo[1] & ((int)1 << 5)) != 0; m_bmi1 = (cpuInfo[1] & ((int)1 << 3)) != 0; m_bmi2 = (cpuInfo[1] & ((int)1 << 8)) != 0; m_adx = (cpuInfo[1] & ((int)1 << 19)) != 0; m_sha = (cpuInfo[1] & ((int)1 << 29)) != 0; m_prefetchwt1 = (cpuInfo[2] & ((int)1 << 0)) != 0; m_avx512f = (cpuInfo[1] & ((int)1 << 16)) != 0; m_avx512cd = (cpuInfo[1] & ((int)1 << 28)) != 0; m_avx512pf = (cpuInfo[1] & ((int)1 << 26)) != 0; m_avx512er = (cpuInfo[1] & ((int)1 << 27)) != 0; m_avx512vl = (cpuInfo[1] & ((int)1 << 31)) != 0; m_avx512bw = (cpuInfo[1] & ((int)1 << 30)) != 0; m_avx512dq = (cpuInfo[1] & ((int)1 << 17)) != 0; m_avx512ifma = (cpuInfo[1] & ((int)1 << 21)) != 0; m_avx512vbmi = (cpuInfo[2] & ((int)1 << 1)) != 0; } if (nExIds >= 0x80000001) { __cpuidex(cpuInfo, 0x80000001, 0); m_x64 = (cpuInfo[3] & ((int)1 << 29)) != 0; m_abm = (cpuInfo[2] & ((int)1 << 5)) != 0; m_sse4a = (cpuInfo[2] & ((int)1 << 6)) != 0; m_fma4 = (cpuInfo[2] & ((int)1 << 16)) != 0; m_hop = (cpuInfo[2] & ((int)1 << 11)) != 0; } }