[98970] | 1 | /* $Id: CPUM-armv8.cpp 101549 2023-10-23 09:53:09Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
| 3 | * CPUM - CPU Monitor / Manager (ARMv8 variant).
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
| 7 | * Copyright (C) 2023 Oracle and/or its affiliates.
|
---|
| 8 | *
|
---|
| 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
| 11 | *
|
---|
| 12 | * This program is free software; you can redistribute it and/or
|
---|
| 13 | * modify it under the terms of the GNU General Public License
|
---|
| 14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 15 | * License.
|
---|
| 16 | *
|
---|
| 17 | * This program is distributed in the hope that it will be useful, but
|
---|
| 18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 20 | * General Public License for more details.
|
---|
| 21 | *
|
---|
| 22 | * You should have received a copy of the GNU General Public License
|
---|
| 23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 24 | *
|
---|
| 25 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
| 26 | */
|
---|
| 27 |
|
---|
| 28 | /** @page pg_cpum CPUM - CPU Monitor / Manager
|
---|
| 29 | *
|
---|
| 30 | * The CPU Monitor / Manager keeps track of all the CPU registers.
|
---|
[101539] | 31 | * This is the ARMv8 variant which is doing much less than its x86/AMD6464
|
---|
[98970] | 32 | * counterpart due to the fact that we currently only support the NEM backends
|
---|
| 33 | * for running ARM guests. It might become complex iff we decide to implement our
|
---|
| 34 | * own hypervisor.
|
---|
| 35 | *
|
---|
[99026] | 36 | * @section sec_cpum_logging_armv8 Logging Level Assignments.
|
---|
[98970] | 37 | *
|
---|
| 38 | * Following log level assignments:
|
---|
| 39 | * - @todo
|
---|
| 40 | *
|
---|
| 41 | */
|
---|
| 42 |
|
---|
| 43 |
|
---|
| 44 | /*********************************************************************************************************************************
|
---|
| 45 | * Header Files *
|
---|
| 46 | *********************************************************************************************************************************/
|
---|
| 47 | #define LOG_GROUP LOG_GROUP_CPUM
|
---|
| 48 | #define CPUM_WITH_NONCONST_HOST_FEATURES
|
---|
| 49 | #include <VBox/vmm/cpum.h>
|
---|
| 50 | #include <VBox/vmm/cpumdis.h>
|
---|
| 51 | #include <VBox/vmm/pgm.h>
|
---|
| 52 | #include <VBox/vmm/mm.h>
|
---|
| 53 | #include <VBox/vmm/em.h>
|
---|
| 54 | #include <VBox/vmm/iem.h>
|
---|
| 55 | #include <VBox/vmm/dbgf.h>
|
---|
| 56 | #include <VBox/vmm/ssm.h>
|
---|
| 57 | #include "CPUMInternal-armv8.h"
|
---|
| 58 | #include <VBox/vmm/vm.h>
|
---|
| 59 |
|
---|
| 60 | #include <VBox/param.h>
|
---|
| 61 | #include <VBox/dis.h>
|
---|
| 62 | #include <VBox/err.h>
|
---|
| 63 | #include <VBox/log.h>
|
---|
| 64 | #include <iprt/assert.h>
|
---|
| 65 | #include <iprt/cpuset.h>
|
---|
| 66 | #include <iprt/mem.h>
|
---|
| 67 | #include <iprt/mp.h>
|
---|
| 68 | #include <iprt/string.h>
|
---|
[99051] | 69 | #include <iprt/armv8.h>
|
---|
[98970] | 70 |
|
---|
| 71 |
|
---|
| 72 | /*********************************************************************************************************************************
|
---|
[99956] | 73 | * Defined Constants And Macros *
|
---|
| 74 | *********************************************************************************************************************************/
|
---|
| 75 |
|
---|
| 76 | /** Internal form used by the macros. */
|
---|
| 77 | #ifdef VBOX_WITH_STATISTICS
|
---|
| 78 | # define RINT(a_uFirst, a_uLast, a_enmRdFn, a_enmWrFn, a_offCpumCpu, a_uInitOrReadValue, a_fWrIgnMask, a_fWrGpMask, a_szName) \
|
---|
| 79 | { a_uFirst, a_uLast, a_enmRdFn, a_enmWrFn, a_offCpumCpu, 0, 0, a_uInitOrReadValue, a_fWrIgnMask, a_fWrGpMask, a_szName, \
|
---|
| 80 | { 0 }, { 0 }, { 0 }, { 0 } }
|
---|
| 81 | #else
|
---|
| 82 | # define RINT(a_uFirst, a_uLast, a_enmRdFn, a_enmWrFn, a_offCpumCpu, a_uInitOrReadValue, a_fWrIgnMask, a_fWrGpMask, a_szName) \
|
---|
| 83 | { a_uFirst, a_uLast, a_enmRdFn, a_enmWrFn, a_offCpumCpu, 0, 0, a_uInitOrReadValue, a_fWrIgnMask, a_fWrGpMask, a_szName }
|
---|
| 84 | #endif
|
---|
| 85 |
|
---|
| 86 | /** Function handlers, extended version. */
|
---|
| 87 | #define MFX(a_uMsr, a_szName, a_enmRdFnSuff, a_enmWrFnSuff, a_uValue, a_fWrIgnMask, a_fWrGpMask) \
|
---|
| 88 | RINT(a_uMsr, a_uMsr, kCpumSysRegRdFn_##a_enmRdFnSuff, kCpumSysRegWrFn_##a_enmWrFnSuff, 0, a_uValue, a_fWrIgnMask, a_fWrGpMask, a_szName)
|
---|
| 89 | /** Function handlers, read-only. */
|
---|
| 90 | #define MFO(a_uMsr, a_szName, a_enmRdFnSuff) \
|
---|
| 91 | RINT(a_uMsr, a_uMsr, kCpumSysRegRdFn_##a_enmRdFnSuff, kCpumSysRegWrFn_ReadOnly, 0, 0, 0, UINT64_MAX, a_szName)
|
---|
| 92 | /** Read-only fixed value, ignores all writes. */
|
---|
| 93 | #define MVI(a_uMsr, a_szName, a_uValue) \
|
---|
| 94 | RINT(a_uMsr, a_uMsr, kCpumSysRegRdFn_FixedValue, kCpumSysRegWrFn_IgnoreWrite, 0, a_uValue, UINT64_MAX, 0, a_szName)
|
---|
| 95 |
|
---|
| 96 |
|
---|
| 97 | /*********************************************************************************************************************************
|
---|
[98970] | 98 | * Structures and Typedefs *
|
---|
| 99 | *********************************************************************************************************************************/
|
---|
| 100 |
|
---|
| 101 | /**
|
---|
| 102 | * What kind of cpu info dump to perform.
|
---|
| 103 | */
|
---|
| 104 | typedef enum CPUMDUMPTYPE
|
---|
| 105 | {
|
---|
| 106 | CPUMDUMPTYPE_TERSE,
|
---|
| 107 | CPUMDUMPTYPE_DEFAULT,
|
---|
| 108 | CPUMDUMPTYPE_VERBOSE
|
---|
| 109 | } CPUMDUMPTYPE;
|
---|
| 110 | /** Pointer to a cpu info dump type. */
|
---|
| 111 | typedef CPUMDUMPTYPE *PCPUMDUMPTYPE;
|
---|
| 112 |
|
---|
| 113 |
|
---|
| 114 | /*********************************************************************************************************************************
|
---|
| 115 | * Internal Functions *
|
---|
| 116 | *********************************************************************************************************************************/
|
---|
| 117 | static DECLCALLBACK(int) cpumR3LiveExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass);
|
---|
| 118 | static DECLCALLBACK(int) cpumR3SaveExec(PVM pVM, PSSMHANDLE pSSM);
|
---|
| 119 | static DECLCALLBACK(int) cpumR3LoadPrep(PVM pVM, PSSMHANDLE pSSM);
|
---|
| 120 | static DECLCALLBACK(int) cpumR3LoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
|
---|
| 121 | static DECLCALLBACK(int) cpumR3LoadDone(PVM pVM, PSSMHANDLE pSSM);
|
---|
| 122 | static DECLCALLBACK(void) cpumR3InfoAll(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
|
---|
| 123 | static DECLCALLBACK(void) cpumR3InfoGuest(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
|
---|
| 124 | static DECLCALLBACK(void) cpumR3InfoGuestInstr(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
|
---|
| 125 |
|
---|
| 126 |
|
---|
| 127 | /*********************************************************************************************************************************
|
---|
| 128 | * Global Variables *
|
---|
| 129 | *********************************************************************************************************************************/
|
---|
[101103] | 130 | #if defined(RT_ARCH_ARM64)
|
---|
| 131 | /** Host CPU features. */
|
---|
| 132 | DECL_HIDDEN_DATA(CPUHOSTFEATURES) g_CpumHostFeatures;
|
---|
| 133 | #endif
|
---|
| 134 |
|
---|
[99956] | 135 | /**
|
---|
| 136 | * System register ranges.
|
---|
| 137 | */
|
---|
| 138 | static CPUMSYSREGRANGE const g_aSysRegRanges[] =
|
---|
| 139 | {
|
---|
| 140 | MFX(ARMV8_AARCH64_SYSREG_OSLAR_EL1, "OSLAR_EL1", WriteOnly, OslarEl1, 0, UINT64_C(0xfffffffffffffffe), UINT64_C(0xfffffffffffffffe)),
|
---|
| 141 | MFO(ARMV8_AARCH64_SYSREG_OSLSR_EL1, "OSLSR_EL1", OslsrEl1),
|
---|
| 142 | MVI(ARMV8_AARCH64_SYSREG_OSDLR_EL1, "OSDLR_EL1", 0)
|
---|
| 143 | };
|
---|
| 144 |
|
---|
| 145 |
|
---|
[98970] | 146 | /** Saved state field descriptors for CPUMCTX. */
|
---|
| 147 | static const SSMFIELD g_aCpumCtxFields[] =
|
---|
| 148 | {
|
---|
| 149 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[0].x),
|
---|
| 150 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[1].x),
|
---|
| 151 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[2].x),
|
---|
| 152 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[3].x),
|
---|
| 153 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[4].x),
|
---|
| 154 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[5].x),
|
---|
| 155 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[6].x),
|
---|
| 156 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[7].x),
|
---|
| 157 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[8].x),
|
---|
| 158 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[9].x),
|
---|
| 159 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[10].x),
|
---|
| 160 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[11].x),
|
---|
| 161 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[12].x),
|
---|
| 162 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[13].x),
|
---|
| 163 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[14].x),
|
---|
| 164 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[15].x),
|
---|
| 165 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[16].x),
|
---|
| 166 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[17].x),
|
---|
| 167 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[18].x),
|
---|
| 168 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[19].x),
|
---|
| 169 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[20].x),
|
---|
| 170 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[21].x),
|
---|
| 171 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[22].x),
|
---|
| 172 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[23].x),
|
---|
| 173 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[24].x),
|
---|
| 174 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[25].x),
|
---|
| 175 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[26].x),
|
---|
| 176 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[27].x),
|
---|
| 177 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[28].x),
|
---|
| 178 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[29].x),
|
---|
| 179 | SSMFIELD_ENTRY( CPUMCTX, aGRegs[30].x),
|
---|
| 180 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[0].v),
|
---|
| 181 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[1].v),
|
---|
| 182 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[2].v),
|
---|
| 183 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[3].v),
|
---|
| 184 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[4].v),
|
---|
| 185 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[5].v),
|
---|
| 186 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[6].v),
|
---|
| 187 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[7].v),
|
---|
| 188 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[8].v),
|
---|
| 189 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[9].v),
|
---|
| 190 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[10].v),
|
---|
| 191 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[11].v),
|
---|
| 192 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[12].v),
|
---|
| 193 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[13].v),
|
---|
| 194 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[14].v),
|
---|
| 195 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[15].v),
|
---|
| 196 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[16].v),
|
---|
| 197 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[17].v),
|
---|
| 198 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[18].v),
|
---|
| 199 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[19].v),
|
---|
| 200 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[20].v),
|
---|
| 201 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[21].v),
|
---|
| 202 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[22].v),
|
---|
| 203 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[23].v),
|
---|
| 204 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[24].v),
|
---|
| 205 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[25].v),
|
---|
| 206 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[26].v),
|
---|
| 207 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[27].v),
|
---|
| 208 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[28].v),
|
---|
| 209 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[29].v),
|
---|
| 210 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[30].v),
|
---|
| 211 | SSMFIELD_ENTRY( CPUMCTX, aVRegs[31].v),
|
---|
| 212 | SSMFIELD_ENTRY( CPUMCTX, aSpReg[0].u64),
|
---|
| 213 | SSMFIELD_ENTRY( CPUMCTX, aSpReg[1].u64),
|
---|
| 214 | SSMFIELD_ENTRY( CPUMCTX, Pc.u64),
|
---|
| 215 | SSMFIELD_ENTRY( CPUMCTX, Spsr.u64),
|
---|
| 216 | SSMFIELD_ENTRY( CPUMCTX, Elr.u64),
|
---|
[100727] | 217 | SSMFIELD_ENTRY( CPUMCTX, Sctlr.u64),
|
---|
| 218 | SSMFIELD_ENTRY( CPUMCTX, Tcr.u64),
|
---|
| 219 | SSMFIELD_ENTRY( CPUMCTX, Ttbr0.u64),
|
---|
| 220 | SSMFIELD_ENTRY( CPUMCTX, Ttbr1.u64),
|
---|
| 221 | SSMFIELD_ENTRY( CPUMCTX, VBar.u64),
|
---|
| 222 | SSMFIELD_ENTRY( CPUMCTX, aBp[0].Ctrl.u64),
|
---|
| 223 | SSMFIELD_ENTRY( CPUMCTX, aBp[0].Value.u64),
|
---|
| 224 | SSMFIELD_ENTRY( CPUMCTX, aBp[1].Ctrl.u64),
|
---|
| 225 | SSMFIELD_ENTRY( CPUMCTX, aBp[1].Value.u64),
|
---|
| 226 | SSMFIELD_ENTRY( CPUMCTX, aBp[2].Ctrl.u64),
|
---|
| 227 | SSMFIELD_ENTRY( CPUMCTX, aBp[2].Value.u64),
|
---|
| 228 | SSMFIELD_ENTRY( CPUMCTX, aBp[3].Ctrl.u64),
|
---|
| 229 | SSMFIELD_ENTRY( CPUMCTX, aBp[3].Value.u64),
|
---|
| 230 | SSMFIELD_ENTRY( CPUMCTX, aBp[4].Ctrl.u64),
|
---|
| 231 | SSMFIELD_ENTRY( CPUMCTX, aBp[4].Value.u64),
|
---|
| 232 | SSMFIELD_ENTRY( CPUMCTX, aBp[5].Ctrl.u64),
|
---|
| 233 | SSMFIELD_ENTRY( CPUMCTX, aBp[5].Value.u64),
|
---|
| 234 | SSMFIELD_ENTRY( CPUMCTX, aBp[6].Ctrl.u64),
|
---|
| 235 | SSMFIELD_ENTRY( CPUMCTX, aBp[6].Value.u64),
|
---|
| 236 | SSMFIELD_ENTRY( CPUMCTX, aBp[7].Ctrl.u64),
|
---|
| 237 | SSMFIELD_ENTRY( CPUMCTX, aBp[7].Value.u64),
|
---|
| 238 | SSMFIELD_ENTRY( CPUMCTX, aBp[8].Ctrl.u64),
|
---|
| 239 | SSMFIELD_ENTRY( CPUMCTX, aBp[8].Value.u64),
|
---|
| 240 | SSMFIELD_ENTRY( CPUMCTX, aBp[9].Ctrl.u64),
|
---|
| 241 | SSMFIELD_ENTRY( CPUMCTX, aBp[9].Value.u64),
|
---|
| 242 | SSMFIELD_ENTRY( CPUMCTX, aBp[10].Ctrl.u64),
|
---|
| 243 | SSMFIELD_ENTRY( CPUMCTX, aBp[10].Value.u64),
|
---|
| 244 | SSMFIELD_ENTRY( CPUMCTX, aBp[11].Ctrl.u64),
|
---|
| 245 | SSMFIELD_ENTRY( CPUMCTX, aBp[11].Value.u64),
|
---|
| 246 | SSMFIELD_ENTRY( CPUMCTX, aBp[12].Ctrl.u64),
|
---|
| 247 | SSMFIELD_ENTRY( CPUMCTX, aBp[12].Value.u64),
|
---|
| 248 | SSMFIELD_ENTRY( CPUMCTX, aBp[13].Ctrl.u64),
|
---|
| 249 | SSMFIELD_ENTRY( CPUMCTX, aBp[13].Value.u64),
|
---|
| 250 | SSMFIELD_ENTRY( CPUMCTX, aBp[14].Ctrl.u64),
|
---|
| 251 | SSMFIELD_ENTRY( CPUMCTX, aBp[14].Value.u64),
|
---|
| 252 | SSMFIELD_ENTRY( CPUMCTX, aBp[15].Ctrl.u64),
|
---|
| 253 | SSMFIELD_ENTRY( CPUMCTX, aBp[15].Value.u64),
|
---|
| 254 | SSMFIELD_ENTRY( CPUMCTX, aWp[0].Ctrl.u64),
|
---|
| 255 | SSMFIELD_ENTRY( CPUMCTX, aWp[0].Value.u64),
|
---|
| 256 | SSMFIELD_ENTRY( CPUMCTX, aWp[1].Ctrl.u64),
|
---|
| 257 | SSMFIELD_ENTRY( CPUMCTX, aWp[1].Value.u64),
|
---|
| 258 | SSMFIELD_ENTRY( CPUMCTX, aWp[2].Ctrl.u64),
|
---|
| 259 | SSMFIELD_ENTRY( CPUMCTX, aWp[2].Value.u64),
|
---|
| 260 | SSMFIELD_ENTRY( CPUMCTX, aWp[3].Ctrl.u64),
|
---|
| 261 | SSMFIELD_ENTRY( CPUMCTX, aWp[3].Value.u64),
|
---|
| 262 | SSMFIELD_ENTRY( CPUMCTX, aWp[4].Ctrl.u64),
|
---|
| 263 | SSMFIELD_ENTRY( CPUMCTX, aWp[4].Value.u64),
|
---|
| 264 | SSMFIELD_ENTRY( CPUMCTX, aWp[5].Ctrl.u64),
|
---|
| 265 | SSMFIELD_ENTRY( CPUMCTX, aWp[5].Value.u64),
|
---|
| 266 | SSMFIELD_ENTRY( CPUMCTX, aWp[6].Ctrl.u64),
|
---|
| 267 | SSMFIELD_ENTRY( CPUMCTX, aWp[6].Value.u64),
|
---|
| 268 | SSMFIELD_ENTRY( CPUMCTX, aWp[7].Ctrl.u64),
|
---|
| 269 | SSMFIELD_ENTRY( CPUMCTX, aWp[7].Value.u64),
|
---|
| 270 | SSMFIELD_ENTRY( CPUMCTX, aWp[8].Ctrl.u64),
|
---|
| 271 | SSMFIELD_ENTRY( CPUMCTX, aWp[8].Value.u64),
|
---|
| 272 | SSMFIELD_ENTRY( CPUMCTX, aWp[9].Ctrl.u64),
|
---|
| 273 | SSMFIELD_ENTRY( CPUMCTX, aWp[9].Value.u64),
|
---|
| 274 | SSMFIELD_ENTRY( CPUMCTX, aWp[10].Ctrl.u64),
|
---|
| 275 | SSMFIELD_ENTRY( CPUMCTX, aWp[10].Value.u64),
|
---|
| 276 | SSMFIELD_ENTRY( CPUMCTX, aWp[11].Ctrl.u64),
|
---|
| 277 | SSMFIELD_ENTRY( CPUMCTX, aWp[11].Value.u64),
|
---|
| 278 | SSMFIELD_ENTRY( CPUMCTX, aWp[12].Ctrl.u64),
|
---|
| 279 | SSMFIELD_ENTRY( CPUMCTX, aWp[12].Value.u64),
|
---|
| 280 | SSMFIELD_ENTRY( CPUMCTX, aWp[13].Ctrl.u64),
|
---|
| 281 | SSMFIELD_ENTRY( CPUMCTX, aWp[13].Value.u64),
|
---|
| 282 | SSMFIELD_ENTRY( CPUMCTX, aWp[14].Ctrl.u64),
|
---|
| 283 | SSMFIELD_ENTRY( CPUMCTX, aWp[14].Value.u64),
|
---|
| 284 | SSMFIELD_ENTRY( CPUMCTX, aWp[15].Ctrl.u64),
|
---|
| 285 | SSMFIELD_ENTRY( CPUMCTX, aWp[15].Value.u64),
|
---|
| 286 | SSMFIELD_ENTRY( CPUMCTX, Mdscr.u64),
|
---|
| 287 | SSMFIELD_ENTRY( CPUMCTX, Apda.Low.u64),
|
---|
| 288 | SSMFIELD_ENTRY( CPUMCTX, Apda.High.u64),
|
---|
| 289 | SSMFIELD_ENTRY( CPUMCTX, Apdb.Low.u64),
|
---|
| 290 | SSMFIELD_ENTRY( CPUMCTX, Apdb.High.u64),
|
---|
| 291 | SSMFIELD_ENTRY( CPUMCTX, Apga.Low.u64),
|
---|
| 292 | SSMFIELD_ENTRY( CPUMCTX, Apga.High.u64),
|
---|
| 293 | SSMFIELD_ENTRY( CPUMCTX, Apia.Low.u64),
|
---|
| 294 | SSMFIELD_ENTRY( CPUMCTX, Apia.High.u64),
|
---|
| 295 | SSMFIELD_ENTRY( CPUMCTX, Apib.Low.u64),
|
---|
| 296 | SSMFIELD_ENTRY( CPUMCTX, Apib.High.u64),
|
---|
| 297 | SSMFIELD_ENTRY( CPUMCTX, Afsr0.u64),
|
---|
| 298 | SSMFIELD_ENTRY( CPUMCTX, Afsr1.u64),
|
---|
| 299 | SSMFIELD_ENTRY( CPUMCTX, Amair.u64),
|
---|
| 300 | SSMFIELD_ENTRY( CPUMCTX, CntKCtl.u64),
|
---|
| 301 | SSMFIELD_ENTRY( CPUMCTX, ContextIdr.u64),
|
---|
| 302 | SSMFIELD_ENTRY( CPUMCTX, Cpacr.u64),
|
---|
| 303 | SSMFIELD_ENTRY( CPUMCTX, Csselr.u64),
|
---|
| 304 | SSMFIELD_ENTRY( CPUMCTX, Esr.u64),
|
---|
| 305 | SSMFIELD_ENTRY( CPUMCTX, Far.u64),
|
---|
| 306 | SSMFIELD_ENTRY( CPUMCTX, Mair.u64),
|
---|
| 307 | SSMFIELD_ENTRY( CPUMCTX, Par.u64),
|
---|
| 308 | SSMFIELD_ENTRY( CPUMCTX, TpIdrRoEl0.u64),
|
---|
| 309 | SSMFIELD_ENTRY( CPUMCTX, aTpIdr[0].u64),
|
---|
| 310 | SSMFIELD_ENTRY( CPUMCTX, aTpIdr[1].u64),
|
---|
| 311 | SSMFIELD_ENTRY( CPUMCTX, MDccInt.u64),
|
---|
[98970] | 312 | SSMFIELD_ENTRY( CPUMCTX, fpcr),
|
---|
| 313 | SSMFIELD_ENTRY( CPUMCTX, fpsr),
|
---|
| 314 | SSMFIELD_ENTRY( CPUMCTX, fPState),
|
---|
[100727] | 315 | SSMFIELD_ENTRY( CPUMCTX, fOsLck),
|
---|
| 316 | SSMFIELD_ENTRY( CPUMCTX, CntvCtlEl0),
|
---|
| 317 | SSMFIELD_ENTRY( CPUMCTX, CntvCValEl0),
|
---|
[98970] | 318 | SSMFIELD_ENTRY_TERM()
|
---|
| 319 | };
|
---|
| 320 |
|
---|
| 321 |
|
---|
| 322 | /**
|
---|
[99956] | 323 | * Initializes the guest system register states.
|
---|
| 324 | *
|
---|
| 325 | * @returns VBox status code.
|
---|
| 326 | * @param pVM The cross context VM structure.
|
---|
| 327 | */
|
---|
| 328 | static int cpumR3InitSysRegs(PVM pVM)
|
---|
| 329 | {
|
---|
| 330 | for (uint32_t i = 0; i < RT_ELEMENTS(g_aSysRegRanges); i++)
|
---|
| 331 | {
|
---|
| 332 | int rc = CPUMR3SysRegRangesInsert(pVM, &g_aSysRegRanges[i]);
|
---|
| 333 | AssertLogRelRCReturn(rc, rc);
|
---|
| 334 | }
|
---|
| 335 |
|
---|
| 336 | return VINF_SUCCESS;
|
---|
| 337 | }
|
---|
| 338 |
|
---|
| 339 |
|
---|
| 340 | /**
|
---|
[98970] | 341 | * Initializes the CPUM.
|
---|
| 342 | *
|
---|
| 343 | * @returns VBox status code.
|
---|
| 344 | * @param pVM The cross context VM structure.
|
---|
| 345 | */
|
---|
| 346 | VMMR3DECL(int) CPUMR3Init(PVM pVM)
|
---|
| 347 | {
|
---|
| 348 | LogFlow(("CPUMR3Init\n"));
|
---|
| 349 |
|
---|
| 350 | /*
|
---|
| 351 | * Assert alignment, sizes and tables.
|
---|
| 352 | */
|
---|
| 353 | AssertCompileMemberAlignment(VM, cpum.s, 32);
|
---|
| 354 | AssertCompile(sizeof(pVM->cpum.s) <= sizeof(pVM->cpum.padding));
|
---|
| 355 | AssertCompileSizeAlignment(CPUMCTX, 64);
|
---|
| 356 | AssertCompileMemberAlignment(VM, cpum, 64);
|
---|
| 357 | AssertCompileMemberAlignment(VMCPU, cpum.s, 64);
|
---|
[99196] | 358 | #ifdef VBOX_STRICT
|
---|
| 359 | int rc2 = cpumR3SysRegStrictInitChecks();
|
---|
| 360 | AssertRCReturn(rc2, rc2);
|
---|
| 361 | #endif
|
---|
[98970] | 362 |
|
---|
[99383] | 363 | pVM->cpum.s.GuestInfo.paSysRegRangesR3 = &pVM->cpum.s.GuestInfo.aSysRegRanges[0];
|
---|
| 364 |
|
---|
[101549] | 365 | PCFGMNODE pCpumCfg = CFGMR3GetChild(CFGMR3GetRoot(pVM), "CPUM");
|
---|
| 366 |
|
---|
| 367 | /** @cfgm{/CPUM/ResetPcValue, string}
|
---|
| 368 | * Program counter value after a reset, sets the address of the first isntruction to execute. */
|
---|
| 369 | int rc = CFGMR3QueryU64Def(pCpumCfg, "ResetPcValue", &pVM->cpum.s.u64ResetPc, 0);
|
---|
| 370 | AssertLogRelRCReturn(rc, rc);
|
---|
| 371 |
|
---|
[98970] | 372 | /*
|
---|
| 373 | * Register saved state data item.
|
---|
| 374 | */
|
---|
[101549] | 375 | rc = SSMR3RegisterInternal(pVM, "cpum", 1, CPUM_SAVED_STATE_VERSION, sizeof(CPUM),
|
---|
| 376 | NULL, cpumR3LiveExec, NULL,
|
---|
| 377 | NULL, cpumR3SaveExec, NULL,
|
---|
| 378 | cpumR3LoadPrep, cpumR3LoadExec, cpumR3LoadDone);
|
---|
[98970] | 379 | if (RT_FAILURE(rc))
|
---|
| 380 | return rc;
|
---|
| 381 |
|
---|
| 382 | /*
|
---|
| 383 | * Register info handlers and registers with the debugger facility.
|
---|
| 384 | */
|
---|
| 385 | DBGFR3InfoRegisterInternalEx(pVM, "cpum", "Displays the all the cpu states.",
|
---|
| 386 | &cpumR3InfoAll, DBGFINFO_FLAGS_ALL_EMTS);
|
---|
| 387 | DBGFR3InfoRegisterInternalEx(pVM, "cpumguest", "Displays the guest cpu state.",
|
---|
| 388 | &cpumR3InfoGuest, DBGFINFO_FLAGS_ALL_EMTS);
|
---|
[101103] | 389 | DBGFR3InfoRegisterInternalEx(pVM, "cpumguestinstr", "Displays the current guest instruction.",
|
---|
| 390 | &cpumR3InfoGuestInstr, DBGFINFO_FLAGS_ALL_EMTS);
|
---|
| 391 | DBGFR3InfoRegisterInternal( pVM, "cpuid", "Displays the guest cpuid information.",
|
---|
| 392 | &cpumR3CpuIdInfo);
|
---|
[101121] | 393 | DBGFR3InfoRegisterInternal( pVM, "cpufeat", "Displays the guest features.",
|
---|
| 394 | &cpumR3CpuFeatInfo);
|
---|
[98970] | 395 |
|
---|
| 396 | rc = cpumR3DbgInit(pVM);
|
---|
| 397 | if (RT_FAILURE(rc))
|
---|
| 398 | return rc;
|
---|
| 399 |
|
---|
| 400 | /*
|
---|
[99956] | 401 | * Initialize the Guest system register states.
|
---|
| 402 | */
|
---|
| 403 | rc = cpumR3InitSysRegs(pVM);
|
---|
| 404 | if (RT_FAILURE(rc))
|
---|
| 405 | return rc;
|
---|
| 406 |
|
---|
| 407 | /*
|
---|
[98970] | 408 | * Initialize the general guest CPU state.
|
---|
| 409 | */
|
---|
| 410 | CPUMR3Reset(pVM);
|
---|
| 411 |
|
---|
| 412 | return VINF_SUCCESS;
|
---|
| 413 | }
|
---|
| 414 |
|
---|
| 415 |
|
---|
| 416 | /**
|
---|
| 417 | * Applies relocations to data and code managed by this
|
---|
| 418 | * component. This function will be called at init and
|
---|
| 419 | * whenever the VMM need to relocate it self inside the GC.
|
---|
| 420 | *
|
---|
| 421 | * The CPUM will update the addresses used by the switcher.
|
---|
| 422 | *
|
---|
| 423 | * @param pVM The cross context VM structure.
|
---|
| 424 | */
|
---|
| 425 | VMMR3DECL(void) CPUMR3Relocate(PVM pVM)
|
---|
| 426 | {
|
---|
| 427 | RT_NOREF(pVM);
|
---|
| 428 | }
|
---|
| 429 |
|
---|
| 430 |
|
---|
| 431 | /**
|
---|
| 432 | * Terminates the CPUM.
|
---|
| 433 | *
|
---|
| 434 | * Termination means cleaning up and freeing all resources,
|
---|
| 435 | * the VM it self is at this point powered off or suspended.
|
---|
| 436 | *
|
---|
| 437 | * @returns VBox status code.
|
---|
| 438 | * @param pVM The cross context VM structure.
|
---|
| 439 | */
|
---|
| 440 | VMMR3DECL(int) CPUMR3Term(PVM pVM)
|
---|
| 441 | {
|
---|
| 442 | RT_NOREF(pVM);
|
---|
| 443 | return VINF_SUCCESS;
|
---|
| 444 | }
|
---|
| 445 |
|
---|
| 446 |
|
---|
| 447 | /**
|
---|
| 448 | * Resets a virtual CPU.
|
---|
| 449 | *
|
---|
| 450 | * Used by CPUMR3Reset and CPU hot plugging.
|
---|
| 451 | *
|
---|
| 452 | * @param pVM The cross context VM structure.
|
---|
| 453 | * @param pVCpu The cross context virtual CPU structure of the CPU that is
|
---|
| 454 | * being reset. This may differ from the current EMT.
|
---|
| 455 | */
|
---|
| 456 | VMMR3DECL(void) CPUMR3ResetCpu(PVM pVM, PVMCPU pVCpu)
|
---|
| 457 | {
|
---|
| 458 | RT_NOREF(pVM);
|
---|
| 459 |
|
---|
| 460 | /** @todo anything different for VCPU > 0? */
|
---|
| 461 | PCPUMCTX pCtx = &pVCpu->cpum.s.Guest;
|
---|
| 462 |
|
---|
| 463 | /*
|
---|
| 464 | * Initialize everything to ZERO first.
|
---|
| 465 | */
|
---|
| 466 | RT_BZERO(pCtx, sizeof(*pCtx));
|
---|
[99051] | 467 |
|
---|
| 468 | /* Start in Supervisor mode. */
|
---|
| 469 | /** @todo Differentiate between Aarch64 and Aarch32 configuation. */
|
---|
| 470 | pCtx->fPState = ARMV8_SPSR_EL2_AARCH64_SET_EL(ARMV8_AARCH64_EL_1)
|
---|
| 471 | | ARMV8_SPSR_EL2_AARCH64_SP
|
---|
| 472 | | ARMV8_SPSR_EL2_AARCH64_D
|
---|
| 473 | | ARMV8_SPSR_EL2_AARCH64_A
|
---|
| 474 | | ARMV8_SPSR_EL2_AARCH64_I
|
---|
| 475 | | ARMV8_SPSR_EL2_AARCH64_F;
|
---|
[101549] | 476 |
|
---|
| 477 | pCtx->Pc.u64 = pVM->cpum.s.u64ResetPc;
|
---|
[98970] | 478 | /** @todo */
|
---|
| 479 | }
|
---|
| 480 |
|
---|
| 481 |
|
---|
| 482 | /**
|
---|
| 483 | * Resets the CPU.
|
---|
| 484 | *
|
---|
| 485 | * @param pVM The cross context VM structure.
|
---|
| 486 | */
|
---|
| 487 | VMMR3DECL(void) CPUMR3Reset(PVM pVM)
|
---|
| 488 | {
|
---|
| 489 | for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
|
---|
| 490 | {
|
---|
| 491 | PVMCPU pVCpu = pVM->apCpusR3[idCpu];
|
---|
| 492 | CPUMR3ResetCpu(pVM, pVCpu);
|
---|
| 493 | }
|
---|
| 494 | }
|
---|
| 495 |
|
---|
| 496 |
|
---|
| 497 |
|
---|
| 498 |
|
---|
| 499 | /**
|
---|
| 500 | * Pass 0 live exec callback.
|
---|
| 501 | *
|
---|
| 502 | * @returns VINF_SSM_DONT_CALL_AGAIN.
|
---|
| 503 | * @param pVM The cross context VM structure.
|
---|
| 504 | * @param pSSM The saved state handle.
|
---|
| 505 | * @param uPass The pass (0).
|
---|
| 506 | */
|
---|
| 507 | static DECLCALLBACK(int) cpumR3LiveExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass)
|
---|
| 508 | {
|
---|
| 509 | AssertReturn(uPass == 0, VERR_SSM_UNEXPECTED_PASS);
|
---|
[101190] | 510 | cpumR3SaveCpuId(pVM, pSSM);
|
---|
[98970] | 511 | return VINF_SSM_DONT_CALL_AGAIN;
|
---|
| 512 | }
|
---|
| 513 |
|
---|
| 514 |
|
---|
| 515 | /**
|
---|
| 516 | * Execute state save operation.
|
---|
| 517 | *
|
---|
| 518 | * @returns VBox status code.
|
---|
| 519 | * @param pVM The cross context VM structure.
|
---|
| 520 | * @param pSSM SSM operation handle.
|
---|
| 521 | */
|
---|
| 522 | static DECLCALLBACK(int) cpumR3SaveExec(PVM pVM, PSSMHANDLE pSSM)
|
---|
| 523 | {
|
---|
| 524 | /*
|
---|
| 525 | * Save.
|
---|
| 526 | */
|
---|
| 527 | SSMR3PutU32(pSSM, pVM->cCpus);
|
---|
[100727] | 528 | for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
|
---|
| 529 | {
|
---|
| 530 | PVMCPU const pVCpu = pVM->apCpusR3[idCpu];
|
---|
| 531 | PCPUMCTX const pGstCtx = &pVCpu->cpum.s.Guest;
|
---|
| 532 |
|
---|
| 533 | SSMR3PutStructEx(pSSM, pGstCtx, sizeof(*pGstCtx), 0, g_aCpumCtxFields, NULL);
|
---|
| 534 |
|
---|
| 535 | SSMR3PutU32(pSSM, pVCpu->cpum.s.fChanged);
|
---|
| 536 | }
|
---|
[101190] | 537 |
|
---|
| 538 | cpumR3SaveCpuId(pVM, pSSM);
|
---|
[98970] | 539 | return VINF_SUCCESS;
|
---|
| 540 | }
|
---|
| 541 |
|
---|
| 542 |
|
---|
| 543 | /**
|
---|
| 544 | * @callback_method_impl{FNSSMINTLOADPREP}
|
---|
| 545 | */
|
---|
| 546 | static DECLCALLBACK(int) cpumR3LoadPrep(PVM pVM, PSSMHANDLE pSSM)
|
---|
| 547 | {
|
---|
| 548 | RT_NOREF(pSSM);
|
---|
| 549 | pVM->cpum.s.fPendingRestore = true;
|
---|
| 550 | return VINF_SUCCESS;
|
---|
| 551 | }
|
---|
| 552 |
|
---|
| 553 |
|
---|
| 554 | /**
|
---|
| 555 | * @callback_method_impl{FNSSMINTLOADEXEC}
|
---|
| 556 | */
|
---|
| 557 | static DECLCALLBACK(int) cpumR3LoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
|
---|
| 558 | {
|
---|
| 559 | /*
|
---|
| 560 | * Validate version.
|
---|
| 561 | */
|
---|
[100727] | 562 | if (uVersion != CPUM_SAVED_STATE_VERSION)
|
---|
| 563 | {
|
---|
| 564 | AssertMsgFailed(("cpumR3LoadExec: Invalid version uVersion=%d!\n", uVersion));
|
---|
| 565 | return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
|
---|
| 566 | }
|
---|
[98970] | 567 |
|
---|
| 568 | if (uPass == SSM_PASS_FINAL)
|
---|
| 569 | {
|
---|
[100755] | 570 | uint32_t cCpus;
|
---|
| 571 | int rc = SSMR3GetU32(pSSM, &cCpus); AssertRCReturn(rc, rc);
|
---|
| 572 | AssertLogRelMsgReturn(cCpus == pVM->cCpus, ("Mismatching CPU counts: saved: %u; configured: %u \n", cCpus, pVM->cCpus),
|
---|
| 573 | VERR_SSM_UNEXPECTED_DATA);
|
---|
| 574 |
|
---|
[100727] | 575 | /*
|
---|
| 576 | * Do the per-CPU restoring.
|
---|
| 577 | */
|
---|
| 578 | for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
|
---|
| 579 | {
|
---|
| 580 | PVMCPU pVCpu = pVM->apCpusR3[idCpu];
|
---|
| 581 | PCPUMCTX pGstCtx = &pVCpu->cpum.s.Guest;
|
---|
| 582 |
|
---|
| 583 | /*
|
---|
[100755] | 584 | * Restore the CPUMCTX structure.
|
---|
[100727] | 585 | */
|
---|
[100755] | 586 | rc = SSMR3GetStructEx(pSSM, pGstCtx, sizeof(*pGstCtx), 0, g_aCpumCtxFields, NULL);
|
---|
[100727] | 587 | AssertRCReturn(rc, rc);
|
---|
| 588 |
|
---|
| 589 | /*
|
---|
| 590 | * Restore a couple of flags.
|
---|
| 591 | */
|
---|
| 592 | SSMR3GetU32(pSSM, &pVCpu->cpum.s.fChanged);
|
---|
| 593 | }
|
---|
[98970] | 594 | }
|
---|
| 595 |
|
---|
| 596 | pVM->cpum.s.fPendingRestore = false;
|
---|
[101190] | 597 |
|
---|
| 598 | /* Load CPUID and explode guest features. */
|
---|
| 599 | return cpumR3LoadCpuId(pVM, pSSM, uVersion);
|
---|
[98970] | 600 | }
|
---|
| 601 |
|
---|
| 602 |
|
---|
| 603 | /**
|
---|
| 604 | * @callback_method_impl{FNSSMINTLOADDONE}
|
---|
| 605 | */
|
---|
| 606 | static DECLCALLBACK(int) cpumR3LoadDone(PVM pVM, PSSMHANDLE pSSM)
|
---|
| 607 | {
|
---|
| 608 | if (RT_FAILURE(SSMR3HandleGetStatus(pSSM)))
|
---|
| 609 | return VINF_SUCCESS;
|
---|
| 610 |
|
---|
| 611 | /* just check this since we can. */ /** @todo Add a SSM unit flag for indicating that it's mandatory during a restore. */
|
---|
| 612 | if (pVM->cpum.s.fPendingRestore)
|
---|
| 613 | {
|
---|
| 614 | LogRel(("CPUM: Missing state!\n"));
|
---|
| 615 | return VERR_INTERNAL_ERROR_2;
|
---|
| 616 | }
|
---|
| 617 |
|
---|
| 618 | /** @todo */
|
---|
| 619 | return VINF_SUCCESS;
|
---|
| 620 | }
|
---|
| 621 |
|
---|
| 622 |
|
---|
| 623 | /**
|
---|
| 624 | * Checks if the CPUM state restore is still pending.
|
---|
| 625 | *
|
---|
| 626 | * @returns true / false.
|
---|
| 627 | * @param pVM The cross context VM structure.
|
---|
| 628 | */
|
---|
| 629 | VMMDECL(bool) CPUMR3IsStateRestorePending(PVM pVM)
|
---|
| 630 | {
|
---|
| 631 | return pVM->cpum.s.fPendingRestore;
|
---|
| 632 | }
|
---|
| 633 |
|
---|
| 634 |
|
---|
| 635 | /**
|
---|
| 636 | * Formats the PSTATE value into mnemonics.
|
---|
| 637 | *
|
---|
| 638 | * @param pszPState Where to write the mnemonics. (Assumes sufficient buffer space.)
|
---|
| 639 | * @param fPState The PSTATE value with both guest hardware and VBox
|
---|
| 640 | * internal bits included.
|
---|
| 641 | */
|
---|
| 642 | static void cpumR3InfoFormatPState(char *pszPState, uint32_t fPState)
|
---|
| 643 | {
|
---|
| 644 | /*
|
---|
| 645 | * Format the flags.
|
---|
| 646 | */
|
---|
| 647 | static const struct
|
---|
| 648 | {
|
---|
| 649 | const char *pszSet; const char *pszClear; uint32_t fFlag;
|
---|
| 650 | } s_aFlags[] =
|
---|
| 651 | {
|
---|
[100727] | 652 | { "SP", "nSP", ARMV8_SPSR_EL2_AARCH64_SP },
|
---|
| 653 | { "M4", "nM4", ARMV8_SPSR_EL2_AARCH64_M4 },
|
---|
| 654 | { "T", "nT", ARMV8_SPSR_EL2_AARCH64_T },
|
---|
| 655 | { "nF", "F", ARMV8_SPSR_EL2_AARCH64_F },
|
---|
| 656 | { "nI", "I", ARMV8_SPSR_EL2_AARCH64_I },
|
---|
| 657 | { "nA", "A", ARMV8_SPSR_EL2_AARCH64_A },
|
---|
| 658 | { "nD", "D", ARMV8_SPSR_EL2_AARCH64_D },
|
---|
| 659 | { "V", "nV", ARMV8_SPSR_EL2_AARCH64_V },
|
---|
| 660 | { "C", "nC", ARMV8_SPSR_EL2_AARCH64_C },
|
---|
| 661 | { "Z", "nZ", ARMV8_SPSR_EL2_AARCH64_Z },
|
---|
| 662 | { "N", "nN", ARMV8_SPSR_EL2_AARCH64_N },
|
---|
[98970] | 663 | };
|
---|
| 664 | char *psz = pszPState;
|
---|
| 665 | for (unsigned i = 0; i < RT_ELEMENTS(s_aFlags); i++)
|
---|
| 666 | {
|
---|
| 667 | const char *pszAdd = s_aFlags[i].fFlag & fPState ? s_aFlags[i].pszSet : s_aFlags[i].pszClear;
|
---|
| 668 | if (pszAdd)
|
---|
| 669 | {
|
---|
| 670 | strcpy(psz, pszAdd);
|
---|
| 671 | psz += strlen(pszAdd);
|
---|
| 672 | *psz++ = ' ';
|
---|
| 673 | }
|
---|
| 674 | }
|
---|
| 675 | psz[-1] = '\0';
|
---|
| 676 | }
|
---|
| 677 |
|
---|
| 678 |
|
---|
| 679 | /**
|
---|
| 680 | * Formats a full register dump.
|
---|
| 681 | *
|
---|
| 682 | * @param pVM The cross context VM structure.
|
---|
| 683 | * @param pCtx The context to format.
|
---|
| 684 | * @param pHlp Output functions.
|
---|
| 685 | * @param enmType The dump type.
|
---|
| 686 | */
|
---|
[100727] | 687 | static void cpumR3InfoOne(PVM pVM, PCPUMCTX pCtx, PCDBGFINFOHLP pHlp, CPUMDUMPTYPE enmType)
|
---|
[98970] | 688 | {
|
---|
[100727] | 689 | RT_NOREF(pVM);
|
---|
[98970] | 690 |
|
---|
| 691 | /*
|
---|
| 692 | * Format the PSTATE.
|
---|
| 693 | */
|
---|
| 694 | char szPState[80];
|
---|
| 695 | cpumR3InfoFormatPState(&szPState[0], pCtx->fPState);
|
---|
| 696 |
|
---|
[100727] | 697 | /*
|
---|
| 698 | * Format the registers.
|
---|
| 699 | */
|
---|
| 700 | switch (enmType)
|
---|
| 701 | {
|
---|
| 702 | case CPUMDUMPTYPE_TERSE:
|
---|
| 703 | if (CPUMIsGuestIn64BitCodeEx(pCtx))
|
---|
| 704 | pHlp->pfnPrintf(pHlp,
|
---|
| 705 | "x0=%016RX64 x1=%016RX64 x2=%016RX64 x3=%016RX64\n"
|
---|
| 706 | "x4=%016RX64 x5=%016RX64 x6=%016RX64 x7=%016RX64\n"
|
---|
| 707 | "x8=%016RX64 x9=%016RX64 x10=%016RX64 x11=%016RX64\n"
|
---|
| 708 | "x12=%016RX64 x13=%016RX64 x14=%016RX64 x15=%016RX64\n"
|
---|
| 709 | "x16=%016RX64 x17=%016RX64 x18=%016RX64 x19=%016RX64\n"
|
---|
| 710 | "x20=%016RX64 x21=%016RX64 x22=%016RX64 x23=%016RX64\n"
|
---|
| 711 | "x24=%016RX64 x25=%016RX64 x26=%016RX64 x27=%016RX64\n"
|
---|
| 712 | "x28=%016RX64 x29=%016RX64 x30=%016RX64\n"
|
---|
| 713 | "pc=%016RX64 pstate=%016RX64 %s\n"
|
---|
| 714 | "sp_el0=%016RX64 sp_el1=%016RX64\n",
|
---|
| 715 | pCtx->aGRegs[0], pCtx->aGRegs[1], pCtx->aGRegs[2], pCtx->aGRegs[3],
|
---|
| 716 | pCtx->aGRegs[4], pCtx->aGRegs[5], pCtx->aGRegs[6], pCtx->aGRegs[7],
|
---|
| 717 | pCtx->aGRegs[8], pCtx->aGRegs[9], pCtx->aGRegs[10], pCtx->aGRegs[11],
|
---|
| 718 | pCtx->aGRegs[12], pCtx->aGRegs[13], pCtx->aGRegs[14], pCtx->aGRegs[15],
|
---|
| 719 | pCtx->aGRegs[16], pCtx->aGRegs[17], pCtx->aGRegs[18], pCtx->aGRegs[19],
|
---|
| 720 | pCtx->aGRegs[20], pCtx->aGRegs[21], pCtx->aGRegs[22], pCtx->aGRegs[23],
|
---|
| 721 | pCtx->aGRegs[24], pCtx->aGRegs[25], pCtx->aGRegs[26], pCtx->aGRegs[27],
|
---|
| 722 | pCtx->aGRegs[28], pCtx->aGRegs[29], pCtx->aGRegs[30],
|
---|
| 723 | pCtx->Pc.u64, pCtx->fPState, szPState,
|
---|
| 724 | pCtx->aSpReg[0].u64, pCtx->aSpReg[1].u64);
|
---|
| 725 | else
|
---|
| 726 | AssertFailed();
|
---|
| 727 | break;
|
---|
| 728 |
|
---|
| 729 | case CPUMDUMPTYPE_DEFAULT:
|
---|
| 730 | if (CPUMIsGuestIn64BitCodeEx(pCtx))
|
---|
| 731 | pHlp->pfnPrintf(pHlp,
|
---|
| 732 | "x0=%016RX64 x1=%016RX64 x2=%016RX64 x3=%016RX64\n"
|
---|
| 733 | "x4=%016RX64 x5=%016RX64 x6=%016RX64 x7=%016RX64\n"
|
---|
| 734 | "x8=%016RX64 x9=%016RX64 x10=%016RX64 x11=%016RX64\n"
|
---|
| 735 | "x12=%016RX64 x13=%016RX64 x14=%016RX64 x15=%016RX64\n"
|
---|
| 736 | "x16=%016RX64 x17=%016RX64 x18=%016RX64 x19=%016RX64\n"
|
---|
| 737 | "x20=%016RX64 x21=%016RX64 x22=%016RX64 x23=%016RX64\n"
|
---|
| 738 | "x24=%016RX64 x25=%016RX64 x26=%016RX64 x27=%016RX64\n"
|
---|
| 739 | "x28=%016RX64 x29=%016RX64 x30=%016RX64\n"
|
---|
| 740 | "pc=%016RX64 pstate=%016RX64 %s\n"
|
---|
| 741 | "sp_el0=%016RX64 sp_el1=%016RX64 sctlr_el1=%016RX64\n"
|
---|
| 742 | "tcr_el1=%016RX64 ttbr0_el1=%016RX64 ttbr1_el1=%016RX64\n"
|
---|
| 743 | "vbar_el1=%016RX64 elr_el1=%016RX64 esr_el1=%016RX64\n",
|
---|
| 744 | pCtx->aGRegs[0], pCtx->aGRegs[1], pCtx->aGRegs[2], pCtx->aGRegs[3],
|
---|
| 745 | pCtx->aGRegs[4], pCtx->aGRegs[5], pCtx->aGRegs[6], pCtx->aGRegs[7],
|
---|
| 746 | pCtx->aGRegs[8], pCtx->aGRegs[9], pCtx->aGRegs[10], pCtx->aGRegs[11],
|
---|
| 747 | pCtx->aGRegs[12], pCtx->aGRegs[13], pCtx->aGRegs[14], pCtx->aGRegs[15],
|
---|
| 748 | pCtx->aGRegs[16], pCtx->aGRegs[17], pCtx->aGRegs[18], pCtx->aGRegs[19],
|
---|
| 749 | pCtx->aGRegs[20], pCtx->aGRegs[21], pCtx->aGRegs[22], pCtx->aGRegs[23],
|
---|
| 750 | pCtx->aGRegs[24], pCtx->aGRegs[25], pCtx->aGRegs[26], pCtx->aGRegs[27],
|
---|
| 751 | pCtx->aGRegs[28], pCtx->aGRegs[29], pCtx->aGRegs[30],
|
---|
| 752 | pCtx->Pc.u64, pCtx->fPState, szPState,
|
---|
| 753 | pCtx->aSpReg[0].u64, pCtx->aSpReg[1].u64, pCtx->Sctlr.u64,
|
---|
| 754 | pCtx->Tcr.u64, pCtx->Ttbr0.u64, pCtx->Ttbr1.u64,
|
---|
| 755 | pCtx->VBar.u64, pCtx->Elr.u64, pCtx->Esr.u64);
|
---|
| 756 | else
|
---|
| 757 | AssertFailed();
|
---|
| 758 | break;
|
---|
| 759 |
|
---|
| 760 | case CPUMDUMPTYPE_VERBOSE:
|
---|
| 761 | if (CPUMIsGuestIn64BitCodeEx(pCtx))
|
---|
| 762 | pHlp->pfnPrintf(pHlp,
|
---|
| 763 | "x0=%016RX64 x1=%016RX64 x2=%016RX64 x3=%016RX64\n"
|
---|
| 764 | "x4=%016RX64 x5=%016RX64 x6=%016RX64 x7=%016RX64\n"
|
---|
| 765 | "x8=%016RX64 x9=%016RX64 x10=%016RX64 x11=%016RX64\n"
|
---|
| 766 | "x12=%016RX64 x13=%016RX64 x14=%016RX64 x15=%016RX64\n"
|
---|
| 767 | "x16=%016RX64 x17=%016RX64 x18=%016RX64 x19=%016RX64\n"
|
---|
| 768 | "x20=%016RX64 x21=%016RX64 x22=%016RX64 x23=%016RX64\n"
|
---|
| 769 | "x24=%016RX64 x25=%016RX64 x26=%016RX64 x27=%016RX64\n"
|
---|
| 770 | "x28=%016RX64 x29=%016RX64 x30=%016RX64\n"
|
---|
| 771 | "pc=%016RX64 pstate=%016RX64 %s\n"
|
---|
| 772 | "sp_el0=%016RX64 sp_el1=%016RX64 sctlr_el1=%016RX64\n"
|
---|
| 773 | "tcr_el1=%016RX64 ttbr0_el1=%016RX64 ttbr1_el1=%016RX64\n"
|
---|
| 774 | "vbar_el1=%016RX64 elr_el1=%016RX64 esr_el1=%016RX64\n"
|
---|
| 775 | "contextidr_el1=%016RX64 tpidrr0_el0=%016RX64\n"
|
---|
| 776 | "tpidr_el0=%016RX64 tpidr_el1=%016RX64\n"
|
---|
| 777 | "far_el1=%016RX64 mair_el1=%016RX64 par_el1=%016RX64\n"
|
---|
| 778 | "cntv_ctl_el0=%016RX64 cntv_val_el0=%016RX64\n"
|
---|
| 779 | "afsr0_el1=%016RX64 afsr0_el1=%016RX64 amair_el1=%016RX64\n"
|
---|
| 780 | "cntkctl_el1=%016RX64 cpacr_el1=%016RX64 csselr_el1=%016RX64\n"
|
---|
| 781 | "mdccint_el1=%016RX64\n",
|
---|
| 782 | pCtx->aGRegs[0], pCtx->aGRegs[1], pCtx->aGRegs[2], pCtx->aGRegs[3],
|
---|
| 783 | pCtx->aGRegs[4], pCtx->aGRegs[5], pCtx->aGRegs[6], pCtx->aGRegs[7],
|
---|
| 784 | pCtx->aGRegs[8], pCtx->aGRegs[9], pCtx->aGRegs[10], pCtx->aGRegs[11],
|
---|
| 785 | pCtx->aGRegs[12], pCtx->aGRegs[13], pCtx->aGRegs[14], pCtx->aGRegs[15],
|
---|
| 786 | pCtx->aGRegs[16], pCtx->aGRegs[17], pCtx->aGRegs[18], pCtx->aGRegs[19],
|
---|
| 787 | pCtx->aGRegs[20], pCtx->aGRegs[21], pCtx->aGRegs[22], pCtx->aGRegs[23],
|
---|
| 788 | pCtx->aGRegs[24], pCtx->aGRegs[25], pCtx->aGRegs[26], pCtx->aGRegs[27],
|
---|
| 789 | pCtx->aGRegs[28], pCtx->aGRegs[29], pCtx->aGRegs[30],
|
---|
| 790 | pCtx->Pc.u64, pCtx->fPState, szPState,
|
---|
| 791 | pCtx->aSpReg[0].u64, pCtx->aSpReg[1].u64, pCtx->Sctlr.u64,
|
---|
| 792 | pCtx->Tcr.u64, pCtx->Ttbr0.u64, pCtx->Ttbr1.u64,
|
---|
| 793 | pCtx->VBar.u64, pCtx->Elr.u64, pCtx->Esr.u64,
|
---|
| 794 | pCtx->ContextIdr.u64, pCtx->TpIdrRoEl0.u64,
|
---|
| 795 | pCtx->aTpIdr[0].u64, pCtx->aTpIdr[1].u64,
|
---|
| 796 | pCtx->Far.u64, pCtx->Mair.u64, pCtx->Par.u64,
|
---|
| 797 | pCtx->CntvCtlEl0, pCtx->CntvCValEl0,
|
---|
| 798 | pCtx->Afsr0.u64, pCtx->Afsr1.u64, pCtx->Amair.u64,
|
---|
| 799 | pCtx->CntKCtl.u64, pCtx->Cpacr.u64, pCtx->Csselr.u64,
|
---|
| 800 | pCtx->MDccInt.u64);
|
---|
| 801 | else
|
---|
| 802 | AssertFailed();
|
---|
| 803 |
|
---|
| 804 | pHlp->pfnPrintf(pHlp, "fpcr=%016RX64 fpsr=%016RX64\n", pCtx->fpcr, pCtx->fpsr);
|
---|
| 805 | for (unsigned i = 0; i < RT_ELEMENTS(pCtx->aVRegs); i++)
|
---|
| 806 | pHlp->pfnPrintf(pHlp,
|
---|
| 807 | i & 1
|
---|
| 808 | ? "q%u%s=%08RX32'%08RX32'%08RX32'%08RX32\n"
|
---|
| 809 | : "q%u%s=%08RX32'%08RX32'%08RX32'%08RX32 ",
|
---|
| 810 | i, i < 10 ? " " : "",
|
---|
| 811 | pCtx->aVRegs[i].au32[3],
|
---|
| 812 | pCtx->aVRegs[i].au32[2],
|
---|
| 813 | pCtx->aVRegs[i].au32[1],
|
---|
| 814 | pCtx->aVRegs[i].au32[0]);
|
---|
| 815 |
|
---|
| 816 | pHlp->pfnPrintf(pHlp, "mdscr_el1=%016RX64\n", pCtx->Mdscr.u64);
|
---|
| 817 | for (unsigned i = 0; i < RT_ELEMENTS(pCtx->aBp); i++)
|
---|
| 818 | pHlp->pfnPrintf(pHlp, "DbgBp%u%s: Control=%016RX64 Value=%016RX64\n",
|
---|
| 819 | i, i < 10 ? " " : "",
|
---|
| 820 | pCtx->aBp[i].Ctrl, pCtx->aBp[i].Value);
|
---|
| 821 |
|
---|
| 822 | for (unsigned i = 0; i < RT_ELEMENTS(pCtx->aWp); i++)
|
---|
| 823 | pHlp->pfnPrintf(pHlp, "DbgWp%u%s: Control=%016RX64 Value=%016RX64\n",
|
---|
| 824 | i, i < 10 ? " " : "",
|
---|
| 825 | pCtx->aWp[i].Ctrl, pCtx->aWp[i].Value);
|
---|
| 826 |
|
---|
| 827 | pHlp->pfnPrintf(pHlp, "APDAKey=%016RX64'%016RX64\n", pCtx->Apda.High.u64, pCtx->Apda.Low.u64);
|
---|
| 828 | pHlp->pfnPrintf(pHlp, "APDBKey=%016RX64'%016RX64\n", pCtx->Apdb.High.u64, pCtx->Apdb.Low.u64);
|
---|
| 829 | pHlp->pfnPrintf(pHlp, "APGAKey=%016RX64'%016RX64\n", pCtx->Apga.High.u64, pCtx->Apga.Low.u64);
|
---|
| 830 | pHlp->pfnPrintf(pHlp, "APIAKey=%016RX64'%016RX64\n", pCtx->Apia.High.u64, pCtx->Apia.Low.u64);
|
---|
| 831 | pHlp->pfnPrintf(pHlp, "APIBKey=%016RX64'%016RX64\n", pCtx->Apib.High.u64, pCtx->Apib.Low.u64);
|
---|
| 832 |
|
---|
| 833 | break;
|
---|
| 834 | }
|
---|
[98970] | 835 | }
|
---|
| 836 |
|
---|
| 837 |
|
---|
| 838 | /**
|
---|
| 839 | * Display all cpu states and any other cpum info.
|
---|
| 840 | *
|
---|
| 841 | * @param pVM The cross context VM structure.
|
---|
| 842 | * @param pHlp The info helper functions.
|
---|
| 843 | * @param pszArgs Arguments, ignored.
|
---|
| 844 | */
|
---|
| 845 | static DECLCALLBACK(void) cpumR3InfoAll(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
|
---|
| 846 | {
|
---|
| 847 | cpumR3InfoGuest(pVM, pHlp, pszArgs);
|
---|
| 848 | cpumR3InfoGuestInstr(pVM, pHlp, pszArgs);
|
---|
| 849 | }
|
---|
| 850 |
|
---|
| 851 |
|
---|
| 852 | /**
|
---|
| 853 | * Parses the info argument.
|
---|
| 854 | *
|
---|
| 855 | * The argument starts with 'verbose', 'terse' or 'default' and then
|
---|
| 856 | * continues with the comment string.
|
---|
| 857 | *
|
---|
| 858 | * @param pszArgs The pointer to the argument string.
|
---|
| 859 | * @param penmType Where to store the dump type request.
|
---|
| 860 | * @param ppszComment Where to store the pointer to the comment string.
|
---|
| 861 | */
|
---|
| 862 | static void cpumR3InfoParseArg(const char *pszArgs, CPUMDUMPTYPE *penmType, const char **ppszComment)
|
---|
| 863 | {
|
---|
| 864 | if (!pszArgs)
|
---|
| 865 | {
|
---|
| 866 | *penmType = CPUMDUMPTYPE_DEFAULT;
|
---|
| 867 | *ppszComment = "";
|
---|
| 868 | }
|
---|
| 869 | else
|
---|
| 870 | {
|
---|
| 871 | if (!strncmp(pszArgs, RT_STR_TUPLE("verbose")))
|
---|
| 872 | {
|
---|
| 873 | pszArgs += 7;
|
---|
| 874 | *penmType = CPUMDUMPTYPE_VERBOSE;
|
---|
| 875 | }
|
---|
| 876 | else if (!strncmp(pszArgs, RT_STR_TUPLE("terse")))
|
---|
| 877 | {
|
---|
| 878 | pszArgs += 5;
|
---|
| 879 | *penmType = CPUMDUMPTYPE_TERSE;
|
---|
| 880 | }
|
---|
| 881 | else if (!strncmp(pszArgs, RT_STR_TUPLE("default")))
|
---|
| 882 | {
|
---|
| 883 | pszArgs += 7;
|
---|
| 884 | *penmType = CPUMDUMPTYPE_DEFAULT;
|
---|
| 885 | }
|
---|
| 886 | else
|
---|
| 887 | *penmType = CPUMDUMPTYPE_DEFAULT;
|
---|
| 888 | *ppszComment = RTStrStripL(pszArgs);
|
---|
| 889 | }
|
---|
| 890 | }
|
---|
| 891 |
|
---|
| 892 |
|
---|
| 893 | /**
|
---|
| 894 | * Display the guest cpu state.
|
---|
| 895 | *
|
---|
| 896 | * @param pVM The cross context VM structure.
|
---|
| 897 | * @param pHlp The info helper functions.
|
---|
| 898 | * @param pszArgs Arguments.
|
---|
| 899 | */
|
---|
| 900 | static DECLCALLBACK(void) cpumR3InfoGuest(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
|
---|
| 901 | {
|
---|
| 902 | CPUMDUMPTYPE enmType;
|
---|
| 903 | const char *pszComment;
|
---|
| 904 | cpumR3InfoParseArg(pszArgs, &enmType, &pszComment);
|
---|
| 905 |
|
---|
| 906 | PVMCPU pVCpu = VMMGetCpu(pVM);
|
---|
| 907 | if (!pVCpu)
|
---|
| 908 | pVCpu = pVM->apCpusR3[0];
|
---|
| 909 |
|
---|
| 910 | pHlp->pfnPrintf(pHlp, "Guest CPUM (VCPU %d) state: %s\n", pVCpu->idCpu, pszComment);
|
---|
| 911 |
|
---|
| 912 | PCPUMCTX pCtx = &pVCpu->cpum.s.Guest;
|
---|
[100727] | 913 | cpumR3InfoOne(pVM, pCtx, pHlp, enmType);
|
---|
[98970] | 914 | }
|
---|
| 915 |
|
---|
| 916 |
|
---|
| 917 | /**
|
---|
| 918 | * Display the current guest instruction
|
---|
| 919 | *
|
---|
| 920 | * @param pVM The cross context VM structure.
|
---|
| 921 | * @param pHlp The info helper functions.
|
---|
| 922 | * @param pszArgs Arguments, ignored.
|
---|
| 923 | */
|
---|
| 924 | static DECLCALLBACK(void) cpumR3InfoGuestInstr(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
|
---|
| 925 | {
|
---|
| 926 | NOREF(pszArgs);
|
---|
| 927 |
|
---|
| 928 | PVMCPU pVCpu = VMMGetCpu(pVM);
|
---|
| 929 | if (!pVCpu)
|
---|
| 930 | pVCpu = pVM->apCpusR3[0];
|
---|
| 931 |
|
---|
| 932 | char szInstruction[256];
|
---|
| 933 | szInstruction[0] = '\0';
|
---|
| 934 | DBGFR3DisasInstrCurrent(pVCpu, szInstruction, sizeof(szInstruction));
|
---|
| 935 | pHlp->pfnPrintf(pHlp, "\nCPUM%u: %s\n\n", pVCpu->idCpu, szInstruction);
|
---|
| 936 | }
|
---|
| 937 |
|
---|
| 938 |
|
---|
| 939 | /**
|
---|
| 940 | * Called when the ring-3 init phase completes.
|
---|
| 941 | *
|
---|
| 942 | * @returns VBox status code.
|
---|
| 943 | * @param pVM The cross context VM structure.
|
---|
| 944 | * @param enmWhat Which init phase.
|
---|
| 945 | */
|
---|
| 946 | VMMR3DECL(int) CPUMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat)
|
---|
| 947 | {
|
---|
| 948 | RT_NOREF(pVM, enmWhat);
|
---|
| 949 | return VINF_SUCCESS;
|
---|
| 950 | }
|
---|
| 951 |
|
---|
| 952 |
|
---|
| 953 | /**
|
---|
| 954 | * Called when the ring-0 init phases completed.
|
---|
| 955 | *
|
---|
| 956 | * @param pVM The cross context VM structure.
|
---|
| 957 | */
|
---|
| 958 | VMMR3DECL(void) CPUMR3LogCpuIdAndMsrFeatures(PVM pVM)
|
---|
| 959 | {
|
---|
| 960 | /*
|
---|
| 961 | * Enable log buffering as we're going to log a lot of lines.
|
---|
| 962 | */
|
---|
| 963 | bool const fOldBuffered = RTLogRelSetBuffering(true /*fBuffered*/);
|
---|
| 964 |
|
---|
| 965 | /*
|
---|
| 966 | * Log the cpuid.
|
---|
| 967 | */
|
---|
| 968 | RTCPUSET OnlineSet;
|
---|
| 969 | LogRel(("CPUM: Logical host processors: %u present, %u max, %u online, online mask: %016RX64\n",
|
---|
| 970 | (unsigned)RTMpGetPresentCount(), (unsigned)RTMpGetCount(), (unsigned)RTMpGetOnlineCount(),
|
---|
| 971 | RTCpuSetToU64(RTMpGetOnlineSet(&OnlineSet)) ));
|
---|
| 972 | RTCPUID cCores = RTMpGetCoreCount();
|
---|
| 973 | if (cCores)
|
---|
| 974 | LogRel(("CPUM: Physical host cores: %u\n", (unsigned)cCores));
|
---|
| 975 | LogRel(("************************* CPUID dump ************************\n"));
|
---|
| 976 | DBGFR3Info(pVM->pUVM, "cpuid", "verbose", DBGFR3InfoLogRelHlp());
|
---|
| 977 | LogRel(("\n"));
|
---|
| 978 | DBGFR3_INFO_LOG_SAFE(pVM, "cpuid", "verbose"); /* macro */
|
---|
| 979 | LogRel(("******************** End of CPUID dump **********************\n"));
|
---|
| 980 |
|
---|
[101121] | 981 | LogRel(("******************** CPU feature dump ***********************\n"));
|
---|
| 982 | DBGFR3Info(pVM->pUVM, "cpufeat", "verbose", DBGFR3InfoLogRelHlp());
|
---|
| 983 | LogRel(("\n"));
|
---|
| 984 | DBGFR3_INFO_LOG_SAFE(pVM, "cpufeat", "verbose"); /* macro */
|
---|
| 985 | LogRel(("***************** End of CPU feature dump *******************\n"));
|
---|
| 986 |
|
---|
[98970] | 987 | /*
|
---|
| 988 | * Restore the log buffering state to what it was previously.
|
---|
| 989 | */
|
---|
| 990 | RTLogRelSetBuffering(fOldBuffered);
|
---|
| 991 | }
|
---|
| 992 |
|
---|
| 993 |
|
---|
| 994 | /**
|
---|
| 995 | * Marks the guest debug state as active.
|
---|
| 996 | *
|
---|
| 997 | * @param pVCpu The cross context virtual CPU structure.
|
---|
| 998 | *
|
---|
| 999 | * @note This is used solely by NEM (hence the name) to set the correct flags here
|
---|
| 1000 | * without loading the host's DRx registers, which is not possible from ring-3 anyway.
|
---|
| 1001 | * The specific NEM backends have to make sure to load the correct values.
|
---|
| 1002 | */
|
---|
| 1003 | VMMR3_INT_DECL(void) CPUMR3NemActivateGuestDebugState(PVMCPUCC pVCpu)
|
---|
| 1004 | {
|
---|
| 1005 | ASMAtomicAndU32(&pVCpu->cpum.s.fUseFlags, ~CPUM_USED_DEBUG_REGS_HYPER);
|
---|
| 1006 | ASMAtomicOrU32(&pVCpu->cpum.s.fUseFlags, CPUM_USED_DEBUG_REGS_GUEST);
|
---|
| 1007 | }
|
---|
| 1008 |
|
---|
| 1009 |
|
---|
| 1010 | /**
|
---|
| 1011 | * Marks the hyper debug state as active.
|
---|
| 1012 | *
|
---|
| 1013 | * @param pVCpu The cross context virtual CPU structure.
|
---|
| 1014 | *
|
---|
| 1015 | * @note This is used solely by NEM (hence the name) to set the correct flags here
|
---|
| 1016 | * without loading the host's debug registers, which is not possible from ring-3 anyway.
|
---|
| 1017 | * The specific NEM backends have to make sure to load the correct values.
|
---|
| 1018 | */
|
---|
| 1019 | VMMR3_INT_DECL(void) CPUMR3NemActivateHyperDebugState(PVMCPUCC pVCpu)
|
---|
| 1020 | {
|
---|
| 1021 | ASMAtomicAndU32(&pVCpu->cpum.s.fUseFlags, ~CPUM_USED_DEBUG_REGS_GUEST);
|
---|
| 1022 | ASMAtomicOrU32(&pVCpu->cpum.s.fUseFlags, CPUM_USED_DEBUG_REGS_HYPER);
|
---|
| 1023 | }
|
---|