tests: mmu: Add tests for instruction translation
authorPaul Mackerras <paulus@ozlabs.org>
Tue, 28 Apr 2020 06:00:00 +0000 (16:00 +1000)
committerPaul Mackerras <paulus@ozlabs.org>
Fri, 8 May 2020 02:12:02 +0000 (12:12 +1000)
This adds tests of instruction translation to the mmu test.

This also clears the BSS and improves the linker script.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
tests/mmu/head.S
tests/mmu/mmu.c
tests/mmu/powerpc.lds
tests/test_mmu.bin
tests/test_mmu.console_out

index 3627cffaf2b63202793eeb397e6baef52ed6df77..083b1c55758c050236993e8d4175d3c308be7dda 100644 (file)
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#define STACK_TOP 0x4000
-
 /* Load an immediate 64-bit value into a register */
 #define LOAD_IMM64(r, e)                       \
        lis     r,(e)@highest;                  \
        . = 0
 .global _start
 _start:
-       b       boot_entry
+       LOAD_IMM64(%r10,__bss_start)
+       LOAD_IMM64(%r11,__bss_end)
+       subf    %r11,%r10,%r11
+       addi    %r11,%r11,63
+       srdi.   %r11,%r11,6
+       beq     2f
+       mtctr   %r11
+1:     dcbz    0,%r10
+       addi    %r10,%r10,64
+       bdnz    1b
 
-.global boot_entry
-boot_entry:
-       /* setup stack */
-       LOAD_IMM64(%r1, STACK_TOP - 0x100)
+2:     LOAD_IMM64(%r1,__stack_top)
+       li      %r0,0
+       stdu    %r0,-16(%r1)
        LOAD_IMM64(%r12, main)
        mtctr   %r12
        bctrl
@@ -74,6 +80,12 @@ test_write:
        mtmsrd  %r9,0
        blr
 
+       .globl  test_exec
+test_exec:
+       mtsrr0  %r4
+       mtsrr1  %r5
+       rfid
+
 #define EXCEPTION(nr)          \
        .= nr                   ;\
        attn
@@ -86,9 +98,17 @@ test_write:
        mtsrr0  %r10
        rfid
 
-       /* More exception stubs */
        EXCEPTION(0x380)
-       EXCEPTION(0x400)
+
+       /*
+        * ISI vector - jump to LR to return from the test,
+        * with r3 cleared
+        */
+       . = 0x400
+       li      %r3,0
+       blr
+
+       /* More exception stubs */
        EXCEPTION(0x480)
        EXCEPTION(0x500)
        EXCEPTION(0x600)
@@ -98,7 +118,14 @@ test_write:
        EXCEPTION(0x980)
        EXCEPTION(0xa00)
        EXCEPTION(0xb00)
-       EXCEPTION(0xc00)
+
+       /*
+        * System call - used to exit from tests where MSR[PR]
+        * may have been set.
+        */
+       . = 0xc00
+       blr
+
        EXCEPTION(0xd00)
        EXCEPTION(0xe00)
        EXCEPTION(0xe20)
@@ -110,3 +137,29 @@ test_write:
        EXCEPTION(0xf40)
        EXCEPTION(0xf60)
        EXCEPTION(0xf80)
+
+       . = 0x1000
+       /*
+        * This page gets mapped at various locations and
+        * the tests try to execute from it.
+        * r3 contains the test number.
+        */
+       .globl  test_start
+test_start:
+       nop
+       nop
+       cmpdi   %r3,1
+       beq     test_1
+       cmpdi   %r3,2
+       beq     test_2
+test_return:
+       li      %r3,1
+       sc
+
+       . = 0x1ff8
+       /* test a branch near the end of a page */
+test_1:        b       test_return
+
+       /* test flowing from one page to the next */
+test_2:        nop
+       b       test_return
index 0a717c7a32ba1654d7aaed2e9c52a38532c1d8ba..a44c79de61263eb2c7aed11d6d6b1491e0abb079 100644 (file)
@@ -4,14 +4,23 @@
 
 #include "console.h"
 
+#define MSR_DR 0x10
+#define MSR_IR 0x20
+
 extern int test_read(long *addr, long *ret, long init);
 extern int test_write(long *addr, long val);
