kernel: trap-dependent state restore, trace fixes

. restore state depends on how saving of state was done;
	  also remember trap style in sig context
	. actually set and restore TRACEBIT with new trap styles;
	  have to remove it once process enters kernel though, done
	  in debug trap exception handler
	. introduce MF_STEP that makes arch-specific code
	  turn on trace bit instead of setting TRACEBIT directly,
	  a bit more arch-friendly and avoids keeping precious
	  state in per-process PSW arch-dependently
This commit is contained in:
Ben Gras 2013-01-06 18:18:41 +00:00
parent b258ab0e66
commit 604046faf3
12 changed files with 64 additions and 22 deletions

View file

@ -25,6 +25,7 @@ struct sigframe { /* stack frame created for signalled process */
};
struct sigcontext {
int trap_style; /* how should context be restored? KTS_* */
int sc_flags; /* sigstack state to restore (including
* MF_FPU_INITIALIZED)
*/

View file

@ -48,7 +48,8 @@ void arch_proc_reset(struct proc *pr)
pr->p_reg.psr = INIT_PSR;
}
void arch_proc_setcontext(struct proc *p, struct stackframe_s *state, int isuser)
void arch_proc_setcontext(struct proc *p, struct stackframe_s *state,
int isuser, int trapstyle)
{
}

View file

