From: Ben Gras Date: Sun, 6 Jan 2013 18:18:41 +0000 (+0000) Subject: kernel: trap-dependent state restore, trace fixes X-Git-Tag: v3.2.1~135 X-Git-Url: http://zhaoyanbai.com/repos/man.rndc.html?a=commitdiff_plain;h=604046faf3601a19517f26236bc3bad09a740bdc;p=minix.git 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 --- diff --git a/include/arch/i386/include/signal.h b/include/arch/i386/include/signal.h index cf07f6277..c3436460a 100644 --- a/include/arch/i386/include/signal.h +++ b/include/arch/i386/include/signal.h @@ -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) */ diff --git a/kernel/arch/arm/arch_system.c b/kernel/arch/arm/arch_system.c index 7e1922495..8852cd123 100644 --- a/kernel/arch/arm/arch_system.c +++ b/kernel/arch/arm/arch_system.c @@ -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) { } diff --git a/kernel/arch/i386/arch_system.c b/kernel/arch/i386/arch_system.c index 15ffa5cd5..14ce73e06 100644 --- a/kernel/arch/i386/arch_system.c +++ b/kernel/arch/i386/arch_system.c @@ -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 - diff --git a/kernel/arch/i386/exception.c b/kernel/arch/i386/exception.c index 3a4064d8d..08e73e419 100644 --- a/kernel/arch/i386/exception.c +++ b/kernel/arch/i386/exception.c @@ -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) { diff --git a/kernel/arch/i386/mpx.S b/kernel/arch/i386/mpx.S index 75305e7aa..68f7a0b1d 100644 --- a/kernel/arch/i386/mpx.S +++ b/kernel/arch/i386/mpx.S @@ -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) diff --git a/kernel/arch/i386/usermapped_glo_ipc.S b/kernel/arch/i386/usermapped_glo_ipc.S index 72d9bb8a9..cb3b55b34 100644 --- a/kernel/arch/i386/usermapped_glo_ipc.S +++ b/kernel/arch/i386/usermapped_glo_ipc.S @@ -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 ;\ diff --git a/kernel/proc.h b/kernel/proc.h index f645d3ea5..439396937 100644 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -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]) diff --git a/kernel/proto.h b/kernel/proto.h index c0065dd89..fc0207b39 100644 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -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 diff --git a/kernel/system/do_fork.c b/kernel/system/do_fork.c index dfad1db37..f30927025 100644 --- a/kernel/system/do_fork.c +++ b/kernel/system/do_fork.c @@ -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; diff --git a/kernel/system/do_sigreturn.c b/kernel/system/do_sigreturn.c index b3603179c..606314b18 100644 --- a/kernel/system/do_sigreturn.c +++ b/kernel/system/do_sigreturn.c @@ -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) { diff --git a/kernel/system/do_sigsend.c b/kernel/system/do_sigsend.c index a8107a4df..bbf21149d 100644 --- a/kernel/system/do_sigsend.c +++ b/kernel/system/do_sigsend.c @@ -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; diff --git a/kernel/system/do_trace.c b/kernel/system/do_trace.c index 83f30c5b6..24bfcc588 100644 --- a/kernel/system/do_trace.c +++ b/kernel/system/do_trace.c @@ -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;