+extern int test_exec(int testno, unsigned long pc, unsigned long msr);
 
 static inline void do_tlbie(unsigned long rb, unsigned long rs)
 {
        __asm__ volatile("tlbie %0,%1" : : "r" (rb), "r" (rs) : "memory");
 }
 
+#define DSISR  18
+#define DAR    19
+#define SRR0   26
+#define SRR1   27
+
 static inline unsigned long mfspr(int sprnum)
 {
        long val;
@@ -135,6 +144,8 @@ void map(void *ea, void *pa, unsigned long perm_attr)
                free_ptr += 512 * sizeof(unsigned long);
        }
        ptep = read_pgd(i);
+       if (ptep[j])
+               do_tlbie(((unsigned long)ea & ~0xfff), 0);
        store_pte(&ptep[j], 0xc000000000000000 | ((unsigned long)pa & 0x00fffffffffff000) | perm_attr);
        eas_mapped[neas_mapped++] = ea;
 }
@@ -175,14 +186,14 @@ int mmu_test_1(void)
        if (val != 0xdeadbeefd00d)
                return 2;
        /* DAR and DSISR should be set correctly */
-       if (mfspr(19) != (long) ptr || mfspr(18) != 0x40000000)
+       if (mfspr(DAR) != (long) ptr || mfspr(DSISR) != 0x40000000)
                return 3;
        return 0;
 }
 
 int mmu_test_2(void)
 {
-       long *mem = (long *) 0x4000;
+       long *mem = (long *) 0x8000;
        long *ptr = (long *) 0x124000;
        long *ptr2 = (long *) 0x1124000;
        long val;
@@ -215,8 +226,8 @@ int mmu_test_2(void)
 
 int mmu_test_3(void)
 {
-       long *mem = (long *) 0x5000;
-       long *ptr = (long *) 0x149000;
+       long *mem = (long *) 0x9000;
+       long *ptr = (long *) 0x14a000;
        long val;
 
        /* create PTE */
@@ -238,16 +249,16 @@ int mmu_test_3(void)
        if (val != 0xdeadbeefd0d0)
                return 4;
        /* DAR and DSISR should be set correctly */
-       if (mfspr(19) != (long) &ptr[45] || mfspr(18) != 0x40000000)
+       if (mfspr(DAR) != (long) &ptr[45] || mfspr(DSISR) != 0x40000000)
                return 5;
        return 0;
 }
 
 int mmu_test_4(void)
 {
-       long *mem = (long *) 0x6000;
-       long *ptr = (long *) 0x10a000;
-       long *ptr2 = (long *) 0x110a000;
+       long *mem = (long *) 0xa000;
+       long *ptr = (long *) 0x10b000;
+       long *ptr2 = (long *) 0x110b000;
        long val;
 
        /* create PTE */
@@ -279,7 +290,7 @@ int mmu_test_4(void)
 
 int mmu_test_5(void)
 {
-       long *mem = (long *) 0x7ffd;
+       long *mem = (long *) 0xbffd;
        long *ptr = (long *) 0x39fffd;
        long val;
 
@@ -292,14 +303,14 @@ int mmu_test_5(void)
        if (val != 0xdeadbeef0dd0)
                return 2;
        /* DAR and DSISR should be set correctly */
-       if (mfspr(19) != ((long)ptr & ~0xfff) + 0x1000 || mfspr(18) != 0x40000000)
+       if (mfspr(DAR) != ((long)ptr & ~0xfff) + 0x1000 || mfspr(DSISR) != 0x40000000)
                return 3;
        return 0;
 }
 
 int mmu_test_6(void)
 {
-       long *mem = (long *) 0x7ffd;
+       long *mem = (long *) 0xbffd;
        long *ptr = (long *) 0x39fffd;
 
        /* create PTE */
@@ -310,14 +321,14 @@ int mmu_test_6(void)
        if (test_write(ptr, 0xdeadbeef0dd0))
                return 1;
        /* DAR and DSISR should be set correctly */
-       if (mfspr(19) != ((long)ptr & ~0xfff) + 0x1000 || mfspr(18) != 0x42000000)
+       if (mfspr(DAR) != ((long)ptr & ~0xfff) + 0x1000 || mfspr(DSISR) != 0x42000000)
                return 2;
        return 0;
 }
 
 int mmu_test_7(void)
 {
-       long *mem = (long *) 0x4000;
+       long *mem = (long *) 0x8000;
        long *ptr = (long *) 0x124000;
        long val;
 
@@ -331,13 +342,13 @@ int mmu_test_7(void)
        if (val != 0xdeadd00dbeef)
                return 2;
        /* DAR and DSISR should be set correctly */
-       if (mfspr(19) != (long) ptr || mfspr(18) != 0x00040000)
+       if (mfspr(DAR) != (long) ptr || mfspr(DSISR) != 0x00040000)
                return 3;
        /* this should fail */
        if (test_write(ptr, 0xdeadbeef0dd0))
                return 4;
        /* DAR and DSISR should be set correctly */
-       if (mfspr(19) != (long)ptr || mfspr(18) != 0x02040000)
+       if (mfspr(DAR) != (long)ptr || mfspr(DSISR) != 0x02040000)
                return 5;
        /* memory should be unchanged */
        if (*mem != 0x123456789abcdef0)
@@ -347,7 +358,7 @@ int mmu_test_7(void)
 
 int mmu_test_8(void)
 {
-       long *mem = (long *) 0x4000;
+       long *mem = (long *) 0x8000;
        long *ptr = (long *) 0x124000;
        long val;
 
@@ -361,7 +372,7 @@ int mmu_test_8(void)
        if (test_write(ptr, 0xdeadbeef0dd1))
                return 2;
        /* DAR and DSISR should be set correctly */
-       if (mfspr(19) != (long)ptr || mfspr(18) != 0x02040000)
+       if (mfspr(DAR) != (long)ptr || mfspr(DSISR) != 0x02040000)
                return 3;
        /* memory should be unchanged */
        if (*mem != 0x123456789abcdef0)
@@ -371,7 +382,7 @@ int mmu_test_8(void)
 
 int mmu_test_9(void)
 {
-       long *mem = (long *) 0x4000;
+       long *mem = (long *) 0x8000;
        long *ptr = (long *) 0x124000;
        long val;
 
@@ -385,13 +396,13 @@ int mmu_test_9(void)
        if (val != 0xdeadd00dbeef)
                return 2;
        /* DAR and DSISR should be set correctly */
-       if (mfspr(19) != (long) ptr || mfspr(18) != 0x08000000)
+       if (mfspr(DAR) != (long) ptr || mfspr(DSISR) != 0x08000000)
                return 3;
        /* this should fail */
        if (test_write(ptr, 0xdeadbeef0dd1))
                return 4;
        /* DAR and DSISR should be set correctly */
-       if (mfspr(19) != (long)ptr || mfspr(18) != 0x0a000000)
+       if (mfspr(DAR) != (long)ptr || mfspr(DSISR) != 0x0a000000)
                return 5;
        /* memory should be unchanged */
        if (*mem != 0x123456789abcdef0)
@@ -401,7 +412,7 @@ int mmu_test_9(void)
 
 int mmu_test_10(void)
 {
-       long *mem = (long *) 0x4000;
+       long *mem = (long *) 0x8000;
        long *ptr = (long *) 0x124000;
        long val;
 
@@ -415,7 +426,7 @@ int mmu_test_10(void)
        if (test_write(ptr, 0xdeadbeef0dd1))
                return 2;
        /* DAR and DSISR should be set correctly */
-       if (mfspr(19) != (long)ptr || mfspr(18) != 0x0a000000)
+       if (mfspr(DAR) != (long)ptr || mfspr(DSISR) != 0x0a000000)
                return 3;
        /* memory should be unchanged */
        if (*mem != 0x123456789abcdef0)
@@ -423,14 +434,159 @@ int mmu_test_10(void)
        return 0;
 }
 
+int mmu_test_11(void)
+{
+       unsigned long ptr = 0x523000;
+
+       /* this should fail */
+       if (test_exec(0, ptr, MSR_IR))
+               return 1;
+       /* SRR0 and SRR1 should be set correctly */
+       if (mfspr(SRR0) != (long) ptr || mfspr(SRR1) != 0x40000020)
+               return 2;
+       return 0;
+}
+
+int mmu_test_12(void)
+{
+       unsigned long mem = 0x1000;
+       unsigned long ptr = 0x324000;
+       unsigned long ptr2 = 0x1324000;
+
+       /* create PTE */
+       map((void *)ptr, (void *)mem, PERM_EX | REF);
+       /* this should succeed and be a cache miss */
+       if (!test_exec(0, ptr, MSR_IR))
+               return 1;
+       /* create a second PTE */
+       map((void *)ptr2, (void *)mem, PERM_EX | REF);
+       /* this should succeed and be a cache hit */
+       if (!test_exec(0, ptr2, MSR_IR))
+               return 2;
+       return 0;
+}
+
+int mmu_test_13(void)
+{
+       unsigned long mem = 0x1000;
+       unsigned long ptr = 0x349000;
+       unsigned long ptr2 = 0x34a000;
+
+       /* create a PTE */
+       map((void *)ptr, (void *)mem, PERM_EX | REF);
+       /* this should succeed */
+       if (!test_exec(1, ptr, MSR_IR))
+               return 1;
+       /* invalidate the PTE */
+       unmap((void *)ptr);
+       /* install a second PTE */
+       map((void *)ptr2, (void *)mem, PERM_EX | REF);
+       /* this should fail */
+       if (test_exec(1, ptr, MSR_IR))
+               return 2;
+       /* SRR0 and SRR1 should be set correctly */
+       if (mfspr(SRR0) != (long) ptr || mfspr(SRR1) != 0x40000020)
+               return 3;
+       return 0;
+}
+
+int mmu_test_14(void)
+{
+       unsigned long mem = 0x1000;
+       unsigned long mem2 = 0x2000;
+       unsigned long ptr = 0x30a000;
+       unsigned long ptr2 = 0x30b000;
+
+       /* create a PTE */
+       map((void *)ptr, (void *)mem, PERM_EX | REF);
+       /* this should fail due to second page not being mapped */
+       if (test_exec(2, ptr, MSR_IR))
+               return 1;
+       /* SRR0 and SRR1 should be set correctly */
+       if (mfspr(SRR0) != ptr2 || mfspr(SRR1) != 0x40000020)
+               return 2;
+       /* create a PTE for the second page */
+       map((void *)ptr2, (void *)mem2, PERM_EX | REF);
+       /* this should succeed */
+       if (!test_exec(2, ptr, MSR_IR))
+               return 3;
+       return 0;
+}
+
+int mmu_test_15(void)
+{
+       unsigned long mem = 0x1000;
+       unsigned long ptr = 0x324000;
+
+       /* create a PTE without execute permission */
+       map((void *)ptr, (void *)mem, DFLT_PERM);
+       /* this should fail */
+       if (test_exec(0, ptr, MSR_IR))
+               return 1;
+       /* SRR0 and SRR1 should be set correctly */
+       if (mfspr(SRR0) != ptr || mfspr(SRR1) != 0x10000020)
+               return 2;
+       return 0;
+}
+
+int mmu_test_16(void)
+{
+       unsigned long mem = 0x1000;
+       unsigned long mem2 = 0x2000;
+       unsigned long ptr = 0x30a000;
+       unsigned long ptr2 = 0x30b000;
+
+       /* create a PTE */
+       map((void *)ptr, (void *)mem, PERM_EX | REF);
+       /* create a PTE for the second page without execute permission */
+       map((void *)ptr2, (void *)mem2, PERM_RD | REF);
+       /* this should fail due to second page being no-execute */
+       if (test_exec(2, ptr, MSR_IR))
+               return 1;
+       /* SRR0 and SRR1 should be set correctly */
+       if (mfspr(SRR0) != ptr2 || mfspr(SRR1) != 0x10000020)
+               return 2;
+       /* create a PTE for the second page with execute permission */
+       map((void *)ptr2, (void *)mem2, PERM_RD | PERM_EX | REF);
+       /* this should succeed */
+       if (!test_exec(2, ptr, MSR_IR))
+               return 3;
+       return 0;
+}
+
+int mmu_test_17(void)
+{
+       unsigned long mem = 0x1000;
+       unsigned long ptr = 0x349000;
+
+       /* create a PTE without the ref bit set */
+       map((void *)ptr, (void *)mem, PERM_EX);
+       /* this should fail */
+       if (test_exec(2, ptr, MSR_IR))
+               return 1;
+       /* SRR0 and SRR1 should be set correctly */
+       if (mfspr(SRR0) != (long) ptr || mfspr(SRR1) != 0x00040020)
+               return 2;
+       /* create a PTE without ref or execute permission */
+       map((void *)ptr, (void *)mem, 0);
+       /* this should fail */
+       if (test_exec(2, ptr, MSR_IR))
+               return 1;
+       /* SRR0 and SRR1 should be set correctly */
+       /* RC update fail bit should not be set */
+       if (mfspr(SRR0) != (long) ptr || mfspr(SRR1) != 0x10000020)
+               return 2;
+       return 0;
+}
+
 int fail = 0;
 
 void do_test(int num, int (*test)(void))
 {
        int ret;
 
-       mtspr(18, 0);
-       mtspr(19, 0);
+       mtspr(DSISR, 0);
+       mtspr(DAR, 0);
        unmap_all();
        print_test_number(num);
        ret = test();
@@ -440,10 +596,17 @@ void do_test(int num, int (*test)(void))
                fail = 1;
                print_string("FAIL ");
                putchar(ret + '0');
-               print_string(" DAR=");
-               print_hex(mfspr(19));
-               print_string(" DSISR=");
-               print_hex(mfspr(18));
+               if (num <= 10) {
+                       print_string(" DAR=");
+                       print_hex(mfspr(DAR));
+                       print_string(" DSISR=");
+                       print_hex(mfspr(DSISR));
+               } else {
+                       print_string(" SRR0=");
+                       print_hex(mfspr(SRR0));
+                       print_string(" SRR1=");
+                       print_hex(mfspr(SRR1));
+               }
                print_string("\r\n");
        }
 }
@@ -463,6 +626,13 @@ int main(void)
        do_test(8, mmu_test_8);
        do_test(9, mmu_test_9);
        do_test(10, mmu_test_10);
+       do_test(11, mmu_test_11);
+       do_test(12, mmu_test_12);
+       do_test(13, mmu_test_13);
+       do_test(14, mmu_test_14);
+       do_test(15, mmu_test_15);
+       do_test(16, mmu_test_16);
+       do_test(17, mmu_test_17);
 
        return fail;
 }
index c4bff135025e14c0ff5507bfe5aeaab996b2cbc8..99611ab41cea7a6ffc10153e49abb329675ddee0 100644 (file)
@@ -1,13 +1,27 @@
 SECTIONS
 {
-       _start = .;
        . = 0;
+       _start = .;
        .head : {
                KEEP(*(.head))
        }
-       . = 0x1000;
-       .text : { *(.text) }
-       . = 0x3000;
-       .data : { *(.data) }
-       .bss : { *(.bss) }
+       . = ALIGN(0x1000);
+       .text : { *(.text) *(.text.*) *(.rodata) *(.rodata.*) }
+       . = ALIGN(0x1000);
+       .data : { *(.data) *(.data.*) *(.got) *(.toc) }
+       . = ALIGN(0x80);
+       __bss_start = .;
+       .bss : {
+               *(.dynsbss)
+               *(.sbss)
+               *(.scommon)
+               *(.dynbss)
+               *(.bss)
+               *(.common)
+               *(.bss.*)
+       }
+       . = ALIGN(0x80);
+       __bss_end = .;
+       . = . + 0x4000;
+       __stack_top = .;
 }
index 961e2df8a24786b52775933f1f9573d2beea9c7e..afae999223bcb15bede8df58d6abc88bc7ea06dc 100755 (executable)
Binary files a/tests/test_mmu.bin and b/tests/test_mmu.bin differ
index 3e84260ef42ce41163511d6966475e0ccfa1dc0f..a8e2dcb10339117b827d3a27d3eca947a5b2f727 100644 (file)
@@ -8,3 +8,10 @@ test 07:PASS
 test 08:PASS\r
 test 09:PASS\r
 test 10:PASS\r
+test 11:PASS\r
+test 12:PASS\r
+test 13:PASS\r
+test 14:PASS\r
+test 15:PASS\r
+test 16:PASS\r
+test 17:PASS\r