diff --git a/tests/modes/head.S b/tests/modes/head.S index d9e69dc..8b00bdd 100644 --- a/tests/modes/head.S +++ b/tests/modes/head.S @@ -230,3 +230,63 @@ restore: ld %r0,16(%r1) mtlr %r0 blr + + .global do_lq +do_lq: + lq %r6,0(%r3) + std %r6,0(%r4) + std %r7,8(%r4) + li %r3,0 + blr + + .global do_lq_np /* "non-preferred" form of lq */ +do_lq_np: + mr %r7,%r3 + lq %r6,0(%r7) + std %r6,0(%r4) + std %r7,8(%r4) + li %r3,0 + blr + + .global do_lq_bad /* illegal form of lq */ +do_lq_bad: + mr %r6,%r3 + .long 0xe0c60000 /* lq %r6,0(%r6) */ + std %r6,0(%r4) + std %r7,8(%r4) + li %r3,0 + blr + + .global do_stq +do_stq: + ld %r8,0(%r4) + ld %r9,8(%r4) + stq %r8,0(%r3) + li %r3,0 + blr + + /* big-endian versions of the above */ + .global do_lq_be +do_lq_be: + .long 0x0000c3e0 + .long 0x0000c4f8 + .long 0x0800e4f8 + .long 0x00006038 + .long 0x2000804e + + .global do_lq_np_be /* "non-preferred" form of lq */ +do_lq_np_be: + .long 0x781b677c + .long 0x0000c7e0 + .long 0x0000c4f8 + .long 0x0800e4f8 + .long 0x00006038 + .long 0x2000804e + + .global do_stq_be +do_stq_be: + .long 0x000004e9 + .long 0x080024e9 + .long 0x020003f9 + .long 0x00006038 + .long 0x2000804e diff --git a/tests/modes/modes.c b/tests/modes/modes.c index fa4872c..f37e70b 100644 --- a/tests/modes/modes.c +++ b/tests/modes/modes.c @@ -12,6 +12,14 @@ extern unsigned long callit(unsigned long arg1, unsigned long arg2, unsigned long fn, unsigned long msr); +extern void do_lq(void *src, unsigned long *regs); +extern void do_lq_np(void *src, unsigned long *regs); +extern void do_lq_bad(void *src, unsigned long *regs); +extern void do_stq(void *dst, unsigned long *regs); +extern void do_lq_be(void *src, unsigned long *regs); +extern void do_lq_np_be(void *src, unsigned long *regs); +extern void do_stq_be(void *dst, unsigned long *regs); + static inline void do_tlbie(unsigned long rb, unsigned long rs) { __asm__ volatile("tlbie %0,%1" : : "r" (rb), "r" (rs) : "memory"); @@ -25,6 +33,8 @@ static inline void do_tlbie(unsigned long rb, unsigned long rs) #define SPRG0 272 #define SPRG1 273 #define SPRG3 275 +#define HSRR0 314 +#define HSRR1 315 #define PTCR 464 static inline unsigned long mfspr(int sprnum) @@ -294,6 +304,166 @@ int mode_test_6(void) return 0; } +int mode_test_7(void) +{ + unsigned long quad[4] __attribute__((__aligned__(16))); + unsigned long regs[2]; + unsigned long ret, msr; + + /* + * Test lq/stq in LE mode + */ + msr = MSR_SF | MSR_LE; + quad[0] = 0x123456789abcdef0ul; + quad[1] = 0xfafa5959bcbc3434ul; + ret = callit((unsigned long)quad, (unsigned long)regs, + (unsigned long)&do_lq, msr); + if (ret) + return ret | 1; + if (regs[0] != quad[1] || regs[1] != quad[0]) + return 2; + /* unaligned may give alignment interrupt */ + quad[2] = 0x0011223344556677ul; + ret = callit((unsigned long)&quad[1], (unsigned long)regs, + (unsigned long)&do_lq, msr); + if (ret == 0) { + if (regs[0] != quad[2] || regs[1] != quad[1]) + return 3; + } else if (ret == 0x600) { + if (mfspr(SPRG0) != (unsigned long) &do_lq || + mfspr(DAR) != (unsigned long) &quad[1]) + return ret | 4; + } else + return ret | 5; + + /* try stq */ + regs[0] = 0x5238523852385238ul; + regs[1] = 0x5239523952395239ul; + ret = callit((unsigned long)quad, (unsigned long)regs, + (unsigned long)&do_stq, msr); + if (ret) + return ret | 5; + if (quad[0] != regs[1] || quad[1] != regs[0]) + return 6; + regs[0] = 0x0172686966746564ul; + regs[1] = 0xfe8d0badd00dabcdul; + ret = callit((unsigned long)quad + 1, (unsigned long)regs, + (unsigned long)&do_stq, msr); + if (ret) + return ret | 7; + if (((quad[0] >> 8) | (quad[1] << 56)) != regs[1] || + ((quad[1] >> 8) | (quad[2] << 56)) != regs[0]) + return 8; + + /* try lq non-preferred form */ + quad[0] = 0x56789abcdef01234ul; + quad[1] = 0x5959bcbc3434fafaul; + ret = callit((unsigned long)quad, (unsigned long)regs, + (unsigned long)&do_lq_np, msr); + if (ret) + return ret | 9; + if (regs[0] != quad[1] || regs[1] != quad[0]) + return 10; + /* unaligned should give alignment interrupt in uW implementation */ + quad[2] = 0x6677001122334455ul; + ret = callit((unsigned long)&quad[1], (unsigned long)regs, + (unsigned long)&do_lq_np, msr); + if (ret == 0x600) { + if (mfspr(SPRG0) != (unsigned long) &do_lq_np + 4 || + mfspr(DAR) != (unsigned long) &quad[1]) + return ret | 11; + } else + return 12; + + /* make sure lq with rt = ra causes a HEAI interrupt */ + ret = callit((unsigned long)quad, (unsigned long)regs, + (unsigned long)&do_lq_bad, msr); + if (ret != 0xe40) + return 13; + if (mfspr(HSRR0) != (unsigned long)&do_lq_bad + 4) + return 14; + return 0; +} + +int mode_test_8(void) +{ + unsigned long quad[4] __attribute__((__aligned__(16))); + unsigned long regs[2]; + unsigned long ret, msr; + + /* + * Test lq/stq in BE mode + */ + msr = MSR_SF; + quad[0] = 0x123456789abcdef0ul; + quad[1] = 0xfafa5959bcbc3434ul; + ret = callit((unsigned long)quad, (unsigned long)regs, + (unsigned long)&do_lq_be, msr); + if (ret) + return ret | 1; + if (regs[0] != quad[0] || regs[1] != quad[1]) { + print_hex(regs[0], 16); + print_string(" "); + print_hex(regs[1], 16); + print_string(" "); + return 2; + } + /* don't expect alignment interrupt */ + quad[2] = 0x0011223344556677ul; + ret = callit((unsigned long)&quad[1], (unsigned long)regs, + (unsigned long)&do_lq_be, msr); + if (ret == 0) { + if (regs[0] != quad[1] || regs[1] != quad[2]) + return 3; + } else + return ret | 5; + + /* try stq */ + regs[0] = 0x5238523852385238ul; + regs[1] = 0x5239523952395239ul; + ret = callit((unsigned long)quad, (unsigned long)regs, + (unsigned long)&do_stq_be, msr); + if (ret) + return ret | 5; + if (quad[0] != regs[0] || quad[1] != regs[1]) + return 6; + regs[0] = 0x0172686966746564ul; + regs[1] = 0xfe8d0badd00dabcdul; + ret = callit((unsigned long)quad + 1, (unsigned long)regs, + (unsigned long)&do_stq_be, msr); + if (ret) + return ret | 7; + if (((quad[0] >> 8) | (quad[1] << 56)) != regs[0] || + ((quad[1] >> 8) | (quad[2] << 56)) != regs[1]) { + print_hex(quad[0], 16); + print_string(" "); + print_hex(quad[1], 16); + print_string(" "); + print_hex(quad[2], 16); + print_string(" "); + return 8; + } + + /* try lq non-preferred form */ + quad[0] = 0x56789abcdef01234ul; + quad[1] = 0x5959bcbc3434fafaul; + ret = callit((unsigned long)quad, (unsigned long)regs, + (unsigned long)&do_lq_np_be, msr); + if (ret) + return ret | 9; + if (regs[0] != quad[0] || regs[1] != quad[1]) + return 10; + /* unaligned should not give alignment interrupt in uW implementation */ + quad[2] = 0x6677001122334455ul; + ret = callit((unsigned long)&quad[1], (unsigned long)regs, + (unsigned long)&do_lq_np_be, msr); + if (ret) + return ret | 11; + if (regs[0] != quad[1] || regs[1] != quad[2]) + return 12; + return 0; +} + int fail = 0; void do_test(int num, int (*test)(void)) @@ -338,6 +508,8 @@ int main(void) do_test(4, mode_test_4); do_test(5, mode_test_5); do_test(6, mode_test_6); + do_test(7, mode_test_7); + do_test(8, mode_test_8); return fail; } diff --git a/tests/prefix/head.S b/tests/prefix/head.S index 961c2a9..9a46e4b 100644 --- a/tests/prefix/head.S +++ b/tests/prefix/head.S @@ -245,3 +245,23 @@ test_pstw: pstw %r3,wvar(0) li %r3,0 blr + + .globl test_plq +test_plq: + nop + nop + plq %r4,qvar(0) + std %r4,0(%r3) + std %r5,8(%r3) + li %r3,0 + blr + + .globl test_pstq +test_pstq: + nop + nop + ld %r4,0(%r3) + ld %r5,8(%r3) + pstq %r4,qvar(0) + li %r3,0 + blr diff --git a/tests/prefix/prefix.c b/tests/prefix/prefix.c index d594037..8cc117d 100644 --- a/tests/prefix/prefix.c +++ b/tests/prefix/prefix.c @@ -33,6 +33,8 @@ extern long test_pstd(long arg); extern long test_psth(long arg); extern long test_pstw(long arg); extern long test_plfd(long arg); +extern long test_plq(long arg); +extern long test_pstq(long arg); static inline unsigned long mfspr(int sprnum) { @@ -183,6 +185,39 @@ long int prefix_test_3(void) return 0; } +unsigned long qvar[2] __attribute__((__aligned__(16))); +#define V1 0x678912345a5a2b2bull +#define V2 0xa0549922bbccddeeull + +/* test plq and pstq */ +long int prefix_test_4(void) +{ + long int ret; + unsigned long x[2]; + + qvar[0] = V1; + qvar[1] = V2; + ret = trapit((long)&x, test_plq); + if (ret) + return ret | 1; + if (x[0] != V1 || x[1] != V2) { + print_hex(x[0], 16, " "); + print_hex(x[1], 16, " "); + return 2; + } + x[0] = ~V2; + x[1] = ~V1; + ret = trapit((long)&x, test_pstq); + if (ret) + return ret | 3; + if (qvar[0] != ~V2 || qvar[1] != ~V1) { + print_hex(qvar[0], 16, " "); + print_hex(qvar[1], 16, " "); + return 4; + } + return 0; +} + int fail = 0; void do_test(int num, long int (*test)(void)) @@ -210,6 +245,7 @@ int main(void) do_test(1, prefix_test_1); do_test(2, prefix_test_2); do_test(3, prefix_test_3); + do_test(4, prefix_test_4); return fail; } diff --git a/tests/reservation/head.S b/tests/reservation/head.S index ce258b5..4ff85ce 100644 --- a/tests/reservation/head.S +++ b/tests/reservation/head.S @@ -155,3 +155,31 @@ call_ret: ld %r31,248(%r1) addi %r1,%r1,256 blr + + .global do_lqarx +do_lqarx: + /* r3 = src, r4 = regs */ + lqarx %r10,0,%r3 + std %r10,0(%r4) + std %r11,8(%r4) + li %r3,0 + blr + + .global do_lqarx_bad +do_lqarx_bad: + /* r3 = src, r4 = regs */ + .long 0x7d405228 /* lqarx %r10,0,%r10 */ + std %r10,0(%r4) + std %r11,8(%r4) + li %r3,0 + blr + + .global do_stqcx +do_stqcx: + /* r3 = dest, r4 = regs, return CR */ + ld %r10,0(%r4) + ld %r11,8(%r4) + stqcx. %r10,0,%r3 + mfcr %r3 + oris %r3,%r3,1 /* to distinguish from trap number */ + blr diff --git a/tests/reservation/reservation.c b/tests/reservation/reservation.c index 79bbc1f..502b285 100644 --- a/tests/reservation/reservation.c +++ b/tests/reservation/reservation.c @@ -7,6 +7,10 @@ extern unsigned long callit(unsigned long arg1, unsigned long arg2, unsigned long (*fn)(unsigned long, unsigned long)); +extern unsigned long do_lqarx(unsigned long src, unsigned long regs); +extern unsigned long do_lqarx_bad(unsigned long src, unsigned long regs); +extern unsigned long do_stqcx(unsigned long dst, unsigned long regs); + #define DSISR 18 #define DAR 19 #define SRR0 26 @@ -180,6 +184,63 @@ int resv_test_2(void) return 0; } +/* test lqarx/stqcx */ +int resv_test_3(void) +{ + unsigned long x[4] __attribute__((__aligned__(16))); + unsigned long y[2], regs[2]; + unsigned long ret, offset; + int count; + + x[0] = 0x7766554433221100ul; + x[1] = 0xffeeddccbbaa9988ul; + y[0] = 0x0badcafef00dd00dul; + y[1] = 0xdeadbeef07070707ul; + for (count = 0; count < 1000; ++count) { + ret = callit((unsigned long)x, (unsigned long)regs, do_lqarx); + if (ret) + return ret | 1; + ret = callit((unsigned long)x, (unsigned long)y, do_stqcx); + if (ret < 0x10000) + return ret | 2; + if (ret & 0x20000000) + break; + } + if (count == 1000) + return 3; + if (x[0] != y[1] || x[1] != y[0]) + return 4; + if (regs[1] != 0x7766554433221100ul || regs[0] != 0xffeeddccbbaa9988ul) + return 5; + ret = callit((unsigned long)x, (unsigned long)regs, do_stqcx); + if (ret < 0x10000 || (ret & 0x20000000)) + return ret | 12; + /* test alignment interrupts */ + for (offset = 0; offset < 16; ++offset) { + ret = callit((unsigned long)x + offset, (unsigned long)regs, do_lqarx); + if (ret == 0 && (offset & 15) != 0) + return 6; + if (ret == 0x600) { + if ((offset & 15) == 0) + return ret + 7; + } else if (ret) + return ret; + ret = callit((unsigned long)x + offset, (unsigned long)y, do_stqcx); + if (ret >= 0x10000 && (offset & 15) != 0) + return 8; + if (ret == 0x600) { + if ((offset & 15) == 0) + return ret + 9; + } else if (ret < 0x10000) + return ret; + } + /* test illegal interrupt for bad lqarx case */ + ret = callit((unsigned long)x, (unsigned long)regs, do_lqarx_bad); + if (ret != 0xe40) + return ret + 10; + return 0; +} + int fail = 0; void do_test(int num, int (*test)(void)) @@ -204,6 +265,7 @@ int main(void) do_test(1, resv_test_1); do_test(2, resv_test_2); + do_test(3, resv_test_3); return fail; } diff --git a/tests/test_modes.bin b/tests/test_modes.bin index 24e3981..d0c24d7 100755 Binary files a/tests/test_modes.bin and b/tests/test_modes.bin differ diff --git a/tests/test_modes.console_out b/tests/test_modes.console_out index a49bb9b..25e791c 100644 --- a/tests/test_modes.console_out +++ b/tests/test_modes.console_out @@ -4,3 +4,5 @@ test 03:PASS test 04:PASS test 05:PASS test 06:PASS +test 07:PASS +test 08:PASS diff --git a/tests/test_prefix.bin b/tests/test_prefix.bin index 8690be7..e84e70e 100755 Binary files a/tests/test_prefix.bin and b/tests/test_prefix.bin differ diff --git a/tests/test_prefix.console_out b/tests/test_prefix.console_out index 623335d..90cfed1 100644 --- a/tests/test_prefix.console_out +++ b/tests/test_prefix.console_out @@ -1,3 +1,4 @@ test 01:PASS test 02:PASS test 03:PASS +test 04:PASS diff --git a/tests/test_reservation.bin b/tests/test_reservation.bin index 1cb6250..9c9ad8f 100755 Binary files a/tests/test_reservation.bin and b/tests/test_reservation.bin differ diff --git a/tests/test_reservation.console_out b/tests/test_reservation.console_out index 0c39ae3..623335d 100644 --- a/tests/test_reservation.console_out +++ b/tests/test_reservation.console_out @@ -1,2 +1,3 @@ test 01:PASS test 02:PASS +test 03:PASS