@ -182,7 +182,7 @@ void arch_proc_reset(struct proc *pr)
pr->p_reg.ds = USER_DS_SELECTOR;
/* set full context and make sure it gets restored */
arch_proc_setcontext(pr, &reg, 0);
arch_proc_setcontext(pr, &reg, 0, KTS_FULLCONTEXT);
}
void arch_set_secondary_ipc_return(struct proc *p, u32_t val)
@ -511,14 +511,21 @@ struct proc * arch_finish_switch_to_user(void)
*((reg_t *)stk) = (reg_t) p;
/* make sure IF is on in FLAGS so that interrupts won't be disabled
* once p's context is restored. this should not be possible.
* once p's context is restored.
*/
assert(p->p_reg.psw & (1L << 9));
p->p_reg.psw |= IF_MASK;
/* Set TRACEBIT state properly. */
if(p->p_misc_flags & MF_STEP)
p->p_reg.psw |= TRACEBIT;
else
p->p_reg.psw &= ~TRACEBIT;
return p;
}
void arch_proc_setcontext(struct proc *p, struct stackframe_s *state, int isuser)
void arch_proc_setcontext(struct proc *p, struct stackframe_s *state,
int isuser, int trap_style)
{
if(isuser) {
/* Restore user bits of psw from sc, maintain system bits
@ -555,7 +562,7 @@ void arch_proc_setcontext(struct proc *p, struct stackframe_s *state, int isuser
}
if(p->p_seg.p_kern_trap_style == KTS_NONE)
printf("WARNINIG: setting full context of out-of-kernel process\n");
p->p_seg.p_kern_trap_style = KTS_FULLCONTEXT;
p->p_seg.p_kern_trap_style = trap_style;
}
void restore_user_context(struct proc *p)
@ -666,4 +673,3 @@ static void ser_init(void)
outb(COM1_LCR, lcr);
}
#endif

View file

@ -228,6 +228,26 @@ void exception_handler(int is_nested, struct exception_frame * frame)
frame->eip = (reg_t) __frstor_failure;
return;
}
if(frame->vector == DEBUG_VECTOR
&& (saved_proc->p_reg.psw & TRACEBIT)
&& (saved_proc->p_seg.p_kern_trap_style == KTS_NONE)) {
/* Getting a debug trap in the kernel is legitimate
* if a traced process entered the kernel using sysenter
* or syscall; the trap flag is not cleared then.
*
* It triggers on the first kernel entry so the trap
* style is still KTS_NONE.
*/
frame->eflags &= ~TRACEBIT;
return;
/* If control passes, this case is not recognized as legitimate
* and we panic later on after all.
*/
}
}
if(frame->vector == PAGE_FAULT_VECTOR) {

View file

@ -240,6 +240,11 @@ syscall_sysenter_common:
mov %esi, SPREG(%ebp) /* esi is return esp */
mov %edx, PCREG(%ebp) /* edx is return eip */
/* save PSW */
pushf
pop %edx
mov %edx, PSWREG(%ebp)
/* check for call type; do_ipc? */
cmp $IPCVEC_UM, %edi
jz ipc_entry_common
@ -396,6 +401,7 @@ ENTRY(restore_user_context_sysenter)
mov SPREG(%ebp), %ecx /* sysexit restores ESP using ECX */
mov AXREG(%ebp), %eax /* trap return value */
mov BXREG(%ebp), %ebx /* secondary return value */
movl PSWREG(%ebp), %edi /* load desired PSW to EDI */
sti /* enable interrupts */
sysexit /* jump to EIP in user */
@ -410,6 +416,7 @@ ENTRY(restore_user_context_syscall)
mov SPREG(%ebp), %esp /* restore ESP directly */
mov AXREG(%ebp), %eax /* trap return value */
mov BXREG(%ebp), %ebx /* secondary return value */
movl PSWREG(%ebp), %edi /* load desired PSW to EDI */
sysret /* jump to EIP in user */
ENTRY(restore_user_context_int)

View file

@ -35,6 +35,8 @@ ENTRY(usermapped_ ## name ## _sysenter) ;\
SETARGS /* call-specific register setup */ ;\
sysenter /* disappear into kernel */ ;\
0: ;\
push %edi /* kernel has desired PSW in %edi */ ;\
popf /* set PSW kernel wants us to have */ ;\
mov %ebx, %ecx /* return w. state mangled; save %ebx */;\
pop %edi ;\
pop %esi ;\
@ -59,6 +61,8 @@ ENTRY(usermapped_ ## name ## _syscall) ;\
SETARGS /* call-specific register setup */ ;\
movl %ecx, %edx /* %ecx is clobbered by SYSCALL */ ;\
syscall /* disappear into kernel */ ;\
push %edi /* kernel has desired PSW in %edi */ ;\
popf /* set PSW kernel wants us to have */ ;\
mov %ebx, %ecx /* return w. state mangled; save %ebx */;\
pop %edi ;\
pop %esi ;\

View file

@ -252,6 +252,7 @@ struct proc {
message from this sender but could not
because of VM modifying the sender's address
space*/
#define MF_STEP 0x40000 /* Single-step process */
/* Magic process table addresses. */
#define BEG_PROC_ADDR (&proc[0])

View file

@ -59,7 +59,8 @@ void enqueue(struct proc *rp);
void dequeue(struct proc *rp);
void switch_to_user(void);
void arch_proc_reset(struct proc *rp);
void arch_proc_setcontext(struct proc *rp, struct stackframe_s *state, int user);
void arch_proc_setcontext(struct proc *rp, struct stackframe_s *state,
int user, int restorestyle);
struct proc * arch_finish_switch_to_user(void);
struct proc *endpoint_lookup(endpoint_t ep);
#if DEBUG_ENABLE_IPC_WARNINGS

View file

@ -71,11 +71,8 @@ int do_fork(struct proc * caller, message * m_ptr)
rpc->p_user_time = 0; /* set all the accounting times to 0 */
rpc->p_sys_time = 0;
#if defined(__i386__)
rpc->p_reg.psw &= ~TRACEBIT; /* clear trace bit */
#endif
rpc->p_misc_flags &=
~(MF_VIRT_TIMER | MF_PROF_TIMER | MF_SC_TRACE | MF_SPROF_SEEN);
~(MF_VIRT_TIMER | MF_PROF_TIMER | MF_SC_TRACE | MF_SPROF_SEEN | MF_STEP);
rpc->p_virt_left = 0; /* disable, clear the process-virtual timers */
rpc->p_prof_left = 0;

View file

@ -51,7 +51,7 @@ int do_sigreturn(struct proc * caller, message * m_ptr)
#endif
/* Restore the registers. */
arch_proc_setcontext(rp, &sc.sc_regs, 1);
arch_proc_setcontext(rp, &sc.sc_regs, 1, sc.trap_style);
#if defined(__i386__)
if(sc.sc_flags & MF_FPU_INITIALIZED)
{

View file

@ -43,13 +43,21 @@ int do_sigsend(struct proc * caller, message * m_ptr)
/* Copy the registers to the sigcontext structure. */
memcpy(&sc.sc_regs, (char *) &rp->p_reg, sizeof(sigregs));
#if defined(__i386__)
#if defined(__i386__)
sc.trap_style = rp->p_seg.p_kern_trap_style;
if(sc.trap_style == KTS_NONE) {
printf("do_sigsend: sigsend an unsaved process\n");
return EINVAL;
}
if(proc_used_fpu(rp)) {
/* save the FPU context before saving it to the sig context */
save_fpu(rp);
memcpy(&sc.sc_fpu_state, rp->p_seg.fpu_state, FPU_XFP_SIZE);
}
#endif
#endif
/* Finish the sigcontext initialization. */
sc.sc_mask = smsg.sm_mask;

View file

@ -87,10 +87,8 @@ int do_trace(struct proc * caller, message * m_ptr)
switch (tr_request) {
case T_STOP: /* stop process */
RTS_SET(rp, RTS_P_STOP);
#if defined(__i386__)
rp->p_reg.psw &= ~TRACEBIT; /* clear trace bit */
#endif
rp->p_misc_flags &= ~MF_SC_TRACE; /* clear syscall trace flag */
/* clear syscall trace and single step flags */
rp->p_misc_flags &= ~(MF_SC_TRACE | MF_STEP);
return(OK);
case T_GETINS: /* return value from instruction space */
@ -170,9 +168,7 @@ int do_trace(struct proc * caller, message * m_ptr)
break;
case T_STEP: /* set trace bit */
#if defined(__i386__)
rp->p_reg.psw |= TRACEBIT;
#endif
rp->p_misc_flags |= MF_STEP;
RTS_UNSET(rp, RTS_P_STOP);
m_ptr->CTL_DATA = 0;
break;