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:
parent
b258ab0e66
commit
604046faf3
12 changed files with 64 additions and 22 deletions
|
@ -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)
|
||||
*/
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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, ®, 0);
|
||||
arch_proc_setcontext(pr, ®, 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
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 ;\
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue