tests: mmu: Add tests for instruction translation

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>
pull/169/head
Paul Mackerras 5 years ago
parent 01046527ba
commit b342312e4e

@ -14,8 +14,6 @@
* limitations under the License. * limitations under the License.
*/ */


#define STACK_TOP 0x4000

/* Load an immediate 64-bit value into a register */ /* Load an immediate 64-bit value into a register */
#define LOAD_IMM64(r, e) \ #define LOAD_IMM64(r, e) \
lis r,(e)@highest; \ lis r,(e)@highest; \
@ -33,12 +31,20 @@
. = 0 . = 0
.global _start .global _start
_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 2: LOAD_IMM64(%r1,__stack_top)
boot_entry: li %r0,0
/* setup stack */ stdu %r0,-16(%r1)
LOAD_IMM64(%r1, STACK_TOP - 0x100)
LOAD_IMM64(%r12, main) LOAD_IMM64(%r12, main)
mtctr %r12 mtctr %r12
bctrl bctrl
@ -74,6 +80,12 @@ test_write:
mtmsrd %r9,0 mtmsrd %r9,0
blr blr


.globl test_exec
test_exec:
mtsrr0 %r4
mtsrr1 %r5
rfid

#define EXCEPTION(nr) \ #define EXCEPTION(nr) \
.= nr ;\ .= nr ;\
attn attn
@ -86,9 +98,17 @@ test_write:
mtsrr0 %r10 mtsrr0 %r10
rfid rfid


/* More exception stubs */
EXCEPTION(0x380) 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(0x480)
EXCEPTION(0x500) EXCEPTION(0x500)
EXCEPTION(0x600) EXCEPTION(0x600)
@ -98,7 +118,14 @@ test_write:
EXCEPTION(0x980) EXCEPTION(0x980)
EXCEPTION(0xa00) EXCEPTION(0xa00)
EXCEPTION(0xb00) EXCEPTION(0xb00)
EXCEPTION(0xc00)
/*
* System call - used to exit from tests where MSR[PR]
* may have been set.
*/
. = 0xc00
blr

EXCEPTION(0xd00) EXCEPTION(0xd00)
EXCEPTION(0xe00) EXCEPTION(0xe00)
EXCEPTION(0xe20) EXCEPTION(0xe20)
@ -110,3 +137,29 @@ test_write:
EXCEPTION(0xf40) EXCEPTION(0xf40)
EXCEPTION(0xf60) EXCEPTION(0xf60)
EXCEPTION(0xf80) 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

@ -4,14 +4,23 @@


#include "console.h" #include "console.h"


#define MSR_DR 0x10
#define MSR_IR 0x20

extern int test_read(long *addr, long *ret, long init); extern int test_read(long *addr, long *ret, long init);
extern int test_write(long *addr, long val); 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) static inline void do_tlbie(unsigned long rb, unsigned long rs)
{ {
__asm__ volatile("tlbie %0,%1" : : "r" (rb), "r" (rs) : "memory"); __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) static inline unsigned long mfspr(int sprnum)
{ {
long val; long val;
@ -135,6 +144,8 @@ void map(void *ea, void *pa, unsigned long perm_attr)
free_ptr += 512 * sizeof(unsigned long); free_ptr += 512 * sizeof(unsigned long);
} }
ptep = read_pgd(i); 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); store_pte(&ptep[j], 0xc000000000000000 | ((unsigned long)pa & 0x00fffffffffff000) | perm_attr);
eas_mapped[neas_mapped++] = ea; eas_mapped[neas_mapped++] = ea;
} }
@ -175,14 +186,14 @@ int mmu_test_1(void)
if (val != 0xdeadbeefd00d) if (val != 0xdeadbeefd00d)
return 2; return 2;
/* DAR and DSISR should be set correctly */ /* 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 3;
return 0; return 0;
} }


int mmu_test_2(void) int mmu_test_2(void)
{ {
long *mem = (long *) 0x4000; long *mem = (long *) 0x8000;
long *ptr = (long *) 0x124000; long *ptr = (long *) 0x124000;
long *ptr2 = (long *) 0x1124000; long *ptr2 = (long *) 0x1124000;
long val; long val;
@ -215,8 +226,8 @@ int mmu_test_2(void)


int mmu_test_3(void) int mmu_test_3(void)
{ {
long *mem = (long *) 0x5000; long *mem = (long *) 0x9000;
long *ptr = (long *) 0x149000; long *ptr = (long *) 0x14a000;
long val; long val;


/* create PTE */ /* create PTE */
@ -238,16 +249,16 @@ int mmu_test_3(void)
if (val != 0xdeadbeefd0d0) if (val != 0xdeadbeefd0d0)
return 4; return 4;
/* DAR and DSISR should be set correctly */ /* 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 5;
return 0; return 0;
} }


int mmu_test_4(void) int mmu_test_4(void)
{ {
long *mem = (long *) 0x6000; long *mem = (long *) 0xa000;
long *ptr = (long *) 0x10a000; long *ptr = (long *) 0x10b000;
long *ptr2 = (long *) 0x110a000; long *ptr2 = (long *) 0x110b000;
long val; long val;


/* create PTE */ /* create PTE */
@ -279,7 +290,7 @@ int mmu_test_4(void)


