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

@@ -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 ;\