Clean up userret/ast handling. Now called ONLY when its 100% clear that it is

returning to userland.
This commit is contained in:
reinoud 2012-01-17 19:46:55 +00:00
parent 1d7281ae96
commit e6afed1597
1 changed files with 52 additions and 54 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: trap.c,v 1.57 2012/01/14 21:45:28 reinoud Exp $ */
/* $NetBSD: trap.c,v 1.58 2012/01/17 19:46:55 reinoud Exp $ */
/*-
* Copyright (c) 2011 Reinoud Zandijk <reinoud@netbsd.org>
@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.57 2012/01/14 21:45:28 reinoud Exp $");
__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.58 2012/01/17 19:46:55 reinoud Exp $");
#include <sys/types.h>
#include <sys/param.h>
@ -50,14 +50,13 @@ __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.57 2012/01/14 21:45:28 reinoud Exp $");
/* forwards and externals */
void setup_signal_handlers(void);
void stop_all_signal_handlers(void);
void userret(struct lwp *l);
static void mem_access_handler(int sig, siginfo_t *info, void *ctx);
static void illegal_instruction_handler(int sig, siginfo_t *info, void *ctx);
extern int errno;
static void pagefault(vaddr_t pc, vaddr_t va);
static void illegal_instruction(void);
static void pagefault(vaddr_t from_userland, vaddr_t pc, vaddr_t va);
static void illegal_instruction(vaddr_t from_userland);
bool pmap_fault(pmap_t pmap, vaddr_t va, vm_prot_t *atype);
@ -120,6 +119,33 @@ stop_all_signal_handlers(void)
}
/* ast and userret */
void
userret(struct lwp *l)
{
/* invoke MI userret code */
mi_userret(l);
while (astpending) {
astpending = 0;
curcpu()->ci_data.cpu_ntrap++;
#if 0
/* profiling */
if (l->l_pflag & LP_OWEUPC) {
l->l_pflag &= ~LP_OWEUPC;
ADDUPROF(l);
}
#endif
/* allow a forced task switch */
if (l->l_cpu->ci_want_resched)
preempt();
mi_userret(l);
}
}
/* signal handler switching to a pagefault context */
static void
mem_access_handler(int sig, siginfo_t *info, void *ctx)
@ -128,6 +154,7 @@ mem_access_handler(int sig, siginfo_t *info, void *ctx)
struct lwp *l;
struct pcb *pcb;
vaddr_t va, sp, pc, fp;
int from_userland;
assert((info->si_signo == SIGSEGV) || (info->si_signo == SIGBUS));
@ -176,9 +203,12 @@ mem_access_handler(int sig, siginfo_t *info, void *ctx)
#endif
/* if we're running on a stack of our own, use the system stack */
from_userland = 0;
if ((sp < (vaddr_t) pcb->sys_stack) || (sp > (vaddr_t) pcb->sys_stack_top)) {
sp = (vaddr_t) pcb->sys_stack_top - sizeof(register_t);
fp = (vaddr_t) &pcb->pcb_userret_ucp;
if (pc < kmem_user_end)
from_userland = 1;
} else {
/* stack grows down */
fp = sp - sizeof(ucontext_t) - sizeof(register_t); /* slack */
@ -198,56 +228,13 @@ mem_access_handler(int sig, siginfo_t *info, void *ctx)
pcb->pcb_ucp.uc_flags = _UC_STACK | _UC_CPU;
thunk_makecontext(&pcb->pcb_ucp, (void (*)(void)) pagefault,
2, (void *) pc, (void *) va, NULL);
3, (void *) from_userland, (void *) pc, (void *) va);
/* switch to the new pagefault entry on return from signal */
memcpy(ctx, &pcb->pcb_ucp, sizeof(ucontext_t));
}
/* ast and userret */
void
userret(struct lwp *l)
{
struct pcb *pcb;
ucontext_t ucp, *nucp;
vaddr_t pc;
KASSERT(l);
/* are we going back to userland? */
pcb = lwp_getpcb(l);
KASSERT(pcb);
/* where are we going back to ? */
thunk_getcontext(&ucp);
nucp = (ucontext_t *) ucp.uc_link;
pc = md_get_pc(nucp);
if (pc >= kmem_k_start)
return;
/* ok, going to userland, proceed! */
if (astpending) {
astpending = 0;
curcpu()->ci_data.cpu_ntrap++;
#if 0
/* profiling */
if (l->l_pflag & LP_OWEUPC) {
l->l_pflag &= ~LP_OWEUPC;
ADDUPROF(l);
}
#endif
/* allow a forced task switch */
if (l->l_cpu->ci_want_resched)
preempt();
}
/* invoke MI userret code */
mi_userret(l);
}
/* signal handler switching to a illegal instruction context */
static void
illegal_instruction_handler(int sig, siginfo_t *info, void *ctx)
@ -255,7 +242,8 @@ illegal_instruction_handler(int sig, siginfo_t *info, void *ctx)
ucontext_t *ucp = ctx;
struct lwp *l;
struct pcb *pcb;
vaddr_t sp, fp;
vaddr_t sp, pc, fp;
int from_userland;
assert(info->si_signo == SIGILL);
#if 0
@ -291,14 +279,21 @@ illegal_instruction_handler(int sig, siginfo_t *info, void *ctx)
l = curlwp;
pcb = lwp_getpcb(l);
/* get PC address of faulted instruction */
pc = md_get_pc(ctx);
/* setup for illegal_instruction context */
sp = md_get_sp(ctx);
/* if we're running on a stack of our own, use the system stack */
from_userland = 0;
if ((sp < (vaddr_t) pcb->sys_stack) ||
(sp > (vaddr_t) pcb->sys_stack_top)) {
sp = (vaddr_t) pcb->sys_stack_top - sizeof(register_t);
fp = (vaddr_t) &pcb->pcb_userret_ucp;
KASSERT(pc < kmem_user_end);
from_userland = 1;
} else {
panic("illegal instruction inside kernel?");
#if 0
@ -321,7 +316,7 @@ illegal_instruction_handler(int sig, siginfo_t *info, void *ctx)
pcb->pcb_ucp.uc_flags = _UC_STACK | _UC_CPU;
thunk_makecontext(&pcb->pcb_ucp, (void (*)(void)) illegal_instruction,
0, NULL, NULL, NULL);
1, (void *) from_userland, NULL, NULL);
/* switch to the new illegal instruction entry on return from signal */
memcpy(ctx, &pcb->pcb_ucp, sizeof(ucontext_t));
@ -333,7 +328,7 @@ illegal_instruction_handler(int sig, siginfo_t *info, void *ctx)
* pmap reference fault or let uvm handle it.
*/
static void
pagefault(vaddr_t pc, vaddr_t va)
pagefault(vaddr_t from_userland, vaddr_t pc, vaddr_t va)
{
struct proc *p;
struct lwp *l;
@ -435,6 +430,7 @@ pagefault(vaddr_t pc, vaddr_t va)
// thunk_printf("pagefault leave\n");
out:
if (from_userland)
userret(l);
out_quick:
thunk_seterrno(lwp_errno);
@ -445,7 +441,7 @@ out_quick:
* Context for handing illegal instruction from the sigill handler
*/
static void
illegal_instruction(void)
illegal_instruction(vaddr_t from_userland)
{
struct lwp *l = curlwp;
struct pcb *pcb = lwp_getpcb(l);
@ -457,6 +453,7 @@ illegal_instruction(void)
if (md_syscall_check_opcode(ucp)) {
syscall();
// thunk_printf("illegal instruction leave\n");
KASSERT(from_userland);
userret(l);
return;
}
@ -475,6 +472,7 @@ illegal_instruction(void)
#else
trapsignal(l, &ksi);
#endif
KASSERT(from_userland);
userret(l);
}