From: Roland McGrath Date: Sat, 3 Dec 1994 14:00:08 +0000 (+0000) Subject: Set up frame for `rei' to restore on user stack, aligned to an 8-word X-Git-Tag: upstream/2.30~10627^2~4025 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5c87d70ba0acb34548c43934949306b684c98938;p=external%2Fglibc.git Set up frame for `rei' to restore on user stack, aligned to an 8-word boundary and with a PS value that restores user's stack alignment. --- diff --git a/sysdeps/mach/hurd/alpha/sigreturn.c b/sysdeps/mach/hurd/alpha/sigreturn.c index 37f36b6..6ef718c 100644 --- a/sysdeps/mach/hurd/alpha/sigreturn.c +++ b/sysdeps/mach/hurd/alpha/sigreturn.c @@ -154,18 +154,54 @@ __sigreturn (struct sigcontext *scp) /* Load all the registers from the sigcontext. */ #define restore_gpr(n) \ - asm volatile ("ldq $" #n ",%0" : : "m" (scpreg->sc_gpr[n])) + asm volatile ("ldq $" #n ",%0" : : "m" (scpreg->sc_regs[n])) { - /* The `rei' PAL pseudo-instruction restores registers $2..$7, - the PC and processor status. So we can use these few registers - for our working variables. */ + /* The `rei' PAL pseudo-instruction restores registers $2..$7, the PC + and processor status. So we can use these few registers for our + working variables. Unfortunately, it finds its data on the stack + and merely pops the SP ($30) over the words of state restored, + allowing no other option for the new SP value. So we must push the + registers and PSW it will to restore, onto the user's stack and let + it pop them from there. */ register const struct sigcontext *const scpreg asm ("$2") = scp; - register long int *sp asm ("$30"); + register integer_t *usp asm ("$3") = scpreg->sc_regs[30]; + register integer_t usp_align asm ("$4"); + register integer_t *sp asm ("$30"); + + /* Push an 8-word "trap frame" onto the user stack for `rei': + registers $2..$7, the PC, and the PSW. */ + + register struct rei_frame + { + integer_t regs[5], pc, ps; + } *rei_frame asm ("$5"); + + usp -= 8; + /* `rei' demands that the stack be aligned to a 64 byte (8 word) + boundary; bits 61..56 of the PSW are OR'd back into the SP value + after popping the 8-word trap frame, so we store (sp % 64) + there and this restores the original user SP. */ + usp_align = (integer_t) usp & 63L; + rei_frame = (void *) ((integer_t) usp & ~63L); + + /* Copy the registers and PC from the sigcontext. */ + memcpy (rei_frame->regs, &scpreg->sc_regs[2], sizeof rei_frame->regs); + rei_frame->pc = scpreg->sc_pc; + + /* Compute the new PS value to be restored. `rei' adds the value at + bits 61..56 to the SP to compensate for the alignment above that + cleared the low 6 bits; bits 5..3 are the new mode/privilege level + (must be >= current mode; 3 == user mode); bits 2..0 are "software", + unused by the processor or kernel (XXX should trampoline save these? + How?); in user mode, `rei' demands that all other bits be zero. */ + rei_frame->ps = (usp_align << 56) | (3 << 3); /* XXX low 3 bits??? */ asm volatile (".set noreorder; .set noat;"); - /* Restore the other general registers. */ + /* Restore the other general registers: everything except $2..$7, which + are in the `rei' trap frame we set up above, and $30, which is the + SP which is popped by `rei'. */ restore_gpr (1); restore_gpr (8); restore_gpr (9); @@ -189,30 +225,14 @@ __sigreturn (struct sigcontext *scp) restore_gpr (27); restore_gpr (28); restore_gpr (29); - restore_gpr (30); /* Stack pointer. */ - - /* The magical `rei' instruction looks at the SP ($30) for: - - sp--> t1 ($2) - +0x8 t2 ($3) - +0x10 t3 ($4) - +0x18 t4 ($5) - +0x20 t5 ($6) - +0x28 t6 ($7) - +0x30 PC - +0x38 PS - - For the first six words, &scp->sc_regs[2] already looks like this. - So we clobber the following words words where $8 and $9 were saved - (we already restored them above) with the PC and PS to be restored, - and then point the SP there. */ - - scpreg->sc_regs[8] = scpreg->sc_pc; - /* scpreg->sc_regs[9] = scpreg->sc_ps; XXX where to get it from??? */ - - /* XXX What will restore the user's SP??? */ - sp = &scpreg->sc_regs[2]; - asm volatile ("call_pal %0" : : "i" (op_rei)); + + /* Switch the stack pointer to the trap frame set up on + the user stack and do the magical `rei' PAL call. */ + asm volatile ("mov %0, $30\n" + "call_pal %0" + : : "r" (rei_frame), "i" (op_rei)); + /* Firewall. */ + asm volatile ("call_pal %0" : : "i" (op_halt)); asm volatile (".set reorder; .set at;"); }