summaryrefslogtreecommitdiffstats
path: root/src/VBox/VMM/include/EMHandleRCTmpl.h
blob: 758dfad43867cec44d8e5f192f1c329def6bbd28 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
/* $Id: EMHandleRCTmpl.h $ */
/** @file
 * EM - emR3[Raw|Hm|Nem]HandleRC template.
 */

/*
 * Copyright (C) 2006-2020 Oracle Corporation
 *
 * This file is part of VirtualBox Open Source Edition (OSE), as
 * available from http://www.virtualbox.org. This file is free software;
 * you can redistribute it and/or modify it under the terms of the GNU
 * General Public License (GPL) as published by the Free Software
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 */

#ifndef VMM_INCLUDED_SRC_include_EMHandleRCTmpl_h
#define VMM_INCLUDED_SRC_include_EMHandleRCTmpl_h
#ifndef RT_WITHOUT_PRAGMA_ONCE
# pragma once
#endif

#if defined(EMHANDLERC_WITH_PATM) + defined(EMHANDLERC_WITH_HM) + defined(EMHANDLERC_WITH_NEM) != 1
# error "Exactly one of these must be defined: EMHANDLERC_WITH_PATM, EMHANDLERC_WITH_HM, EMHANDLERC_WITH_NEM"
#endif


/**
 * Process a subset of the raw-mode, HM and NEM return codes.
 *
 * Since we have to share this with raw-mode single stepping, this inline
 * function has been created to avoid code duplication.
 *
 * @returns VINF_SUCCESS if it's ok to continue raw mode.
 * @returns VBox status code to return to the EM main loop.
 *
 * @param   pVM     The cross context VM structure.
 * @param   pVCpu   The cross context virtual CPU structure.
 * @param   rc      The return code.
 */
#if defined(EMHANDLERC_WITH_HM) || defined(DOXYGEN_RUNNING)
int emR3HmHandleRC(PVM pVM, PVMCPU pVCpu, int rc)
#elif defined(EMHANDLERC_WITH_NEM)
int emR3NemHandleRC(PVM pVM, PVMCPU pVCpu, int rc)
#endif
{
    switch (rc)
    {
        /*
         * Common & simple ones.
         */
        case VINF_SUCCESS:
            break;
        case VINF_EM_RESCHEDULE_RAW:
        case VINF_EM_RESCHEDULE_HM:
        case VINF_EM_RAW_INTERRUPT:
        case VINF_EM_RAW_TO_R3:
        case VINF_EM_RAW_TIMER_PENDING:
        case VINF_EM_PENDING_REQUEST:
            rc = VINF_SUCCESS;
            break;

#ifndef EMHANDLERC_WITH_NEM
        /*
         * Conflict or out of page tables.
         *
         * VM_FF_PGM_SYNC_CR3 is set by the hypervisor and all we need to
         * do here is to execute the pending forced actions.
         */
        case VINF_PGM_SYNC_CR3:
            AssertMsg(VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL),
                      ("VINF_PGM_SYNC_CR3 and no VMCPU_FF_PGM_SYNC_CR3*!\n"));
            rc = VINF_SUCCESS;
            break;

        /*
         * PGM pool flush pending (guest SMP only).
         */
        /** @todo jumping back and forth between ring 0 and 3 can burn a lot of cycles
         * if the EMT thread that's supposed to handle the flush is currently not active
         * (e.g. waiting to be scheduled) -> fix this properly!
         *
         * bird: Since the clearing is global and done via a rendezvous any CPU can do
         *       it. They would have to choose who to call VMMR3EmtRendezvous and send
         *       the rest to VMMR3EmtRendezvousFF ... Hmm ... that's not going to work
         *       all that well since the latter will race the setup done by the
         *       first.  Guess that means we need some new magic in that area for
         *       handling this case. :/
         */
        case VINF_PGM_POOL_FLUSH_PENDING:
            rc = VINF_SUCCESS;
            break;

        /*
         * Paging mode change.
         */
        case VINF_PGM_CHANGE_MODE:
            CPUM_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR3 | CPUMCTX_EXTRN_CR4 | CPUMCTX_EXTRN_EFER);
            rc = PGMChangeMode(pVCpu, pVCpu->cpum.GstCtx.cr0, pVCpu->cpum.GstCtx.cr4, pVCpu->cpum.GstCtx.msrEFER);
            if (rc == VINF_SUCCESS)
                rc = VINF_EM_RESCHEDULE;
            AssertMsg(RT_FAILURE(rc) || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST), ("%Rrc\n", rc));
            break;
#endif /* !EMHANDLERC_WITH_NEM */

        /*
         * I/O Port access - emulate the instruction.
         */
        case VINF_IOM_R3_IOPORT_READ:
        case VINF_IOM_R3_IOPORT_WRITE:
        case VINF_EM_RESUME_R3_HISTORY_EXEC: /* Resume EMHistoryExec after VMCPU_FF_IOM. */
            rc = emR3ExecuteIOInstruction(pVM, pVCpu);
            break;

        /*
         * Execute pending I/O Port access.
         */
        case VINF_EM_PENDING_R3_IOPORT_WRITE:
            rc = VBOXSTRICTRC_TODO(emR3ExecutePendingIoPortWrite(pVM, pVCpu));
            break;
        case VINF_EM_PENDING_R3_IOPORT_READ:
            rc = VBOXSTRICTRC_TODO(emR3ExecutePendingIoPortRead(pVM, pVCpu));
            break;

        /*
         * Memory mapped I/O access - emulate the instruction.
         */
        case VINF_IOM_R3_MMIO_READ:
        case VINF_IOM_R3_MMIO_WRITE:
        case VINF_IOM_R3_MMIO_READ_WRITE:
            rc = emR3ExecuteInstruction(pVM, pVCpu, "MMIO");
            break;

        /*
         * Machine specific register access - emulate the instruction.
         */
        case VINF_CPUM_R3_MSR_READ:
        case VINF_CPUM_R3_MSR_WRITE:
            rc = emR3ExecuteInstruction(pVM, pVCpu, "MSR");
            break;

        /*
         * GIM hypercall.
         */
        case VINF_GIM_R3_HYPERCALL:
            rc = emR3ExecuteInstruction(pVM, pVCpu, "Hypercall");
            break;

