summaryrefslogtreecommitdiff
path: root/src/VBox/VMM/VMMR3/CPUM-armv8.cpp
blob: 5d0d654ce86aafc31b50913ccdd73ae4b9bd0a48 (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
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
/* $Id$ */
/** @file
 * CPUM - CPU Monitor / Manager (ARMv8 variant).
 */

/*
 * Copyright (C) 2023 Oracle and/or its affiliates.
 *
 * This file is part of VirtualBox base platform packages, as
 * available from https://www.virtualbox.org.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation, in version 3 of the
 * License.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <https://www.gnu.org/licenses>.
 *
 * SPDX-License-Identifier: GPL-3.0-only
 */

/** @page pg_cpum CPUM - CPU Monitor / Manager
 *
 * The CPU Monitor / Manager keeps track of all the CPU registers.
 * This is the ARMv8 variant which is doing much less than its x86/amd64
 * counterpart due to the fact that we currently only support the NEM backends
 * for running ARM guests. It might become complex iff we decide to implement our
 * own hypervisor.
 *
 * @section sec_cpum_logging_armv8      Logging Level Assignments.
 *
 * Following log level assignments:
 *      - @todo
 *
 */


/*********************************************************************************************************************************
*   Header Files                                                                                                                 *
*********************************************************************************************************************************/
#define LOG_GROUP LOG_GROUP_CPUM
#define CPUM_WITH_NONCONST_HOST_FEATURES
#include <VBox/vmm/cpum.h>
#include <VBox/vmm/cpumdis.h>
#include <VBox/vmm/pgm.h>
#include <VBox/vmm/mm.h>
#include <VBox/vmm/em.h>
#include <VBox/vmm/iem.h>
#include <VBox/vmm/dbgf.h>
#include <VBox/vmm/ssm.h>
#include "CPUMInternal-armv8.h"
#include <VBox/vmm/vm.h>

#include <VBox/param.h>
#include <VBox/dis.h>
#include <VBox/err.h>
#include <VBox/log.h>
#include <iprt/assert.h>
#include <iprt/cpuset.h>
#include <iprt/mem.h>
#include <iprt/mp.h>
#include <iprt/string.h>
#include <iprt/armv8.h>


/*********************************************************************************************************************************
*   Structures and Typedefs                                                                                                      *
*********************************************************************************************************************************/

/**
 * What kind of cpu info dump to perform.
 */
typedef enum CPUMDUMPTYPE
{
    CPUMDUMPTYPE_TERSE,
    CPUMDUMPTYPE_DEFAULT,
    CPUMDUMPTYPE_VERBOSE
} CPUMDUMPTYPE;
/** Pointer to a cpu info dump type. */
typedef CPUMDUMPTYPE *PCPUMDUMPTYPE;


/*********************************************************************************************************************************
*   Internal Functions                                                                                                           *
*********************************************************************************************************************************/
static DECLCALLBACK(int)  cpumR3LiveExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass);
static DECLCALLBACK(int)  cpumR3SaveExec(PVM pVM, PSSMHANDLE pSSM);
static DECLCALLBACK(int)  cpumR3LoadPrep(PVM pVM, PSSMHANDLE pSSM);
static DECLCALLBACK(int)  cpumR3LoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
static DECLCALLBACK(int)  cpumR3LoadDone(PVM pVM, PSSMHANDLE pSSM);
static DECLCALLBACK(void) cpumR3InfoAll(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
static DECLCALLBACK(void) cpumR3InfoGuest(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
static DECLCALLBACK(void) cpumR3InfoGuestInstr(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);


/*********************************************************************************************************************************
*   Global Variables                                                                                                             *
*********************************************************************************************************************************/
#if 0 /** @todo Will come later. */
/** Saved state field descriptors for CPUMCTX. */
static const SSMFIELD g_aCpumCtxFields[] =
{
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[0].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[1].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[2].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[3].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[4].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[5].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[6].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[7].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[8].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[9].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[10].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[11].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[12].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[13].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[14].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[15].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[16].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[17].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[18].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[19].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[20].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[21].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[22].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[23].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[24].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[25].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[26].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[27].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[28].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[29].x),
    SSMFIELD_ENTRY(         CPUMCTX, aGRegs[30].x),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[0].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[1].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[2].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[3].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[4].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[5].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[6].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[7].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[8].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[9].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[10].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[11].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[12].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[13].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[14].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[15].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[16].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[17].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[18].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[19].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[20].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[21].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[22].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[23].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[24].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[25].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[26].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[27].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[28].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[29].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[30].v),
    SSMFIELD_ENTRY(         CPUMCTX, aVRegs[31].v),
    SSMFIELD_ENTRY(         CPUMCTX, aSpReg[0].u64),
    SSMFIELD_ENTRY(         CPUMCTX, aSpReg[1].u64),
    SSMFIELD_ENTRY(         CPUMCTX, Pc.u64),
    SSMFIELD_ENTRY(         CPUMCTX, Spsr.u64),
    SSMFIELD_ENTRY(         CPUMCTX, Elr.u64),
    SSMFIELD_ENTRY(         CPUMCTX, fpcr),
    SSMFIELD_ENTRY(         CPUMCTX, fpsr),
    SSMFIELD_ENTRY(         CPUMCTX, fPState),
    /** @todo */
    SSMFIELD_ENTRY_TERM()
};
#endif


/**
 * Initializes the CPUM.
 *
 * @returns VBox status code.
 * @param   pVM         The cross context VM structure.
 */
VMMR3DECL(int) CPUMR3Init(PVM pVM)
{
    LogFlow(("CPUMR3Init\n"));

    /*
     * Assert alignment, sizes and tables.
     */
    AssertCompileMemberAlignment(VM, cpum.s, 32);
    AssertCompile(sizeof(pVM->cpum.s) <= sizeof(pVM->cpum.padding));
    AssertCompileSizeAlignment(CPUMCTX, 64);
    AssertCompileMemberAlignment(VM, cpum, 64);
    AssertCompileMemberAlignment(VMCPU, cpum.s, 64);
#ifdef VBOX_STRICT
    int rc2 = cpumR3SysRegStrictInitChecks();
    AssertRCReturn(rc2, rc2);
#endif

    pVM->cpum.s.GuestInfo.paSysRegRangesR3 = &pVM->cpum.s.GuestInfo.aSysRegRanges[0];

    /*
     * Register saved state data item.
     */
    int rc = SSMR3RegisterInternal(pVM, "cpum", 1, CPUM_SAVED_STATE_VERSION, sizeof(CPUM),
                                   NULL, cpumR3LiveExec, NULL,
                                   NULL, cpumR3SaveExec, NULL,
                                   cpumR3LoadPrep, cpumR3LoadExec, cpumR3LoadDone);
    if (RT_FAILURE(rc))
        return rc;

    /*
     * Register info handlers and registers with the debugger facility.
     */
    DBGFR3InfoRegisterInternalEx(pVM, "cpum",             "Displays the all the cpu states.",
                                 &cpumR3InfoAll, DBGFINFO_FLAGS_ALL_EMTS);
    DBGFR3InfoRegisterInternalEx(pVM, "cpumguest",        "Displays the guest cpu state.",
                                 &cpumR3InfoGuest, DBGFINFO_FLAGS_ALL_EMTS);

    rc = cpumR3DbgInit(pVM);
    if (RT_FAILURE(rc))
        return rc;

    /*
     * Initialize the general guest CPU state.
     */
    CPUMR3Reset(pVM);

    return VINF_SUCCESS;
}


/**
 * Applies relocations to data and code managed by this
 * component. This function will be called at init and
 * whenever the VMM need to relocate it self inside the GC.
 *
 * The CPUM will update the addresses used by the switcher.
 *
 * @param   pVM     The cross context VM structure.
 */
VMMR3DECL(void) CPUMR3Relocate(PVM pVM)
{
    RT_NOREF(pVM);
}


/**
 * Terminates the CPUM.
 *
 * Termination means cleaning up and freeing all resources,
 * the VM it self is at this point powered off or suspended.
 *
 * @returns VBox status code.
 * @param   pVM         The cross context VM structure.
 */
VMMR3DECL(int) CPUMR3Term(PVM pVM)
{
    RT_NOREF(pVM);
    return VINF_SUCCESS;
}


/**
 * Resets a virtual CPU.
 *
 * Used by CPUMR3Reset and CPU hot plugging.
 *
 * @param   pVM     The cross context VM structure.
 * @param   pVCpu   The cross context virtual CPU structure of the CPU that is
 *                  being reset.  This may differ from the current EMT.
 */
