tools/kvm/arm: cp15 test. We catch undef faults, so we can test that we get them where we expect.
diff --git a/tools/kvm/arm/Makefile b/tools/kvm/arm/Makefile index 016b25a..175773b 100644 --- a/tools/kvm/arm/Makefile +++ b/tools/kvm/arm/Makefile
@@ -24,7 +24,7 @@ CFLAGS = -Wall -I../../../include -I../../../arch/arm/include -D__EXPORTED_HEADERS__ -marm -TESTS=mmio vfp +TESTS=mmio vfp cp15 GUESTS=$(TESTS:%=%-guest) HOST_DRIVERS=$(TESTS:%=%-host.o)
diff --git a/tools/kvm/arm/cp15-guest.c b/tools/kvm/arm/cp15-guest.c new file mode 100644 index 0000000..a1d8149 --- /dev/null +++ b/tools/kvm/arm/cp15-guest.c
@@ -0,0 +1,83 @@ +#include "guest.h" + +extern u32 mcr_insn, mrc_insn, mcrr_insn, mrrc_insn; + +/* Alter mcr or mrc instruction */ +static void alter_insn32(u32 *insn, + unsigned int opc1, + unsigned int crn, + unsigned int crm, + unsigned int opc2) +{ + /* This actually works in both ARM and Thumb mode. */ + *insn &= 0xFF10FF10; + *insn |= (opc1 << 21) | (crn << 16) | (opc2 << 5) | crm; + /* ICIALLU */ + asm("mcr p15, 0, %0, c7, c5, 0" : : "r" (0)); +} + +/* Alter mcrr or mrrc instruction */ +static void alter_insn64(u32 *insn, + unsigned int opc1, + unsigned int crm) +{ + /* This actually works in both ARM and Thumb mode. */ + *insn &= 0xFFFFFF00; + *insn |= (opc1 << 4) | crm; + /* ICIALLU */ + asm("mcr p15, 0, %0, c7, c5, 0" : : "r" (0)); +} + +static bool cp15_write(unsigned int opc1, + unsigned int crn, + unsigned int crm, + unsigned int opc2, + u32 val) +{ + alter_insn32(&mcr_insn, opc1, crn, crm, opc2); + + skip_undef++; + undef_count = 0; + asm volatile(".globl mcr_insn\n" + "mcr_insn:\n" + " mcr p15, 0, %0, c0, c0, 0" : : "r"(val) : "memory"); + skip_undef--; + + /* This is incremented if we fault. */ + return undef_count; +} + +static bool cp15_read(unsigned int opc1, + unsigned int crn, + unsigned int crm, + unsigned int opc2, + u32 *val) +{ + alter_insn32(&mrc_insn, opc1, crn, crm, opc2); + *val = 0xdeadbeef; + + skip_undef++; + undef_count = 0; + asm volatile(".globl mrc_insn\n" + "mrc_insn:\n" + " mrc p15, 0, %0, c0, c0, 0" : "=r"(val) : : "memory"); + skip_undef--; + + /* This is incremented if we fault. */ + return undef_count; +} + +int test(void) +{ + bool faulted; + + print("Perform an mrc\n"); + faulted = cp15_write(0, 0, 0, 0, 100); + + if (faulted) + print("IT FAULTED\n"); + else + print("IT DID NOT FAULT\n"); + + return 0; +}
diff --git a/tools/kvm/arm/cp15-host.c b/tools/kvm/arm/cp15-host.c new file mode 100644 index 0000000..f0f21c7 --- /dev/null +++ b/tools/kvm/arm/cp15-host.c
@@ -0,0 +1,8 @@ +#include <stdbool.h> +#include <string.h> +#include <linux/kvm.h> + +#include "guest-driver.h" + +/* We don't have any special mmio addresses for cp15 testing. */ +GUEST_TEST(cp15, NULL);
diff --git a/tools/kvm/arm/guest.h b/tools/kvm/arm/guest.h index 1d9d8bd..e857440 100644 --- a/tools/kvm/arm/guest.h +++ b/tools/kvm/arm/guest.h
@@ -1,5 +1,7 @@ #ifndef GUEST_H #define GUEST_H +#include <stdint.h> +#include <stdbool.h> void ok(void); void fail(void); @@ -26,6 +28,8 @@ ok(); \ } while(0) +typedef uint32_t u32; + /* Each guest needs to write this. */ int test(void); #endif /* GUEST_H */