From a722be4938df1e51a53f4d0187de2f179b7e46b5 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Fri, 21 Nov 2003 05:29:08 +0000 Subject: [PATCH] Implement an upcall mechanism to support userland LWKT. This mechanism will allow multiple processes sharing the same VM space (aka clone/threading) to send each other what are basically IPIs. Two new system calls have been added, upc_register() and upc_control(). Documentation is forthcoming. The upcalls are nicely abstracted and a program can register as many as it wants up to the kernel limit (which is 32 at the moment). The upcalls will be used for passing asynch data from kernel to userland, such as asynch syscall message replies, for thread preemption timing, software interrupts, IPIs between virtual cpus (e.g. between the processes that are sharing the single VM space). --- sys/conf/files | 3 +- sys/cpu/i386/include/cpu.h | 4 +- sys/i386/i386/genassym.c | 3 +- sys/i386/i386/machdep.c | 128 ++++++++++++- sys/i386/i386/trap.c | 11 +- sys/i386/include/cpu.h | 4 +- sys/i386/isa/ipl.s | 4 +- sys/kern/init_sysent.c | 4 +- sys/kern/kern_exit.c | 10 +- sys/kern/kern_upcall.c | 276 +++++++++++++++++++++++++++ sys/kern/syscalls.c | 4 +- sys/kern/syscalls.master | 6 +- sys/platform/pc32/i386/genassym.c | 3 +- sys/platform/pc32/i386/machdep.c | 128 ++++++++++++- sys/platform/pc32/i386/trap.c | 11 +- sys/platform/pc32/isa/ipl.s | 4 +- sys/platform/vkernel/i386/genassym.c | 3 +- sys/sys/globaldata.h | 7 +- sys/sys/proc.h | 6 +- sys/sys/signalvar.h | 5 +- sys/sys/syscall-hide.h | 4 +- sys/sys/syscall.h | 6 +- sys/sys/syscall.mk | 6 +- sys/sys/sysproto.h | 23 ++- sys/sys/sysunion.h | 4 +- sys/sys/upcall.h | 65 +++++++ sys/vm/vm_map.c | 4 +- sys/vm/vm_map.h | 19 +- 28 files changed, 723 insertions(+), 32 deletions(-) create mode 100644 sys/kern/kern_upcall.c create mode 100644 sys/sys/upcall.h diff --git a/sys/conf/files b/sys/conf/files index a9460156b6..d78be7a34d 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,5 +1,5 @@ # $FreeBSD: src/sys/conf/files,v 1.340.2.137 2003/06/04 17:10:30 sam Exp $ -# $DragonFly: src/sys/conf/files,v 1.29 2003/11/16 10:32:46 asmodai Exp $ +# $DragonFly: src/sys/conf/files,v 1.30 2003/11/21 05:29:05 dillon Exp $ # # The long compile-with and dependency lines are required because of # limitations in config: backslash-newline doesn't work in strings, and @@ -629,6 +629,7 @@ kern/kern_resource.c standard kern/kern_slaballoc.c standard kern/kern_shutdown.c standard kern/kern_sig.c standard +kern/kern_upcall.c standard kern/kern_subr.c standard kern/kern_switch.c standard kern/lwkt_thread.c standard diff --git a/sys/cpu/i386/include/cpu.h b/sys/cpu/i386/include/cpu.h index 2d5c2f59ab..b299ed8b83 100644 --- a/sys/cpu/i386/include/cpu.h +++ b/sys/cpu/i386/include/cpu.h @@ -35,7 +35,7 @@ * * from: @(#)cpu.h 5.4 (Berkeley) 5/9/91 * $FreeBSD: src/sys/i386/include/cpu.h,v 1.43.2.2 2001/06/15 09:37:57 scottl Exp $ - * $DragonFly: src/sys/cpu/i386/include/cpu.h,v 1.11 2003/08/26 21:42:18 rob Exp $ + * $DragonFly: src/sys/cpu/i386/include/cpu.h,v 1.12 2003/11/21 05:29:08 dillon Exp $ */ #ifndef _MACHINE_CPU_H_ @@ -78,6 +78,8 @@ atomic_set_int_nonlocked(&mycpu->gd_reqflags, RQF_AST_OWEUPC) #define signotify() \ atomic_set_int_nonlocked(&mycpu->gd_reqflags, RQF_AST_SIGNAL) +#define sigupcall() \ + atomic_set_int_nonlocked(&mycpu->gd_reqflags, RQF_AST_UPCALL) #define clear_resched() \ atomic_clear_int_nonlocked(&mycpu->gd_reqflags, RQF_AST_RESCHED) #define resched_wanted() \ diff --git a/sys/i386/i386/genassym.c b/sys/i386/i386/genassym.c index d893087084..fb51fe9e09 100644 --- a/sys/i386/i386/genassym.c +++ b/sys/i386/i386/genassym.c @@ -35,7 +35,7 @@ * * from: @(#)genassym.c 5.11 (Berkeley) 5/10/91 * $FreeBSD: src/sys/i386/i386/genassym.c,v 1.86.2.3 2002/03/03 05:42:49 nyan Exp $ - * $DragonFly: src/sys/i386/i386/Attic/genassym.c,v 1.31 2003/10/24 14:10:45 daver Exp $ + * $DragonFly: src/sys/i386/i386/Attic/genassym.c,v 1.32 2003/11/21 05:29:07 dillon Exp $ */ #include "opt_user_ldt.h" @@ -198,6 +198,7 @@ ASSYM(RQF_INTPEND, RQF_INTPEND); ASSYM(RQF_AST_OWEUPC, RQF_AST_OWEUPC); ASSYM(RQF_AST_SIGNAL, RQF_AST_SIGNAL); ASSYM(RQF_AST_RESCHED, RQF_AST_RESCHED); +ASSYM(RQF_AST_UPCALL, RQF_AST_UPCALL); ASSYM(RQF_AST_MASK, RQF_AST_MASK); ASSYM(GD_FPENDING, offsetof(struct mdglobaldata, gd_fpending)); diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c index ac12a6cfd3..7c607fca18 100644 --- a/sys/i386/i386/machdep.c +++ b/sys/i386/i386/machdep.c @@ -36,7 +36,7 @@ * * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91 * $FreeBSD: src/sys/i386/i386/machdep.c,v 1.385.2.30 2003/05/31 08:48:05 alc Exp $ - * $DragonFly: src/sys/i386/i386/Attic/machdep.c,v 1.44 2003/11/15 21:05:43 dillon Exp $ + * $DragonFly: src/sys/i386/i386/Attic/machdep.c,v 1.45 2003/11/21 05:29:07 dillon Exp $ */ #include "use_apm.h" @@ -74,6 +74,7 @@ #include #include #include +#include #include #include @@ -685,6 +686,131 @@ sigreturn(struct sigreturn_args *uap) return(EJUSTRETURN); } +/* + * Stack frame on entry to function. %eax will contain the function vector, + * %ecx will contain the function data. flags, ecx, and eax will have + * already been pushed on the stack. + */ +struct upc_frame { + register_t eax; + register_t ecx; + register_t flags; + register_t oldip; +}; + +void +sendupcall(struct vmupcall *vu, int morepending) +{ + struct proc *p = curproc; + struct trapframe *regs; + struct upcall upcall; + struct upc_frame upc_frame; + + /* + * Get the upcall data structure + */ + if (copyin(p->p_upcall, &upcall, sizeof(upcall))) { + vu->vu_pending = 0; + printf("bad upcall address\n"); + return; + } + + /* + * If the data structure is already marked pending or has a critical + * section count, mark the data structure as pending and return + * without doing an upcall. vu_pending is left set. + */ + if (upcall.pending || upcall.crit_count) { + if (upcall.pending == 0) { + upcall.pending = 1; + copyout(&upcall.pending, &p->p_upcall->pending, + sizeof(upcall.pending)); + } + return; + } + + /* + * We can run this upcall now, clear vu_pending. + * + * Bump our critical section count and set or clear the + * user pending flag depending on whether more upcalls are + * pending. The user will be responsible for calling + * upc_dispatch(-1) to process remaining upcalls. + */ + vu->vu_pending = 0; + upcall.pending = morepending; + upcall.crit_count += TDPRI_CRIT; + copyout(&upcall, p->p_upcall, sizeof(upcall)); + + /* + * Construct a stack frame and issue the upcall + */ + regs = p->p_md.md_regs; + upc_frame.eax = regs->tf_eax; + upc_frame.ecx = regs->tf_ecx; + upc_frame.flags = regs->tf_eflags; + upc_frame.oldip = regs->tf_eip; + if (copyout(&upc_frame, (void *)(regs->tf_esp - sizeof(upc_frame)), + sizeof(upc_frame)) != 0) { + printf("bad stack on upcall\n"); + } else { + regs->tf_eax = (register_t)vu->vu_func; + regs->tf_ecx = (register_t)vu->vu_data; + regs->tf_eip = (register_t)vu->vu_ctx; + regs->tf_esp -= sizeof(upc_frame); + } +} + +/* + * fetchupcall occurs in the context of a system call, which means that + * regs->tf_eax and regs->tf_edx are overritten by res[0] and res[1]. + * + * if vu is not NULL we return the new context in %edx, the new data in %ecx, + * and the function pointer in %eax. + */ +int +fetchupcall (struct vmupcall *vu, int morepending, int *res, void *rsp) +{ + struct upc_frame upc_frame; + struct proc *p; + struct trapframe *regs; + int error; + + p = curproc; + regs = p->p_md.md_regs; + + error = copyout(&morepending, &p->p_upcall->pending, sizeof(int)); + if (error == 0) { + if (vu) { + /* + * This jumps us to the next ready context. + */ + vu->vu_pending = 0; + error = copyin(&p->p_upcall->crit_count, &morepending, sizeof(int)); + morepending += TDPRI_CRIT; + if (error == 0) + error = copyout(&morepending, &p->p_upcall->crit_count, sizeof(int)); + regs->tf_eax = (register_t)vu->vu_func; + regs->tf_ecx = (register_t)vu->vu_data; + regs->tf_eip = (register_t)vu->vu_ctx; + regs->tf_esp = (register_t)rsp; + } else { + /* + * This returns us to the originally interrupted code. + */ + error = copyin(rsp, &upc_frame, sizeof(upc_frame)); + regs->tf_eax = upc_frame.eax; + regs->tf_ecx = upc_frame.ecx; + regs->tf_eflags = upc_frame.flags; + regs->tf_eip = upc_frame.oldip; + regs->tf_esp = (register_t)((char *)rsp + sizeof(upc_frame)); + } + } + if (error == 0) + error = EJUSTRETURN; + return(error); +} + /* * Machine dependent boot() routine * diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c index 363d14ea6a..21f1e259f6 100644 --- a/sys/i386/i386/trap.c +++ b/sys/i386/i386/trap.c @@ -36,7 +36,7 @@ * * from: @(#)trap.c 7.4 (Berkeley) 5/13/91 * $FreeBSD: src/sys/i386/i386/trap.c,v 1.147.2.11 2003/02/27 19:09:59 luoqi Exp $ - * $DragonFly: src/sys/i386/i386/Attic/trap.c,v 1.42 2003/11/20 06:05:30 dillon Exp $ + * $DragonFly: src/sys/i386/i386/Attic/trap.c,v 1.43 2003/11/21 05:29:07 dillon Exp $ */ /* @@ -68,6 +68,7 @@ #ifdef KTRACE #include #endif +#include #include #include @@ -271,6 +272,14 @@ userret(struct proc *p, struct trapframe *frame, u_quad_t oticks) { int sig; + /* + * Post any pending upcalls + */ + if (p->p_flag & P_UPCALLPEND) { + p->p_flag &= ~P_UPCALLPEND; + postupcall(p); + } + /* * Post any pending signals */ diff --git a/sys/i386/include/cpu.h b/sys/i386/include/cpu.h index 1628b84548..8e183c8b8a 100644 --- a/sys/i386/include/cpu.h +++ b/sys/i386/include/cpu.h @@ -35,7 +35,7 @@ * * from: @(#)cpu.h 5.4 (Berkeley) 5/9/91 * $FreeBSD: src/sys/i386/include/cpu.h,v 1.43.2.2 2001/06/15 09:37:57 scottl Exp $ - * $DragonFly: src/sys/i386/include/Attic/cpu.h,v 1.11 2003/08/26 21:42:18 rob Exp $ + * $DragonFly: src/sys/i386/include/Attic/cpu.h,v 1.12 2003/11/21 05:29:08 dillon Exp $ */ #ifndef _MACHINE_CPU_H_ @@ -78,6 +78,8 @@ atomic_set_int_nonlocked(&mycpu->gd_reqflags, RQF_AST_OWEUPC) #define signotify() \ atomic_set_int_nonlocked(&mycpu->gd_reqflags, RQF_AST_SIGNAL) +#define sigupcall() \ + atomic_set_int_nonlocked(&mycpu->gd_reqflags, RQF_AST_UPCALL) #define clear_resched() \ atomic_clear_int_nonlocked(&mycpu->gd_reqflags, RQF_AST_RESCHED) #define resched_wanted() \ diff --git a/sys/i386/isa/ipl.s b/sys/i386/isa/ipl.s index f9bf86b4a1..d4a252bd91 100644 --- a/sys/i386/isa/ipl.s +++ b/sys/i386/isa/ipl.s @@ -37,7 +37,7 @@ * @(#)ipl.s * * $FreeBSD: src/sys/i386/isa/ipl.s,v 1.32.2.3 2002/05/16 16:03:56 bde Exp $ - * $DragonFly: src/sys/i386/isa/Attic/ipl.s,v 1.14 2003/10/02 22:26:59 dillon Exp $ + * $DragonFly: src/sys/i386/isa/Attic/ipl.s,v 1.15 2003/11/21 05:29:08 dillon Exp $ */ @@ -256,7 +256,7 @@ doreti_intr: * to do is a reschedule. */ doreti_ast: - andl $~RQF_AST_SIGNAL,PCPU(reqflags) + andl $~(RQF_AST_SIGNAL|RQF_AST_UPCALL),PCPU(reqflags) sti movl %eax,%esi /* save cpl (can't use stack) */ movl $T_ASTFLT,TF_TRAPNO(%esp) diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c index b8f4310053..c20171963a 100644 --- a/sys/kern/init_sysent.c +++ b/sys/kern/init_sysent.c @@ -2,7 +2,7 @@ * System call switch table. * * DO NOT EDIT-- this file is automatically generated. - * $DragonFly: src/sys/kern/init_sysent.c,v 1.12 2003/11/20 06:05:30 dillon Exp $ + * $DragonFly: src/sys/kern/init_sysent.c,v 1.13 2003/11/21 05:29:04 dillon Exp $ * created from DragonFly: src/sys/kern/syscalls.master,v 1.8 2003/11/10 23:58:57 dillon Exp */ @@ -475,4 +475,6 @@ struct sysent sysent[] = { { AS(varsym_set_args), (sy_call_t *)varsym_set }, /* 450 = varsym_set */ { AS(varsym_get_args), (sy_call_t *)varsym_get }, /* 451 = varsym_get */ { AS(varsym_list_args), (sy_call_t *)varsym_list }, /* 452 = varsym_list */ + { AS(upc_register_args), (sy_call_t *)upc_register }, /* 453 = upc_register */ + { AS(upc_control_args), (sy_call_t *)upc_control }, /* 454 = upc_control */ }; diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 03af96fc65..7fe4fea117 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -37,7 +37,7 @@ * * @(#)kern_exit.c 8.7 (Berkeley) 2/12/94 * $FreeBSD: src/sys/kern/kern_exit.c,v 1.92.2.11 2003/01/13 22:51:16 dillon Exp $ - * $DragonFly: src/sys/kern/kern_exit.c,v 1.28 2003/11/04 04:17:37 dillon Exp $ + * $DragonFly: src/sys/kern/kern_exit.c,v 1.29 2003/11/21 05:29:04 dillon Exp $ */ #include "opt_compat.h" @@ -63,6 +63,7 @@ #include #include #include +#include #include #include @@ -198,6 +199,13 @@ exit1(int rv) /* The next two chunks should probably be moved to vmspace_exit. */ vm = p->p_vmspace; + + /* + * Release upcalls associated with this process + */ + if (vm->vm_upcalls) + upc_release(vm, p); + /* * Release user portion of address space. * This releases references to vnodes, diff --git a/sys/kern/kern_upcall.c b/sys/kern/kern_upcall.c new file mode 100644 index 0000000000..127a1d7a06 --- /dev/null +++ b/sys/kern/kern_upcall.c @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2003 Matthew Dillon + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $DragonFly: src/sys/kern/kern_upcall.c,v 1.1 2003/11/21 05:29:04 dillon Exp $ + */ + +/* + * Implement upcall registration and dispatch. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +MALLOC_DEFINE(M_UPCALL, "upcalls", "upcall registration structures"); + +#ifdef SMP + +static void +sigupcall_remote(void *arg) +{ + struct proc *p = arg; + if (p == lwkt_preempted_proc()) + sigupcall(); +} + +#endif + +/* + * upc_register: + * + * Register an upcall context wrapper and procedure. Note that the + * upcall context is set globally for the process, not for each upcall. + * + * ARGS(struct upcall *upc, upcall_func_t ctx, upcall_func_t func, void *data) + */ +int +upc_register(struct upc_register_args *uap) +{ + struct proc *p = curproc; + struct vmspace *vm = p->p_vmspace; + struct vmupcall *vu; + + if (vm->vm_upccount >= UPCALL_MAXCOUNT) + return(EFBIG); + + vu = malloc(sizeof(struct vmupcall), M_UPCALL, M_WAITOK|M_ZERO); + vu->vu_ctx = uap->ctxfunc; + vu->vu_func = uap->func; + vu->vu_data = uap->data; + vu->vu_proc = p; + p->p_upcall = uap->upc; + + if (vm->vm_upcalls != NULL) + vu->vu_id = vm->vm_upcalls->vu_id + 1; + else + vu->vu_id = 1; + vu->vu_next = vm->vm_upcalls; + vm->vm_upcalls = vu; + ++vm->vm_upccount; + uap->sysmsg_result = vu->vu_id; + return(0); +} + +/* + * upc_control: + * + * ARGS(int cmd, int upcid, void *data) + */ +int +upc_control(struct upc_control_args *uap) +{ + struct proc *p = curproc; + struct proc *targp; + struct vmspace *vms = p->p_vmspace; + struct vmupcall *vu; + struct vmupcall *vu_send; + struct vmupcall **vupp; + int error; + + switch(uap->cmd) { + case UPC_CONTROL_DISPATCH: + /* + * Dispatch the specified upcall id or the next pending id if -1. + * the upcall will be marked pending but an actual upcall will only + * occur if userland is not in a critical section and the userland + * pending bit is not set. + * + * You can dispatch an upcall associated with your process or another + * process sharing the same VM space. + */ + error = (uap->upcid == -1) ? 0 : ENOENT; + for (vu = vms->vm_upcalls; vu; vu = vu->vu_next) { + if (vu->vu_id == uap->upcid || + (uap->upcid == -1 && vu->vu_pending && vu->vu_proc == p) + ) { + vu->vu_pending = 1; + error = 0; + targp = vu->vu_proc; + targp->p_flag |= P_UPCALLPEND; +#ifdef SMP + if (targp->p_thread->td_gd != mycpu) + lwkt_send_ipiq(targp->p_thread->td_gd->gd_cpuid, sigupcall_remote, targp); + else + sigupcall(); +#else + sigupcall(); +#endif + break; + } + } + break; + case UPC_CONTROL_NEXT: + /* + * This is used by the context code to fetch the next pending upcall. + * The context code has two choices: (A) it can drop + * upcall->crit_count and set upcall->pending then make this call + * unconditionally or * (B) it can drop upcall->crit_count and then + * test upcall->pending and only make this call if upcall->pending + * is set. If upcall->pending is clear the context code can pop + * the upcall stack itself and return without entering into the kernel + * again. (B) is more efficient but leaves a small window of + * opportunity where multiple upcalls can pushdown the stack. + * + * If another upcall is pending the crit_count will be bumped and + * the function, data, and context pointers will be returned in + * registers (C cannot call this routine). If no more upcalls are + * pending the pending bit will be cleared and the 'data' argument + * is expected to be pointing at the upcall context which we will + * then pop, returning to the original code that was interrupted + * (NOT the context code). + */ + vu_send = NULL; + for (vu = vms->vm_upcalls; vu; vu = vu->vu_next) { + if (vu->vu_proc == p && vu->vu_pending) { + if (vu_send) + break; + vu_send = vu; + } + } + /* + * vu_send may be NULL, indicating that no more upcalls are pending + * for this cpu. We set the userland pending bit based on whether + * additional upcalls are pending or not. + */ + error = fetchupcall(vu_send, vu != NULL, &uap->sysmsg_result, uap->data); + break; + case UPC_CONTROL_DELETE: + /* + * Delete the specified upcall id. If the upcall id is -1, delete + * all upcall id's associated with the current process. + */ + error = (uap->upcid == -1) ? 0 : ENOENT; + vupp = &vms->vm_upcalls; + while ((vu = *vupp) != NULL) { + if (vu->vu_id == uap->upcid || + (uap->upcid == -1 && vu->vu_proc == p) + ) { + *vupp = vu->vu_next; + error = 0; + free(vu, M_UPCALL); + } else { + vupp = &vu->vu_next; + } + } + break; + case UPC_CONTROL_POLL: + case UPC_CONTROL_POLLANDCLEAR: + /* + * If upcid is -1 poll for the first pending upcall and return the + * id or 0 if no upcalls are pending. + * + * If upcid is a particular upcall then poll that upcall and return + * its pending status (0 or 1). For POLLANDCLEAR, also clear the + * pending status. The userland pending bit is not modified by + * this call (maybe we should modify it for poll-and-clear). + */ + error = (uap->upcid == -1) ? 0 : ENOENT; + for (vu = vms->vm_upcalls; vu; vu = vu->vu_next) { + if (vu->vu_id == uap->upcid || + (uap->upcid == -1 && vu->vu_pending && vu->vu_proc == p) + ) { + error = 0; + if (uap->upcid == -1) + uap->sysmsg_result = vu->vu_id; + else + uap->sysmsg_result = vu->vu_pending; + if (uap->cmd == UPC_CONTROL_POLLANDCLEAR) + vu->vu_pending = 0; + break; + } + } + break; + default: + error = EINVAL; + break; + } + return(error); +} + +void +upc_release(struct vmspace *vm, struct proc *p) +{ + struct vmupcall **vupp; + struct vmupcall *vu; + + vupp = &vm->vm_upcalls; + while ((vu = *vupp) != NULL) { + if (vu->vu_proc == p) { + *vupp = vu->vu_next; + free(vu, M_UPCALL); + --vm->vm_upccount; + } else { + vupp = &vu->vu_next; + } + } +} + +void +postupcall(struct proc *p) +{ + struct vmspace *vm = p->p_vmspace; + struct vmupcall *vu; + struct vmupcall *vu_send = NULL; + + for (vu = vm->vm_upcalls; vu; vu = vu->vu_next) { + if (vu->vu_proc == p && vu->vu_pending) { + if (vu_send) { + sendupcall(vu, 1); + return; + } + vu_send = vu; + } + } + if (vu_send) + sendupcall(vu_send, 0); +} + diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c index b55fff5d76..7a20609c8c 100644 --- a/sys/kern/syscalls.c +++ b/sys/kern/syscalls.c @@ -2,7 +2,7 @@ * System call names. * * DO NOT EDIT-- this file is automatically generated. - * $DragonFly: src/sys/kern/syscalls.c,v 1.12 2003/11/20 06:05:30 dillon Exp $ + * $DragonFly: src/sys/kern/syscalls.c,v 1.13 2003/11/21 05:29:04 dillon Exp $ * created from DragonFly: src/sys/kern/syscalls.master,v 1.8 2003/11/10 23:58:57 dillon Exp */ @@ -460,4 +460,6 @@ char *syscallnames[] = { "varsym_set", /* 450 = varsym_set */ "varsym_get", /* 451 = varsym_get */ "varsym_list", /* 452 = varsym_list */ + "upc_register", /* 453 = upc_register */ + "upc_control", /* 454 = upc_control */ }; diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 7bd9c466c0..6d54875ab3 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -1,4 +1,4 @@ - $DragonFly: src/sys/kern/syscalls.master,v 1.8 2003/11/10 23:58:57 dillon Exp $ + $DragonFly: src/sys/kern/syscalls.master,v 1.9 2003/11/21 05:29:04 dillon Exp $ ; @(#)syscalls.master 8.2 (Berkeley) 1/13/94 ; $FreeBSD: src/sys/kern/syscalls.master,v 1.72.2.10 2002/07/12 08:22:46 alfred Exp $ @@ -615,3 +615,7 @@ 450 STD BSD { int varsym_set(int level, const char *name, const char *data); } 451 STD BSD { int varsym_get(int mask, const char *wild, char *buf, int bufsize); } 452 STD BSD { int varsym_list(int level, char *buf, int maxsize, int *marker); } +453 STD BSD { int upc_register(struct upcall *upc, void *ctxfunc, void *func, void *data); } +454 STD BSD { int upc_control(int cmd, int upcid, void *data); } + + diff --git a/sys/platform/pc32/i386/genassym.c b/sys/platform/pc32/i386/genassym.c index 666db5fe0a..660b689a7d 100644 --- a/sys/platform/pc32/i386/genassym.c +++ b/sys/platform/pc32/i386/genassym.c @@ -35,7 +35,7 @@ * * from: @(#)genassym.c 5.11 (Berkeley) 5/10/91 * $FreeBSD: src/sys/i386/i386/genassym.c,v 1.86.2.3 2002/03/03 05:42:49 nyan Exp $ - * $DragonFly: src/sys/platform/pc32/i386/genassym.c,v 1.31 2003/10/24 14:10:45 daver Exp $ + * $DragonFly: src/sys/platform/pc32/i386/genassym.c,v 1.32 2003/11/21 05:29:07 dillon Exp $ */ #include "opt_user_ldt.h" @@ -198,6 +198,7 @@ ASSYM(RQF_INTPEND, RQF_INTPEND); ASSYM(RQF_AST_OWEUPC, RQF_AST_OWEUPC); ASSYM(RQF_AST_SIGNAL, RQF_AST_SIGNAL); ASSYM(RQF_AST_RESCHED, RQF_AST_RESCHED); +ASSYM(RQF_AST_UPCALL, RQF_AST_UPCALL); ASSYM(RQF_AST_MASK, RQF_AST_MASK); ASSYM(GD_FPENDING, offsetof(struct mdglobaldata, gd_fpending)); diff --git a/sys/platform/pc32/i386/machdep.c b/sys/platform/pc32/i386/machdep.c index 9cc4deeb10..1b654d0617 100644 --- a/sys/platform/pc32/i386/machdep.c +++ b/sys/platform/pc32/i386/machdep.c @@ -36,7 +36,7 @@ * * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91 * $FreeBSD: src/sys/i386/i386/machdep.c,v 1.385.2.30 2003/05/31 08:48:05 alc Exp $ - * $DragonFly: src/sys/platform/pc32/i386/machdep.c,v 1.44 2003/11/15 21:05:43 dillon Exp $ + * $DragonFly: src/sys/platform/pc32/i386/machdep.c,v 1.45 2003/11/21 05:29:07 dillon Exp $ */ #include "use_apm.h" @@ -74,6 +74,7 @@ #include #include #include +#include #include #include @@ -685,6 +686,131 @@ sigreturn(struct sigreturn_args *uap) return(EJUSTRETURN); } +/* + * Stack frame on entry to function. %eax will contain the function vector, + * %ecx will contain the function data. flags, ecx, and eax will have + * already been pushed on the stack. + */ +struct upc_frame { + register_t eax; + register_t ecx; + register_t flags; + register_t oldip; +}; + +void +sendupcall(struct vmupcall *vu, int morepending) +{ + struct proc *p = curproc; + struct trapframe *regs; + struct upcall upcall; + struct upc_frame upc_frame; + + /* + * Get the upcall data structure + */ + if (copyin(p->p_upcall, &upcall, sizeof(upcall))) { + vu->vu_pending = 0; + printf("bad upcall address\n"); + return; + } + + /* + * If the data structure is already marked pending or has a critical + * section count, mark the data structure as pending and return + * without doing an upcall. vu_pending is left set. + */ + if (upcall.pending || upcall.crit_count) { + if (upcall.pending == 0) { + upcall.pending = 1; + copyout(&upcall.pending, &p->p_upcall->pending, + sizeof(upcall.pending)); + } + return; + } + + /* + * We can run this upcall now, clear vu_pending. + * + * Bump our critical section count and set or clear the + * user pending flag depending on whether more upcalls are + * pending. The user will be responsible for calling + * upc_dispatch(-1) to process remaining upcalls. + */ + vu->vu_pending = 0; + upcall.pending = morepending; + upcall.crit_count += TDPRI_CRIT; + copyout(&upcall, p->p_upcall, sizeof(upcall)); + + /* + * Construct a stack frame and issue the upcall + */ + regs = p->p_md.md_regs; + upc_frame.eax = regs->tf_eax; + upc_frame.ecx = regs->tf_ecx; + upc_frame.flags = regs->tf_eflags; + upc_frame.oldip = regs->tf_eip; + if (copyout(&upc_frame, (void *)(regs->tf_esp - sizeof(upc_frame)), + sizeof(upc_frame)) != 0) { + printf("bad stack on upcall\n"); + } else { + regs->tf_eax = (register_t)vu->vu_func; + regs->tf_ecx = (register_t)vu->vu_data; + regs->tf_eip = (register_t)vu->vu_ctx; + regs->tf_esp -= sizeof(upc_frame); + } +} + +/* + * fetchupcall occurs in the context of a system call, which means that + * regs->tf_eax and regs->tf_edx are overritten by res[0] and res[1]. + * + * if vu is not NULL we return the new context in %edx, the new data in %ecx, + * and the function pointer in %eax. + */ +int +fetchupcall (struct vmupcall *vu, int morepending, int *res, void *rsp) +{ + struct upc_frame upc_frame; + struct proc *p; + struct trapframe *regs; + int error; + + p = curproc; + regs = p->p_md.md_regs; + + error = copyout(&morepending, &p->p_upcall->pending, sizeof(int)); + if (error == 0) { + if (vu) { + /* + * This jumps us to the next ready context. + */ + vu->vu_pending = 0; + error = copyin(&p->p_upcall->crit_count, &morepending, sizeof(int)); + morepending += TDPRI_CRIT; + if (error == 0) + error = copyout(&morepending, &p->p_upcall->crit_count, sizeof(int)); + regs->tf_eax = (register_t)vu->vu_func; + regs->tf_ecx = (register_t)vu->vu_data; + regs->tf_eip = (register_t)vu->vu_ctx; + regs->tf_esp = (register_t)rsp; + } else { + /* + * This returns us to the originally interrupted code. + */ + error = copyin(rsp, &upc_frame, sizeof(upc_frame)); + regs->tf_eax = upc_frame.eax; + regs->tf_ecx = upc_frame.ecx; + regs->tf_eflags = upc_frame.flags; + regs->tf_eip = upc_frame.oldip; + regs->tf_esp = (register_t)((char *)rsp + sizeof(upc_frame)); + } + } + if (error == 0) + error = EJUSTRETURN; + return(error); +} + /* * Machine dependent boot() routine * diff --git a/sys/platform/pc32/i386/trap.c b/sys/platform/pc32/i386/trap.c index 34915cd4ff..b7acd58bfd 100644 --- a/sys/platform/pc32/i386/trap.c +++ b/sys/platform/pc32/i386/trap.c @@ -36,7 +36,7 @@ * * from: @(#)trap.c 7.4 (Berkeley) 5/13/91 * $FreeBSD: src/sys/i386/i386/trap.c,v 1.147.2.11 2003/02/27 19:09:59 luoqi Exp $ - * $DragonFly: src/sys/platform/pc32/i386/trap.c,v 1.42 2003/11/20 06:05:30 dillon Exp $ + * $DragonFly: src/sys/platform/pc32/i386/trap.c,v 1.43 2003/11/21 05:29:07 dillon Exp $ */ /* @@ -68,6 +68,7 @@ #ifdef KTRACE #include #endif +#include #include #include @@ -271,6 +272,14 @@ userret(struct proc *p, struct trapframe *frame, u_quad_t oticks) { int sig; + /* + * Post any pending upcalls + */ + if (p->p_flag & P_UPCALLPEND) { + p->p_flag &= ~P_UPCALLPEND; + postupcall(p); + } + /* * Post any pending signals */ diff --git a/sys/platform/pc32/isa/ipl.s b/sys/platform/pc32/isa/ipl.s index a2831c68f2..257f37f2b9 100644 --- a/sys/platform/pc32/isa/ipl.s +++ b/sys/platform/pc32/isa/ipl.s @@ -37,7 +37,7 @@ * @(#)ipl.s * * $FreeBSD: src/sys/i386/isa/ipl.s,v 1.32.2.3 2002/05/16 16:03:56 bde Exp $ - * $DragonFly: src/sys/platform/pc32/isa/ipl.s,v 1.14 2003/10/02 22:26:59 dillon Exp $ + * $DragonFly: src/sys/platform/pc32/isa/ipl.s,v 1.15 2003/11/21 05:29:08 dillon Exp $ */ @@ -256,7 +256,7 @@ doreti_intr: * to do is a reschedule. */ doreti_ast: - andl $~RQF_AST_SIGNAL,PCPU(reqflags) + andl $~(RQF_AST_SIGNAL|RQF_AST_UPCALL),PCPU(reqflags) sti movl %eax,%esi /* save cpl (can't use stack) */ movl $T_ASTFLT,TF_TRAPNO(%esp) diff --git a/sys/platform/vkernel/i386/genassym.c b/sys/platform/vkernel/i386/genassym.c index 869d015978..fc8d961d5b 100644 --- a/sys/platform/vkernel/i386/genassym.c +++ b/sys/platform/vkernel/i386/genassym.c @@ -35,7 +35,7 @@ * * from: @(#)genassym.c 5.11 (Berkeley) 5/10/91 * $FreeBSD: src/sys/i386/i386/genassym.c,v 1.86.2.3 2002/03/03 05:42:49 nyan Exp $ - * $DragonFly: src/sys/platform/vkernel/i386/genassym.c,v 1.31 2003/10/24 14:10:45 daver Exp $ + * $DragonFly: src/sys/platform/vkernel/i386/genassym.c,v 1.32 2003/11/21 05:29:07 dillon Exp $ */ #include "opt_user_ldt.h" @@ -198,6 +198,7 @@ ASSYM(RQF_INTPEND, RQF_INTPEND); ASSYM(RQF_AST_OWEUPC, RQF_AST_OWEUPC); ASSYM(RQF_AST_SIGNAL, RQF_AST_SIGNAL); ASSYM(RQF_AST_RESCHED, RQF_AST_RESCHED); +ASSYM(RQF_AST_UPCALL, RQF_AST_UPCALL); ASSYM(RQF_AST_MASK, RQF_AST_MASK); ASSYM(GD_FPENDING, offsetof(struct mdglobaldata, gd_fpending)); diff --git a/sys/sys/globaldata.h b/sys/sys/globaldata.h index de1f14aab0..4edc0e97bd 100644 --- a/sys/sys/globaldata.h +++ b/sys/sys/globaldata.h @@ -24,7 +24,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/i386/include/globaldata.h,v 1.11.2.1 2000/05/16 06:58:10 dillon Exp $ - * $DragonFly: src/sys/sys/globaldata.h,v 1.19 2003/11/20 06:05:31 dillon Exp $ + * $DragonFly: src/sys/sys/globaldata.h,v 1.20 2003/11/21 05:29:02 dillon Exp $ */ #ifndef _SYS_GLOBALDATA_H_ @@ -112,13 +112,16 @@ typedef struct globaldata *globaldata_t; #define RQB_AST_OWEUPC 2 #define RQB_AST_SIGNAL 3 #define RQB_AST_RESCHED 4 +#define RQB_AST_UPCALL 5 #define RQF_IPIQ (1 << RQB_IPIQ) #define RQF_INTPEND (1 << RQB_INTPEND) #define RQF_AST_OWEUPC (1 << RQB_AST_OWEUPC) #define RQF_AST_SIGNAL (1 << RQB_AST_SIGNAL) #define RQF_AST_RESCHED (1 << RQB_AST_RESCHED) -#define RQF_AST_MASK (RQF_AST_OWEUPC|RQF_AST_SIGNAL|RQF_AST_RESCHED) +#define RQF_AST_UPCALL (1 << RQB_AST_UPCALL) +#define RQF_AST_MASK (RQF_AST_OWEUPC|RQF_AST_SIGNAL|RQF_AST_RESCHED|\ + RQF_AST_UPCALL) #endif diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 611c389eab..55c8602eac 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -37,7 +37,7 @@ * * @(#)proc.h 8.15 (Berkeley) 5/19/95 * $FreeBSD: src/sys/sys/proc.h,v 1.99.2.9 2003/06/06 20:21:32 tegge Exp $ - * $DragonFly: src/sys/sys/proc.h,v 1.35 2003/11/05 23:26:21 dillon Exp $ + * $DragonFly: src/sys/sys/proc.h,v 1.36 2003/11/21 05:29:02 dillon Exp $ */ #ifndef _SYS_PROC_H_ @@ -55,6 +55,7 @@ #include /* For struct klist */ #include #include +#include #ifdef _KERNEL #include #endif @@ -226,6 +227,7 @@ struct proc { struct proc *p_leader; void *p_emuldata; /* process-specific emulator state data */ struct thread *p_thread; /* temporarily embed thread struct in proc */ + struct upcall *p_upcall; /* USERLAND POINTER! registered upcall */ }; #if defined(_KERNEL) @@ -264,7 +266,7 @@ struct proc { /* was P_NOSWAP 0x08000 was: Do not swap upages; p->p_hold */ /* was P_PHYSIO 0x10000 was: Doing physical I/O; use p->p_hold */ -#define P_UNUSED20000 0x20000 +#define P_UPCALLPEND 0x20000 /* an upcall is pending */ #define P_SWAPPING 0x40000 /* Process is being swapped. */ #define P_SWAPINREQ 0x80000 /* Swapin request due to wakeup */ diff --git a/sys/sys/signalvar.h b/sys/sys/signalvar.h index 29e2595391..292ab26e18 100644 --- a/sys/sys/signalvar.h +++ b/sys/sys/signalvar.h @@ -32,7 +32,7 @@ * * @(#)signalvar.h 8.6 (Berkeley) 2/19/95 * $FreeBSD: src/sys/sys/signalvar.h,v 1.34.2.1 2000/05/16 06:58:05 dillon Exp $ - * $DragonFly: src/sys/sys/signalvar.h,v 1.7 2003/10/24 14:10:46 daver Exp $ + * $DragonFly: src/sys/sys/signalvar.h,v 1.8 2003/11/21 05:29:02 dillon Exp $ */ #ifndef _SYS_SIGNALVAR_H_ /* tmp for user.h */ @@ -167,6 +167,7 @@ typedef void (*proc_func_t)(struct proc *); struct pgrp; struct proc; struct sigio; +struct vmupcall; extern int sugid_coredump; /* Sysctl variable kern.sugid_coredump */ @@ -192,6 +193,8 @@ proc_func_t register_ckpt_func(proc_func_t func); * Machine-dependent functions: */ void sendsig (sig_t action, int sig, sigset_t *retmask, u_long code); +void sendupcall (struct vmupcall *vu, int morepending); +int fetchupcall (struct vmupcall *vu, int morepending, int *res, void *rsp); void sigexit (struct proc *p, int sig); /* diff --git a/sys/sys/syscall-hide.h b/sys/sys/syscall-hide.h index e8b6b54235..82f51f743b 100644 --- a/sys/sys/syscall-hide.h +++ b/sys/sys/syscall-hide.h @@ -2,7 +2,7 @@ * System call hiders. * * DO NOT EDIT-- this file is automatically generated. - * $DragonFly: src/sys/sys/syscall-hide.h,v 1.13 2003/11/20 06:05:31 dillon Exp $ + * $DragonFly: src/sys/sys/syscall-hide.h,v 1.14 2003/11/21 05:29:02 dillon Exp $ * created from DragonFly: src/sys/kern/syscalls.master,v 1.8 2003/11/10 23:58:57 dillon Exp */ @@ -278,3 +278,5 @@ HIDE_BSD(sendfile) HIDE_BSD(varsym_set) HIDE_BSD(varsym_get) HIDE_BSD(varsym_list) +HIDE_BSD(upc_register) +HIDE_BSD(upc_control) diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h index 0d8fc3937d..32e96c3d50 100644 --- a/sys/sys/syscall.h +++ b/sys/sys/syscall.h @@ -2,7 +2,7 @@ * System call numbers. * * DO NOT EDIT-- this file is automatically generated. - * $DragonFly: src/sys/sys/syscall.h,v 1.13 2003/11/20 06:05:31 dillon Exp $ + * $DragonFly: src/sys/sys/syscall.h,v 1.14 2003/11/21 05:29:02 dillon Exp $ * created from DragonFly: src/sys/kern/syscalls.master,v 1.8 2003/11/10 23:58:57 dillon Exp */ @@ -289,4 +289,6 @@ #define SYS_varsym_set 450 #define SYS_varsym_get 451 #define SYS_varsym_list 452 -#define SYS_MAXSYSCALL 453 +#define SYS_upc_register 453 +#define SYS_upc_control 454 +#define SYS_MAXSYSCALL 455 diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk index e82802b535..3f00955acd 100644 --- a/sys/sys/syscall.mk +++ b/sys/sys/syscall.mk @@ -1,6 +1,6 @@ # DragonFly system call names. # DO NOT EDIT-- this file is automatically generated. -# $DragonFly: src/sys/sys/syscall.mk,v 1.13 2003/11/20 06:05:31 dillon Exp $ +# $DragonFly: src/sys/sys/syscall.mk,v 1.14 2003/11/21 05:29:02 dillon Exp $ # created from DragonFly: src/sys/kern/syscalls.master,v 1.8 2003/11/10 23:58:57 dillon Exp MIASM = \ syscall.o \ @@ -238,4 +238,6 @@ MIASM = \ sendfile.o \ varsym_set.o \ varsym_get.o \ - varsym_list.o + varsym_list.o \ + upc_register.o \ + upc_control.o diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h index 527bb8451c..c859828687 100644 --- a/sys/sys/sysproto.h +++ b/sys/sys/sysproto.h @@ -2,7 +2,7 @@ * System call prototypes. * * DO NOT EDIT-- this file is automatically generated. - * $DragonFly: src/sys/sys/sysproto.h,v 1.13 2003/11/20 06:05:31 dillon Exp $ + * $DragonFly: src/sys/sys/sysproto.h,v 1.14 2003/11/21 05:29:02 dillon Exp $ * created from DragonFly: src/sys/kern/syscalls.master,v 1.8 2003/11/10 23:58:57 dillon Exp */ @@ -1985,6 +1985,25 @@ struct varsym_list_args { int maxsize; char maxsize_[PAD_(int)]; int * marker; char marker_[PAD_(int *)]; }; +struct upc_register_args { +#ifdef _KERNEL + struct sysmsg sysmsg; +#endif + union usrmsg usrmsg; + struct upcall * upc; char upc_[PAD_(struct upcall *)]; + void * ctxfunc; char ctxfunc_[PAD_(void *)]; + void * func; char func_[PAD_(void *)]; + void * data; char data_[PAD_(void *)]; +}; +struct upc_control_args { +#ifdef _KERNEL + struct sysmsg sysmsg; +#endif + union usrmsg usrmsg; + int cmd; char cmd_[PAD_(int)]; + int upcid; char upcid_[PAD_(int)]; + void * data; char data_[PAD_(void *)]; +}; #ifdef _KERNEL @@ -2222,6 +2241,8 @@ int sendfile (struct sendfile_args *); int varsym_set (struct varsym_set_args *); int varsym_get (struct varsym_get_args *); int varsym_list (struct varsym_list_args *); +int upc_register (struct upc_register_args *); +int upc_control (struct upc_control_args *); #endif /* _KERNEL */ diff --git a/sys/sys/sysunion.h b/sys/sys/sysunion.h index db024dd9f1..a7fb60aaa8 100644 --- a/sys/sys/sysunion.h +++ b/sys/sys/sysunion.h @@ -2,7 +2,7 @@ * Union of syscall args for messaging. * * DO NOT EDIT-- this file is automatically generated. - * $DragonFly: src/sys/sys/sysunion.h,v 1.10 2003/11/20 06:05:31 dillon Exp $ + * $DragonFly: src/sys/sys/sysunion.h,v 1.11 2003/11/21 05:29:02 dillon Exp $ * created from DragonFly: src/sys/kern/syscalls.master,v 1.8 2003/11/10 23:58:57 dillon Exp */ @@ -323,4 +323,6 @@ union sysunion { struct varsym_set_args varsym_set; struct varsym_get_args varsym_get; struct varsym_list_args varsym_list; + struct upc_register_args upc_register; + struct upc_control_args upc_control; }; diff --git a/sys/sys/upcall.h b/sys/sys/upcall.h new file mode 100644 index 0000000000..d2efe974c9 --- /dev/null +++ b/sys/sys/upcall.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2003 Matthew Dillon + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $DragonFly: src/sys/sys/upcall.h,v 1.1 2003/11/21 05:29:02 dillon Exp $ + */ + +#ifndef _SYS_UPCALL_H_ +#define _SYS_UPCALL_H_ + +typedef void (*upcall_func_t)(void *); + +struct upcall { + int magic; + int crit_count; + int pending; /* must follow crit_count */ + int vcpu; /* virtual cpu number */ +}; + +#define UPCALL_MAGIC 0x55504331 +#define UPCALL_MAXCOUNT 32 + +#define UPC_CONTROL_DISPATCH 1 +#define UPC_CONTROL_NEXT 2 +#define UPC_CONTROL_DELETE 3 +#define UPC_CONTROL_POLL 4 +#define UPC_CONTROL_POLLANDCLEAR 5 + +#if defined(_KERNEL) + +struct vmspace; + +void upc_release(struct vmspace *vm, struct proc *p); +void postupcall(struct proc *p); + +#else + +int upc_register(struct upcall *, upcall_func_t, upcall_func_t, void *); +int upc_dispatch(int upcid); + +#endif + +#endif + diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index d64aeb1168..2848cd0e57 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -62,7 +62,7 @@ * rights to redistribute these changes. * * $FreeBSD: src/sys/vm/vm_map.c,v 1.187.2.19 2003/05/27 00:47:02 alc Exp $ - * $DragonFly: src/sys/vm/vm_map.c,v 1.14 2003/10/19 00:23:30 dillon Exp $ + * $DragonFly: src/sys/vm/vm_map.c,v 1.15 2003/11/21 05:29:08 dillon Exp $ */ /* @@ -204,6 +204,8 @@ vmspace_dofree(struct vmspace *vm) */ shmexit(vm); + KKASSERT(vm->vm_upcalls == NULL); + /* * Lock the map, to wait out all other references to it. * Delete all of the mappings and pages they hold, then call diff --git a/sys/vm/vm_map.h b/sys/vm/vm_map.h index 5764afb73c..ce15e0e023 100644 --- a/sys/vm/vm_map.h +++ b/sys/vm/vm_map.h @@ -62,7 +62,7 @@ * rights to redistribute these changes. * * $FreeBSD: src/sys/vm/vm_map.h,v 1.54.2.5 2003/01/13 22:51:17 dillon Exp $ - * $DragonFly: src/sys/vm/vm_map.h,v 1.8 2003/10/02 21:00:20 hmp Exp $ + * $DragonFly: src/sys/vm/vm_map.h,v 1.9 2003/11/21 05:29:08 dillon Exp $ */ /* @@ -186,6 +186,21 @@ struct vm_map { #define max_offset header.end }; +/* + * Registered upcall + */ +struct upcall; + +struct vmupcall { + struct vmupcall *vu_next; + void *vu_func; /* user upcall function */ + void *vu_data; /* user data */ + void *vu_ctx; /* user context function */ + struct proc *vu_proc; /* process that registered upcall */ + int vu_id; /* upcall identifier */ + int vu_pending; /* upcall request pending */ +}; + /* * Shareable process virtual address space. * May eventually be merged with vm_map. @@ -208,6 +223,8 @@ struct vmspace { caddr_t vm_maxsaddr; /* user VA at max stack growth */ caddr_t vm_minsaddr; /* user VA at max stack growth */ int vm_exitingcnt; /* several procsses zombied in exit1 */ + int vm_upccount; /* number of registered upcalls */ + struct vmupcall *vm_upcalls; /* registered upcalls */ }; /* -- 2.41.0