VMMR3DECL(void) CPUMR3ResetCpu(PVM pVM, PVMCPU pVCpu)
{
    RT_NOREF(pVM);

    /** @todo anything different for VCPU > 0? */
    PCPUMCTX pCtx = &pVCpu->cpum.s.Guest;

    /*
     * Initialize everything to ZERO first.
     */
    RT_BZERO(pCtx, sizeof(*pCtx));

    /* Start in Supervisor mode. */
    /** @todo Differentiate between Aarch64 and Aarch32 configuation. */
    pCtx->fPState =   ARMV8_SPSR_EL2_AARCH64_SET_EL(ARMV8_AARCH64_EL_1)
                    | ARMV8_SPSR_EL2_AARCH64_SP
                    | ARMV8_SPSR_EL2_AARCH64_D
                    | ARMV8_SPSR_EL2_AARCH64_A
                    | ARMV8_SPSR_EL2_AARCH64_I
                    | ARMV8_SPSR_EL2_AARCH64_F;
    /** @todo */
}


/**
 * Resets the CPU.
 *
 * @returns VINF_SUCCESS.
 * @param   pVM         The cross context VM structure.
 */
VMMR3DECL(void) CPUMR3Reset(PVM pVM)
{
    for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
    {
        PVMCPU pVCpu = pVM->apCpusR3[idCpu];
        CPUMR3ResetCpu(pVM, pVCpu);
    }
}




/**
 * Pass 0 live exec callback.
 *
 * @returns VINF_SSM_DONT_CALL_AGAIN.
 * @param   pVM                 The cross context VM structure.
 * @param   pSSM                The saved state handle.
 * @param   uPass               The pass (0).
 */
static DECLCALLBACK(int) cpumR3LiveExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass)
{
    AssertReturn(uPass == 0, VERR_SSM_UNEXPECTED_PASS);
    /** @todo */ RT_NOREF(pVM, pSSM);
    return VINF_SSM_DONT_CALL_AGAIN;
}


/**
 * Execute state save operation.
 *
 * @returns VBox status code.
 * @param   pVM             The cross context VM structure.
 * @param   pSSM            SSM operation handle.
 */
static DECLCALLBACK(int) cpumR3SaveExec(PVM pVM, PSSMHANDLE pSSM)
{
    /*
     * Save.
     */
    SSMR3PutU32(pSSM, pVM->cCpus);
    /** @todo */
    return VINF_SUCCESS;
}


/**
 * @callback_method_impl{FNSSMINTLOADPREP}
 */
static DECLCALLBACK(int) cpumR3LoadPrep(PVM pVM, PSSMHANDLE pSSM)
{
    RT_NOREF(pSSM);
    pVM->cpum.s.fPendingRestore = true;
    return VINF_SUCCESS;
}


/**
 * @callback_method_impl{FNSSMINTLOADEXEC}
 */
static DECLCALLBACK(int) cpumR3LoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
{
    /*
     * Validate version.
     */
    /** @todo */ RT_NOREF(pSSM, uVersion);

    if (uPass == SSM_PASS_FINAL)
    {
        /** @todo */
    }

    pVM->cpum.s.fPendingRestore = false;
    return VINF_SUCCESS;
}


/**
 * @callback_method_impl{FNSSMINTLOADDONE}
 */
static DECLCALLBACK(int) cpumR3LoadDone(PVM pVM, PSSMHANDLE pSSM)
{
    if (RT_FAILURE(SSMR3HandleGetStatus(pSSM)))
        return VINF_SUCCESS;

    /* just check this since we can. */ /** @todo Add a SSM unit flag for indicating that it's mandatory during a restore.  */
    if (pVM->cpum.s.fPendingRestore)
    {
        LogRel(("CPUM: Missing state!\n"));
        return VERR_INTERNAL_ERROR_2;
    }

    /** @todo */
    return VINF_SUCCESS;
}


/**
 * Checks if the CPUM state restore is still pending.
 *
 * @returns true / false.
 * @param   pVM                 The cross context VM structure.
 */
VMMDECL(bool) CPUMR3IsStateRestorePending(PVM pVM)
{
    return pVM->cpum.s.fPendingRestore;
}


/**
 * Formats the PSTATE value into mnemonics.
 *
 * @param   pszPState   Where to write the mnemonics. (Assumes sufficient buffer space.)
 * @param   fPState     The PSTATE value with both guest hardware and VBox
 *                      internal bits included.
 */
static void cpumR3InfoFormatPState(char *pszPState, uint32_t fPState)
{
    /*
     * Format the flags.
     */
    static const struct
    {
        const char *pszSet; const char *pszClear; uint32_t fFlag;
    }   s_aFlags[] =
    {
        { NULL, NULL, 0 }, /** @todo */
    };
    char *psz = pszPState;
    for (unsigned i = 0; i < RT_ELEMENTS(s_aFlags); i++)
    {
        const char *pszAdd = s_aFlags[i].fFlag & fPState ? s_aFlags[i].pszSet : s_aFlags[i].pszClear;
        if (pszAdd)
        {
            strcpy(psz, pszAdd);
            psz += strlen(pszAdd);
            *psz++ = ' ';
        }
    }
    psz[-1] = '\0';
}


/**
 * Formats a full register dump.
 *
 * @param   pVM         The cross context VM structure.
 * @param   pCtx        The context to format.
 * @param   pHlp        Output functions.
 * @param   enmType     The dump type.
 * @param   pszPrefix   Register name prefix.
 */
static void cpumR3InfoOne(PVM pVM, PCPUMCTX pCtx, PCDBGFINFOHLP pHlp, CPUMDUMPTYPE enmType, const char *pszPrefix)
{
    RT_NOREF(pVM, pHlp, enmType, pszPrefix);

    /*
     * Format the PSTATE.
     */
    char szPState[80];
    cpumR3InfoFormatPState(&szPState[0], pCtx->fPState);

    /** @todo */
}


/**
 * Display all cpu states and any other cpum info.
 *
 * @param   pVM         The cross context VM structure.
 * @param   pHlp        The info helper functions.
 * @param   pszArgs     Arguments, ignored.
 */
