VirtualBox

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

Last change on this file since 62517 was 62478, checked in by vboxsync, 8 years ago

(C) 2016

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.9 KB
Line 
1/* $Id: GIMAll.cpp 62478 2016-07-22 18:29:06Z vboxsync $ */
2/** @file
3 * GIM - Guest Interface Manager - All Contexts.
4 */
5
6/*
7 * Copyright (C) 2014-2016 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_R3_HYPERCALL re-start the hypercall from ring-3.
95 * @retval VERR_GIM_HYPERCALL_ACCESS_DENIED CPL is insufficient.
96 * @retval VERR_GIM_HYPERCALLS_NOT_AVAILABLE hypercalls unavailable.
97 * @retval VERR_GIM_NOT_ENABLED GIM is not enabled (shouldn't really happen)
98 * @retval VERR_GIM_HYPERCALL_MEMORY_READ_FAILED hypercall failed while reading
99 * memory.
100 * @retval VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED hypercall failed while
101 * writing memory.
102 *
103 * @param pVCpu The cross context virtual CPU structure.
104 * @param pCtx Pointer to the guest-CPU context.
105 *
106 * @thread EMT.
107 */
108VMM_INT_DECL(VBOXSTRICTRC) GIMHypercall(PVMCPU pVCpu, PCPUMCTX pCtx)
109{
110 PVM pVM = pVCpu->CTX_SUFF(pVM);
111 VMCPU_ASSERT_EMT(pVCpu);
112
113 if (RT_UNLIKELY(!GIMIsEnabled(pVM)))
114 return VERR_GIM_NOT_ENABLED;
115
116 switch (pVM->gim.s.enmProviderId)
117 {
118 case GIMPROVIDERID_HYPERV:
119 return gimHvHypercall(pVCpu, pCtx);
120
121 case GIMPROVIDERID_KVM:
122 return gimKvmHypercall(pVCpu, pCtx);
123
124 default:
125 AssertMsgFailed(("GIMHypercall: for provider %u not available/implemented\n", pVM->gim.s.enmProviderId));
126 return VERR_GIM_HYPERCALLS_NOT_AVAILABLE;
127 }
128}
129
130
131/**
132 * Disassembles the instruction at RIP and if it's a hypercall
133 * instruction, performs the hypercall.
134 *
135 * @param pVCpu The cross context virtual CPU structure.
136 * @param pCtx Pointer to the guest-CPU context.
137 * @param pcbInstr Where to store the disassembled instruction length.
138 * Optional, can be NULL.
139 *
140 * @todo This interface should disappear when IEM/REM execution engines
141 * handle VMCALL/VMMCALL instructions to call into GIM when
142 * required. See @bugref{7270#c168}.
143 */
144VMM_INT_DECL(VBOXSTRICTRC) GIMExecHypercallInstr(PVMCPU pVCpu, PCPUMCTX pCtx, uint8_t *pcbInstr)
145{
146 PVM pVM = pVCpu->CTX_SUFF(pVM);
147 VMCPU_ASSERT_EMT(pVCpu);
148
149 if (RT_UNLIKELY(!GIMIsEnabled(pVM)))
150 return VERR_GIM_NOT_ENABLED;
151
152 unsigned cbInstr;
153 DISCPUSTATE Dis;
154 int rc = EMInterpretDisasCurrent(pVM, pVCpu, &Dis, &cbInstr);
155 if (RT_SUCCESS(rc))
156 {
157 if (pcbInstr)
158 *pcbInstr = (uint8_t)cbInstr;
159 switch (pVM->gim.s.enmProviderId)
160 {
161 case GIMPROVIDERID_HYPERV:
162 return gimHvExecHypercallInstr(pVCpu, pCtx, &Dis);
163
164 case GIMPROVIDERID_KVM:
165 return gimKvmExecHypercallInstr(pVCpu, pCtx, &Dis);
166
167 default:
168 AssertMsgFailed(("GIMExecHypercallInstr: for provider %u not available/implemented\n", pVM->gim.s.enmProviderId));
169 return VERR_GIM_HYPERCALLS_NOT_AVAILABLE;
170 }
171 }
172
173 Log(("GIM: GIMExecHypercallInstr: Failed to disassemble CS:RIP=%04x:%08RX64. rc=%Rrc\n", pCtx->cs.Sel, pCtx->rip, rc));
174 return rc;
175}
176
177
178/**
179 * Returns whether the guest has configured and setup the use of paravirtualized
180 * TSC.
181 *
182 * Paravirtualized TSCs are per-VM and the rest of the execution engine logic
183 * relies on that.
184 *
185 * @returns true if enabled and usable, false otherwise.
186 * @param pVM The cross context VM structure.
187 */
188VMM_INT_DECL(bool) GIMIsParavirtTscEnabled(PVM pVM)
189{
190 switch (pVM->gim.s.enmProviderId)
191 {
192 case GIMPROVIDERID_HYPERV:
193 return gimHvIsParavirtTscEnabled(pVM);
194
195 case GIMPROVIDERID_KVM:
196 return gimKvmIsParavirtTscEnabled(pVM);
197
198 default:
199 break;
200 }
201 return false;
202}
203
204
205/**
206 * Whether \#UD exceptions in the guest needs to be intercepted by the GIM
207 * provider.
208 *
209 * At the moment, the reason why this isn't a more generic interface wrt to
210 * exceptions is because of performance (each VM-exit would have to manually
211 * check whether or not GIM needs to be notified). Left as a todo for later if
212 * really required.
213 *
214 * @returns true if needed, false otherwise.
215 * @param pVCpu The cross context virtual CPU structure.
216 */
217VMM_INT_DECL(bool) GIMShouldTrapXcptUD(PVMCPU pVCpu)
218{
219 PVM pVM = pVCpu->CTX_SUFF(pVM);
220 if (!GIMIsEnabled(pVM))
221 return false;
222
223 switch (pVM->gim.s.enmProviderId)
224 {
225 case GIMPROVIDERID_KVM:
226 return gimKvmShouldTrapXcptUD(pVCpu);
227
228 case GIMPROVIDERID_HYPERV:
229 return gimHvShouldTrapXcptUD(pVCpu);
230
231 default:
232 return false;
233 }
234}
235
236
237/**
238 * Exception handler for \#UD when requested by the GIM provider.
239 *
240 * @returns Strict VBox status code.
241 * @retval VINF_SUCCESS if the hypercall succeeded (even if its operation
242 * failed).
243 * @retval VINF_GIM_R3_HYPERCALL restart the hypercall from ring-3.
244 * @retval VINF_GIM_HYPERCALL_CONTINUING continue hypercall without updating
245 * RIP.
246 * @retval VERR_GIM_HYPERCALL_ACCESS_DENIED CPL is insufficient.
247 * @retval VERR_GIM_INVALID_HYPERCALL_INSTR instruction at RIP is not a valid
248 * hypercall instruction.
249 *
250 * @param pVCpu The cross context virtual CPU structure.
251 * @param pCtx Pointer to the guest-CPU context.
252 * @param pDis Pointer to the disassembled instruction state at RIP.
253 * If NULL is passed, it implies the disassembly of the
254 * the instruction at RIP is the responsibility of the
255 * GIM provider.
256 * @param pcbInstr Where to store the instruction length of the hypercall
257 * instruction. Optional, can be NULL.
258 *
259 * @thread EMT(pVCpu).
260 */
261VMM_INT_DECL(VBOXSTRICTRC) GIMXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis, uint8_t *pcbInstr)
262{
263 PVM pVM = pVCpu->CTX_SUFF(pVM);
264 Assert(GIMIsEnabled(pVM));
265 Assert(pDis || pcbInstr);
266
267 switch (pVM->gim.s.enmProviderId)
268 {
269 case GIMPROVIDERID_KVM:
270 return gimKvmXcptUD(pVCpu, pCtx, pDis, pcbInstr);
271
272 case GIMPROVIDERID_HYPERV:
273 return gimHvXcptUD(pVCpu, pCtx, pDis, pcbInstr);
274
275 default:
276 return VERR_GIM_OPERATION_FAILED;
277 }
278}
279
280
281/**
282 * Invokes the read-MSR handler for the GIM provider configured for the VM.
283 *
284 * @returns Strict VBox status code like CPUMQueryGuestMsr.
285 * @retval VINF_CPUM_R3_MSR_READ
286 * @retval VERR_CPUM_RAISE_GP_0
287 *
288 * @param pVCpu The cross context virtual CPU structure.
289 * @param idMsr The MSR to read.
290 * @param pRange The range this MSR belongs to.
291 * @param puValue Where to store the MSR value read.
292 */
293VMM_INT_DECL(VBOXSTRICTRC) GIMReadMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue)
294{
295 Assert(pVCpu);
296 PVM pVM = pVCpu->CTX_SUFF(pVM);
297 Assert(GIMIsEnabled(pVM));
298 VMCPU_ASSERT_EMT(pVCpu);
299
300 switch (pVM->gim.s.enmProviderId)
301 {
302 case GIMPROVIDERID_HYPERV:
303 return gimHvReadMsr(pVCpu, idMsr, pRange, puValue);
304
305 case GIMPROVIDERID_KVM:
306 return gimKvmReadMsr(pVCpu, idMsr, pRange, puValue);
307
308 default:
309 AssertMsgFailed(("GIMReadMsr: for unknown provider %u idMsr=%#RX32 -> #GP(0)", pVM->gim.s.enmProviderId, idMsr));
310 return VERR_CPUM_RAISE_GP_0;
311 }
312}
313
314
315/**
316 * Invokes the write-MSR handler for the GIM provider configured for the VM.
317 *
318 * @returns Strict VBox status code like CPUMSetGuestMsr.
319 * @retval VINF_CPUM_R3_MSR_WRITE
320 * @retval VERR_CPUM_RAISE_GP_0
321 *
322 * @param pVCpu The cross context virtual CPU structure.
323 * @param idMsr The MSR to write.
324 * @param pRange The range this MSR belongs to.
325 * @param uValue The value to set, ignored bits masked.
326 * @param uRawValue The raw value with the ignored bits not masked.
327 */
328VMM_INT_DECL(VBOXSTRICTRC) GIMWriteMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uValue, uint64_t uRawValue)
329{
330 AssertPtr(pVCpu);
331 NOREF(uValue);
332
333 PVM pVM = pVCpu->CTX_SUFF(pVM);
334 Assert(GIMIsEnabled(pVM));
335 VMCPU_ASSERT_EMT(pVCpu);
336
337 switch (pVM->gim.s.enmProviderId)
338 {
339 case GIMPROVIDERID_HYPERV:
340 return gimHvWriteMsr(pVCpu, idMsr, pRange, uRawValue);
341
342 case GIMPROVIDERID_KVM:
343 return gimKvmWriteMsr(pVCpu, idMsr, pRange, uRawValue);
344
345 default:
346 AssertMsgFailed(("GIMWriteMsr: for unknown provider %u idMsr=%#RX32 -> #GP(0)", pVM->gim.s.enmProviderId, idMsr));
347 return VERR_CPUM_RAISE_GP_0;
348 }
349}
350
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