VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/GIMAll.cpp@ 72255

Last change on this file since 72255 was 69111, checked in by vboxsync, 7 years ago

(C) year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.0 KB
Line 
1/* $Id: GIMAll.cpp 69111 2017-10-17 14:26:02Z vboxsync $ */
2/** @file
3 * GIM - Guest Interface Manager - All Contexts.
4 */
5
6/*
7 * Copyright (C) 2014-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_GIM
23#include <VBox/vmm/gim.h>
24#include <VBox/vmm/em.h> /* For EMInterpretDisasCurrent */
25#include "GIMInternal.h"
26#include <VBox/vmm/vm.h>
27
28#include <VBox/dis.h> /* For DISCPUSTATE */
29#include <VBox/err.h>
30
31/* Include all the providers. */
32#include "GIMHvInternal.h"
33#include "GIMMinimalInternal.h"
34
35
36/**
37 * Checks whether GIM is being used by this VM.
38 *
39 * @retval true if used.
40 * @retval false if no GIM provider ("none") is used.
41 *
42 * @param pVM The cross context VM structure.
43 */
44VMMDECL(bool) GIMIsEnabled(PVM pVM)
45{
46 return pVM->gim.s.enmProviderId != GIMPROVIDERID_NONE;
47}
48
49
50/**
51 * Gets the GIM provider configured for this VM.
52 *
53 * @returns The GIM provider Id.
54 * @param pVM The cross context VM structure.
55 */
56VMMDECL(GIMPROVIDERID) GIMGetProvider(PVM pVM)
57{
58 return pVM->gim.s.enmProviderId;
59}
60
61
62/**
63 * Returns whether the guest has configured and enabled calls to the hypervisor.
64 *
65 * @returns true if hypercalls are enabled and usable, false otherwise.
66 * @param pVCpu The cross context virtual CPU structure.
67 */
68VMM_INT_DECL(bool) GIMAreHypercallsEnabled(PVMCPU pVCpu)
69{
70 PVM pVM = pVCpu->CTX_SUFF(pVM);
71 if (!GIMIsEnabled(pVM))
72 return false;
73
74 switch (pVM->gim.s.enmProviderId)
75 {
76 case GIMPROVIDERID_HYPERV:
77 return gimHvAreHypercallsEnabled(pVCpu);
78
79 case GIMPROVIDERID_KVM:
80 return gimKvmAreHypercallsEnabled(pVCpu);
81
82 default:
83 return false;
84 }
85}
86
87
88/**
89 * Implements a GIM hypercall with the provider configured for the VM.
90 *
91 * @returns Strict VBox status code.
92 * @retval VINF_SUCCESS if the hypercall succeeded (even if its operation
93 * failed).
94 * @retval VINF_GIM_HYPERCALL_CONTINUING continue hypercall without updating
95 * RIP.
96 * @retval VINF_GIM_R3_HYPERCALL re-start the hypercall from ring-3.
97 * @retval VERR_GIM_HYPERCALL_ACCESS_DENIED CPL is insufficient.
98 * @retval VERR_GIM_HYPERCALLS_NOT_AVAILABLE hypercalls unavailable.
99 * @retval VERR_GIM_NOT_ENABLED GIM is not enabled (shouldn't really happen)
100 * @retval VERR_GIM_HYPERCALL_MEMORY_READ_FAILED hypercall failed while reading
101 * memory.
102 * @retval VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED hypercall failed while
103 * writing memory.
104 *
105 * @param pVCpu The cross context virtual CPU structure.
106 * @param pCtx Pointer to the guest-CPU context.
107 *
108 * @remarks The caller of this function needs to advance RIP as required.
109 * @thread EMT.
110 */
111VMM_INT_DECL(VBOXSTRICTRC) GIMHypercall(PVMCPU pVCpu, PCPUMCTX pCtx)
112{
113 PVM pVM = pVCpu->CTX_SUFF(pVM);
114 VMCPU_ASSERT_EMT(pVCpu);
115
116 if (RT_UNLIKELY(!GIMIsEnabled(pVM)))
117 return VERR_GIM_NOT_ENABLED;
118
119 switch (pVM->gim.s.enmProviderId)
120 {
121 case GIMPROVIDERID_HYPERV:
122 return gimHvHypercall(pVCpu, pCtx);
123
124 case GIMPROVIDERID_KVM:
125 return gimKvmHypercall(pVCpu, pCtx);
126
127 default:
128 AssertMsgFailed(("GIMHypercall: for provider %u not available/implemented\n", pVM->gim.s.enmProviderId));
129 return VERR_GIM_HYPERCALLS_NOT_AVAILABLE;
130 }
131}
132
133
134/**
135 * Disassembles the instruction at RIP and if it's a hypercall
136 * instruction, performs the hypercall.
137 *
138 * @param pVCpu The cross context virtual CPU structure.
139 * @param pCtx Pointer to the guest-CPU context.
140 * @param pcbInstr Where to store the disassembled instruction length.
141 * Optional, can be NULL.
142 *
143 * @todo This interface should disappear when IEM/REM execution engines
144 * handle VMCALL/VMMCALL instructions to call into GIM when
145 * required. See @bugref{7270#c168}.
146 */
147VMM_INT_DECL(VBOXSTRICTRC) GIMExecHypercallInstr(PVMCPU pVCpu, PCPUMCTX pCtx, uint8_t *pcbInstr)
148{
149 PVM pVM = pVCpu->CTX_SUFF(pVM);
150 VMCPU_ASSERT_EMT(pVCpu);
151
152 if (RT_UNLIKELY(!GIMIsEnabled(pVM)))
153 return VERR_GIM_NOT_ENABLED;
154
155 unsigned cbInstr;
156 DISCPUSTATE Dis;
157 int rc = EMInterpretDisasCurrent(pVM, pVCpu, &Dis, &cbInstr);
158 if (RT_SUCCESS(rc))
159 {
160 if (pcbInstr)
161 *pcbInstr = (uint8_t)cbInstr;
162 switch (pVM->gim.s.enmProviderId)
163 {
164 case GIMPROVIDERID_HYPERV:
165 return gimHvExecHypercallInstr(pVCpu, pCtx, &Dis);
166
167 case GIMPROVIDERID_KVM:
168 return gimKvmExecHypercallInstr(pVCpu, pCtx, &Dis);
169
170 default:
171 AssertMsgFailed(("GIMExecHypercallInstr: for provider %u not available/implemented\n", pVM->gim.s.enmProviderId));
172 return VERR_GIM_HYPERCALLS_NOT_AVAILABLE;
173 }
174 }
175
176 Log(("GIM: GIMExecHypercallInstr: Failed to disassemble CS:RIP=%04x:%08RX64. rc=%Rrc\n", pCtx->cs.Sel, pCtx->rip, rc));
177 return rc;
178}
179
180
181/**
182 * Returns whether the guest has configured and setup the use of paravirtualized
183 * TSC.
184 *
185 * Paravirtualized TSCs are per-VM and the rest of the execution engine logic
186 * relies on that.
187 *
188 * @returns true if enabled and usable, false otherwise.
189 * @param pVM The cross context VM structure.
190 */
191VMM_INT_DECL(bool) GIMIsParavirtTscEnabled(PVM pVM)
192{
193 switch (pVM->gim.s.enmProviderId)
194 {
195 case GIMPROVIDERID_HYPERV:
196 return gimHvIsParavirtTscEnabled(pVM);
197
198 case GIMPROVIDERID_KVM:
199 return gimKvmIsParavirtTscEnabled(pVM);
200
201 default:
202 break;
203 }
204 return false;
205}
206
207
208/**
209 * Whether \#UD exceptions in the guest needs to be intercepted by the GIM
210 * provider.
211 *
212 * At the moment, the reason why this isn't a more generic interface wrt to
213 * exceptions is because of performance (each VM-exit would have to manually
214 * check whether or not GIM needs to be notified). Left as a todo for later if
215 * really required.
216 *
217 * @returns true if needed, false otherwise.
218 * @param pVCpu The cross context virtual CPU structure.
219 */
220VMM_INT_DECL(bool) GIMShouldTrapXcptUD(PVMCPU pVCpu)
221{
222 PVM pVM = pVCpu->CTX_SUFF(pVM);
223 if (!GIMIsEnabled(pVM))
224 return false;
225
226 switch (pVM->gim.s.enmProviderId)
227 {
228 case GIMPROVIDERID_KVM:
229 return gimKvmShouldTrapXcptUD(pVCpu);
230
231 case GIMPROVIDERID_HYPERV:
232 return gimHvShouldTrapXcptUD(pVCpu);
233
234 default:
235 return false;
236 }
237}
238
239
240/**
241 * Exception handler for \#UD when requested by the GIM provider.
242 *
243 * @returns Strict VBox status code.
244 * @retval VINF_SUCCESS if the hypercall succeeded (even if its operation
245 * failed).
246 * @retval VINF_GIM_R3_HYPERCALL restart the hypercall from ring-3.
247 * @retval VINF_GIM_HYPERCALL_CONTINUING continue hypercall without updating
248 * RIP.
249 * @retval VERR_GIM_HYPERCALL_ACCESS_DENIED CPL is insufficient.
250 * @retval VERR_GIM_INVALID_HYPERCALL_INSTR instruction at RIP is not a valid
251 * hypercall instruction.
252 *
253 * @param pVCpu The cross context virtual CPU structure.
254 * @param pCtx Pointer to the guest-CPU context.
255 * @param pDis Pointer to the disassembled instruction state at RIP.
256 * If NULL is passed, it implies the disassembly of the
257 * the instruction at RIP is the responsibility of the
258 * GIM provider.
259 * @param pcbInstr Where to store the instruction length of the hypercall
260 * instruction. Optional, can be NULL.
261 *
262 * @thread EMT(pVCpu).
263 */
264VMM_INT_DECL(VBOXSTRICTRC) GIMXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis, uint8_t *pcbInstr)
265{
266 PVM pVM = pVCpu->CTX_SUFF(pVM);
267 Assert(GIMIsEnabled(pVM));
268 Assert(pDis || pcbInstr);
269
270 switch (pVM->gim.s.enmProviderId)
271 {
272 case GIMPROVIDERID_KVM:
273 return gimKvmXcptUD(pVCpu, pCtx, pDis, pcbInstr);
274
275 case GIMPROVIDERID_HYPERV:
276 return gimHvXcptUD(pVCpu, pCtx, pDis, pcbInstr);
277
278 default:
279 return VERR_GIM_OPERATION_FAILED;
280 }
281}
282
283
284/**
285 * Invokes the read-MSR handler for the GIM provider configured for the VM.
286 *
287 * @returns Strict VBox status code like CPUMQueryGuestMsr.
288 * @retval VINF_CPUM_R3_MSR_READ
289 * @retval VERR_CPUM_RAISE_GP_0
290 *
291 * @param pVCpu The cross context virtual CPU structure.
292 * @param idMsr The MSR to read.
293 * @param pRange The range this MSR belongs to.
294 * @param puValue Where to store the MSR value read.
295 */
296VMM_INT_DECL(VBOXSTRICTRC) GIMReadMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue)
297{
298 Assert(pVCpu);
299 PVM pVM = pVCpu->CTX_SUFF(pVM);
300 Assert(GIMIsEnabled(pVM));
301 VMCPU_ASSERT_EMT(pVCpu);
302
303 switch (pVM->gim.s.enmProviderId)
304 {
305 case GIMPROVIDERID_HYPERV:
306 return gimHvReadMsr(pVCpu, idMsr, pRange, puValue);
307
308 case GIMPROVIDERID_KVM:
309 return gimKvmReadMsr(pVCpu, idMsr, pRange, puValue);
310
311 default:
312 AssertMsgFailed(("GIMReadMsr: for unknown provider %u idMsr=%#RX32 -> #GP(0)", pVM->gim.s.enmProviderId, idMsr));
313 return VERR_CPUM_RAISE_GP_0;
314 }
315}
316
317
318/**
319 * Invokes the write-MSR handler for the GIM provider configured for the VM.
320 *
321 * @returns Strict VBox status code like CPUMSetGuestMsr.
322 * @retval VINF_CPUM_R3_MSR_WRITE
323 * @retval VERR_CPUM_RAISE_GP_0
324 *
325 * @param pVCpu The cross context virtual CPU structure.
326 * @param idMsr The MSR to write.
327 * @param pRange The range this MSR belongs to.
328 * @param uValue The value to set, ignored bits masked.
329 * @param uRawValue The raw value with the ignored bits not masked.
330 */
331VMM_INT_DECL(VBOXSTRICTRC) GIMWriteMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uValue, uint64_t uRawValue)
332{
333 AssertPtr(pVCpu);
334 NOREF(uValue);
335
336 PVM pVM = pVCpu->CTX_SUFF(pVM);
337 Assert(GIMIsEnabled(pVM));
338 VMCPU_ASSERT_EMT(pVCpu);
339
340 switch (pVM->gim.s.enmProviderId)
341 {
342 case GIMPROVIDERID_HYPERV:
343 return gimHvWriteMsr(pVCpu, idMsr, pRange, uRawValue);
344
345 case GIMPROVIDERID_KVM:
346 return gimKvmWriteMsr(pVCpu, idMsr, pRange, uRawValue);
347
348 default:
349 AssertMsgFailed(("GIMWriteMsr: for unknown provider %u idMsr=%#RX32 -> #GP(0)", pVM->gim.s.enmProviderId, idMsr));
350 return VERR_CPUM_RAISE_GP_0;
351 }
352}
353
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette