instead of setting pcb_onfault on every calls of copyin and friends,
make the fault handler investigate program counter of faulting code. inspired from linux.
This commit is contained in:
parent
5155a3ee9b
commit
d0f12a6ad9
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: copy.S,v 1.11 2007/11/21 00:15:08 dsl Exp $ */
|
||||
/* $NetBSD: copy.S,v 1.12 2007/11/29 09:53:33 yamt Exp $ */
|
||||
/* NetBSD: locore.S,v 1.34 2005/04/01 11:59:31 yamt Exp $ */
|
||||
|
||||
/*-
|
||||
@ -124,30 +124,25 @@ ENTRY(fillw)
|
||||
ENTRY(kcopy)
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
GET_CURPCB(%eax) # load curpcb into eax and set on-fault
|
||||
pushl PCB_ONFAULT(%eax)
|
||||
movl $_C_LABEL(kcopy_fault), PCB_ONFAULT(%eax)
|
||||
|
||||
movl 16(%esp),%esi
|
||||
movl 20(%esp),%edi
|
||||
movl 24(%esp),%ecx
|
||||
.Lkcopy_start:
|
||||
movl 12(%esp),%esi
|
||||
movl 16(%esp),%edi
|
||||
movl 20(%esp),%ecx
|
||||
movl %edi,%eax
|
||||
subl %esi,%eax
|
||||
cmpl %ecx,%eax # overlapping?
|
||||
movl %ecx,%edx
|
||||
jb 1f
|
||||
# nope, copy forward
|
||||
shrl $2,%ecx # copy by 32-bit words
|
||||
rep
|
||||
movsl
|
||||
movl 24(%esp),%ecx
|
||||
movl %edx,%ecx
|
||||
andl $3,%ecx # any bytes left?
|
||||
jz 0f
|
||||
rep
|
||||
movsb
|
||||
0:
|
||||
|
||||
GET_CURPCB(%edx) # XXX save curpcb?
|
||||
popl PCB_ONFAULT(%edx)
|
||||
popl %edi
|
||||
popl %esi
|
||||
xorl %eax,%eax
|
||||
@ -162,7 +157,7 @@ ENTRY(kcopy)
|
||||
decl %esi
|
||||
rep
|
||||
movsb
|
||||
movl 24(%esp),%ecx # copy remainder by 32-bit words
|
||||
movl %edx,%ecx # copy remainder by 32-bit words
|
||||
shrl $2,%ecx
|
||||
subl $3,%esi
|
||||
subl $3,%edi
|
||||
@ -170,8 +165,7 @@ ENTRY(kcopy)
|
||||
movsl
|
||||
cld
|
||||
|
||||
GET_CURPCB(%edx)
|
||||
popl PCB_ONFAULT(%edx)
|
||||
.Lkcopy_end:
|
||||
popl %edi
|
||||
popl %esi
|
||||
xorl %eax,%eax
|
||||
@ -192,17 +186,14 @@ ENTRY(kcopy)
|
||||
|
||||
/* LINTSTUB: Func: int copyout(const void *kaddr, void *uaddr, size_t len) */
|
||||
ENTRY(copyout)
|
||||
DO_DEFERRED_SWITCH
|
||||
|
||||
GET_CURPCB(%edx)
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
pushl $0 /* PCB_ONFAULT(%edx) */
|
||||
.Lcopyout_start:
|
||||
DO_DEFERRED_SWITCH_RETRY
|
||||
|
||||
movl 16(%esp),%esi
|
||||
movl 20(%esp),%edi
|
||||
movl 24(%esp),%eax
|
||||
movl $_C_LABEL(copy_fault),PCB_ONFAULT(%edx)
|
||||
movl 12(%esp),%esi
|
||||
movl 16(%esp),%edi
|
||||
movl 20(%esp),%eax
|
||||
|
||||
/*
|
||||
* We check that the end of the destination buffer is not past the end
|
||||
@ -223,8 +214,7 @@ ENTRY(copyout)
|
||||
rep
|
||||
movsb
|
||||
1:
|
||||
GET_CURPCB(%edx)
|
||||
popl PCB_ONFAULT(%edx)
|
||||
.Lcopyout_end:
|
||||
popl %edi
|
||||
popl %esi
|
||||
xorl %eax,%eax
|
||||
@ -238,17 +228,14 @@ ENTRY(copyout)
|
||||
|
||||
/* LINTSTUB: Func: int copyin(const void *uaddr, void *kaddr, size_t len) */
|
||||
ENTRY(copyin)
|
||||
DO_DEFERRED_SWITCH
|
||||
|
||||
GET_CURPCB(%edx)
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
pushl $0 /* PCB_ONFAULT(%edx) */
|
||||
.Lcopyin_start:
|
||||
DO_DEFERRED_SWITCH_RETRY
|
||||
|
||||
movl 16(%esp),%esi
|
||||
movl 20(%esp),%edi
|
||||
movl 24(%esp),%eax
|
||||
movl $_C_LABEL(copy_fault),PCB_ONFAULT(%edx)
|
||||
movl 12(%esp),%esi
|
||||
movl 16(%esp),%edi
|
||||
movl 20(%esp),%eax
|
||||
|
||||
/*
|
||||
* We check that the end of the destination buffer is not past the end
|
||||
@ -270,8 +257,7 @@ ENTRY(copyin)
|
||||
rep
|
||||
movsb
|
||||
1:
|
||||
GET_CURPCB(%edx)
|
||||
popl PCB_ONFAULT(%edx)
|
||||
.Lcopyin_end:
|
||||
popl %edi
|
||||
popl %esi
|
||||
xorl %eax,%eax
|
||||
@ -288,16 +274,12 @@ NENTRY(copy_efault)
|
||||
*/
|
||||
/* LINTSTUB: Ignore */
|
||||
NENTRY(kcopy_fault)
|
||||
GET_CURPCB(%edx)
|
||||
popl PCB_ONFAULT(%edx)
|
||||
popl %edi
|
||||
popl %esi
|
||||
ret
|
||||
|
||||
/* LINTSTUB: Ignore */
|
||||
NENTRY(copy_fault)
|
||||
GET_CURPCB(%edx)
|
||||
popl PCB_ONFAULT(%edx)
|
||||
popl %edi
|
||||
popl %esi
|
||||
ret
|
||||
@ -315,14 +297,14 @@ ENTRY(copyoutstr)
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
|
||||
DO_DEFERRED_SWITCH
|
||||
.Lcopyoutstr_start:
|
||||
DO_DEFERRED_SWITCH_RETRY
|
||||
|
||||
movl 12(%esp),%esi # esi = from
|
||||
movl 16(%esp),%edi # edi = to
|
||||
movl 20(%esp),%edx # edx = maxlen
|
||||
|
||||
5: GET_CURPCB(%eax)
|
||||
movl $_C_LABEL(copystr_fault),PCB_ONFAULT(%eax)
|
||||
5:
|
||||
/*
|
||||
* Get min(%edx, VM_MAXUSER_ADDRESS-%edi).
|
||||
*/
|
||||
@ -341,6 +323,7 @@ ENTRY(copyoutstr)
|
||||
lodsb
|
||||
stosb
|
||||
testb %al,%al
|
||||
.Lcopyoutstr_end:
|
||||
jnz 1b
|
||||
|
||||
/* Success -- 0 byte reached. */
|
||||
@ -367,10 +350,8 @@ ENTRY(copyinstr)
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
|
||||
DO_DEFERRED_SWITCH
|
||||
|
||||
GET_CURPCB(%ecx)
|
||||
movl $_C_LABEL(copystr_fault),PCB_ONFAULT(%ecx)
|
||||
.Lcopyinstr_start:
|
||||
DO_DEFERRED_SWITCH_RETRY
|
||||
|
||||
movl 12(%esp),%esi # %esi = from
|
||||
movl 16(%esp),%edi # %edi = to
|
||||
@ -394,6 +375,7 @@ ENTRY(copyinstr)
|
||||
lodsb
|
||||
stosb
|
||||
testb %al,%al
|
||||
.Lcopyinstr_end:
|
||||
jnz 1b
|
||||
|
||||
/* Success -- 0 byte reached. */
|
||||
@ -415,8 +397,6 @@ NENTRY(copystr_efault)
|
||||
NENTRY(copystr_fault)
|
||||
copystr_return:
|
||||
/* Set *lencopied and return %eax. */
|
||||
GET_CURPCB(%ecx)
|
||||
movl $0,PCB_ONFAULT(%ecx)
|
||||
movl 20(%esp),%ecx
|
||||
subl %edx,%ecx
|
||||
movl 24(%esp),%edx
|
||||
@ -655,14 +635,13 @@ ENTRY(subyte)
|
||||
*/
|
||||
ENTRY(x86_copyargs)
|
||||
pushl %esi
|
||||
GET_CURPCB(%eax)
|
||||
pushl $0
|
||||
movl $_C_LABEL(x86_copyargs_fault),PCB_ONFAULT(%eax)
|
||||
|
||||
movl 12(%esp),%esi
|
||||
movl 16(%esp),%edx
|
||||
movl 20(%esp),%ecx
|
||||
movl 8(%esp),%esi
|
||||
movl 12(%esp),%edx
|
||||
movl 16(%esp),%ecx
|
||||
|
||||
.Lx86_copyargs_start:
|
||||
DO_DEFERRED_SWITCH_RETRY
|
||||
/*
|
||||
* We check that the end of the destination buffer is not past the end
|
||||
* of the user's address space. If it's not, then we only need to
|
||||
@ -685,8 +664,6 @@ ENTRY(x86_copyargs)
|
||||
movl %ecx,12(%edx)
|
||||
ja 2f /* Optimise since most sycalls have <= 4 args */
|
||||
1:
|
||||
GET_CURPCB(%edx)
|
||||
popl PCB_ONFAULT(%edx)
|
||||
popl %esi
|
||||
xorl %eax,%eax
|
||||
ret
|
||||
@ -703,6 +680,7 @@ ENTRY(x86_copyargs)
|
||||
movl 36(%esi),%ecx
|
||||
movl %eax,32(%edx)
|
||||
movl %ecx,36(%edx)
|
||||
.Lx86_copyargs_end:
|
||||
jmp 1b
|
||||
|
||||
/* LINTSTUB: Ignore */
|
||||
@ -711,7 +689,36 @@ NENTRY(x86_copyargs_efault)
|
||||
|
||||
/* LINTSTUB: Ignore */
|
||||
NENTRY(x86_copyargs_fault)
|
||||
GET_CURPCB(%edx)
|
||||
popl PCB_ONFAULT(%edx)
|
||||
popl %esi
|
||||
ret
|
||||
|
||||
.section ".rodata"
|
||||
.globl _C_LABEL(onfault_table)
|
||||
_C_LABEL(onfault_table):
|
||||
.long .Lcopyin_start
|
||||
.long .Lcopyin_end
|
||||
.long _C_LABEL(copy_fault)
|
||||
|
||||
.long .Lcopyout_start
|
||||
.long .Lcopyout_end
|
||||
.long _C_LABEL(copy_fault)
|
||||
|
||||
.long .Lkcopy_start
|
||||
.long .Lkcopy_end
|
||||
.long _C_LABEL(kcopy_fault)
|
||||
|
||||
.long .Lcopyoutstr_start
|
||||
.long .Lcopyoutstr_end
|
||||
.long _C_LABEL(copystr_fault)
|
||||
|
||||
.long .Lcopyinstr_start
|
||||
.long .Lcopyinstr_end
|
||||
.long _C_LABEL(copystr_fault)
|
||||
|
||||
.long .Lx86_copyargs_start
|
||||
.long .Lx86_copyargs_end
|
||||
.long _C_LABEL(x86_copyargs_fault)
|
||||
|
||||
.long 0 /* terminate */
|
||||
|
||||
.text
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: trap.c,v 1.225 2007/11/28 14:02:30 yamt Exp $ */
|
||||
/* $NetBSD: trap.c,v 1.226 2007/11/29 09:53:33 yamt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1998, 2000, 2005 The NetBSD Foundation, Inc.
|
||||
@ -75,7 +75,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.225 2007/11/28 14:02:30 yamt Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.226 2007/11/29 09:53:33 yamt Exp $");
|
||||
|
||||
#include "opt_ddb.h"
|
||||
#include "opt_kgdb.h"
|
||||
@ -230,6 +230,30 @@ xmm_si_code(struct lwp *l)
|
||||
}
|
||||
}
|
||||
|
||||
static void *
|
||||
onfault_handler(const struct pcb *pcb, const struct trapframe *tf)
|
||||
{
|
||||
struct onfault_table {
|
||||
uintptr_t start;
|
||||
uintptr_t end;
|
||||
void *handler;
|
||||
};
|
||||
extern const struct onfault_table onfault_table[];
|
||||
const struct onfault_table *p;
|
||||
uintptr_t pc;
|
||||
|
||||
if (pcb->pcb_onfault != NULL) {
|
||||
return pcb->pcb_onfault;
|
||||
}
|
||||
|
||||
pc = tf->tf_eip;
|
||||
for (p = onfault_table; p->start; p++) {
|
||||
if (p->start <= pc && pc < p->end) {
|
||||
return p->handler;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* trap(frame):
|
||||
@ -351,11 +375,12 @@ trap(frame)
|
||||
if (p == NULL)
|
||||
goto we_re_toast;
|
||||
/* Check for copyin/copyout fault. */
|
||||
if (pcb->pcb_onfault != 0) {
|
||||
onfault = onfault_handler(pcb, frame);
|
||||
if (onfault != NULL) {
|
||||
copyefault:
|
||||
error = EFAULT;
|
||||
copyfault:
|
||||
frame->tf_eip = (int)pcb->pcb_onfault;
|
||||
frame->tf_eip = (uintptr_t)onfault;
|
||||
frame->tf_eax = error;
|
||||
return;
|
||||
}
|
||||
@ -570,8 +595,9 @@ copyfault:
|
||||
* fusubail is used by [fs]uswintr() to prevent page faulting
|
||||
* from inside the profiling interrupt.
|
||||
*/
|
||||
if (pcb->pcb_onfault == fusubail)
|
||||
if ((onfault = pcb->pcb_onfault) == fusubail) {
|
||||
goto copyefault;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* XXX - check only applies to 386's and 486's with WP off */
|
||||
@ -652,9 +678,13 @@ copyfault:
|
||||
* it never touch userspace.
|
||||
*/
|
||||
|
||||
if (onfault != kcopy_fault &&
|
||||
curcpu()->ci_want_pmapload)
|
||||
pmap_load();
|
||||
if (curcpu()->ci_want_pmapload) {
|
||||
onfault = onfault_handler(pcb, frame);
|
||||
if (onfault != NULL &&
|
||||
onfault != kcopy_fault) {
|
||||
pmap_load();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
KERNEL_UNLOCK_LAST(l);
|
||||
@ -671,7 +701,8 @@ copyfault:
|
||||
}
|
||||
|
||||
if (type == T_PAGEFLT) {
|
||||
if (pcb->pcb_onfault != 0) {
|
||||
onfault = onfault_handler(pcb, frame);
|
||||
if (onfault != NULL) {
|
||||
KERNEL_UNLOCK_ONE(NULL);
|
||||
goto copyfault;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: frameasm.h,v 1.9 2007/11/14 11:09:49 ad Exp $ */
|
||||
/* $NetBSD: frameasm.h,v 1.10 2007/11/29 09:53:33 yamt Exp $ */
|
||||
|
||||
#ifndef _I386_FRAMEASM_H_
|
||||
#define _I386_FRAMEASM_H_
|
||||
@ -90,6 +90,14 @@
|
||||
call _C_LABEL(pmap_load) ; \
|
||||
1:
|
||||
|
||||
#define DO_DEFERRED_SWITCH_RETRY \
|
||||
1: ; \
|
||||
cmpl $0, CPUVAR(WANT_PMAPLOAD) ; \
|
||||
jz 1f ; \
|
||||
call _C_LABEL(pmap_load) ; \
|
||||
jmp 1b ; \
|
||||
1:
|
||||
|
||||
#define CHECK_DEFERRED_SWITCH \
|
||||
cmpl $0, CPUVAR(WANT_PMAPLOAD)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user