diff --git a/tests/mmu/head.S b/tests/mmu/head.S index 3627cff..083b1c5 100644 --- a/tests/mmu/head.S +++ b/tests/mmu/head.S @@ -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; \ @@ -33,12 +31,20 @@ . = 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 diff --git a/tests/mmu/mmu.c b/tests/mmu/mmu.c index 0a717c7..a44c79d 100644 --- a/tests/mmu/mmu.c +++ b/tests/mmu/mmu.c @@ -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; } diff --git a/tests/mmu/powerpc.lds b/tests/mmu/powerpc.lds index c4bff13..99611ab 100644 --- a/tests/mmu/powerpc.lds +++ b/tests/mmu/powerpc.lds @@ -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 = .; } diff --git a/tests/test_mmu.bin b/tests/test_mmu.bin index 961e2df..afae999 100755 Binary files a/tests/test_mmu.bin and b/tests/test_mmu.bin differ diff --git a/tests/test_mmu.console_out b/tests/test_mmu.console_out index 3e84260..a8e2dcb 100644 --- a/tests/test_mmu.console_out +++ b/tests/test_mmu.console_out @@ -8,3 +8,10 @@ test 07:PASS test 08:PASS test 09:PASS test 10:PASS +test 11:PASS +test 12:PASS +test 13:PASS +test 14:PASS +test 15:PASS +test 16:PASS +test 17:PASS