#ifdef EMHANDLERC_WITH_HM
        case VINF_EM_HM_PATCH_TPR_INSTR:
            rc = HMR3PatchTprInstr(pVM, pVCpu);
            break;
#endif

        case VINF_EM_RAW_GUEST_TRAP:
        case VINF_EM_RAW_EMULATE_INSTR:
            Assert(!TRPMHasTrap(pVCpu)); /* We're directly executing instructions below without respecting any pending traps! */
            rc = emR3ExecuteInstruction(pVM, pVCpu, "EMUL: ");
            break;

        case VINF_EM_RAW_INJECT_TRPM_EVENT:
            CPUM_IMPORT_EXTRN_RET(pVCpu, IEM_CPUMCTX_EXTRN_XCPT_MASK);
            rc = VBOXSTRICTRC_VAL(IEMInjectTrpmEvent(pVCpu));
            /* The following condition should be removed when IEM_IMPLEMENTS_TASKSWITCH becomes true. */
            if (rc == VERR_IEM_ASPECT_NOT_IMPLEMENTED)
                rc = emR3ExecuteInstruction(pVM, pVCpu, "EVENT: ");
            break;


        /*
         * Up a level.
         */
        case VINF_EM_TERMINATE:
        case VINF_EM_OFF:
        case VINF_EM_RESET:
        case VINF_EM_SUSPEND:
        case VINF_EM_HALT:
        case VINF_EM_RESUME:
        case VINF_EM_NO_MEMORY:
        case VINF_EM_RESCHEDULE:
        case VINF_EM_RESCHEDULE_REM:
        case VINF_EM_WAIT_SIPI:
            break;

        /*
         * Up a level and invoke the debugger.
         */
        case VINF_EM_DBG_STEPPED:
        case VINF_EM_DBG_BREAKPOINT:
        case VINF_EM_DBG_STEP:
        case VINF_EM_DBG_HYPER_BREAKPOINT:
        case VINF_EM_DBG_HYPER_STEPPED:
        case VINF_EM_DBG_HYPER_ASSERTION:
        case VINF_EM_DBG_STOP:
        case VINF_EM_DBG_EVENT:
            break;

        /*
         * Up a level, dump and debug.
         */
        case VERR_TRPM_DONT_PANIC:
        case VERR_TRPM_PANIC:
        case VERR_VMM_RING0_ASSERTION:
        case VINF_EM_TRIPLE_FAULT:
        case VERR_VMM_HYPER_CR3_MISMATCH:
        case VERR_VMM_RING3_CALL_DISABLED:
        case VERR_IEM_INSTR_NOT_IMPLEMENTED:
        case VERR_IEM_ASPECT_NOT_IMPLEMENTED:
        case VERR_EM_GUEST_CPU_HANG:
            break;

#ifdef EMHANDLERC_WITH_HM
        /*
         * Up a level, after Hm have done some release logging.
         */
        case VERR_VMX_INVALID_VMCS_FIELD:
        case VERR_VMX_INVALID_VMCS_PTR:
        case VERR_VMX_INVALID_VMXON_PTR:
        case VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE:
        case VERR_VMX_UNEXPECTED_EXCEPTION:
        case VERR_VMX_UNEXPECTED_EXIT:
        case VERR_VMX_INVALID_GUEST_STATE:
        case VERR_VMX_UNABLE_TO_START_VM:
        case VERR_SVM_UNKNOWN_EXIT:
        case VERR_SVM_UNEXPECTED_EXIT:
        case VERR_SVM_UNEXPECTED_PATCH_TYPE:
        case VERR_SVM_UNEXPECTED_XCPT_EXIT:
            HMR3CheckError(pVM, rc);
            break;

        /* Up a level; fatal */
        case VERR_VMX_IN_VMX_ROOT_MODE:
        case VERR_SVM_IN_USE:
        case VERR_SVM_UNABLE_TO_START_VM:
            break;
#endif

        /*
         * These two should be handled via the force flag already, but just in
         * case they end up here deal with it.
         */
        case VINF_IOM_R3_IOPORT_COMMIT_WRITE:
        case VINF_IOM_R3_MMIO_COMMIT_WRITE:
            AssertFailed();
            rc = VBOXSTRICTRC_TODO(IOMR3ProcessForceFlag(pVM, pVCpu, rc));
            break;

        /*
         * Anything which is not known to us means an internal error
         * and the termination of the VM!
         */
        default:
            AssertMsgFailed(("Unknown GC return code: %Rra\n", rc));
            break;
    }
    return rc;
}

#endif /* !VMM_INCLUDED_SRC_include_EMHandleRCTmpl_h */