From e7a08f33ebdec6c3825f60c0834734455301160e Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 22 Aug 2020 19:53:59 +1000 Subject: [PATCH] tests: Add a test for the load-reserve and store-conditional instructions This checks that the instructions seem to update memory as expected, and also that they generate alignment interrupts when necessary. We don't check whether the memory update is atomic as we don't have SMP yet. Signed-off-by: Paul Mackerras --- tests/reservation/Makefile | 3 + tests/reservation/head.S | 157 +++++++++++++++++++++ tests/reservation/powerpc.lds | 27 ++++ tests/reservation/reservation.c | 210 +++++++++++++++++++++++++++++ tests/test_reservation.bin | Bin 0 -> 10896 bytes tests/test_reservation.console_out | 2 + tests/update_console_tests | 2 +- 7 files changed, 400 insertions(+), 1 deletion(-) create mode 100644 tests/reservation/Makefile create mode 100644 tests/reservation/head.S create mode 100644 tests/reservation/powerpc.lds create mode 100644 tests/reservation/reservation.c create mode 100755 tests/test_reservation.bin create mode 100644 tests/test_reservation.console_out diff --git a/tests/reservation/Makefile b/tests/reservation/Makefile new file mode 100644 index 0000000..42aa52a --- /dev/null +++ b/tests/reservation/Makefile @@ -0,0 +1,3 @@ +TEST=reservation + +include ../Makefile.test diff --git a/tests/reservation/head.S b/tests/reservation/head.S new file mode 100644 index 0000000..ce258b5 --- /dev/null +++ b/tests/reservation/head.S @@ -0,0 +1,157 @@ +/* Copyright 2013-2014 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Load an immediate 64-bit value into a register */ +#define LOAD_IMM64(r, e) \ + lis r,(e)@highest; \ + ori r,r,(e)@higher; \ + rldicr r,r, 32, 31; \ + oris r,r, (e)@h; \ + ori r,r, (e)@l; + + .section ".head","ax" + + /* + * Microwatt currently enters in LE mode at 0x0, so we don't need to + * do any endian fix ups + */ + . = 0 +.global _start +_start: + 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 + +2: LOAD_IMM64(%r1,__stack_top) + li %r0,0 + stdu %r0,-16(%r1) + mtsprg2 %r0 + LOAD_IMM64(%r12, main) + mtctr %r12 + bctrl + attn // terminate on exit + b . + +exception: + mfsprg2 %r0 + cmpdi %r0,0 + bne call_ret + attn + +#define EXCEPTION(nr) \ + .= nr ;\ + li %r3,nr ;\ + b exception + + EXCEPTION(0x300) + EXCEPTION(0x380) + EXCEPTION(0x400) + EXCEPTION(0x480) + EXCEPTION(0x500) + EXCEPTION(0x600) + EXCEPTION(0x700) + EXCEPTION(0x800) + EXCEPTION(0x900) + EXCEPTION(0x980) + EXCEPTION(0xa00) + EXCEPTION(0xb00) + EXCEPTION(0xc00) + EXCEPTION(0xd00) + EXCEPTION(0xe00) + EXCEPTION(0xe20) + EXCEPTION(0xe40) + EXCEPTION(0xe60) + EXCEPTION(0xe80) + EXCEPTION(0xf00) + EXCEPTION(0xf20) + EXCEPTION(0xf40) + EXCEPTION(0xf60) + EXCEPTION(0xf80) + + . = 0x1000 + /* + * Call a function in a context with a given MSR value. + * r3, r4 = args; r5 = function + */ + .globl callit +callit: + mflr %r0 + std %r0,16(%r1) + stdu %r1,-256(%r1) + mfcr %r8 + stw %r8,100(%r1) + std %r13,104(%r1) + std %r14,112(%r1) + std %r15,120(%r1) + std %r16,128(%r1) + std %r17,136(%r1) + std %r18,144(%r1) + std %r19,152(%r1) + std %r20,160(%r1) + std %r21,168(%r1) + std %r22,176(%r1) + std %r23,184(%r1) + std %r24,192(%r1) + std %r25,200(%r1) + std %r26,208(%r1) + std %r27,216(%r1) + std %r28,224(%r1) + std %r29,232(%r1) + std %r30,240(%r1) + std %r31,248(%r1) + mtsprg0 %r0 + mtsprg1 %r1 + mtsprg2 %r2 + mtctr %r5 + mr %r12,%r5 + bctrl +call_ret: + mfsprg0 %r0 /* restore regs in case of trap */ + mfsprg1 %r1 + mfsprg2 %r2 + li %r7,0 + mtsprg2 %r7 + mtlr %r0 + lwz %r8,100(%r1) + mtcr %r8 + ld %r13,104(%r1) + ld %r14,112(%r1) + ld %r15,120(%r1) + ld %r16,128(%r1) + ld %r17,136(%r1) + ld %r18,144(%r1) + ld %r19,152(%r1) + ld %r20,160(%r1) + ld %r21,168(%r1) + ld %r22,176(%r1) + ld %r23,184(%r1) + ld %r24,192(%r1) + ld %r25,200(%r1) + ld %r26,208(%r1) + ld %r27,216(%r1) + ld %r28,224(%r1) + ld %r29,232(%r1) + ld %r30,240(%r1) + ld %r31,248(%r1) + addi %r1,%r1,256 + blr diff --git a/tests/reservation/powerpc.lds b/tests/reservation/powerpc.lds new file mode 100644 index 0000000..99611ab --- /dev/null +++ b/tests/reservation/powerpc.lds @@ -0,0 +1,27 @@ +SECTIONS +{ + . = 0; + _start = .; + .head : { + KEEP(*(.head)) + } + . = 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/reservation/reservation.c b/tests/reservation/reservation.c new file mode 100644 index 0000000..280d76f --- /dev/null +++ b/tests/reservation/reservation.c @@ -0,0 +1,210 @@ +#include +#include +#include + +#include "console.h" + +extern unsigned long callit(unsigned long arg1, unsigned long arg2, + unsigned long (*fn)(unsigned long, unsigned long)); + +#define DSISR 18 +#define DAR 19 +#define SRR0 26 +#define SRR1 27 +#define PID 48 +#define SPRG0 272 +#define SPRG1 273 +#define PRTBL 720 + +static inline unsigned long mfspr(int sprnum) +{ + long val; + + __asm__ volatile("mfspr %0,%1" : "=r" (val) : "i" (sprnum)); + return val; +} + +static inline void mtspr(int sprnum, unsigned long val) +{ + __asm__ volatile("mtspr %0,%1" : : "i" (sprnum), "r" (val)); +} + +static inline void store_pte(unsigned long *p, unsigned long pte) +{ + __asm__ volatile("stdbrx %1,0,%0" : : "r" (p), "r" (pte) : "memory"); +} + +void print_string(const char *str) +{ + for (; *str; ++str) + putchar(*str); +} + +void print_hex(unsigned long val, int ndigits) +{ + int i, x; + + for (i = (ndigits - 1) * 4; i >= 0; i -= 4) { + x = (val >> i) & 0xf; + if (x >= 10) + putchar(x + 'a' - 10); + else + putchar(x + '0'); + } +} + +// i < 100 +void print_test_number(int i) +{ + print_string("test "); + putchar(48 + i/10); + putchar(48 + i%10); + putchar(':'); +} + +#define DO_LARX(instr, addr, val) __asm__ volatile(instr " %0,0,%1" : "=r" (val) : "r" (addr)) +#define DO_STCX(instr, addr, val, cc) __asm__ volatile(instr " %2,0,%1; mfcr %0" : "=r" (cc) \ + : "r" (addr), "r" (val) : "cr0", "memory"); + +int resv_test_1(void) +{ + unsigned long x, val, cc = 0; + int count; + + x = 1234; + for (count = 0; count < 1000; ++count) { + DO_LARX("ldarx", &x, val); + DO_STCX("stdcx.", &x, 5678, cc); + if (cc & 0x20000000) + break; + } + /* ldarx/stdcx. should succeed eventually */ + if (count == 1000) + return 1; + if (x != 5678) + return 2; + for (count = 0; count < 1000; ++count) { + DO_LARX("lwarx", &x, val); + DO_STCX("stwcx.", &x, 9876, cc); + if (cc & 0x20000000) + break; + } + /* lwarx/stwcx. should succeed eventually */ + if (count == 1000) + return 3; + if (x != 9876) + return 4; + for (count = 0; count < 1000; ++count) { + DO_LARX("lharx", &x, val); + DO_STCX("sthcx.", &x, 3210, cc); + if (cc & 0x20000000) + break; + } + /* lharx/sthcx. should succeed eventually */ + if (count == 1000) + return 5; + if (x != 3210) + return 6; + return 0; +} + +unsigned long do_larx(unsigned long size, unsigned long addr) +{ + unsigned long val; + + switch (size) { + case 1: + DO_LARX("lbarx", addr, val); + break; + case 2: + DO_LARX("lharx", addr, val); + break; + case 4: + DO_LARX("lwarx", addr, val); + break; + case 8: + DO_LARX("ldarx", addr, val); + break; + } + return 0; +} + +unsigned long do_stcx(unsigned long size, unsigned long addr) +{ + unsigned long val = 0, cc; + + switch (size) { + case 1: + DO_STCX("stbcx.", addr, val, cc); + break; + case 2: + DO_STCX("sthcx.", addr, val, cc); + break; + case 4: + DO_STCX("stwcx.", addr, val, cc); + break; + case 8: + DO_STCX("stdcx.", addr, val, cc); + break; + } + return 0; +} + +int resv_test_2(void) +{ + unsigned long x[3]; + unsigned long offset, j, size, ret; + + x[0] = 1234; + x[1] = x[2] = 0; + for (j = 0; j <= 3; ++j) { + 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) + return j + 1; + if (ret == 0x600) { + if ((offset & (size - 1)) == 0) + return j + 0x10; + } else if (ret) + return ret; + ret = callit(size, (unsigned long)&x[0] + offset, do_stcx); + if (ret == 0 && (offset & (size - 1)) != 0) + return j + 0x20; + if (ret == 0x600) { + if ((offset & (size - 1)) == 0) + return j + 0x30; + } else if (ret) + return ret; + } + } + return 0; +} + +int fail = 0; + +void do_test(int num, int (*test)(void)) +{ + int ret; + + print_test_number(num); + ret = test(); + if (ret == 0) { + print_string("PASS\r\n"); + } else { + fail = 1; + print_string("FAIL "); + print_hex(ret, 4); + print_string("\r\n"); + } +} + +int main(void) +{ + console_init(); + + do_test(1, resv_test_1); + do_test(2, resv_test_2); + + return fail; +} diff --git a/tests/test_reservation.bin b/tests/test_reservation.bin new file mode 100755 index 0000000000000000000000000000000000000000..31d3c8cac00d9ca0e705463d9c4175951796d156 GIT binary patch literal 10896 zcmeHNU2GKB6+W}O-W?ocwiSvjL6ccb=-S<+TPdn$v&PKWK#hTbAQe2c)ocus!KsAR zR9d&Q*|Ez5M3xE_56~t!sMU%_Q1Rf0R7xegR8gwFB$ZXAZ3=e7!~VFEAxX2|CAt01 z%q+XM%K9Nfe(;WTxp&Sv_nhzh?wwirGDO;TqW;7?f&LNn$0^#MATnSZf^7)4q2pF` zC~@%U$Q1T_F`S zy-blAdcVAT1Nh&q!yo>^I(`lQzB+yb{%{??1;1R! z|K$nR&yexRW{{+!Btpe)M5$vWogbtti>GLMF-dca7D=Tu6e^t~y>yWhr8j7_bd|1@ zZqRh;Et)G$kyL({Lgn{JFMmLZ@+^&(vvj4rK-1+S&6P8~K{M0)Ewn>s#`{|{`HgEP z|IMH2fxQRzoo)qJTT;eArB0BV8{bQ z9vBM1PymJkFcg5H01O3SC;&r&q>!o*&KVk4LxF|@4FwtsG!$qk&`_YEKtq9s0u2Qk z3N#d0qY7lbTI{brC6@8-Nj>v8#TG z3)`HzVa$EH2G2!zuGgJgyL>)s4{P{FVKa^D62@CG_P9M`=Cc49_n#ogRmC#rh1ffY z{to&q`VY~E(a)e?p7&@?-iVv`S@g^E;yZ@e^^gMnoV62kColZ&{h#bQO6+Mj zesWn|iL@@d(WCNN4X@RxpZbPzUL(Yo9YT0^;MgBG-$e52HnA zzn@lU;-`~=KctDK;zFc2CYJomQ|XQO&YH=>uhSZh7C-%u&DX#H*OSO;**U+5oZr6x=X7_V z6bQ`*EctT8?X*fiwDye#Gy_^dAZ1+S|TLlJ{x!iXVj%lQQC$?`{O zA6e?_7_%=5-&Cz0%hrMM%mGi%NUX0;+KAE*` zPZ(ymf8YftcV{l>#^$TB8pq05501|x{=F(slwKJJzek9c;!qyo=*-zT4j3-Kr5I!< zPV4rccmdyU*|GT}N~%VSB^dY}!t2lbZ|U=M`{zX6k)ZqhKr;0u?B`~BBFxX!dfe;a zmHhZ-I)=W6qhw)!B{!YKIj*7puB|i0+VXFL1Wgtmro|L(S4d8vjo7;FrW8#n+sQAF zfD`N;jvYF)7HzB%{Ms@fP4V|@WN-^w|5ou^g}MDBSm(vf{B0ZVe{on&`HGz*H#hW; zSjc1VS&MT z05Ra=-fYg1}?BJac2%;CoScWZ>~y?geXY-5~Jx~x0DZyNmV5!vR~ zpQz$>>jKLx)`I;W8Ze-#jVu3PUm;`lGG0FZqn8!jAJh*YUf)c#Ti>&f?|D2WaON*? z<}YyOFL35BaON*?=I_2s`B`Qzh$|qjfVcwU3WzK4vx->z{ek!bze_ll$Ly=TTi6yv zJ-(!$93o#*mo~LX#I`oHzR!f1VJ9xOK^T(pi+Gd`xY(wl?Sn0ep06%6JS21jHd(@8 z=Q^GAi}IzwFa5u2dd>H`_p)a~`ilOF-g-{@L31nVw{QLH!+-wc?;rT}#}K|1?E+eI zQ3(EFvFA@ny{%Eq*=fhyfnm7bM!SeOyY?>B;ncfoB5zf5W)XV_u_k(|#O}6Z585F7 zIw^1kfmtmH!5CEA2!EM-w*xKRstK z=L|b>RrKt`8{)KMBIcx_y#1xgpw literal 0 HcmV?d00001 diff --git a/tests/test_reservation.console_out b/tests/test_reservation.console_out new file mode 100644 index 0000000..0c39ae3 --- /dev/null +++ b/tests/test_reservation.console_out @@ -0,0 +1,2 @@ +test 01:PASS +test 02:PASS diff --git a/tests/update_console_tests b/tests/update_console_tests index 2101c6b..ffb30c7 100755 --- a/tests/update_console_tests +++ b/tests/update_console_tests @@ -3,7 +3,7 @@ # Script to update console related tests from source # -for i in sc illegal decrementer xics privileged mmu misc modes ; do +for i in sc illegal decrementer xics privileged mmu misc modes reservation ; do cd $i make cd -