1// Copyright 2017 The Fuchsia Authors
2//
3// Use of this source code is governed by a MIT-style
4// license that can be found in the LICENSE file or at
5// https://opensource.org/licenses/MIT
6
7#pragma once
8
9#include <hypervisor/state_invalidator.h>
10
11// clang-format off
12
13#define X86_MSR_IA32_VMX_PINBASED_CTLS                  0x0481
14#define X86_MSR_IA32_VMX_PROCBASED_CTLS                 0x0482
15#define X86_MSR_IA32_VMX_EXIT_CTLS                      0x0483
16#define X86_MSR_IA32_VMX_ENTRY_CTLS                     0x0484
17#define X86_MSR_IA32_VMX_PROCBASED_CTLS2                0x048b
18#define X86_MSR_IA32_VMX_TRUE_PINBASED_CTLS             0x048d
19#define X86_MSR_IA32_VMX_TRUE_PROCBASED_CTLS            0x048e
20#define X86_MSR_IA32_VMX_TRUE_EXIT_CTLS                 0x048f
21#define X86_MSR_IA32_VMX_TRUE_ENTRY_CTLS                0x0490
22
23// PROCBASED_CTLS2 flags.
24static const uint32_t kProcbasedCtls2Ept                = 1u << 1;
25static const uint32_t kProcbasedCtls2Rdtscp             = 1u << 3;
26static const uint32_t kProcbasedCtls2x2Apic             = 1u << 4;
27static const uint32_t kProcbasedCtls2Vpid               = 1u << 5;
28static const uint32_t kProcbasedCtls2UnrestrictedGuest  = 1u << 7;
29static const uint32_t kProcbasedCtls2Invpcid            = 1u << 12;
30
31// PROCBASED_CTLS flags.
32static const uint32_t kProcbasedCtlsIntWindowExiting    = 1u << 2;
33static const uint32_t kProcbasedCtlsHltExiting          = 1u << 7;
34static const uint32_t kProcbasedCtlsCr3LoadExiting      = 1u << 15;
35static const uint32_t kProcbasedCtlsCr3StoreExiting     = 1u << 16;
36static const uint32_t kProcbasedCtlsCr8LoadExiting      = 1u << 19;
37static const uint32_t kProcbasedCtlsCr8StoreExiting     = 1u << 20;
38static const uint32_t kProcbasedCtlsTprShadow           = 1u << 21;
39static const uint32_t kProcbasedCtlsIoExiting           = 1u << 24;
40static const uint32_t kProcbasedCtlsMsrBitmaps          = 1u << 28;
41static const uint32_t kProcbasedCtlsPauseExiting        = 1u << 30;
42static const uint32_t kProcbasedCtlsProcbasedCtls2      = 1u << 31;
43
44// PINBASED_CTLS flags.
45static const uint32_t kPinbasedCtlsExtIntExiting        = 1u << 0;
46static const uint32_t kPinbasedCtlsNmiExiting           = 1u << 3;
47
48// EXIT_CTLS flags.
49static const uint32_t kExitCtls64bitMode                = 1u << 9;
50static const uint32_t kExitCtlsAckIntOnExit             = 1u << 15;
51static const uint32_t kExitCtlsSaveIa32Pat              = 1u << 18;
52static const uint32_t kExitCtlsLoadIa32Pat              = 1u << 19;
53static const uint32_t kExitCtlsSaveIa32Efer             = 1u << 20;
54static const uint32_t kExitCtlsLoadIa32Efer             = 1u << 21;
55
56// ENTRY_CTLS flags.
57static const uint32_t kEntryCtlsIa32eMode               = 1u << 9;
58static const uint32_t kEntryCtlsLoadIa32Pat             = 1u << 14;
59static const uint32_t kEntryCtlsLoadIa32Efer            = 1u << 15;
60
61// LINK_POINTER values.
62static const uint64_t kLinkPointerInvalidate            = UINT64_MAX;
63
64// GUEST_XX_ACCESS_RIGHTS flags.
65static const uint32_t kGuestXxAccessRightsUnusable      = 1u << 16;
66// See Volume 3, Section 24.4.1 for access rights format.
67static const uint32_t kGuestXxAccessRightsTypeA         = 1u << 0;
68static const uint32_t kGuestXxAccessRightsTypeW         = 1u << 1;
69static const uint32_t kGuestXxAccessRightsTypeE         = 1u << 2;
70static const uint32_t kGuestXxAccessRightsTypeCode      = 1u << 3;
71// See Volume 3, Section 3.4.5.1 for valid non-system selector types.
72static const uint32_t kGuestXxAccessRightsS             = 1u << 4;
73static const uint32_t kGuestXxAccessRightsP             = 1u << 7;
74static const uint32_t kGuestXxAccessRightsL             = 1u << 13;
75static const uint32_t kGuestXxAccessRightsD             = 1u << 14;
76// See Volume 3, Section 3.5 for valid system selectors types.
77static const uint32_t kGuestTrAccessRightsTssBusy16Bit  = 3u << 0;
78static const uint32_t kGuestTrAccessRightsTssBusy       = 11u << 0;
79
80static const uint32_t kGuestXxAccessRightsDefault       = kGuestXxAccessRightsTypeA |
81                                                          kGuestXxAccessRightsTypeW |
82                                                          kGuestXxAccessRightsS |
83                                                          kGuestXxAccessRightsP;
84
85// GUEST_INTERRUPTIBILITY_STATE flags.
86static const uint32_t kInterruptibilityStiBlocking      = 1u << 0;
87static const uint32_t kInterruptibilityMovSsBlocking    = 1u << 1;
88
89// VMCS fields.
90enum class VmcsField16 : uint64_t {
91    VPID                                                = 0x0000,
92    GUEST_CS_SELECTOR                                   = 0x0802,
93    GUEST_TR_SELECTOR                                   = 0x080e,
94    HOST_ES_SELECTOR                                    = 0x0c00,
95    HOST_CS_SELECTOR                                    = 0x0c02,
96    HOST_SS_SELECTOR                                    = 0x0c04,
97    HOST_DS_SELECTOR                                    = 0x0c06,
98    HOST_FS_SELECTOR                                    = 0x0c08,
99    HOST_GS_SELECTOR                                    = 0x0c0a,
100    HOST_TR_SELECTOR                                    = 0x0c0c,
101};
102
103enum class VmcsField64 : uint64_t {
104    MSR_BITMAPS_ADDRESS                                 = 0x2004,
105    EXIT_MSR_STORE_ADDRESS                              = 0x2006,
106    EXIT_MSR_LOAD_ADDRESS                               = 0x2008,
107    ENTRY_MSR_LOAD_ADDRESS                              = 0x200a,
108    EPT_POINTER                                         = 0x201a,
109    GUEST_PHYSICAL_ADDRESS                              = 0x2400,
110    LINK_POINTER                                        = 0x2800,
111    GUEST_IA32_PAT                                      = 0x2804,
112    GUEST_IA32_EFER                                     = 0x2806,
113    HOST_IA32_PAT                                       = 0x2c00,
114    HOST_IA32_EFER                                      = 0x2c02,
115};
116
117enum class VmcsField32 : uint64_t {
118    PINBASED_CTLS                                       = 0x4000,
119    PROCBASED_CTLS                                      = 0x4002,
120    EXCEPTION_BITMAP                                    = 0x4004,
121    PAGEFAULT_ERRORCODE_MASK                            = 0x4006,
122    PAGEFAULT_ERRORCODE_MATCH                           = 0x4008,
123    EXIT_CTLS                                           = 0x400c,
124    EXIT_MSR_STORE_COUNT                                = 0x400e,
125    EXIT_MSR_LOAD_COUNT                                 = 0x4010,
126    ENTRY_CTLS                                          = 0x4012,
127    ENTRY_MSR_LOAD_COUNT                                = 0x4014,
128    ENTRY_INTERRUPTION_INFORMATION                      = 0x4016,
129    ENTRY_EXCEPTION_ERROR_CODE                          = 0x4018,
130    PROCBASED_CTLS2                                     = 0x401e,
131    INSTRUCTION_ERROR                                   = 0x4400,
132    EXIT_REASON                                         = 0x4402,
133    EXIT_INTERRUPTION_INFORMATION                       = 0x4404,
134    EXIT_INTERRUPTION_ERROR_CODE                        = 0x4406,
135    EXIT_INSTRUCTION_LENGTH                             = 0x440c,
136    EXIT_INSTRUCTION_INFORMATION                        = 0x440e,
137    HOST_IA32_SYSENTER_CS                               = 0x4c00,
138
139    GUEST_ES_LIMIT                                      = 0x4800,
140    GUEST_CS_LIMIT                                      = 0x4802,
141    GUEST_SS_LIMIT                                      = 0x4804,
142    GUEST_DS_LIMIT                                      = 0x4806,
143    GUEST_FS_LIMIT                                      = 0x4808,
144    GUEST_GS_LIMIT                                      = 0x480a,
145    GUEST_LDTR_LIMIT                                    = 0x480c,
146    GUEST_TR_LIMIT                                      = 0x480e,
147
148    GUEST_GDTR_LIMIT                                    = 0x4810,
149    GUEST_IDTR_LIMIT                                    = 0x4812,
150    GUEST_CS_ACCESS_RIGHTS                              = 0x4816,
151    GUEST_ES_ACCESS_RIGHTS                              = 0x4814,
152    GUEST_SS_ACCESS_RIGHTS                              = 0x4818,
153    GUEST_DS_ACCESS_RIGHTS                              = 0x481a,
154    GUEST_FS_ACCESS_RIGHTS                              = 0x481c,
155    GUEST_GS_ACCESS_RIGHTS                              = 0x481e,
156    GUEST_LDTR_ACCESS_RIGHTS                            = 0x4820,
157    GUEST_TR_ACCESS_RIGHTS                              = 0x4822,
158    GUEST_INTERRUPTIBILITY_STATE                        = 0x4824,
159    GUEST_ACTIVITY_STATE                                = 0x4826,
160    GUEST_IA32_SYSENTER_CS                              = 0x482a,
161};
162
163enum class VmcsFieldXX : uint64_t {
164    CR0_GUEST_HOST_MASK                                 = 0x6000,
165    CR4_GUEST_HOST_MASK                                 = 0x6002,
166    CR0_READ_SHADOW                                     = 0x6004,
167    CR4_READ_SHADOW                                     = 0x6006,
168    EXIT_QUALIFICATION                                  = 0x6400,
169    GUEST_LINEAR_ADDRESS                                = 0x640a,
170    GUEST_CR0                                           = 0x6800,
171    GUEST_CR3                                           = 0x6802,
172    GUEST_CR4                                           = 0x6804,
173
174    GUEST_ES_BASE                                       = 0x6806,
175    GUEST_CS_BASE                                       = 0x6808,
176    GUEST_SS_BASE                                       = 0x680A,
177    GUEST_DS_BASE                                       = 0x680C,
178    GUEST_FS_BASE                                       = 0x680E,
179    GUEST_GS_BASE                                       = 0x6810,
180    GUEST_TR_BASE                                       = 0x6814,
181
182    GUEST_GDTR_BASE                                     = 0x6816,
183    GUEST_IDTR_BASE                                     = 0x6818,
184    GUEST_RSP                                           = 0x681c,
185    GUEST_RIP                                           = 0x681e,
186    GUEST_RFLAGS                                        = 0x6820,
187    GUEST_PENDING_DEBUG_EXCEPTIONS                      = 0x6822,
188    GUEST_IA32_SYSENTER_ESP                             = 0x6824,
189    GUEST_IA32_SYSENTER_EIP                             = 0x6826,
190    HOST_CR0                                            = 0x6c00,
191    HOST_CR3                                            = 0x6c02,
192    HOST_CR4                                            = 0x6c04,
193    HOST_FS_BASE                                        = 0x6c06,
194    HOST_GS_BASE                                        = 0x6c08,
195    HOST_TR_BASE                                        = 0x6c0a,
196    HOST_GDTR_BASE                                      = 0x6c0c,
197    HOST_IDTR_BASE                                      = 0x6c0e,
198    HOST_IA32_SYSENTER_ESP                              = 0x6c10,
199    HOST_IA32_SYSENTER_EIP                              = 0x6c12,
200    HOST_RSP                                            = 0x6c14,
201    HOST_RIP                                            = 0x6c16,
202};
203
204// INVEPT invalidation types.
205enum class InvEpt : uint64_t {
206    SINGLE_CONTEXT                                      = 1,
207    ALL_CONTEXT                                         = 2,
208};
209
210// clang-format on
211
212// Loads a VMCS within a given scope.
213class AutoVmcs : public hypervisor::StateInvalidator {
214public:
215    AutoVmcs(paddr_t vmcs_address_);
216    ~AutoVmcs();
217
218    void Invalidate() override;
219    void InterruptWindowExiting(bool enable);
220    void IssueInterrupt(uint32_t vector);
221
222    uint16_t Read(VmcsField16 field) const;
223    uint32_t Read(VmcsField32 field) const;
224    uint64_t Read(VmcsField64 field) const;
225    uint64_t Read(VmcsFieldXX field) const;
226    void Write(VmcsField16 field, uint16_t val);
227    void Write(VmcsField32 field, uint32_t val);
228    void Write(VmcsField64 field, uint64_t val);
229    void Write(VmcsFieldXX field, uint64_t val);
230
231    zx_status_t SetControl(VmcsField32 controls, uint64_t true_msr, uint64_t old_msr, uint32_t set,
232                           uint32_t clear);
233
234private:
235    paddr_t vmcs_address_;
236};
237
238// Pins execution to a CPU within a given scope.
239class AutoPin {
240public:
241    AutoPin(uint16_t vpid);
242    ~AutoPin();
243
244private:
245    cpu_mask_t prev_cpu_mask_;
246    thread_t* thread_;
247};
248
249bool cr0_is_invalid(AutoVmcs* vmcs, uint64_t cr0_value);
250