This repository was archived by the owner on Apr 8, 2024. It is now read-only.
- Notifications
You must be signed in to change notification settings - Fork 30
/
Copy pathvmexit_cpuid.c
126 lines (101 loc) · 3.1 KB
/
vmexit_cpuid.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*
* Copyright (c) 2015-2019 Intel Corporation.
* All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
#include"vmm_base.h"
#include"gcpu.h"
#include"guest.h"
#include"vmexit_cpuid.h"
/* used for CPUID leaf 0x3.
* if the signature is matched, then evmm is running. */
#defineEVMM_SIGNATURE_CORP 0x43544E49 /* "INTC", edx */
#defineEVMM_SIGNATURE_VMM 0x4D4D5645 /* "EVMM", ecx */
typedefvoid (*cpuid_filter_handler_t) (guest_cpu_handle_t, cpuid_params_t*);
typedefstruct {
/* cpuid leaf index */
uint32_teax;
uint32_tpad;
cpuid_filter_handler_thandler;
} cpuid_filter_t;
static
voidcpuid_leaf_1h_filter(UNUSEDguest_cpu_handle_tgcpu, cpuid_params_t*p_cpuid)
{
/* hide SMX support */
p_cpuid->ecx &= ~CPUID_ECX_SMX;
#ifndefMODULE_NESTED_VT
/* hide VMX support */
p_cpuid->ecx &= ~CPUID_ECX_VMX;
#endif
}
static
voidcpuid_leaf_3h_filter(UNUSEDguest_cpu_handle_tgcpu, cpuid_params_t*p_cpuid)
{
/* use PSN index 3 to indicate whether evmm is running or not. */
/* "EVMM" */
p_cpuid->ecx=EVMM_SIGNATURE_VMM;
/* "INTC" */
p_cpuid->edx=EVMM_SIGNATURE_CORP;
}
#defineDESCRIPTOR_L_BIT 0x2000
static
voidcpuid_leaf_ext_1h_filter(guest_cpu_handle_tgcpu, cpuid_params_t*p_cpuid)
{
uint64_tguest_cs_ar=vmcs_read(gcpu->vmcs, VMCS_GUEST_CS_AR);
if ((guest_cs_ar&DESCRIPTOR_L_BIT) ==0) {
/* Guest is not in 64 bit mode, the bit 11 of EDX should be
* cleared since this bit indicates syscall/sysret available
* in 64 bit mode. See the Intel Software Programmer Manual vol 2A
* CPUID instruction */
p_cpuid->edx &= ~CPUID_EDX_SYSCALL_SYSRET;
}
}
static
voidcpuid_leaf_40000000h_filter(UNUSEDguest_cpu_handle_tgcpu, cpuid_params_t*p_cpuid)
{
p_cpuid->eax=0x40000000; /* Largest basic leaf supported */
p_cpuid->ebx=EVMM_SIGNATURE_VMM;
p_cpuid->ecx=EVMM_SIGNATURE_VMM;
p_cpuid->edx=EVMM_SIGNATURE_VMM;
}
staticcpuid_filter_tg_cpuid_filter[] = {
{0x1,0,cpuid_leaf_1h_filter},
{0x3,0,cpuid_leaf_3h_filter},
{0x40000000,0,cpuid_leaf_40000000h_filter},
{0x80000001,0,cpuid_leaf_ext_1h_filter},
{0xFFFFFFFF,0,NULL}
};
voidvmexit_cpuid_instruction(guest_cpu_handle_tgcpu)
{
cpuid_params_tcpuid_params;
uint32_tcpuid_eax;
uint32_tfilter_id;
D(VMM_ASSERT(gcpu));
cpuid_params.eax=gcpu_get_gp_reg(gcpu, REG_RAX);
cpuid_params.ebx=gcpu_get_gp_reg(gcpu, REG_RBX);
cpuid_params.ecx=gcpu_get_gp_reg(gcpu, REG_RCX);
cpuid_params.edx=gcpu_get_gp_reg(gcpu, REG_RDX);
cpuid_eax=cpuid_params.eax;
asm_cpuid(&cpuid_params);
for (filter_id=0; ; ++filter_id)
{
if(g_cpuid_filter[filter_id].eax==cpuid_eax)
{
g_cpuid_filter[filter_id].handler(gcpu, &cpuid_params);
break;
}
if(g_cpuid_filter[filter_id].eax>cpuid_eax)
break;
if(g_cpuid_filter[filter_id].handler==NULL)
break;
}
/* write back to guest OS */
gcpu_set_gp_reg(gcpu, REG_RAX, cpuid_params.eax);
gcpu_set_gp_reg(gcpu, REG_RBX, cpuid_params.ebx);
gcpu_set_gp_reg(gcpu, REG_RCX, cpuid_params.ecx);
gcpu_set_gp_reg(gcpu, REG_RDX, cpuid_params.edx);
/* increment IP to skip executed CPUID instruction */
gcpu_skip_instruction(gcpu);
}