]> Zhao Yanbai Git Server - minix.git/commitdiff
kernel: trap-dependent state restore, trace fixes
authorBen Gras <ben@minix3.org>
Sun, 6 Jan 2013 18:18:41 +0000 (18:18 +0000)
committerBen Gras <ben@minix3.org>
Tue, 8 Jan 2013 15:47:37 +0000 (15:47 +0000)
. 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

12 files changed:
include/arch/i386/include/signal.h
kernel/arch/arm/arch_system.c
kernel/arch/i386/arch_system.c
kernel/arch/i386/exception.c
kernel/arch/i386/mpx.S
kernel/arch/i386/usermapped_glo_ipc.S
kernel/proc.h
kernel/proto.h
kernel/system/do_fork.c
kernel/system/do_sigreturn.c
kernel/system/do_sigsend.c
kernel/system/do_trace.c

index cf07f6277483a823321d52453f81a017b538c3cf..c3436460a63cd2e72d5dda363331e0b9381a63a9 100644 (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)
                                 */
index 7e19224952173fcfc9e924b8f307144c981dee2f..8852cd1235fc261827bd1fa10d6f3ba9387adacd 100644 (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)
 {
 }
 
index 15ffa5cd55524600a3f655fa7a1b43d8e4825572..14ce73e0604caee23cb25680ca155cdda022991e 100644 (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
-
index 3a4064d8dad9004755d7b5944efa350e0e71caec..08e73e419c41f3cae097b233ea39c68f2cad27df 100644 (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) {
index 75305e7aa73a25fa7de57e7b9a82ec24c51240c9..68f7a0b1d923c7b1565f2f772921cafb50d79c29 100644 (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)
index 72d9bb8a94e097f561606ab35c105ae07b9c5af8..cb3b55b344f9cf1e554518b8d4e47d84dde9522d 100644 (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                                                    ;\
index f645d3ea56853a953cb48011c692814a178b1e1b..43939693761a66b16c6a3ed35e3abd3bb279411c 100644 (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])
index c0065dd8946b2379d12410d1dd60859da0a1724d..fc0207b391863ef9847f89a75376a2ba92485d48 100644 (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
index dfad1db37a25178dc6acfffbf2a3e48d15e1592f..f30927025cefcfcb8b1531f07b8b2e8028b9fa21 100644 (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;
 
index b3603179cbe48956d611595023910a3661c32a51..606314b184f1f61fb8fd67cb3615549c84efd6e5 100644 (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)
   {
index a8107a4dfbe9874c68435b1645db8e8bac5d5f78..bbf21149de07645b62e30ea44f1c728f81884914 100644 (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;
index 83f30c5b6ff20c8127181cb193da58859e1417d5..24bfcc5883bf433d2e3cd1274ceb4a84326dac07 100644 (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;