tests: Add tests for lq/stq and lqarx/stqcx.
authorPaul Mackerras <paulus@ozlabs.org>
Mon, 14 Sep 2020 08:21:27 +0000 (18:21 +1000)
committerPaul Mackerras <paulus@ozlabs.org>
Fri, 15 Jan 2021 01:40:09 +0000 (12:40 +1100)
Lq and stq are tested in both BE and LE modes (though only 64-bit
mode) by the 'modes' test.

Lqarx and stqcx. are tested by the 'reservation' test in LE mode mode
(64-bit).

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
tests/modes/head.S
tests/modes/modes.c
tests/reservation/head.S
tests/reservation/reservation.c
tests/test_modes.bin
tests/test_modes.console_out
tests/test_reservation.bin
tests/test_reservation.console_out

index d9e69dc87748e14270f35ab9e4b533667f3e3e18..8b00bdd45acd0d177866b6291dcfdfd9d4daa416 100644 (file)
@@ -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
index 5d0c8706cd8b4691d397eebff2af30b68b76d416..c8ec9cee7d9b5c762c9ad1f430e81b8fba22b916 100644 (file)
 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");
@@ -24,6 +32,7 @@ static inline void do_tlbie(unsigned long rb, unsigned long rs)
 #define PID    48
 #define SPRG0  272
 #define SPRG1  273
+#define SPRG3  275
 #define PRTBL  720
 
 static inline unsigned long mfspr(int sprnum)
@@ -290,6 +299,167 @@ 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 an illegal instruction interrupt */
+       ret = callit((unsigned long)quad, (unsigned long)regs,
+                    (unsigned long)&do_lq_bad, msr);
+       if (ret != 0x700)
+               return 13;
+       if (mfspr(SPRG0) != (unsigned long)&do_lq_bad + 4 ||
+           !(mfspr(SPRG3) & 0x80000))
+               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))
@@ -334,6 +504,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;
 }
index ce258b5d81a92c9dcc51fe34931a5e242a446330..4ff85ceaac2a03c3225b26acb2bfa6740aaf18c6 100644 (file)
@@ -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
index 280d76ff7641245bbdd4922721490805d1c4727b..4df4511c99b88919154ef113459189334f32ba19 100644 (file)
@@ -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
@@ -161,7 +165,7 @@ int resv_test_2(void)
                size = 1 << j;
                for (offset = 0; offset < 16; ++offset) {
                        ret = callit(size, (unsigned long)&x[0] + offset, do_larx);
-                       if (0 && ret == 0 && (offset & (size - 1)) != 0)
+                       if (ret == 0 && (offset & (size - 1)) != 0)
                                return j + 1;
                        if (ret == 0x600) {
                                if ((offset & (size - 1)) == 0)
@@ -181,6 +185,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 != 0x700 || !(mfspr(SRR1) & 0x80000))
+               return ret + 10;
+       return 0;
+}
+
 int fail = 0;
 
 void do_test(int num, int (*test)(void))
@@ -205,6 +266,7 @@ int main(void)
 
        do_test(1, resv_test_1);
        do_test(2, resv_test_2);
+       do_test(3, resv_test_3);
 
        return fail;
 }
index 0c526280d1c1380597eec3e19573d3891b14a1b4..edbe0c85e906b1d2e51257604fa9ca1687263265 100755 (executable)
Binary files a/tests/test_modes.bin and b/tests/test_modes.bin differ
index a49bb9b00543d7ccbc2c1af7af293d3fc84464ef..25e791c7845c3022d90eeeb6f4e465b8c29742f6 100644 (file)
@@ -4,3 +4,5 @@ test 03:PASS
 test 04:PASS\r
 test 05:PASS\r
 test 06:PASS\r
+test 07:PASS\r
+test 08:PASS\r
index 31d3c8cac00d9ca0e705463d9c4175951796d156..1e305f43af8cbe4213e597cdfc50f1eab71abb5d 100755 (executable)
Binary files a/tests/test_reservation.bin and b/tests/test_reservation.bin differ
index 0c39ae380206b0e9fd84192dd914a43458d1bd62..623335dd309394d687307279070cb36e39321821 100644 (file)
@@ -1,2 +1,3 @@
 test 01:PASS\r
 test 02:PASS\r
+test 03:PASS\r