5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync; $Id$
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync;; @file
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync; CPUM - Patch Helpers.
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync;
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync; Copyright (C) 2015 Oracle Corporation
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync;
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync; This file is part of VirtualBox Open Source Edition (OSE), as
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync; available from http://www.virtualbox.org. This file is free software;
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync; you can redistribute it and/or modify it under the terms of the GNU
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync; General Public License (GPL) as published by the Free Software
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync; Foundation, in version 2 as it comes in the "COPYING" file of the
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync;
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync;*******************************************************************************
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync;* Header Files *
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync;*******************************************************************************
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync%include "VBox/asmdefs.mac"
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync%include "VBox/vmm/cpum.mac"
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync%include "CPUMInternal.mac"
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync%include "VBox/vmm/vm.mac"
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync%include "VMMRC.mac"
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync;*******************************************************************************
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync;* External Symbols *
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync;*******************************************************************************
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsyncextern IMPNAME(g_VM)
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsyncBEGIN_PATCH_HLP_SEG
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync;;
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync; Helper for PATMCpuidReplacement.
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync;
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync; We have at most 32 bytes of stack to play with, .
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync;
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync; @input eax, ecx(, edx, ebx)
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync; @output eax, ebx, ecx, ebx
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync;
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync; @uses eflags (caller saves them)
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync;
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsyncBEGINPROC_EXPORTED CPUMPatchHlpCpuId
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ; Save the registers we use for passthru and sub-leaf matching (eax is not used).
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync push edx
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync push ecx
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync push ebx
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ; Use edi as VM pointer.
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync push edi
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync mov edi, IMP_SEG(ss, g_VM)
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync%define CPUMCPUIDLEAF_SIZE_LOG2 5 ; ASSUMES CPUMCPUIDLEAF_size == 32
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ;
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ; Perform a binary search looking for leaf with the EAX value.
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ;
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync mov edx, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.cCpuIdLeaves]
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync mov ecx, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.paCpuIdLeavesRC]
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync test edx, edx
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync jz cpuid_unknown
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync shl edx, CPUMCPUIDLEAF_SIZE_LOG2
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync add edx, ecx ; edx = end (exclusive); ecx = start.
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsynccpuid_lookup_leaf:
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ; Find the middle element
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync mov ebx, edx
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsynccpuid_lookup_leaf_ebx_loeaded:
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync sub ebx, ecx
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync shr ebx, 1 + CPUMCPUIDLEAF_SIZE_LOG2
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync shl ebx, CPUMCPUIDLEAF_SIZE_LOG2
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync add ebx, ecx ; ebx = middle element.
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ; Compare.
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync cmp eax, [ss:ebx + CPUMCPUIDLEAF.uLeaf]
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync jae cpuid_lookup_split_up
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ; The leaf is before ebx.
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsynccpuid_lookup_split_down:
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync cmp ecx, ebx ; start == middle? if so, we failed.
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync mov edx, ebx ; end = middle;
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync jne cpuid_lookup_leaf_ebx_loeaded
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync jmp cpuid_unknown
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ; The leaf is at or after ebx.
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsynccpuid_lookup_split_up:
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync je cpuid_match_eax
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync lea ecx, [ebx + CPUMCPUIDLEAF_size] ; start = middle + 1
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync cmp ecx, edx ; middle + 1 == start? if so, we failed.
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync jne cpuid_lookup_leaf
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync jmp cpuid_unknown
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ;
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ; We've to a matching leaf, does the sub-leaf match too?
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ;
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsynccpuid_match_eax:
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync mov ecx, [esp + 4]
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync and ecx, [ss:ebx + CPUMCPUIDLEAF.fSubLeafMask]
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync cmp ecx, [ss:ebx + CPUMCPUIDLEAF.uSubLeaf]
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync je cpuid_fetch
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ja cpuid_lookup_subleaf_forwards
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ;
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ; Search backwards.
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ;
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsynccpuid_lookup_subleaf_backwards:
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync mov edx, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.paCpuIdLeavesRC] ; edx = first leaf
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsynccpuid_lookup_subleaf_backwards_loop:
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync cmp ebx, edx ; Is there a leaf before the current?
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync jbe cpuid_subleaf_not_found ; If not we're out of luck.
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync cmp eax, [ss:ebx - CPUMCPUIDLEAF_size + CPUMCPUIDLEAF.uLeaf]
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync jne cpuid_subleaf_not_found ; If the leaf before us does not have the same leaf number, we failed.
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync sub ebx, CPUMCPUIDLEAF_size
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync cmp ecx, [ss:ebx + CPUMCPUIDLEAF.uSubLeaf]
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync je cpuid_fetch ; If the subleaf matches, we're good!.
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync jb cpuid_lookup_subleaf_backwards_loop ; Still hope if the subleaf we're seeking is smaller.
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync jmp cpuid_subleaf_not_found ; Too bad.
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ;
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ; Search forward until we've got a matching sub-leaf (or not).
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ;
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsynccpuid_lookup_subleaf_forwards:
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ; Calculate the last leaf address.
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync mov edx, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.cCpuIdLeaves]
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync dec edx
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync shl edx, CPUMCPUIDLEAF_SIZE_LOG2
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync add edx, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.paCpuIdLeavesRC] ; edx = last leaf (inclusive)
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsynccpuid_subleaf_lookup:
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync cmp ebx, edx
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync jae cpuid_subleaf_not_found
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync cmp eax, [ss:ebx + CPUMCPUIDLEAF_size + CPUMCPUIDLEAF.uLeaf]
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync jne cpuid_subleaf_not_found
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync add ebx, CPUMCPUIDLEAF_size
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync cmp ecx, [ss:ebx + CPUMCPUIDLEAF.uSubLeaf]
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ja cpuid_subleaf_lookup
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync je cpuid_fetch
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ;
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ; Out of range sub-leaves aren't quite as easy and pretty as we emulate them
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ; here, but we do an adequate job.
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ;
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsynccpuid_subleaf_not_found:
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync xor ecx, ecx
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync test dword [ss:ebx + CPUMCPUIDLEAF.fFlags], CPUMCPUIDLEAF_F_INTEL_TOPOLOGY_SUBLEAVES
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync jz cpuid_load_zeros_except_ecx
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync mov ecx, [esp + 4]
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync and ecx, 0ffh
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsynccpuid_load_zeros_except_ecx:
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync xor edx, edx
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync xor eax, eax
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync xor ebx, ebx
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync jmp cpuid_done
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ;
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ; Different CPUs have different ways of dealing with unknown CPUID leaves.
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ;
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsynccpuid_unknown:
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync mov ebx, IMP_SEG(ss, g_VM)
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync mov dword [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.enmUnknownCpuIdMethod], CPUMUNKNOWNCPUID_PASSTHRU
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync je cpuid_unknown_passthru
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ; Load the default cpuid leaf.
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsynccpuid_unknown_def_leaf:
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync mov edx, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.DefCpuId + CPUMCPUID.uEdx]
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync mov ecx, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.DefCpuId + CPUMCPUID.uEcx]
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync mov eax, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.DefCpuId + CPUMCPUID.uEax]
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync mov ebx, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.DefCpuId + CPUMCPUID.uEbx]
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync jmp cpuid_done
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ; Pass thru the input values unmodified (eax is still virgin).
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsynccpuid_unknown_passthru:
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync mov edx, [esp + 8]
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync mov ecx, [esp + 4]
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync mov ebx, [esp]
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync jmp cpuid_done
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ;
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ; Normal return.
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ;
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsynccpuid_fetch:
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync mov edx, [ss:ebx + CPUMCPUIDLEAF.uEdx]
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync mov ecx, [ss:ebx + CPUMCPUIDLEAF.uEcx]
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync mov eax, [ss:ebx + CPUMCPUIDLEAF.uEax]
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync mov ebx, [ss:ebx + CPUMCPUIDLEAF.uEbx]
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsynccpuid_done:
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync pop edi
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync add esp, 12
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync ret
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsyncENDPROC CPUMPatchHlpCpuId
5a7df607b64bfcec6cf547263957ca6db6a20a34vboxsync