@@ -0,0 +1,9 @@
+include $(ROOT)/build/common.mk
+
+NAME := split-access
+CATEGORY := utility
+TEST-ENVS := $(HVM_ENVIRONMENTS)
+
+obj-perenv += main.o
+
+include $(ROOT)/build/gen.mk
@@ -0,0 +1,218 @@
+/**
+ * @file tests/split-access/main.c
+ * @ref test-split-access
+ *
+ * @page test-split-access split-access
+ *
+ * @todo Docs for test-split-access
+ *
+ * @see tests/split-access/main.c
+ */
+#include <xtf.h>
+
+#include <arch/decode.h>
+
+const char test_title[] = "Split memory access insns";
+
+/* Keep the compiler from leveraging undefined behavior. */
+#define touch(x) ({ asm ( "" : "+g" (x) ); })
+
+void do_mov(bool force)
+{
+ const unsigned long *ptr = NULL;
+
+ touch(ptr);
+
+ for ( --ptr; ; )
+ {
+ unsigned long val;
+ exinfo_t fault = 0;
+
+ asm volatile ( "test %[fep], %[fep];"
+ "jz 1f;"
+ _ASM_XEN_FEP
+ "1: mov %[src],%[dst]; 2:"
+ _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_eax)
+ : [dst] "=r" (val), "+a" (fault)
+ : [src] "m" (*ptr), [fep] "q" (force) );
+ if ( fault )
+ {
+ char excstr[16];
+
+ x86_decode_exinfo(excstr, ARRAY_SIZE(excstr), fault);
+ xtf_warning("Got %s for %p'\n", excstr, ptr);
+ }
+ else if ( val != *ptr )
+ xtf_failure("%lx != %lx for %p'\n", val, *ptr, ptr);
+
+ touch(ptr);
+ if ( !ptr )
+ break;
+
+ ptr = (void *)(long)ptr + 1;
+ }
+}
+
+void do_lfs(bool force)
+{
+ const struct __packed { unsigned long off; uint16_t sel; } *ptr = NULL;
+
+ touch(ptr);
+
+ for ( --ptr; ; )
+ {
+ unsigned long off;
+ exinfo_t fault = 0;
+
+ asm volatile ( "test %[fep], %[fep];"
+ "jz 1f;"
+ _ASM_XEN_FEP
+ "1: lfs %[src],%[dst]; 2:"
+ _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_eax)
+ : [dst] "=r" (off), "+a" (fault)
+ : [src] "m" (*ptr), [fep] "q" (force) );
+ if ( fault )
+ {
+ char excstr[16];
+
+ x86_decode_exinfo(excstr, ARRAY_SIZE(excstr), fault);
+ xtf_warning("Got %s for %p'\n", excstr, ptr);
+ }
+ else if ( off != ptr->off )
+ xtf_failure("%lx != %lx for %p'\n", off, ptr->off, ptr);
+
+ touch(ptr);
+ if ( !ptr )
+ break;
+
+ ptr = (void *)(long)ptr + 1;
+ }
+}
+
+void do_lidt(bool force)
+{
+ const desc_ptr *ptr = NULL;
+
+ touch(ptr);
+
+ for ( --ptr; ; )
+ {
+ exinfo_t fault = 0;
+
+ asm volatile ( "test %[fep], %[fep];"
+ "jz 1f;"
+ _ASM_XEN_FEP
+ "1: lidt %[src]; 2:"
+ _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_eax)
+ : "+a" (fault)
+ : [src] "m" (*ptr), [fep] "q" (force) );
+ if ( fault )
+ {
+ char excstr[16];
+
+ x86_decode_exinfo(excstr, ARRAY_SIZE(excstr), fault);
+ xtf_warning("Got %s for %p\n", excstr, ptr);
+ }
+ else
+ asm volatile ( "lidt %0" :: "m" (idt_ptr) );
+
+ touch(ptr);
+ if ( !ptr )
+ break;
+
+ ptr = (void *)(long)ptr + 1;
+ }
+}
+
+#ifndef __x86_64__
+void do_bound(bool force)
+{
+ const struct { unsigned long lo, hi; } *ptr = NULL;
+
+ touch(ptr);
+
+ for ( --ptr; ; )
+ {
+ exinfo_t fault = 0;
+
+ asm volatile ( "test %[fep], %[fep];"
+ "jz 1f;"
+ _ASM_XEN_FEP
+ "1: bound %[off], %[bnd]; 2:"
+ _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_eax)
+ : "+a" (fault)
+ : [bnd] "m" (*ptr), [off] "r" (0), [fep] "q" (force) );
+ if ( fault )
+ {
+ char excstr[16];
+
+ x86_decode_exinfo(excstr, ARRAY_SIZE(excstr), fault);
+ xtf_warning("Got %s for %p\n", excstr, ptr);
+ }
+
+ touch(ptr);
+ if ( !ptr )
+ break;
+
+ ptr = (void *)(long)ptr + 1;
+ }
+}
+#endif
+
+void run_tests(bool force)
+{
+ printk("Testing%s MOV\n", force ? " emulated" : "");
+ do_mov(force);
+
+ printk("Testing%s LFS\n", force ? " emulated" : "");
+ do_lfs(force);
+
+ printk("Testing%s LIDT\n", force ? " emulated" : "");
+ do_lidt(force);
+
+#ifndef __x86_64__
+ printk("Testing%s BOUND\n", force ? " emulated" : "");
+ do_bound(force);
+#endif
+}
+
+void test_main(void)
+{
+#if !defined(__x86_64__) && CONFIG_PAGING_LEVELS > 0
+ /*
+ * To better tell actual hardware behavior, zap the mapping for the last
+ * (large) page below 4Gb. That'll make us see page faults when hardware
+ * when all segmentation checks pass, rather than observing #GP/#SS due to
+ * the emulator being invoked anyway due to accesses touching an unmapped
+ * MMIO range. This matches x86-64 behavior at the 2^^64 boundary.
+ */
+# if CONFIG_PAGING_LEVELS == 2
+ pse_l2_identmap[pse_l2_table_offset(~0UL)] = 0;
+# elif CONFIG_PAGING_LEVELS == 3
+ pae_l2_identmap[pae_l2_table_offset(~0UL)] = 0;
+# else
+# error Bad 32-bit paging mode!
+# endif
+
+ invlpg((void *)~0UL);
+#endif
+
+ run_tests(false);
+
+ if ( !xtf_has_fep )
+ xtf_skip("FEP support not detected - some tests will be skipped\n");
+ else
+ run_tests(true);
+
+ xtf_success(NULL);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
Add tests to verify that accesses crossing the upper address boundary are being handled similarly with and without the emulator involved. Signed-off-by: Jan Beulich <jbeulich@suse.com>