summaryrefslogtreecommitdiff
path: root/xen/arch/x86/hvm/svm/svmdebug.c
blob: 7d6dc9ef47db4c9f16c8a9003c0ffcb920886a95 (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
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * svmdebug.c: debug functions
 * Copyright (c) 2011, Advanced Micro Devices, Inc.
 *
 */

#include <xen/sched.h>
#include <asm/processor.h>
#include <asm/msr-index.h>
#include <asm/hvm/svm/svmdebug.h>

static void svm_dump_sel(const char *name, const struct segment_register *s)
{
    printk("%s: %04x %04x %08x %016"PRIx64"\n",
           name, s->sel, s->attr, s->limit, s->base);
}

void svm_vmcb_dump(const char *from, const struct vmcb_struct *vmcb)
{
    struct vcpu *curr = current;

    /*
     * If we are dumping the VMCB currently in context, some guest state may
     * still be cached in hardware.  Retrieve it.
     */
    if ( vmcb == curr->arch.hvm.svm.vmcb )
        svm_sync_vmcb(curr, vmcb_in_sync);

    printk("Dumping guest's current state at %s...\n", from);
    printk("Size of VMCB = %zu, paddr = %"PRIpaddr", vaddr = %p\n",
           sizeof(struct vmcb_struct), virt_to_maddr(vmcb), vmcb);

    printk("cr_intercepts = %#x dr_intercepts = %#x "
           "exception_intercepts = %#x\n",
           vmcb_get_cr_intercepts(vmcb), vmcb_get_dr_intercepts(vmcb),
           vmcb_get_exception_intercepts(vmcb));
    printk("general1_intercepts = %#x general2_intercepts = %#x\n",
           vmcb_get_general1_intercepts(vmcb), vmcb_get_general2_intercepts(vmcb));
    printk("iopm_base_pa = %#"PRIx64" msrpm_base_pa = %#"PRIx64" tsc_offset = %#"PRIx64"\n",
           vmcb_get_iopm_base_pa(vmcb), vmcb_get_msrpm_base_pa(vmcb),
           vmcb_get_tsc_offset(vmcb));
    printk("tlb_control = %#x vintr = %#"PRIx64" int_stat = %#"PRIx64"\n",
           vmcb->tlb_control, vmcb_get_vintr(vmcb).bytes,
           vmcb->int_stat.raw);
    printk("event_inj %016"PRIx64", valid? %d, ec? %d, type %u, vector %#x\n",
           vmcb->event_inj.raw, vmcb->event_inj.v,
           vmcb->event_inj.ev, vmcb->event_inj.type,
           vmcb->event_inj.vector);
    printk("exitcode = %#"PRIx64" exit_int_info = %#"PRIx64"\n",
           vmcb->exitcode, vmcb->exit_int_info.raw);
    printk("exitinfo1 = %#"PRIx64" exitinfo2 = %#"PRIx64"\n",
           vmcb->exitinfo1, vmcb->exitinfo2);
    printk("np_ctrl = %#"PRIx64" guest_asid = %#x\n",
           vmcb_get_np_ctrl(vmcb), vmcb_get_guest_asid(vmcb));
    printk("virtual vmload/vmsave = %d, virt_ext = %#"PRIx64"\n",
           vmcb->virt_ext.fields.vloadsave_enable, vmcb->virt_ext.bytes);
    printk("cpl = %d efer = %#"PRIx64" star = %#"PRIx64" lstar = %#"PRIx64"\n",
           vmcb_get_cpl(vmcb), vmcb_get_efer(vmcb), vmcb->star, vmcb->lstar);
    printk("CR0 = 0x%016"PRIx64" CR2 = 0x%016"PRIx64"\n",
           vmcb_get_cr0(vmcb), vmcb_get_cr2(vmcb));
    printk("CR3 = 0x%016"PRIx64" CR4 = 0x%016"PRIx64"\n",
           vmcb_get_cr3(vmcb), vmcb_get_cr4(vmcb));
    printk("RSP = 0x%016"PRIx64"  RIP = 0x%016"PRIx64"\n",
           vmcb->rsp, vmcb->rip);
    printk("RAX = 0x%016"PRIx64"  RFLAGS=0x%016"PRIx64"\n",
           vmcb->rax, vmcb->rflags);
    printk("DR6 = 0x%016"PRIx64", DR7 = 0x%016"PRIx64"\n",
           vmcb_get_dr6(vmcb), vmcb_get_dr7(vmcb));
    printk("CSTAR = 0x%016"PRIx64" SFMask = 0x%016"PRIx64"\n",
           vmcb->cstar, vmcb->sfmask);
    printk("KernGSBase = 0x%016"PRIx64" PAT = 0x%016"PRIx64"\n",
           vmcb->kerngsbase, vmcb_get_g_pat(vmcb));
    printk("SSP = 0x%016"PRIx64" S_CET = 0x%016"PRIx64" ISST = 0x%016"PRIx64"\n",
           vmcb->_ssp, vmcb->_msr_s_cet, vmcb->_msr_isst);
    printk("H_CR3 = 0x%016"PRIx64" CleanBits = %#x\n",
           vmcb_get_h_cr3(vmcb), vmcb->cleanbits.raw);

    /* print out all the selectors */
    printk("       sel attr  limit   base\n");
    svm_dump_sel("  CS", &vmcb->cs);
    svm_dump_sel("  DS", &vmcb->ds);
    svm_dump_sel("  SS", &vmcb->ss);
    svm_dump_sel("  ES", &vmcb->es);
    svm_dump_sel("  FS", &vmcb->fs);
    svm_dump_sel("  GS", &vmcb->gs);
    svm_dump_sel("GDTR", &vmcb->gdtr);
    svm_dump_sel("LDTR", &vmcb->ldtr);
    svm_dump_sel("IDTR", &vmcb->idtr);
    svm_dump_sel("  TR", &vmcb->tr);
}

bool svm_vmcb_isvalid(const char *from, const struct vmcb_struct *vmcb,
                      const struct vcpu *v, bool verbose)
{
    bool ret = false; /* ok */
    unsigned long cr0 = vmcb_get_cr0(vmcb);
    unsigned long cr3 = vmcb_get_cr3(vmcb);
    unsigned long cr4 = vmcb_get_cr4(vmcb);
    unsigned long valid;
    uint64_t efer = vmcb_get_efer(vmcb);

#define PRINTF(fmt, args...) do { \
    if ( !verbose ) return true; \
    ret = true; \
    printk(XENLOG_GUEST "%pv[%s]: " fmt, v, from, ## args); \
} while (0)

    if ( !(efer & EFER_SVME) )
        PRINTF("EFER: SVME bit not set (%#"PRIx64")\n", efer);

    if ( !(cr0 & X86_CR0_CD) && (cr0 & X86_CR0_NW) )
        PRINTF("CR0: CD bit is zero and NW bit set (%#"PRIx64")\n", cr0);

    if ( cr0 >> 32 )
        PRINTF("CR0: bits [63:32] are not zero (%#"PRIx64")\n", cr0);

    if ( (cr0 & X86_CR0_PG) &&
         ((cr3 & 7) ||
          ((!(cr4 & X86_CR4_PAE) || (efer & EFER_LMA)) && (cr3 & 0xfe0)) ||
          ((efer & EFER_LMA) &&
           (cr3 >> v->domain->arch.cpuid->extd.maxphysaddr))) )
        PRINTF("CR3: MBZ bits are set (%#"PRIx64")\n", cr3);

    valid = hvm_cr4_guest_valid_bits(v->domain);
    if ( cr4 & ~valid )
        PRINTF("CR4: invalid bits are set (%#"PRIx64", valid: %#"PRIx64")\n",
               cr4, valid);

    if ( vmcb_get_dr6(vmcb) >> 32 )
        PRINTF("DR6: bits [63:32] are not zero (%#"PRIx64")\n",
               vmcb_get_dr6(vmcb));

    if ( vmcb_get_dr7(vmcb) >> 32 )
        PRINTF("DR7: bits [63:32] are not zero (%#"PRIx64")\n",
               vmcb_get_dr7(vmcb));

    if ( efer & ~EFER_KNOWN_MASK )
        PRINTF("EFER: unknown bits are not zero (%#"PRIx64")\n", efer);

    if ( hvm_efer_valid(v, efer, -1) )
        PRINTF("EFER: %s (%"PRIx64")\n", hvm_efer_valid(v, efer, -1), efer);

    if ( (efer & EFER_LME) && (cr0 & X86_CR0_PG) )
    {
        if ( !(cr4 & X86_CR4_PAE) )
            PRINTF("EFER_LME and CR0.PG are both set and CR4.PAE is zero\n");
        if ( !(cr0 & X86_CR0_PE) )
            PRINTF("EFER_LME and CR0.PG are both set and CR0.PE is zero\n");
    }

    if ( (efer & EFER_LME) && (cr0 & X86_CR0_PG) && (cr4 & X86_CR4_PAE) &&
         vmcb->cs.l && vmcb->cs.db )
        PRINTF("EFER_LME, CR0.PG, CR4.PAE, CS.L and CS.D are all non-zero\n");

    if ( !(vmcb_get_general2_intercepts(vmcb) & GENERAL2_INTERCEPT_VMRUN) )
        PRINTF("GENERAL2_INTERCEPT: VMRUN intercept bit is clear (%#"PRIx32")\n",
               vmcb_get_general2_intercepts(vmcb));

    if ( vmcb->event_inj.resvd1 )
        PRINTF("eventinj: MBZ bits are set (%#"PRIx64")\n",
               vmcb->event_inj.raw);

#undef PRINTF
    return ret;
}

/*
 * Local variables:
 * mode: C
 * c-file-style: "BSD"
 * c-basic-offset: 4
 * tab-width: 4
 * indent-tabs-mode: nil
 * End:
 */