static DECLCALLBACK(void) cpumR3InfoAll(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
{
    cpumR3InfoGuest(pVM, pHlp, pszArgs);
    cpumR3InfoGuestInstr(pVM, pHlp, pszArgs);
}


/**
 * Parses the info argument.
 *
 * The argument starts with 'verbose', 'terse' or 'default' and then
 * continues with the comment string.
 *
 * @param   pszArgs         The pointer to the argument string.
 * @param   penmType        Where to store the dump type request.
 * @param   ppszComment     Where to store the pointer to the comment string.
 */
static void cpumR3InfoParseArg(const char *pszArgs, CPUMDUMPTYPE *penmType, const char **ppszComment)
{
    if (!pszArgs)
    {
        *penmType = CPUMDUMPTYPE_DEFAULT;
        *ppszComment = "";
    }
    else
    {
        if (!strncmp(pszArgs, RT_STR_TUPLE("verbose")))
        {
            pszArgs += 7;
            *penmType = CPUMDUMPTYPE_VERBOSE;
        }
        else if (!strncmp(pszArgs, RT_STR_TUPLE("terse")))
        {
            pszArgs += 5;
            *penmType = CPUMDUMPTYPE_TERSE;
        }
        else if (!strncmp(pszArgs, RT_STR_TUPLE("default")))
        {
            pszArgs += 7;
            *penmType = CPUMDUMPTYPE_DEFAULT;
        }
        else
            *penmType = CPUMDUMPTYPE_DEFAULT;
        *ppszComment = RTStrStripL(pszArgs);
    }
}


/**
 * Display the guest cpu state.
 *
 * @param   pVM         The cross context VM structure.
 * @param   pHlp        The info helper functions.
 * @param   pszArgs     Arguments.
 */
static DECLCALLBACK(void) cpumR3InfoGuest(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
{
    CPUMDUMPTYPE enmType;
    const char *pszComment;
    cpumR3InfoParseArg(pszArgs, &enmType, &pszComment);

    PVMCPU pVCpu = VMMGetCpu(pVM);
    if (!pVCpu)
        pVCpu = pVM->apCpusR3[0];

    pHlp->pfnPrintf(pHlp, "Guest CPUM (VCPU %d) state: %s\n", pVCpu->idCpu, pszComment);

    PCPUMCTX pCtx = &pVCpu->cpum.s.Guest;
    cpumR3InfoOne(pVM, pCtx, pHlp, enmType, "");
}


/**
 * Display the current guest instruction
 *
 * @param   pVM         The cross context VM structure.
 * @param   pHlp        The info helper functions.
 * @param   pszArgs     Arguments, ignored.
 */
static DECLCALLBACK(void) cpumR3InfoGuestInstr(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
{
    NOREF(pszArgs);

    PVMCPU pVCpu = VMMGetCpu(pVM);
    if (!pVCpu)
        pVCpu = pVM->apCpusR3[0];

    char szInstruction[256];
    szInstruction[0] = '\0';
    DBGFR3DisasInstrCurrent(pVCpu, szInstruction, sizeof(szInstruction));
    pHlp->pfnPrintf(pHlp, "\nCPUM%u: %s\n\n", pVCpu->idCpu, szInstruction);
}


/**
 * Called when the ring-3 init phase completes.
 *
 * @returns VBox status code.
 * @param   pVM                 The cross context VM structure.
 * @param   enmWhat             Which init phase.
 */
VMMR3DECL(int) CPUMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat)
{
    RT_NOREF(pVM, enmWhat);
    return VINF_SUCCESS;
}


/**
 * Called when the ring-0 init phases completed.
 *
 * @param   pVM                 The cross context VM structure.
 */
VMMR3DECL(void) CPUMR3LogCpuIdAndMsrFeatures(PVM pVM)
{
    /*
     * Enable log buffering as we're going to log a lot of lines.
     */
    bool const fOldBuffered = RTLogRelSetBuffering(true /*fBuffered*/);

    /*
     * Log the cpuid.
     */
    RTCPUSET OnlineSet;
    LogRel(("CPUM: Logical host processors: %u present, %u max, %u online, online mask: %016RX64\n",
                (unsigned)RTMpGetPresentCount(), (unsigned)RTMpGetCount(), (unsigned)RTMpGetOnlineCount(),
                RTCpuSetToU64(RTMpGetOnlineSet(&OnlineSet)) ));
    RTCPUID cCores = RTMpGetCoreCount();
    if (cCores)
        LogRel(("CPUM: Physical host cores: %u\n", (unsigned)cCores));
    RT_NOREF(pVM);
#if 0 /** @todo Someting similar. */
    LogRel(("************************* CPUID dump ************************\n"));
    DBGFR3Info(pVM->pUVM, "cpuid", "verbose", DBGFR3InfoLogRelHlp());
    LogRel(("\n"));
    DBGFR3_INFO_LOG_SAFE(pVM, "cpuid", "verbose"); /* macro */
    LogRel(("******************** End of CPUID dump **********************\n"));
#endif

    /*
     * Restore the log buffering state to what it was previously.
     */
    RTLogRelSetBuffering(fOldBuffered);
}


/**
 * Marks the guest debug state as active.
 *
 * @returns nothing.
 * @param   pVCpu       The cross context virtual CPU structure.
 *
 * @note This is used solely by NEM (hence the name) to set the correct flags here
 *       without loading the host's DRx registers, which is not possible from ring-3 anyway.
 *       The specific NEM backends have to make sure to load the correct values.
 */
VMMR3_INT_DECL(void) CPUMR3NemActivateGuestDebugState(PVMCPUCC pVCpu)
{
    ASMAtomicAndU32(&pVCpu->cpum.s.fUseFlags, ~CPUM_USED_DEBUG_REGS_HYPER);
    ASMAtomicOrU32(&pVCpu->cpum.s.fUseFlags, CPUM_USED_DEBUG_REGS_GUEST);
}


/**
 * Marks the hyper debug state as active.
 *
 * @returns nothing.
 * @param   pVCpu       The cross context virtual CPU structure.
 *
 * @note This is used solely by NEM (hence the name) to set the correct flags here
 *       without loading the host's debug registers, which is not possible from ring-3 anyway.
 *       The specific NEM backends have to make sure to load the correct values.
 */
VMMR3_INT_DECL(void) CPUMR3NemActivateHyperDebugState(PVMCPUCC pVCpu)
{
    ASMAtomicAndU32(&pVCpu->cpum.s.fUseFlags, ~CPUM_USED_DEBUG_REGS_GUEST);
    ASMAtomicOrU32(&pVCpu->cpum.s.fUseFlags, CPUM_USED_DEBUG_REGS_HYPER);
}