hvmloader: Debug build incorporates HVM environment tests which must
authorKeir Fraser <keir.fraser@citrix.com>
Thu, 21 Aug 2008 14:18:05 +0000 (15:18 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Thu, 21 Aug 2008 14:18:05 +0000 (15:18 +0100)
pass for the HVM guest to successfully boot.

Currently only one test (REP INS across page boundaries) but more will
be added in future.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
tools/firmware/Rules.mk
tools/firmware/hvmloader/Makefile
tools/firmware/hvmloader/hvmloader.c
tools/firmware/hvmloader/tests.c [new file with mode: 0644]
tools/firmware/hvmloader/util.h

index 47db139592537467ee6a35ea4e0e82311ca95e43..6cf0dfa2ac01c6979f062da0d6d4a04fd3a63786 100644 (file)
@@ -6,6 +6,10 @@ CFLAGS :=
 
 include $(XEN_ROOT)/tools/Rules.mk
 
+ifneq ($(debug),y)
+CFLAGS += -DNDEBUG
+endif
+
 CFLAGS += -Werror
 
 # Disable PIE/SSP if GCC supports them. They can break us.
index 5988da6816a7054e5251619425b34839578ab082..3d5f91f0372b52829f336550d78412122e53bd8d 100644 (file)
@@ -30,6 +30,9 @@ CFLAGS += $(CFLAGS_include) -I.
 
 SRCS  = hvmloader.c mp_tables.c util.c smbios.c 
 SRCS += 32bitbios_support.c smp.c cacheattr.c
+ifeq ($(debug),y)
+SRCS += tests.c
+endif
 OBJS  = $(patsubst %.c,%.o,$(SRCS))
 
 .PHONY: all
index f0e5816caa040921329ab3bceaac5d287c7f5528..decb1d21881e62ed5eee6f48b83c07ed90d06796 100644 (file)
@@ -460,6 +460,8 @@ int main(void)
 
     smp_initialise();
 
+    perform_tests();
+
     printf("Writing SMBIOS tables ...\n");
     smbios_sz = hvm_write_smbios_tables();
 
diff --git a/tools/firmware/hvmloader/tests.c b/tools/firmware/hvmloader/tests.c
new file mode 100644 (file)
index 0000000..d3ee9cf
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * tests.c: HVM environment tests.
+ *
+ * Copyright (c) 2008, Citrix Systems, Inc.
+ * 
+ * Authors:
+ *    Keir Fraser <keir.fraser@citrix.com>
+ * 
+ * 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 "util.h"
+
+/*
+ * Memory layout during tests:
+ *  4MB to 8MB is cleared.
+ *  Page directory resides at 8MB.
+ *  4 page table pages reside at 8MB+4kB to 8MB+20kB.
+ *  Pagetables identity-map 0-16MB, except 4kB at va 6MB maps to pa 5MB.
+ */
+#define PD_START (8ul << 20)
+#define PT_START (PD_START + 4096)
+
+static void setup_paging(void)
+{
+    uint32_t *pd = (uint32_t *)PD_START;
+    uint32_t *pt = (uint32_t *)PT_START;
+    uint32_t i;
+
+    /* Identity map 0-16MB. */
+    for ( i = 0; i < 4; i++ )
+        pd[i] = (unsigned long)pt + (i<<12) + 3;
+    for ( i = 0; i < (4*1024); i++ )
+        pt[i] = (i << 12) + 3;
+
+    /* Page at virtual 6MB maps to physical 5MB. */
+    pt[6u<<8] -= 0x100000u;
+}
+
+static void start_paging(void)
+{
+    asm volatile (
+        "mov %%eax,%%cr3; mov %%cr0,%%eax; "
+        "orl $0x80000000,%%eax; mov %%eax,%%cr0; "
+        "jmp 1f; 1:"
+        : : "a" (PD_START) : "memory" );
+}
+
+static void stop_paging(void)
+{
+    asm volatile (
+        "mov %%cr0,%%eax; andl $0x7fffffff,%%eax; mov %%eax,%%cr0; "
+        "jmp 1f; 1:"
+        : : : "eax", "memory" );
+}
+
+/*
+ * rep_io_test: Tests REP INSB both forwards and backwards (EF.DF={0,1}) across
+ * a discontiguous page boundary.
+ */
+static int rep_io_test(void)
+{
+    uint32_t *p;
+    uint32_t i, p0, p1, p2;
+    int okay = 1;
+
+    static const struct {
+        unsigned long addr;
+        uint32_t expected;
+    } check[] = {
+        { 0x00500000, 0x987654ff },
+        { 0x00500ffc, 0xff000000 },
+        { 0x005ffffc, 0xff000000 },
+        { 0x00601000, 0x000000ff },
+        { 0, 0 }
+    };
+
+    start_paging();
+
+    /* Phys 5MB = 0xdeadbeef */
+    *(uint32_t *)0x500000ul = 0xdeadbeef;
+
+    /* Phys 5MB = 0x98765432 */
+    *(uint32_t *)0x600000ul = 0x98765432;
+
+    /* Phys 0x5fffff = Phys 0x500000 = 0xff (byte) */
+    asm volatile (
+        "rep insb"
+        : "=d" (p0), "=c" (p1), "=D" (p2)
+        : "0" (0x5f), "1" (2), "2" (0x5ffffful) : "memory" );
+
+    /* Phys 0x500fff = Phys 0x601000 = 0xff (byte) */
+    asm volatile (
+        "std ; rep insb ; cld"
+        : "=d" (p0), "=c" (p1), "=D" (p2)
+        : "0" (0x5f), "1" (2), "2" (0x601000ul) : "memory" );
+
+    stop_paging();
+
+    i = 0;
+    for ( p = (uint32_t *)0x400000ul; p < (uint32_t *)0x700000ul; p++ )
+    {
+        uint32_t expected = 0;
+        if ( check[i].addr == (unsigned long)p )
+        {
+            expected = check[i].expected;
+            i++;
+        }
+        if ( *p != expected )
+        {
+            printf("Bad value at 0x%08lx: saw %08x expected %08x\n",
+                   (unsigned long)p, *p, expected);
+            okay = 0;
+        }
+    }
+
+    return okay;
+}
+
+void perform_tests(void)
+{
+    int i, passed;
+
+    static struct {
+        int (* const test)(void);
+        const char *description;
+    } tests[] = {
+        { rep_io_test, "REP INSB across page boundaries" },
+        { NULL, NULL }
+    };
+
+    printf("Testing HVM environment:\n");
+
+    passed = 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)() )
+        {
+            printf("passed\n");
+            passed++;
+        }
+        else
+        {
+            printf("failed\n");
+        }
+    }
+
+    printf("Passed %d/%d tests\n", passed, i);
+    BUG_ON(passed != i);
+}
index 4d85e2cef959c5c3d842ffd78eb59865588209e7..957f25350e7e23a18f4c1136ecc1078dfe04cc69 100644 (file)
@@ -143,6 +143,12 @@ void create_mp_tables(void);
 int hvm_write_smbios_tables(void);
 void smp_initialise(void);
 
+#ifndef NDEBUG
+void perform_tests(void);
+#else
+#define perform_tests() ((void)0)
+#endif
+
 #define isdigit(c) ((c) >= '0' && (c) <= '9')
 
 extern char _start[], _end[];