int mmu_test_5(void) int mmu_test_5(void)
{ {
long *mem = (long *) 0x7ffd; long *mem = (long *) 0xbffd;
long *ptr = (long *) 0x39fffd; long *ptr = (long *) 0x39fffd;
long val; long val;


@ -292,14 +303,14 @@ int mmu_test_5(void)
if (val != 0xdeadbeef0dd0) if (val != 0xdeadbeef0dd0)
return 2; return 2;
/* DAR and DSISR should be set correctly */ /* 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 3;
return 0; return 0;
} }


int mmu_test_6(void) int mmu_test_6(void)
{ {
long *mem = (long *) 0x7ffd; long *mem = (long *) 0xbffd;
long *ptr = (long *) 0x39fffd; long *ptr = (long *) 0x39fffd;


/* create PTE */ /* create PTE */
@ -310,14 +321,14 @@ int mmu_test_6(void)
if (test_write(ptr, 0xdeadbeef0dd0)) if (test_write(ptr, 0xdeadbeef0dd0))
return 1; return 1;
/* DAR and DSISR should be set correctly */ /* 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 2;
return 0; return 0;
} }


int mmu_test_7(void) int mmu_test_7(void)
{ {
long *mem = (long *) 0x4000; long *mem = (long *) 0x8000;
long *ptr = (long *) 0x124000; long *ptr = (long *) 0x124000;
long val; long val;


@ -331,13 +342,13 @@ int mmu_test_7(void)
if (val != 0xdeadd00dbeef) if (val != 0xdeadd00dbeef)
return 2; return 2;
/* DAR and DSISR should be set correctly */ /* 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; return 3;
/* this should fail */ /* this should fail */
if (test_write(ptr, 0xdeadbeef0dd0)) if (test_write(ptr, 0xdeadbeef0dd0))
return 4; return 4;
/* DAR and DSISR should be set correctly */ /* 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; return 5;
/* memory should be unchanged */ /* memory should be unchanged */
if (*mem != 0x123456789abcdef0) if (*mem != 0x123456789abcdef0)
@ -347,7 +358,7 @@ int mmu_test_7(void)


int mmu_test_8(void) int mmu_test_8(void)
{ {
long *mem = (long *) 0x4000; long *mem = (long *) 0x8000;
long *ptr = (long *) 0x124000; long *ptr = (long *) 0x124000;
long val; long val;


@ -361,7 +372,7 @@ int mmu_test_8(void)
if (test_write(ptr, 0xdeadbeef0dd1)) if (test_write(ptr, 0xdeadbeef0dd1))
return 2; return 2;
/* DAR and DSISR should be set correctly */ /* 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; return 3;
/* memory should be unchanged */ /* memory should be unchanged */
if (*mem != 0x123456789abcdef0) if (*mem != 0x123456789abcdef0)
@ -371,7 +382,7 @@ int mmu_test_8(void)


int mmu_test_9(void) int mmu_test_9(void)
{ {
long *mem = (long *) 0x4000; long *mem = (long *) 0x8000;
long *ptr = (long *) 0x124000; long *ptr = (long *) 0x124000;
long val; long val;


@ -385,13 +396,13 @@ int mmu_test_9(void)
if (val != 0xdeadd00dbeef) if (val != 0xdeadd00dbeef)
return 2; return 2;
/* DAR and DSISR should be set correctly */ /* 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; return 3;
/* this should fail */ /* this should fail */
if (test_write(ptr, 0xdeadbeef0dd1)) if (test_write(ptr, 0xdeadbeef0dd1))
return 4; return 4;
/* DAR and DSISR should be set correctly */ /* 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; return 5;
/* memory should be unchanged */ /* memory should be unchanged */
if (*mem != 0x123456789abcdef0) if (*mem != 0x123456789abcdef0)
@ -401,7 +412,7 @@ int mmu_test_9(void)


int mmu_test_10(void) int mmu_test_10(void)
{ {
long *mem = (long *) 0x4000; long *mem = (long *) 0x8000;
long *ptr = (long *) 0x124000; long *ptr = (long *) 0x124000;
long val; long val;


@ -415,7 +426,7 @@ int mmu_test_10(void)
if (test_write(ptr, 0xdeadbeef0dd1)) if (test_write(ptr, 0xdeadbeef0dd1))
return 2; return 2;
/* DAR and DSISR should be set correctly */ /* 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; return 3;
/* memory should be unchanged */ /* memory should be unchanged */
if (*mem != 0x123456789abcdef0) if (*mem != 0x123456789abcdef0)
@ -423,14 +434,159 @@ int mmu_test_10(void)
return 0; 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; int fail = 0;


void do_test(int num, int (*test)(void)) void do_test(int num, int (*test)(void))
{ {
int ret; int ret;


mtspr(18, 0); mtspr(DSISR, 0);
mtspr(19, 0); mtspr(DAR, 0);
unmap_all(); unmap_all();
print_test_number(num); print_test_number(num);
ret = test(); ret = test();
@ -440,10 +596,17 @@ void do_test(int num, int (*test)(void))
fail = 1; fail = 1;
print_string("FAIL "); print_string("FAIL ");
putchar(ret + '0'); putchar(ret + '0');
print_string(" DAR="); if (num <= 10) {
print_hex(mfspr(19)); print_string(" DAR=");
print_string(" DSISR="); print_hex(mfspr(DAR));
print_hex(mfspr(18)); 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"); print_string("\r\n");
} }
} }
@ -463,6 +626,13 @@ int main(void)
do_test(8, mmu_test_8); do_test(8, mmu_test_8);
do_test(9, mmu_test_9); do_test(9, mmu_test_9);
do_test(10, mmu_test_10); 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; return fail;
} }

@ -1,13 +1,27 @@
SECTIONS SECTIONS
{ {
_start = .;
. = 0; . = 0;
_start = .;
.head : { .head : {
KEEP(*(.head)) KEEP(*(.head))
} }
. = 0x1000; . = ALIGN(0x1000);
.text : { *(.text) } .text : { *(.text) *(.text.*) *(.rodata) *(.rodata.*) }
. = 0x3000; . = ALIGN(0x1000);
.data : { *(.data) } .data : { *(.data) *(.data.*) *(.got) *(.toc) }
.bss : { *(.bss) } . = ALIGN(0x80);
__bss_start = .;
.bss : {
*(.dynsbss)
*(.sbss)
*(.scommon)
*(.dynbss)
*(.bss)
*(.common)
*(.bss.*)
}
. = ALIGN(0x80);
__bss_end = .;
. = . + 0x4000;
__stack_top = .;
} }

Binary file not shown.

@ -8,3 +8,10 @@ test 07:PASS
test 08:PASS test 08:PASS
test 09:PASS test 09:PASS
test 10: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

Loading…
Cancel
Save