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.
24 static const uint32_t kProcbasedCtls2Ept                = 1u << 1;
25 static const uint32_t kProcbasedCtls2Rdtscp             = 1u << 3;
26 static const uint32_t kProcbasedCtls2x2Apic             = 1u << 4;
27 static const uint32_t kProcbasedCtls2Vpid               = 1u << 5;
28 static const uint32_t kProcbasedCtls2UnrestrictedGuest  = 1u << 7;
29 static const uint32_t kProcbasedCtls2Invpcid            = 1u << 12;
30 
31 // PROCBASED_CTLS flags.
32 static const uint32_t kProcbasedCtlsIntWindowExiting    = 1u << 2;
33 static const uint32_t kProcbasedCtlsHltExiting          = 1u << 7;
34 static const uint32_t kProcbasedCtlsCr3LoadExiting      = 1u << 15;
35 static const uint32_t kProcbasedCtlsCr3StoreExiting     = 1u << 16;
36 static const uint32_t kProcbasedCtlsCr8LoadExiting      = 1u << 19;
37 static const uint32_t kProcbasedCtlsCr8StoreExiting     = 1u << 20;
38 static const uint32_t kProcbasedCtlsTprShadow           = 1u << 21;
39 static const uint32_t kProcbasedCtlsIoExiting           = 1u << 24;
40 static const uint32_t kProcbasedCtlsMsrBitmaps          = 1u << 28;
41 static const uint32_t kProcbasedCtlsPauseExiting        = 1u << 30;
42 static const uint32_t kProcbasedCtlsProcbasedCtls2      = 1u << 31;
43 
44 // PINBASED_CTLS flags.
45 static const uint32_t kPinbasedCtlsExtIntExiting        = 1u << 0;
46 static const uint32_t kPinbasedCtlsNmiExiting           = 1u << 3;
47 
48 // EXIT_CTLS flags.
49 static const uint32_t kExitCtls64bitMode                = 1u << 9;
50 static const uint32_t kExitCtlsAckIntOnExit             = 1u << 15;
51 static const uint32_t kExitCtlsSaveIa32Pat              = 1u << 18;
52 static const uint32_t kExitCtlsLoadIa32Pat              = 1u << 19;
53 static const uint32_t kExitCtlsSaveIa32Efer             = 1u << 20;
54 static const uint32_t kExitCtlsLoadIa32Efer             = 1u << 21;
55 
56 // ENTRY_CTLS flags.
57 static const uint32_t kEntryCtlsIa32eMode               = 1u << 9;
58 static const uint32_t kEntryCtlsLoadIa32Pat             = 1u << 14;
59 static const uint32_t kEntryCtlsLoadIa32Efer            = 1u << 15;
60 
61 // LINK_POINTER values.
62 static const uint64_t kLinkPointerInvalidate            = UINT64_MAX;
63 
64 // GUEST_XX_ACCESS_RIGHTS flags.
65 static const uint32_t kGuestXxAccessRightsUnusable      = 1u << 16;
66 // See Volume 3, Section 24.4.1 for access rights format.
67 static const uint32_t kGuestXxAccessRightsTypeA         = 1u << 0;
68 static const uint32_t kGuestXxAccessRightsTypeW         = 1u << 1;
69 static const uint32_t kGuestXxAccessRightsTypeE         = 1u << 2;
70 static const uint32_t kGuestXxAccessRightsTypeCode      = 1u << 3;
71 // See Volume 3, Section 3.4.5.1 for valid non-system selector types.
72 static const uint32_t kGuestXxAccessRightsS             = 1u << 4;
73 static const uint32_t kGuestXxAccessRightsP             = 1u << 7;
74 static const uint32_t kGuestXxAccessRightsL             = 1u << 13;
75 static const uint32_t kGuestXxAccessRightsD             = 1u << 14;
76 // See Volume 3, Section 3.5 for valid system selectors types.
77 static const uint32_t kGuestTrAccessRightsTssBusy16Bit  = 3u << 0;
78 static const uint32_t kGuestTrAccessRightsTssBusy       = 11u << 0;
79 
80 static const uint32_t kGuestXxAccessRightsDefault       = kGuestXxAccessRightsTypeA |
81                                                           kGuestXxAccessRightsTypeW |
82                                                           kGuestXxAccessRightsS |
83                                                           kGuestXxAccessRightsP;
84 
85 // GUEST_INTERRUPTIBILITY_STATE flags.
86 static const uint32_t kInterruptibilityStiBlocking      = 1u << 0;
87 static const uint32_t kInterruptibilityMovSsBlocking    = 1u << 1;
88 
89 // VMCS fields.
90 enum 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 
103 enum 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 
117 enum 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 
163 enum 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.
205 enum 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.
213 class AutoVmcs : public hypervisor::StateInvalidator {
214 public:
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 
234 private:
235     paddr_t vmcs_address_;
236 };
237 
238 // Pins execution to a CPU within a given scope.
239 class AutoPin {
240 public:
241     AutoPin(uint16_t vpid);
242     ~AutoPin();
243 
244 private:
245     cpu_mask_t prev_cpu_mask_;
246     thread_t* thread_;
247 };
248 
249 bool cr0_is_invalid(AutoVmcs* vmcs, uint64_t cr0_value);
250