tests: Add tests for lq/stq and lqarx/stqcx.

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>
pull/267/head
Paul Mackerras 4 years ago
parent 4b2c23703c
commit ec5730a75a

@ -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

@ -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");
@ -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;
}

@ -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

@ -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;
}

Binary file not shown.

@ -4,3 +4,5 @@ test 03:PASS
test 04:PASS
test 05:PASS
test 06:PASS
test 07:PASS
test 08:PASS

Binary file not shown.

@ -1,2 +1,3 @@
test 01:PASS
test 02:PASS
test 03:PASS

Loading…
Cancel
Save