aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/hvm/svm/svmdebug.c
blob: 2cb684fb00d89f9108292f4bbd4a84f858102bc7 (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
/*
 * svmdebug.c: debug functions
 * Copyright (c) 2011, Advanced Micro Devices, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope 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, write to the Free Software Foundation, Inc., 59 Temple
 * Place - Suite 330, Boston, MA 02111-1307 USA.
 *
 */

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

static void svm_dump_sel(const char *name, svm_segment_register_t *s)
{
    printk("%s: sel=0x%04x, attr=0x%04x, limit=0x%08x, base=0x%016llx\n", 
           name, s->sel, s->attr.bytes, s->limit,
           (unsigned long long)s->base);
}

/* This function can directly access fields which are covered by clean bits. */
void svm_vmcb_dump(const char *from, struct vmcb_struct *vmcb)
{
    printk("Dumping guest's current state at %s...\n", from);
    printk("Size of VMCB = %d, paddr = %#lx, vaddr = %p\n",
           (int) sizeof(struct vmcb_struct), virt_to_maddr(vmcb), vmcb);

    printk("cr_intercepts = %#x dr_intercepts = %#x "
           "exception_intercepts = %#x\n",
           vmcb->_cr_intercepts, vmcb->_dr_intercepts, 
           vmcb->_exception_intercepts);
    printk("general1_intercepts = %#x general2_intercepts = %#x\n",
           vmcb->_general1_intercepts, vmcb->_general2_intercepts);
    printk("iopm_base_pa = %#Lx msrpm_base_pa = %#Lx tsc_offset = %#Lx\n",
           (unsigned long long)vmcb->_iopm_base_pa,
           (unsigned long long)vmcb->_msrpm_base_pa,
           (unsigned long long)vmcb->_tsc_offset);
    printk("tlb_control = %#x vintr = %#Lx interrupt_shadow = %#Lx\n",
           vmcb->tlb_control,
           (unsigned long long)vmcb->_vintr.bytes,
           (unsigned long long)vmcb->interrupt_shadow);
    printk("exitcode = %#Lx exitintinfo = %#Lx\n",
           (unsigned long long)vmcb->exitcode,
           (unsigned long long)vmcb->exitintinfo.bytes);
    printk("exitinfo1 = %#Lx exitinfo2 = %#Lx \n",
           (unsigned long long)vmcb->exitinfo1,
           (unsigned long long)vmcb->exitinfo2);
    printk("np_enable = %Lx guest_asid = %#x\n",
           (unsigned long long)vmcb->_np_enable, vmcb->_guest_asid);
    printk("cpl = %d efer = %#Lx star = %#Lx lstar = %#Lx\n",
           vmcb->_cpl, (unsigned long long)vmcb->_efer,
           (unsigned long long)vmcb->star, (unsigned long long)vmcb->lstar);
    printk("CR0 = 0x%016llx CR2 = 0x%016llx\n",
           (unsigned long long)vmcb->_cr0, (unsigned long long)vmcb->_cr2);
    printk("CR3 = 0x%016llx CR4 = 0x%016llx\n", 
           (unsigned long long)vmcb->_cr3, (unsigned long long)vmcb->_cr4);
    printk("RSP = 0x%016llx  RIP = 0x%016llx\n", 
           (unsigned long long)vmcb->rsp, (unsigned long long)vmcb->rip);
    printk("RAX = 0x%016llx  RFLAGS=0x%016llx\n",
           (unsigned long long)vmcb->rax, (unsigned long long)vmcb->rflags);
    printk("DR6 = 0x%016llx, DR7 = 0x%016llx\n", 
           (unsigned long long)vmcb->_dr6, (unsigned long long)vmcb->_dr7);
    printk("CSTAR = 0x%016llx SFMask = 0x%016llx\n",
           (unsigned long long)vmcb->cstar, 
           (unsigned long long)vmcb->sfmask);
    printk("KernGSBase = 0x%016llx PAT = 0x%016llx \n", 
           (unsigned long long)vmcb->kerngsbase,
           (unsigned long long)vmcb->_g_pat);
    printk("H_CR3 = 0x%016llx CleanBits = %#x\n",
           (unsigned long long)vmcb->_h_cr3, vmcb->cleanbits.bytes);

    /* print out all the selectors */
    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_t
svm_vmcb_isvalid(const char *from, struct vmcb_struct *vmcb,
                 bool_t verbose)
{
    bool_t ret = 0; /* ok */

#define PRINTF(...) \
    if (verbose) { ret = 1; printk("%s: ", from); printk(__VA_ARGS__); \
    } else return 1;

    if ((vmcb->_efer & EFER_SVME) == 0) {
        PRINTF("EFER: SVME bit not set (%#"PRIx64")\n", vmcb->_efer);
    }

    if ((vmcb->_cr0 & X86_CR0_CD) == 0 && (vmcb->_cr0 & X86_CR0_NW) != 0) {
        PRINTF("CR0: CD bit is zero and NW bit set (%#"PRIx64")\n",
                vmcb->_cr0);
    }

    if ((vmcb->_cr0 >> 32U) != 0) {
        PRINTF("CR0: bits [63:32] are not zero (%#"PRIx64")\n",
                vmcb->_cr0);
    }

    if ((vmcb->_cr3 & 0x7) != 0) {
        PRINTF("CR3: MBZ bits are set (%#"PRIx64")\n", vmcb->_cr3);
    }
    if ((vmcb->_efer & EFER_LMA) && (vmcb->_cr3 & 0xfe) != 0) {
        PRINTF("CR3: MBZ bits are set (%#"PRIx64")\n", vmcb->_cr3);
    }

    if ((vmcb->_cr4 >> 19U) != 0) {
        PRINTF("CR4: bits [63:19] are not zero (%#"PRIx64")\n",
                vmcb->_cr4);
    }

    if (((vmcb->_cr4 >> 11U) & 0x7fU) != 0) {
        PRINTF("CR4: bits [17:11] are not zero (%#"PRIx64")\n",
                vmcb->_cr4);
    }

    if ((vmcb->_dr6 >> 32U) != 0) {
        PRINTF("DR6: bits [63:32] are not zero (%#"PRIx64")\n",
                vmcb->_dr6);
    }

    if ((vmcb->_dr7 >> 32U) != 0) {
        PRINTF("DR7: bits [63:32] are not zero (%#"PRIx64")\n",
                vmcb->_dr7);
    }

    if ((vmcb->_efer >> 15U) != 0) {
        PRINTF("EFER: bits [63:15] are not zero (%#"PRIx64")\n",
                vmcb->_efer);
    }

    if ((vmcb->_efer & EFER_LME) != 0 && ((vmcb->_cr0 & X86_CR0_PG) != 0)) {
        if ((vmcb->_cr4 & X86_CR4_PAE) == 0) {
            PRINTF("EFER_LME and CR0.PG are both set and CR4.PAE is zero.\n");
        }
        if ((vmcb->_cr0 & X86_CR0_PE) == 0) {
            PRINTF("EFER_LME and CR0.PG are both set and CR0.PE is zero.\n");
        }
    }

    if ((vmcb->_efer & EFER_LME) != 0
        && (vmcb->_cr0 & X86_CR0_PG) != 0
        && (vmcb->_cr4 & X86_CR4_PAE) != 0
        && (vmcb->cs.attr.fields.l != 0)
        && (vmcb->cs.attr.fields.db != 0))
    {
        PRINTF("EFER_LME, CR0.PG, CR4.PAE, CS.L and CS.D are all non-zero.\n");
    }

    if ((vmcb->_general2_intercepts & GENERAL2_INTERCEPT_VMRUN) == 0) {
        PRINTF("GENERAL2_INTERCEPT: VMRUN intercept bit is clear (%#"PRIx32")\n",
            vmcb->_general2_intercepts);
    }

    if (vmcb->eventinj.fields.resvd1 != 0) {
        PRINTF("eventinj: MBZ bits are set (%#"PRIx64")\n",
                vmcb->eventinj.bytes);
    }

    if (vmcb->_np_enable && vmcb->_h_cr3 == 0) {
        PRINTF("nested paging enabled but host cr3 is 0\n");
    }

#undef PRINTF
    return ret;
}

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