From 26de4c1ab18df825607d7882924f57c673af46cf Mon Sep 17 00:00:00 2001 From: George Koehler Date: Sun, 24 Dec 2017 22:37:52 -0500 Subject: [PATCH] Add test for EM _rck_. Fix traps in PowerPC ncg. The new test rck_e.e segfaults on PowerPC unless I make some changes. The inline code for _rck_ was wrong because it didn't allow the trap handler to return. _sig_ forgot to push the old trap handler. Move plat/linuxppc/libsys/trap.s to mach/powerpc/libem/trp.s and rewrite it with simplified/extended mnemonics. Remove .trap alias for .trp procedure. Add a missing `mtspr lr, r0` so we can return from the trap handler. Call write() and _exit() so trp.s works with both linuxppc and osxppc. Before, Mac OS X was wrongly using the trap.s for Linux. In powerpc/libem, simplify .aar4; teach .csa and .csb to raise the trap if the default target is zero. C programs don't need these changes. You may relink your C programs with the changed .csa and .csb, but C code doesn't raise the trap. Modula-2 code can raise traps, so you may want to relink your Modula-2 programs with the changed libem, but you might keep your old .o files from Modula-2. You may need to recompile your Pascal programs (delete old .o files from Pascal) because the Pascal compiler might use _rck_. --- mach/powerpc/libem/aar4.s | 12 +-- mach/powerpc/libem/build.lua | 3 +- mach/powerpc/libem/csa.s | 23 ++-- mach/powerpc/libem/csb.s | 25 ++--- mach/powerpc/libem/rck.s | 4 + mach/powerpc/libem/trp.s | 56 ++++++++++ mach/powerpc/ncg/table | 23 ++-- plat/linuxppc/libsys/build.lua | 1 - plat/linuxppc/libsys/trap.s | 112 -------------------- plat/osxppc/libsys/build.lua | 1 - tests/plat/build.lua | 1 + tests/plat/rck_e.e | 186 +++++++++++++++++++++++++++++++++ 12 files changed, 285 insertions(+), 162 deletions(-) create mode 100644 mach/powerpc/libem/trp.s delete mode 100644 plat/linuxppc/libsys/trap.s create mode 100644 tests/plat/rck_e.e diff --git a/mach/powerpc/libem/aar4.s b/mach/powerpc/libem/aar4.s index fc8620d02..08390b081 100644 --- a/mach/powerpc/libem/aar4.s +++ b/mach/powerpc/libem/aar4.s @@ -8,21 +8,17 @@ .define .aar4 .aar4: - lis r0, hi16[.trap_earray] - ori r0, r0, lo16[.trap_earray] - mtspr ctr, r0 ! load CTR with trap address - lwz r4, 0(sp) ! r4 = address of descriptor lwz r5, 4(sp) ! r5 = index lwz r6, 8(sp) ! r6 = address of array lwz r0, 0(r4) subf. r5, r0, r5 ! subtract lower bound from index - bltctr ! check lower bound + blt .trap_earray ! check lower bound lwz r0, 4(r4) cmplw r5, r0 - bgtctr ! check upper bound + bgt .trap_earray ! check upper bound lwz r3, 8(r4) ! r3 = size of element mullw r5, r5, r3 ! scale index by size @@ -30,3 +26,7 @@ stw r6, 8(sp) ! push address of element addi sp, sp, 8 blr + +.trap_earray: + li r3, 0 ! EARRAY = 0 in h/em_abs.h + b .trp diff --git a/mach/powerpc/libem/build.lua b/mach/powerpc/libem/build.lua index cb5efd281..ac84e3b0f 100644 --- a/mach/powerpc/libem/build.lua +++ b/mach/powerpc/libem/build.lua @@ -6,7 +6,7 @@ for _, plat in ipairs(vars.plats) do acklibrary { name = "lib_"..plat, srcs = { - "./*.s", -- exg.s + "./*.s", -- trp.s }, vars = { plat = plat }, deps = { @@ -15,4 +15,3 @@ for _, plat in ipairs(vars.plats) do } } end - diff --git a/mach/powerpc/libem/csa.s b/mach/powerpc/libem/csa.s index 3898241c4..86d792554 100644 --- a/mach/powerpc/libem/csa.s +++ b/mach/powerpc/libem/csa.s @@ -13,22 +13,21 @@ lwz r4, 4(sp) addi sp, sp, 8 - lwz r5, 0(r3) ! load default - mtspr ctr, r5 - - lwz r5, 4(r3) ! fetch lower bound - subf. r4, r5, r4 ! adjust value - bltctr ! jump to default if out of range + lwz r5, 0(r3) ! r5 = default target - lwz r5, 8(r3) ! fetch range - cmplw r4, r5 - bgtctr ! jump to default if out of range + lwz r6, 4(r3) ! fetch lower bound + subf. r4, r6, r4 ! adjust value + blt 1f ! jump to default if out of range + + lwz r6, 8(r3) ! fetch range + cmplw r4, r6 + bgt 1f ! jump to default if out of range addi r3, r3, 12 ! skip header slwi r4, r4, 2 ! scale value (<<2) - lwzx r5, r3, r4 ! load target - mtspr ctr, r5 + lwzx r5, r3, r4 ! r5 = new target - or. r5, r5, r5 ! test it +1: mtspr ctr, r5 + mr. r5, r5 ! test it bnectr ! jump to target if non-zero b .trap_ecase ! otherwise trap diff --git a/mach/powerpc/libem/csb.s b/mach/powerpc/libem/csb.s index 571bfc210..92c6d096d 100644 --- a/mach/powerpc/libem/csb.s +++ b/mach/powerpc/libem/csb.s @@ -13,23 +13,20 @@ lwz r4, 4(sp) addi sp, sp, 8 - lwz r5, 0(r3) ! load default - mtspr ctr, r5 + lwz r5, 0(r3) ! r5 = default target lwz r6, 4(r3) ! fetch count - -1: - or. r6, r6, r6 ! test count - beqctr ! exit if zero - addi r6, r6, -1 ! otherwise decrement - - lwzu r7, 8(r3) ! fetch target index, increment pointer + mr. r6, r6 ! skip loop if count is zero + beq 3f ! (needed by Modula-2 "CASE i OF END") + mtspr ctr, r6 +1: lwzu r7, 8(r3) ! fetch target index, increment pointer cmpw r4, r7 ! compare with value - bne 1b ! if not equal, go again - - lwz r7, 4(r3) ! fetch target address - mtspr ctr, r7 + beq 2f + bdnz 1b ! if not equal, go again + b 3f - or. r7, r7, r7 ! test it +2: lwz r5, 4(r3) ! r5 = new target +3: mtspr ctr, r5 + mr. r5, r5 ! test target bnectr ! jump to target if non-zero b .trap_ecase ! otherwise trap diff --git a/mach/powerpc/libem/rck.s b/mach/powerpc/libem/rck.s index 9008be610..f1cf7f848 100644 --- a/mach/powerpc/libem/rck.s +++ b/mach/powerpc/libem/rck.s @@ -18,3 +18,7 @@ bgt .trap_erange blr + +.trap_erange: + li r3, 1 ! ERANGE = 1 in h/em_abs.h + b .trp diff --git a/mach/powerpc/libem/trp.s b/mach/powerpc/libem/trp.s new file mode 100644 index 000000000..b07afb929 --- /dev/null +++ b/mach/powerpc/libem/trp.s @@ -0,0 +1,56 @@ +.sect .text + +.define .trap_ecase +.trap_ecase: + li r3, 20 ! ECASE = 20 in h/em_abs.h + ! FALLTHROUGH to .trp + +! Raises an EM trap. +! Expects r3 = trap number. + +.define .trp +.trp: + cmplwi r3, 15 ! traps > 15 can't be ignored + bgt 1f + + lis r4, ha16[.ignmask] + lwz r4, lo16[.ignmask](r4) ! load ignore mask + srw r4, r4, r3 + andi. r4, r4, 1 + bnelr ! return if ignoring trap + +1: lis r4, ha16[.trppc] + lwz r5, lo16[.trppc](r4) ! r5 = user trap routine + mr. r5, r5 + beq 2f ! if no user trap routine, bail out + + mtspr ctr, r5 + mfspr r6, lr + li r0, 0 + stwu r3, -8(sp) ! push trap number + stw r0, lo16[.trppc](r4) ! reset trap routine + stw r6, 4(sp) ! save old lr + bctrl ! call trap routine + + lwz r0, 4(sp) + mtspr lr, r0 + addi sp, sp, 8 ! retract over stack usage + blr + +2: ! No trap handler. Write error message, exit. + li r3, 2 + stwu r3, -12(sp) + lis r4, ha16[message] + addi r4, r4, lo16[message] + li r5, 6 + stw r4, 4(sp) + stw r5, 8(sp) + bl _write ! write(2, message, 6) + + li r3, 1 + stw r3, 0(sp) + bl __exit ! _exit(1) + +.sect .rom +message: + .ascii "TRAP!\n" diff --git a/mach/powerpc/ncg/table b/mach/powerpc/ncg/table index e66ae855f..10ffadb16 100644 --- a/mach/powerpc/ncg/table +++ b/mach/powerpc/ncg/table @@ -2168,10 +2168,13 @@ PATTERNS pat trp /* Raise EM trap */ with REG3 kills ALL - gen bl {LABEL, ".trap"} + gen bl {LABEL, ".trp"} - pat sig /* Set trap handler */ - leaving ste ".trppc" + pat sig /* Set trap handler, yield old */ + leaving + loe ".trppc" + exg 4 + ste ".trppc" pat rtt /* Return from trap */ leaving ret 0 @@ -2216,22 +2219,14 @@ PATTERNS with REG gen move %1, sp - pat lae rck $2==4 /* Range check */ - with REG - kills ALL - gen - cmpwi %1, {C, rom($1, 1)} - blt {LABEL, ".trap_erange"} - cmpwi %1, {C, rom($1, 2)} - bgt {LABEL, ".trap_erange"} - yields %1 + pat rck $1==4 /* Range check */ + leaving cal ".rck" /* Single-precision floating-point */ pat zrf $1==4 /* Push zero */ - leaving - loe ".fs_00000000" + leaving loe ".fs_00000000" pat adf $1==4 /* Add single */ with FSREG FSREG diff --git a/plat/linuxppc/libsys/build.lua b/plat/linuxppc/libsys/build.lua index f7b16b378..696c62d42 100644 --- a/plat/linuxppc/libsys/build.lua +++ b/plat/linuxppc/libsys/build.lua @@ -4,7 +4,6 @@ acklibrary { "./_syscall.s", "./sigaction.s", "./signal.c", - "./trap.s", "plat/linux/libsys/_exit.c", "plat/linux/libsys/_hol0.s", "plat/linux/libsys/close.c", diff --git a/plat/linuxppc/libsys/trap.s b/plat/linuxppc/libsys/trap.s deleted file mode 100644 index 93c5189a4..000000000 --- a/plat/linuxppc/libsys/trap.s +++ /dev/null @@ -1,112 +0,0 @@ -# -! $Source: /cvsroot/tack/Ack/plat/linux386/libsys/_syscall.s,v $ -! $State: Exp $ -! $Revision: 1.1 $ - -! Declare segments (the order is important). - -.sect .text -.sect .rom -.sect .data -.sect .bss - -.sect .text - -#define IFFALSE 4 -#define IFTRUE 12 -#define ALWAYS 20 - -#define LT 0 -#define GT 1 -#define EQ 2 -#define OV 3 - -EARRAY = 0 -ERANGE = 1 -ESET = 2 -EIOVFL = 3 -EFOVFL = 4 -EFUNFL = 5 -EIDIVZ = 6 -EFDIVZ = 7 -EIUND = 8 -EFUND = 9 -ECONV = 10 -ESTACK = 16 -EHEAP = 17 -EILLINS = 18 -EODDZ = 19 -ECASE = 20 -EMEMFLT = 21 -EBADPTR = 22 -EBADPC = 23 -EBADLAE = 24 -EBADMON = 25 -EBADLIN = 26 -EBADGTO = 27 -EUNIMPL = 63 ! unimplemented em-instruction called - -! EM trap handling. - -.define .trap_ecase -.trap_ecase: - addi r3, r0, ECASE - b .trap - -.define .trap_earray -.trap_earray: - addi r3, r0, EARRAY - b .trap - -.define .trap_erange -.trap_erange: - addi r3, r0, ERANGE - b .trap - -.define .trp -.define .trap -.trp: -.trap: - cmpi cr0, 0, r3, 15 ! traps >15 can't be ignored - bc IFTRUE, LT, 1f - - addi r4, r0, 1 - rlwnm r4, r4, r3, 0, 31 ! calculate trap bit - li32 r5, .ignmask - lwz r5, 0(r5) ! load ignore mask - and. r4, r4, r5 ! compare - bclr IFFALSE, EQ, 0 ! return if non-zero - -1: - li32 r4, .trppc - lwz r5, 0(r4) ! load user trap routine - or. r5, r5, r5 ! test - bc IFTRUE, EQ, fatal ! if no user trap routine, bail out - - addi r0, r0, 0 - stw r0, 0(r4) ! reset trap routine - - mfspr r0, lr - stwu r0, -4(sp) ! save old lr - - stwu r3, -4(sp) - mtspr ctr, r5 - bcctrl ALWAYS, 0, 0 ! call trap routine - - lwz r0, 4(sp) ! load old lr again - addi sp, sp, 8 ! retract over stack usage - bclr ALWAYS, 0, 0 ! return - -fatal: - addi r3, r0, 1 - li32 r4, message - addi r5, r0, 6 - addi r0, r0, 4 ! write() - sc 0 - - addi r0, r0, 1 ! exit() - sc 0 - -.sect .rom -message: - .ascii "TRAP!\n" diff --git a/plat/osxppc/libsys/build.lua b/plat/osxppc/libsys/build.lua index 072730b7a..49fc0c934 100644 --- a/plat/osxppc/libsys/build.lua +++ b/plat/osxppc/libsys/build.lua @@ -19,7 +19,6 @@ acklibrary { "./sigaction.s", "./stat.s", "./write.s", - "plat/linuxppc/libsys/trap.s", "plat/osx/libsys/brk.c", "plat/osx/libsys/creat.c", "plat/osx/libsys/isatty.c", diff --git a/tests/plat/build.lua b/tests/plat/build.lua index 666af7d95..fdac9bae3 100644 --- a/tests/plat/build.lua +++ b/tests/plat/build.lua @@ -13,6 +13,7 @@ definerule("plat_testsuite", "tests/plat/dup_e.e", "tests/plat/exg_e.e", "tests/plat/inn_e.e", + "tests/plat/rck_e.e", "tests/plat/rotate_e.e", "tests/plat/*.p", "tests/plat/b/*.b", diff --git a/tests/plat/rck_e.e b/tests/plat/rck_e.e new file mode 100644 index 000000000..cd5c581df --- /dev/null +++ b/tests/plat/rck_e.e @@ -0,0 +1,186 @@ +# + mes 2, EM_WSIZE, EM_PSIZE + +/* + * Uses _rck_ for range checks. Catches the EM trap if a value is out + * of range, and continues with the next instruction after _rck_. + * + * Some back ends, like i80, ignore _rck_, so this test fails. + */ + +testnr + con 1 ; test number +caught + con 0 ; number of caught traps + + inp $next + inp $catch + inp $never + exp $_m_a_i_n + pro $_m_a_i_n,0 + + lim ; load ignore mask + loc 2 + and EM_WSIZE ; check bit 1 << ERANGE + zeq *1 ; fail if ignoring ERANGE +.1 + rom 1I4 + lae .1 + loi 4 + cal $fail + asp 4 +1 + + cal $next ; increment testnr, catch next trap + loc 10125 +.2 + rom 4283, 13644 + lae .2 + rck EM_WSIZE ; testnr 2 in range + asp EM_WSIZE + + cal $next + loc 4282 + lae .2 + rck EM_WSIZE ; testnr 3 out of range + asp EM_WSIZE + + cal $next + loc 4283 + lae .2 + rck EM_WSIZE ; testnr 4 in range + asp EM_WSIZE + + cal $next + loc 13644 + lae .2 + rck EM_WSIZE ; testnr 5 in range + asp EM_WSIZE + + cal $next + loc 13655 + lae .2 + rck EM_WSIZE ; testnr 6 out of range + asp EM_WSIZE + + cal $next + loc -13015 +.7 + rom -31344, -1898 + lae .7 + rck EM_WSIZE ; testnr 7 in range + asp EM_WSIZE + + cal $next + loc 8580 +.8 + rom -26315, 4588 + lae .8 + rck EM_WSIZE ; testnr 8 out of range + asp EM_WSIZE + + ; The last test raised a trap, so now there is no trap handler. + lpi $never + sig ; push old trap handler + loc 0 + loc EM_WSIZE + loc EM_PSIZE + cuu ; push NULL pointer + cmp + zeq *17 ; fail unless old handler is NULL +.17 + rom 17I4 + lae .17 + loi 4 + cal $fail + asp 4 +17 + ; Change the trap handler from $never to $catch. + lpi $catch + sig + lpi $never + cmp + zeq *18 +.18 + rom 18I4 + lae .18 + loi 4 + cal $fail + asp 4 +18 + ; Begin ignoring range traps. + loc 2 ; 1 << ERANGE + sim + loc 18 + ste testnr + loc 8580 + lae .8 + rck EM_WSIZE ; testnr 18 out of range but ignored + + ; Fail if we caught the wrong number of traps. + loe caught + loc 3 + beq *20 +.20 + rom 20I4 + lae .20 + loi 4 + cal $fail + asp 4 +20 + cal $finished + end + + pro $next,0 + ine testnr ; next test + lpi $catch + sig ; catch next EM trap (only one trap) + asp EM_PSIZE + ret 0 + end + + pro $catch,0 + ine caught ; count this trap + + lol 0 ; load trap number + loc 1 + beq *1 ; fail if trap != ERANGE +.101 + rom 257I4 + lae .101 + loi 4 + cal $fail + ; Wrong type of trap. _rtt_ might not work, so exit now. + cal $finished +1 + ; Fail if the wrong test raised this trap. + loe testnr + loc 3 + beq *2 + loe testnr + loc 6 + beq *2 + loe testnr + loc 8 + beq *2 + loc 256 + loe testnr + adi EM_WSIZE ; 0x100 + testnr + loc EM_WSIZE + loc 4 + cuu + cal $fail + asp 4 +2 + rtt ; return from trap handler + end + + pro $never,0 +.200 + rom 200I4 + lae .200 + loi 4 + cal $fail + asp 4 + rtt + end -- 2.34.1