debuggers.hg

view tools/firmware/hvmloader/tests.c @ 19992:8ce42378828b

hvmloader: Add new test for MSR_SHADOW_GS_BASE validity after SWAPGS instruction.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jul 16 10:30:50 2009 +0100 (2009-07-16)
parents 2ec019301ad8
children b9cdcf502aa3
line source
1 /*
2 * tests.c: HVM environment tests.
3 *
4 * Copyright (c) 2008, Citrix Systems, Inc.
5 *
6 * Authors:
7 * Keir Fraser <keir.fraser@citrix.com>
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms and conditions of the GNU General Public License,
11 * version 2, as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
20 * Place - Suite 330, Boston, MA 02111-1307 USA.
21 */
23 #include "util.h"
25 #define TEST_FAIL 0
26 #define TEST_PASS 1
27 #define TEST_SKIP 2
29 /*
30 * Memory layout during tests:
31 * 4MB to 8MB is cleared.
32 * Page directory resides at 8MB.
33 * 4 page table pages reside at 8MB+4kB to 8MB+20kB.
34 * Pagetables identity-map 0-16MB, except 4kB at va 6MB maps to pa 5MB.
35 */
36 #define PD_START (8ul << 20)
37 #define PT_START (PD_START + 4096)
39 static void setup_paging(void)
40 {
41 uint32_t *pd = (uint32_t *)PD_START;
42 uint32_t *pt = (uint32_t *)PT_START;
43 uint32_t i;
45 /* Identity map 0-16MB. */
46 for ( i = 0; i < 4; i++ )
47 pd[i] = (unsigned long)pt + (i<<12) + 3;
48 for ( i = 0; i < (4*1024); i++ )
49 pt[i] = (i << 12) + 3;
51 /* Page at virtual 6MB maps to physical 5MB. */
52 pt[6u<<8] -= 0x100000u;
53 }
55 static void start_paging(void)
56 {
57 asm volatile (
58 "mov %%eax,%%cr3; mov %%cr0,%%eax; "
59 "orl $0x80000000,%%eax; mov %%eax,%%cr0; "
60 "jmp 1f; 1:"
61 : : "a" (PD_START) : "memory" );
62 }
64 static void stop_paging(void)
65 {
66 asm volatile (
67 "mov %%cr0,%%eax; andl $0x7fffffff,%%eax; mov %%eax,%%cr0; "
68 "jmp 1f; 1:"
69 : : : "eax", "memory" );
70 }
72 /*
73 * rep_io_test: Tests REP INSB both forwards and backwards (EF.DF={0,1}) across
74 * a discontiguous page boundary.
75 */
76 static int rep_io_test(void)
77 {
78 uint32_t *p;
79 uint32_t i, p0, p1, p2;
80 int okay = TEST_PASS;
82 static const struct {
83 unsigned long addr;
84 uint32_t expected;
85 } check[] = {
86 { 0x00500000, 0x987654ff },
87 { 0x00500ffc, 0xff000000 },
88 { 0x005ffffc, 0xff000000 },
89 { 0x00601000, 0x000000ff },
90 { 0, 0 }
91 };
93 start_paging();
95 /* Phys 5MB = 0xdeadbeef */
96 *(uint32_t *)0x500000ul = 0xdeadbeef;
98 /* Phys 5MB = 0x98765432 */
99 *(uint32_t *)0x600000ul = 0x98765432;
101 /* Phys 0x5fffff = Phys 0x500000 = 0xff (byte) */
102 asm volatile (
103 "rep insb"
104 : "=d" (p0), "=c" (p1), "=D" (p2)
105 : "0" (0x5f), "1" (2), "2" (0x5ffffful) : "memory" );
107 /* Phys 0x500fff = Phys 0x601000 = 0xff (byte) */
108 asm volatile (
109 "std ; rep insb ; cld"
110 : "=d" (p0), "=c" (p1), "=D" (p2)
111 : "0" (0x5f), "1" (2), "2" (0x601000ul) : "memory" );
113 stop_paging();
115 i = 0;
116 for ( p = (uint32_t *)0x400000ul; p < (uint32_t *)0x700000ul; p++ )
117 {
118 uint32_t expected = 0;
119 if ( check[i].addr == (unsigned long)p )
120 {
121 expected = check[i].expected;
122 i++;
123 }
124 if ( *p != expected )
125 {
126 printf("Bad value at 0x%08lx: saw %08x expected %08x\n",
127 (unsigned long)p, *p, expected);
128 okay = TEST_FAIL;
129 }
130 }
132 return okay;
133 }
135 static int shadow_gs_test(void)
136 {
137 uint64_t *pd = (uint64_t *)PD_START;
138 uint32_t i, eax, ebx, ecx, edx;
140 /* Skip this test if the CPU does not support long mode. */
141 cpuid(0x80000000, &eax, &ebx, &ecx, &edx);
142 if ( eax < 0x80000001 )
143 return TEST_SKIP;
144 cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
145 if ( !(edx & (1u<<29)) )
146 return TEST_SKIP;
148 /* Long mode pagetable setup: Identity map 0-16MB with 2MB mappings. */
149 *pd = (unsigned long)pd + 0x1007; /* Level 4 */
150 pd += 512;
151 *pd = (unsigned long)pd + 0x1007; /* Level 3 */
152 pd += 512;
153 for ( i = 0; i < 8; i++ ) /* Level 2 */
154 *pd++ = (i << 21) + 0x1e3;
156 asm volatile (
157 /* CR4.PAE=1 */
158 "mov $0x20,%%ebx; "
159 "mov %%ebx,%%cr4; "
160 /* CR3 */
161 "mov %%eax,%%cr3; "
162 /* EFER.LME=1 */
163 "mov $0xc0000080,%%ecx; rdmsr; btsl $8,%%eax; wrmsr; "
164 /* CR0.PG=1 */
165 "mov %%cr0,%%eax; btsl $31,%%eax; mov %%eax,%%cr0; "
166 "jmp 1f; 1: "
167 /* GS_BASE=2; SHADOW_GS_BASE=3 */
168 "mov $0xc0000101,%%ecx; xor %%edx,%%edx; mov $2,%%eax; wrmsr; "
169 "mov $0xc0000102,%%ecx; xor %%edx,%%edx; mov $3,%%eax; wrmsr; "
170 /* Push LRETQ stack frame. */
171 "pushl $0; pushl $"STR(SEL_CODE32)"; pushl $0; pushl $2f; "
172 /* Jump to 64-bit mode. */
173 "ljmp $"STR(SEL_CODE64)",$1f; 1: "
174 /* Swap GS_BASE and SHADOW_GS_BASE */
175 ".byte 0x0f,0x01,0xf8; " /* SWAPGS */
176 /* Jump to 32-bit mode. */
177 ".byte 0x89, 0xe4; " /* MOV ESP,ESP */
178 ".byte 0x48, 0xcb; 2: " /* LRETQ */
179 /* Read SHADOW_GS_BASE: should now contain 2 */
180 "mov $0xc0000102,%%ecx; rdmsr; mov %%eax,%%ebx; "
181 /* CR0.PG=0 */
182 "mov %%cr0,%%eax; btcl $31,%%eax; mov %%eax,%%cr0; "
183 "jmp 1f; 1:"
184 /* EFER.LME=0 */
185 "mov $0xc0000080,%%ecx; rdmsr; btcl $8,%%eax; wrmsr; "
186 /* CR4.PAE=0 */
187 "xor %%eax,%%eax; mov %%eax,%%cr4; "
188 : "=b" (ebx) : "a" (PD_START) : "ecx", "edx", "memory" );
190 return (ebx == 2) ? TEST_PASS : TEST_FAIL;
191 }
193 void perform_tests(void)
194 {
195 int i, passed, skipped;
197 static struct {
198 int (* const test)(void);
199 const char *description;
200 } tests[] = {
201 { rep_io_test, "REP INSB across page boundaries" },
202 { shadow_gs_test, "GS base MSRs and SWAPGS" },
203 { NULL, NULL }
204 };
206 printf("Testing HVM environment:\n");
208 passed = skipped = 0;
209 for ( i = 0; tests[i].test; i++ )
210 {
211 printf(" - %s ... ", tests[i].description);
212 memset((char *)(4ul << 20), 0, 4ul << 20);
213 setup_paging();
214 switch ( (*tests[i].test)() )
215 {
216 case TEST_PASS:
217 printf("passed\n");
218 passed++;
219 break;
220 case TEST_FAIL:
221 printf("failed\n");
222 break;
223 case TEST_SKIP:
224 printf("skipped\n");
225 skipped++;
226 break;
227 }
228 }
230 printf("Passed %d of %d tests\n", passed, i);
231 if ( skipped != 0 )
232 printf("Skipped %d of %d tests\n", skipped, i);
233 if ( (passed + skipped) != i )
234 {
235 printf("FAILED %d of %d tests\n", i - passed - skipped, i);
236 BUG();
237 }
238 }