VirtualBox

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

Last change on this file since 61568 was 61559, checked in by vboxsync, 9 years ago

VMM/GIM: Comment typos.

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