# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1247736650 -3600
# Node ID 8ce42378828bfa1576cbc601cadf61cb21439bf7
# Parent fe4c6845a9d7453f5a72cd69cb26c17b4df1c9af
hvmloader: Add new test for MSR_SHADOW_GS_BASE validity after SWAPGS
instruction.
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
tools/firmware/hvmloader/hvmloader.c | 20 +++++-
tools/firmware/hvmloader/hypercall.h | 3 -
tools/firmware/hvmloader/tests.c | 104 +++++++++++++++++++++++++++++------
tools/firmware/hvmloader/util.h | 10 +++
4 files changed, 114 insertions(+), 23 deletions(-)
diff -r fe4c6845a9d7 -r 8ce42378828b tools/firmware/hvmloader/hvmloader.c
--- a/tools/firmware/hvmloader/hvmloader.c Thu Jul 16 10:26:55 2009 +0100
+++ b/tools/firmware/hvmloader/hvmloader.c Thu Jul 16 10:30:50 2009 +0100
@@ -22,8 +22,8 @@
#include "roms.h"
#include "acpi/acpi2_0.h"
+#include "util.h"
#include "hypercall.h"
-#include "util.h"
#include "config.h"
#include "apic_regs.h"
#include "pci_regs.h"
@@ -40,7 +40,15 @@ asm (
/* C runtime kickoff. */
" cld \n"
" cli \n"
- " movl $stack_top,%esp \n"
+ " lgdt gdt_desr \n"
+ " mov $"STR(SEL_DATA32)",%ax \n"
+ " mov %ax,%ds \n"
+ " mov %ax,%es \n"
+ " mov %ax,%fs \n"
+ " mov %ax,%gs \n"
+ " mov %ax,%ss \n"
+ " ljmp $"STR(SEL_CODE32)",$1f \n"
+ "1: movl $stack_top,%esp \n"
" movl %esp,%ebp \n"
" call main \n"
/* Relocate real-mode trampoline to 0x0. */
@@ -50,8 +58,7 @@ asm (
" sub %esi,%ecx \n"
" rep movsb \n"
/* Load real-mode compatible segment state (base 0x0000, limit 0xffff). */
- " lgdt gdt_desr \n"
- " mov $0x0010,%ax \n"
+ " mov $"STR(SEL_DATA16)",%ax \n"
" mov %ax,%ds \n"
" mov %ax,%es \n"
" mov %ax,%fs \n"
@@ -67,7 +74,7 @@ asm (
" xor %esi,%esi \n"
" xor %edi,%edi \n"
/* Enter real mode, reload all segment registers and IDT. */
- " ljmp $0x8,$0x0 \n"
+ " ljmp $"STR(SEL_CODE16)",$0x0\n"
"trampoline_start: .code16 \n"
" mov %eax,%cr0 \n"
" ljmp $0,$1f-trampoline_start\n"
@@ -90,6 +97,9 @@ asm (
" .quad 0x0000000000000000 \n"
" .quad 0x008f9a000000ffff \n" /* Ring 0 16b code, base 0 limit 4G */
" .quad 0x008f92000000ffff \n" /* Ring 0 16b data, base 0 limit 4G */
+ " .quad 0x00cf9a000000ffff \n" /* Ring 0 32b code, base 0 limit 4G */
+ " .quad 0x00cf92000000ffff \n" /* Ring 0 32b data, base 0 limit 4G */
+ " .quad 0x00af9a000000ffff \n" /* Ring 0 64b code */
"gdt_end: \n"
" \n"
" .bss \n"
diff -r fe4c6845a9d7 -r 8ce42378828b tools/firmware/hvmloader/hypercall.h
--- a/tools/firmware/hvmloader/hypercall.h Thu Jul 16 10:26:55 2009 +0100
+++ b/tools/firmware/hvmloader/hypercall.h Thu Jul 16 10:30:50 2009 +0100
@@ -34,9 +34,6 @@
#include <stdint.h>
#include <xen/xen.h>
#include "config.h"
-
-#define __STR(...) #__VA_ARGS__
-#define STR(...) __STR(__VA_ARGS__)
/*
* NB. Hypercall address needs to be relative to a linkage symbol for
diff -r fe4c6845a9d7 -r 8ce42378828b tools/firmware/hvmloader/tests.c
--- a/tools/firmware/hvmloader/tests.c Thu Jul 16 10:26:55 2009 +0100
+++ b/tools/firmware/hvmloader/tests.c Thu Jul 16 10:30:50 2009 +0100
@@ -22,6 +22,10 @@
#include "util.h"
+#define TEST_FAIL 0
+#define TEST_PASS 1
+#define TEST_SKIP 2
+
/*
* Memory layout during tests:
* 4MB to 8MB is cleared.
@@ -73,7 +77,7 @@ static int rep_io_test(void)
{
uint32_t *p;
uint32_t i, p0, p1, p2;
- int okay = 1;
+ int okay = TEST_PASS;
static const struct {
unsigned long addr;
@@ -121,44 +125,114 @@ static int rep_io_test(void)
{
printf("Bad value at 0x%08lx: saw %08x expected %08x\n",
(unsigned long)p, *p, expected);
- okay = 0;
+ okay = TEST_FAIL;
}
}
return okay;
}
+static int shadow_gs_test(void)
+{
+ uint64_t *pd = (uint64_t *)PD_START;
+ uint32_t i, eax, ebx, ecx, edx;
+
+ /* Skip this test if the CPU does not support long mode. */
+ cpuid(0x80000000, &eax, &ebx, &ecx, &edx);
+ if ( eax < 0x80000001 )
+ return TEST_SKIP;
+ cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
+ if ( !(edx & (1u<<29)) )
+ return TEST_SKIP;
+
+ /* Long mode pagetable setup: Identity map 0-16MB with 2MB mappings. */
+ *pd = (unsigned long)pd + 0x1007; /* Level 4 */
+ pd += 512;
+ *pd = (unsigned long)pd + 0x1007; /* Level 3 */
+ pd += 512;
+ for ( i = 0; i < 8; i++ ) /* Level 2 */
+ *pd++ = (i << 21) + 0x1e3;
+
+ asm volatile (
+ /* CR4.PAE=1 */
+ "mov $0x20,%%ebx; "
+ "mov %%ebx,%%cr4; "
+ /* CR3 */
+ "mov %%eax,%%cr3; "
+ /* EFER.LME=1 */
+ "mov $0xc0000080,%%ecx; rdmsr; btsl $8,%%eax; wrmsr; "
+ /* CR0.PG=1 */
+ "mov %%cr0,%%eax; btsl $31,%%eax; mov %%eax,%%cr0; "
+ "jmp 1f; 1: "
+ /* GS_BASE=2; SHADOW_GS_BASE=3 */
+ "mov $0xc0000101,%%ecx; xor %%edx,%%edx; mov $2,%%eax; wrmsr; "
+ "mov $0xc0000102,%%ecx; xor %%edx,%%edx; mov $3,%%eax; wrmsr; "
+ /* Push LRETQ stack frame. */
+ "pushl $0; pushl $"STR(SEL_CODE32)"; pushl $0; pushl $2f; "
+ /* Jump to 64-bit mode. */
+ "ljmp $"STR(SEL_CODE64)",$1f; 1: "
+ /* Swap GS_BASE and SHADOW_GS_BASE */
+ ".byte 0x0f,0x01,0xf8; " /* SWAPGS */
+ /* Jump to 32-bit mode. */
+ ".byte 0x89, 0xe4; " /* MOV ESP,ESP */
+ ".byte 0x48, 0xcb; 2: " /* LRETQ */
+ /* Read SHADOW_GS_BASE: should now contain 2 */
+ "mov $0xc0000102,%%ecx; rdmsr; mov %%eax,%%ebx; "
+ /* CR0.PG=0 */
+ "mov %%cr0,%%eax; btcl $31,%%eax; mov %%eax,%%cr0; "
+ "jmp 1f; 1:"
+ /* EFER.LME=0 */
+ "mov $0xc0000080,%%ecx; rdmsr; btcl $8,%%eax; wrmsr; "
+ /* CR4.PAE=0 */
+ "xor %%eax,%%eax; mov %%eax,%%cr4; "
+ : "=b" (ebx) : "a" (PD_START) : "ecx", "edx", "memory" );
+
+ return (ebx == 2) ? TEST_PASS : TEST_FAIL;
+}
+
void perform_tests(void)
{
- int i, passed;
+ int i, passed, skipped;
static struct {
int (* const test)(void);
const char *description;
} tests[] = {
{ rep_io_test, "REP INSB across page boundaries" },
+ { shadow_gs_test, "GS base MSRs and SWAPGS" },
{ NULL, NULL }
};
printf("Testing HVM environment:\n");
- passed = 0;
+ passed = skipped = 0;
for ( i = 0; tests[i].test; i++ )
{
printf(" - %s ... ", tests[i].description);
memset((char *)(4ul << 20), 0, 4ul << 20);
setup_paging();
- if ( (*tests[i].test)() )
- {
+ switch ( (*tests[i].test)() )
+ {
+ case TEST_PASS:
printf("passed\n");
passed++;
- }
- else
- {
+ break;
+ case TEST_FAIL:
printf("failed\n");
- }
- }
-
- printf("Passed %d/%d tests\n", passed, i);
- BUG_ON(passed != i);
-}
+ break;
+ case TEST_SKIP:
+ printf("skipped\n");
+ skipped++;
+ break;
+ }
+ }
+
+ printf("Passed %d of %d tests\n", passed, i);
+ if ( skipped != 0 )
+ printf("Skipped %d of %d tests\n", skipped, i);
+ if ( (passed + skipped) != i )
+ {
+ printf("FAILED %d of %d tests\n", i - passed - skipped, i);
+ BUG();
+ }
+}
diff -r fe4c6845a9d7 -r 8ce42378828b tools/firmware/hvmloader/util.h
--- a/tools/firmware/hvmloader/util.h Thu Jul 16 10:26:55 2009 +0100
+++ b/tools/firmware/hvmloader/util.h Thu Jul 16 10:30:50 2009 +0100
@@ -4,6 +4,16 @@
#include <stdarg.h>
#include <stdint.h>
#include <xen/hvm/hvm_info_table.h>
+
+#define __STR(...) #__VA_ARGS__
+#define STR(...) __STR(__VA_ARGS__)
+
+/* GDT selector values. */
+#define SEL_CODE16 0x0008
+#define SEL_DATA16 0x0010
+#define SEL_CODE32 0x0018
+#define SEL_DATA32 0x0020
+#define SEL_CODE64 0x0028
#undef offsetof
#define offsetof(t, m) ((unsigned long)&((t *)0)->m)
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|