From 4b4861839bfa72114ad6172ee097f696af88d0ba Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Sun, 14 Jan 2007 20:07:15 +0000 Subject: [PATCH] Link up the interrupt frame to the systimer API. Use PGEX_U to indicate a user frame and adjust CLKF_USERMODE for the virtual kernel. This allows the stat clock in the virtual kernel to account for user vs system time (instead of just counting it all as system time). Consolidate other special virtual kernel and signal flags in tf_xflags and name them the same (FPEX_FAULT -> PGEX_FPFAULT, and add PGEX_MAILBOX) Implement PGEX_MAILBOX for signal frames. On signal return this flag causes P_MAILBOX to be set in order to maintain interlock semantics with mailbox signals. --- sys/cpu/i386/include/cpu.h | 5 +-- sys/cpu/i386/include/frame.h | 26 ++++++++------ sys/cpu/i386/include/pmap.h | 19 +++++++--- sys/platform/pc32/i386/machdep.c | 14 +++++++- sys/platform/pc32/i386/trap.c | 6 ++-- sys/platform/pc32/include/cpu.h | 46 ++++++++++++++++++++++++ sys/platform/vkernel/i386/cpu_regs.c | 15 +++++++- sys/platform/vkernel/i386/trap.c | 24 +++++++++---- sys/platform/vkernel/include/cpu.h | 45 +++++++++++++++++++++++ sys/platform/vkernel/platform/systimer.c | 11 ++++-- 10 files changed, 177 insertions(+), 34 deletions(-) create mode 100644 sys/platform/pc32/include/cpu.h create mode 100644 sys/platform/vkernel/include/cpu.h diff --git a/sys/cpu/i386/include/cpu.h b/sys/cpu/i386/include/cpu.h index 729c230796..109daf60c6 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.21 2006/11/07 18:49:59 dillon Exp $ + * $DragonFly: src/sys/cpu/i386/include/cpu.h,v 1.22 2007/01/14 20:07:11 dillon Exp $ */ #ifndef _CPU_CPU_H_ @@ -64,9 +64,6 @@ #define cpu_swapin(p) /* nothing */ #define cpu_setstack(p, ap) ((p)->p_md.md_regs[SP] = (ap)) -#define CLKF_USERMODE(framep) \ - ((ISPL((framep)->if_cs) == SEL_UPL) || (framep->if_eflags & PSL_VM)) - #define CLKF_INTR(framep) (mycpu->gd_intr_nesting_level > 1 || (curthread->td_flags & TDF_INTTHREAD)) #define CLKF_PC(framep) ((framep)->if_eip) diff --git a/sys/cpu/i386/include/frame.h b/sys/cpu/i386/include/frame.h index 5ca7896af0..05e94e0c64 100644 --- a/sys/cpu/i386/include/frame.h +++ b/sys/cpu/i386/include/frame.h @@ -35,7 +35,7 @@ * * from: @(#)frame.h 5.2 (Berkeley) 1/18/91 * $FreeBSD: src/sys/i386/include/frame.h,v 1.20 1999/09/29 15:06:22 marcel Exp $ - * $DragonFly: src/sys/cpu/i386/include/frame.h,v 1.7 2007/01/08 03:33:37 dillon Exp $ + * $DragonFly: src/sys/cpu/i386/include/frame.h,v 1.8 2007/01/14 20:07:11 dillon Exp $ */ #ifndef _CPU_FRAME_H_ @@ -46,9 +46,9 @@ */ /* - * Exception/Trap Stack Frame + * Exception/Trap Stack Frame. This frame must match or be embedded within + * all other frame types, including signal context frames. */ - struct trapframe { int tf_gs; int tf_fs; @@ -74,8 +74,10 @@ struct trapframe { int tf_ss; }; -/* Superset of trap frame, for traps from virtual-8086 mode */ - +/* + * This frame is postfixed with additinoal information for traps from + * virtual-8086 mode but must otherwise match the trapframe. + */ struct trapframe_vm86 { int tf_gs; int tf_fs; @@ -106,8 +108,10 @@ struct trapframe_vm86 { int tf_vm86_gs; }; -/* Interrupt stack frame */ - +/* + * Interrupt stack frame. This frame is prefixed with additional + * information but must otherwise match the trapframe. + */ struct intrframe { int if_vec; int if_ppl; @@ -118,14 +122,14 @@ struct intrframe { int if_edi; int if_esi; int if_ebp; - int :32; + int if_isp; /* unused/trap frame compat - isp */ int if_ebx; int if_edx; int if_ecx; int if_eax; - int :32; /* for compat with trap frame - trapno */ - int :32; /* for compat with trap frame - xflags */ - int :32; /* for compat with trap frame - err */ + int if_xflags; /* trap frame compat - xflags (vkernel) */ + int if_trapno; /* unused/trap frame compat - trapno */ + int if_err; /* unused/trap frame compat - err */ /* below portion defined in 386 hardware */ int if_eip; int if_cs; diff --git a/sys/cpu/i386/include/pmap.h b/sys/cpu/i386/include/pmap.h index 0a0fb5d308..f7f0deff4e 100644 --- a/sys/cpu/i386/include/pmap.h +++ b/sys/cpu/i386/include/pmap.h @@ -43,7 +43,7 @@ * from: hp300: @(#)pmap.h 7.2 (Berkeley) 12/16/90 * from: @(#)pmap.h 7.4 (Berkeley) 5/12/91 * $FreeBSD: src/sys/i386/include/pmap.h,v 1.65.2.3 2001/10/03 07:15:37 peter Exp $ - * $DragonFly: src/sys/cpu/i386/include/pmap.h,v 1.13 2007/01/09 23:34:01 dillon Exp $ + * $DragonFly: src/sys/cpu/i386/include/pmap.h,v 1.14 2007/01/14 20:07:11 dillon Exp $ */ #ifndef _CPU_PMAP_H_ @@ -79,17 +79,26 @@ * Page Protection Exception bits, stored in tf_err on a real fault * and in tf_xflags on a signal frame or virtual kernel's trap frame. * These only apply to T_PAGEFLT faults. + * + * PGEX_U is also used internally by the virtual kernel to indicate + * whether the frame is a userland frame or a supervisor frame. */ #define PGEX_P 0x01 /* Protection violation vs. not present */ #define PGEX_W 0x02 /* during a Write cycle */ #define PGEX_U 0x04 /* access from User mode (UPL) */ /* - * Virtual kernel bits, managed by software. + * Virtual kernel bits, managed by software. Stored in tf_xflags. + * + * PGEX_FPFAULT - Force the FP unit to generate a T_DNA fault if an + * emulated user process tried to use it. This bit is + * only used by vmspace_ctl(). * - * FPEX_FAULT - Force the FP unit to generate a T_DNA fault if an emulated - * user process tried to use it. + * PGEX_MAILBOX - Set in xflags by signal code to indicate that a mailbox + * signal was pending. Remerged on signal return. This + * bit is only used in a signal vector frame. */ -#define FPEX_FAULT 0x80 +#define PGEX_MAILBOX 0x40 +#define PGEX_FPFAULT 0x80 #endif /* !_CPU_PMAP_H_ */ diff --git a/sys/platform/pc32/i386/machdep.c b/sys/platform/pc32/i386/machdep.c index 2a3b8e83df..6efaf0c290 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.115 2007/01/14 07:59:04 dillon Exp $ + * $DragonFly: src/sys/platform/pc32/i386/machdep.c,v 1.116 2007/01/14 20:07:12 dillon Exp $ */ #include "use_apm.h" @@ -432,6 +432,10 @@ sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code) /* make the size of the saved context visible to userland */ sf.sf_uc.uc_mcontext.mc_len = sizeof(sf.sf_uc.uc_mcontext); + /* save mailbox pending state for syscall interlock semantics */ + if (p->p_flag & P_MAILBOX) + sf.sf_uc.uc_mcontext.mc_xflags |= PGEX_MAILBOX; + /* Allocate and validate space for the signal handler context. */ /* XXX lwp flags */ if ((p->p_flag & P_ALTSTACK) != 0 && !oonstack && @@ -595,6 +599,7 @@ int sys_sigreturn(struct sigreturn_args *uap) { struct lwp *lp = curthread->td_lwp; + struct proc *p = lp->lwp_proc; struct trapframe *regs; ucontext_t *ucp; int cs, eflags; @@ -677,6 +682,13 @@ sys_sigreturn(struct sigreturn_args *uap) bcopy(&ucp->uc_mcontext.mc_gs, regs, sizeof(struct trapframe)); } + /* + * Merge saved signal mailbox pending flag to maintain interlock + * semantics against system calls. + */ + if (ucp->uc_mcontext.mc_xflags & PGEX_MAILBOX) + p->p_flag |= P_MAILBOX; + if (ucp->uc_mcontext.mc_onstack & 1) lp->lwp_sigstk.ss_flags |= SS_ONSTACK; else diff --git a/sys/platform/pc32/i386/trap.c b/sys/platform/pc32/i386/trap.c index a5be1fc928..101a50e713 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.94 2007/01/09 23:34:02 dillon Exp $ + * $DragonFly: src/sys/platform/pc32/i386/trap.c,v 1.95 2007/01/14 20:07:12 dillon Exp $ */ /* @@ -1458,7 +1458,7 @@ fork_return(struct lwp *lp, struct trapframe frame) } /* - * If FPEX_FAULT is set then set FP_VIRTFP in the PCB to force a T_DNA + * If PGEX_FPFAULT is set then set FP_VIRTFP in the PCB to force a T_DNA * fault (which is then passed back to the virtual kernel) if an attempt is * made to use the FP unit. * @@ -1469,7 +1469,7 @@ set_vkernel_fp(struct trapframe *frame) { struct thread *td = curthread; - if (frame->tf_xflags & FPEX_FAULT) { + if (frame->tf_xflags & PGEX_FPFAULT) { td->td_pcb->pcb_flags |= FP_VIRTFP; if (mdcpu->gd_npxthread == td) npxexit(); diff --git a/sys/platform/pc32/include/cpu.h b/sys/platform/pc32/include/cpu.h new file mode 100644 index 0000000000..6013b2d096 --- /dev/null +++ b/sys/platform/pc32/include/cpu.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2006 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Matthew Dillon + * + * 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. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDERS 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/platform/pc32/include/cpu.h,v 1.1 2007/01/14 20:07:13 dillon Exp $ + */ + +#ifndef _MACHINE_CPU_H_ +#define _MACHINE_CPU_H_ + +#include + +#define CLKF_USERMODE(framep) \ + ((ISPL((framep)->if_cs) == SEL_UPL) || (framep->if_eflags & PSL_VM)) + +#endif + diff --git a/sys/platform/vkernel/i386/cpu_regs.c b/sys/platform/vkernel/i386/cpu_regs.c index 14ff1a1533..0a5c6fed7c 100644 --- a/sys/platform/vkernel/i386/cpu_regs.c +++ b/sys/platform/vkernel/i386/cpu_regs.c @@ -37,7 +37,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/vkernel/i386/cpu_regs.c,v 1.10 2007/01/14 07:59:05 dillon Exp $ + * $DragonFly: src/sys/platform/vkernel/i386/cpu_regs.c,v 1.11 2007/01/14 20:07:14 dillon Exp $ */ #include "use_ether.h" @@ -232,6 +232,11 @@ sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code) /* make the size of the saved context visible to userland */ sf.sf_uc.uc_mcontext.mc_len = sizeof(sf.sf_uc.uc_mcontext); + /* save mailbox pending state for syscall interlock semantics */ + if (p->p_flag & P_MAILBOX) + sf.sf_uc.uc_mcontext.mc_xflags |= PGEX_MAILBOX; + + /* Allocate and validate space for the signal handler context. */ /* XXX lwp flags */ if ((p->p_flag & P_ALTSTACK) != 0 && !oonstack && @@ -388,6 +393,7 @@ int sys_sigreturn(struct sigreturn_args *uap) { struct lwp *lp = curthread->td_lwp; + struct proc *p = lp->lwp_proc; struct trapframe *regs; ucontext_t ucp; int cs; @@ -474,6 +480,13 @@ sys_sigreturn(struct sigreturn_args *uap) bcopy(&ucp.uc_mcontext.mc_gs, regs, sizeof(struct trapframe)); } + /* + * Merge saved signal mailbox pending flag to maintain interlock + * semantics against system calls. + */ + if (ucp.uc_mcontext.mc_xflags & PGEX_MAILBOX) + p->p_flag |= P_MAILBOX; + if (ucp.uc_mcontext.mc_onstack & 1) lp->lwp_sigstk.ss_flags |= SS_ONSTACK; else diff --git a/sys/platform/vkernel/i386/trap.c b/sys/platform/vkernel/i386/trap.c index b01cd0a192..6c63f77688 100644 --- a/sys/platform/vkernel/i386/trap.c +++ b/sys/platform/vkernel/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/vkernel/i386/trap.c,v 1.12 2007/01/14 07:59:05 dillon Exp $ + * $DragonFly: src/sys/platform/vkernel/i386/trap.c,v 1.13 2007/01/14 20:07:14 dillon Exp $ */ /* @@ -1402,25 +1402,37 @@ go_user(struct intrframe frame) * unit or not. */ if (mdcpu->gd_npxthread == curthread) { - tf->tf_xflags &= ~FPEX_FAULT; + tf->tf_xflags &= ~PGEX_FPFAULT; } else { - tf->tf_xflags |= FPEX_FAULT; + tf->tf_xflags |= PGEX_FPFAULT; } /* * We must poll the mailbox prior to making the system call * to properly interlock new mailbox signals against the * system call. + * + * Passing a NULL frame causes the interrupt code to assume + * the supervisor. */ if (mdcpu->gd_mailbox) - signalmailbox(&frame); + signalmailbox(NULL); /* * Run emulated user process context. This call interlocks * with new mailbox signals. + * + * Set PGEX_U unconditionally, indicating a user frame (the + * bit is normally set only by T_PAGEFLT). */ r = vmspace_ctl(&curproc->p_vmspace->vm_pmap, VMSPACE_CTL_RUN, tf, &curthread->td_savevext); + frame.if_xflags |= PGEX_U; +#if 0 + kprintf("GO USER %d trap %d EVA %08x EIP %08x ESP %08x XFLAGS %02x/%02x\n", + r, tf->tf_trapno, tf->tf_err, tf->tf_eip, tf->tf_esp, + tf->tf_xflags, frame.if_xflags); +#endif if (r < 0) { if (errno == EINTR) signalmailbox(&frame); @@ -1440,7 +1452,7 @@ go_user(struct intrframe frame) } /* - * If FPEX_FAULT is set then set FP_VIRTFP in the PCB to force a T_DNA + * If PGEX_FPFAULT is set then set FP_VIRTFP in the PCB to force a T_DNA * fault (which is then passed back to the virtual kernel) if an attempt is * made to use the FP unit. * @@ -1451,7 +1463,7 @@ set_vkernel_fp(struct trapframe *frame) { struct thread *td = curthread; - if (frame->tf_xflags & FPEX_FAULT) { + if (frame->tf_xflags & PGEX_FPFAULT) { td->td_pcb->pcb_flags |= FP_VIRTFP; if (mdcpu->gd_npxthread == td) npxexit(); diff --git a/sys/platform/vkernel/include/cpu.h b/sys/platform/vkernel/include/cpu.h new file mode 100644 index 0000000000..2396d51630 --- /dev/null +++ b/sys/platform/vkernel/include/cpu.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2006 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Matthew Dillon + * + * 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. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDERS 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/platform/vkernel/include/cpu.h,v 1.1 2007/01/14 20:07:15 dillon Exp $ + */ + +#ifndef _MACHINE_CPU_H_ +#define _MACHINE_CPU_H_ + +#include + +#define CLKF_USERMODE(framep) ((framep)->if_xflags & PGEX_U) + +#endif + diff --git a/sys/platform/vkernel/platform/systimer.c b/sys/platform/vkernel/platform/systimer.c index 96a0e3fe5e..bc9a734bae 100644 --- a/sys/platform/vkernel/platform/systimer.c +++ b/sys/platform/vkernel/platform/systimer.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/platform/vkernel/platform/systimer.c,v 1.7 2007/01/14 07:59:07 dillon Exp $ + * $DragonFly: src/sys/platform/vkernel/platform/systimer.c,v 1.8 2007/01/14 20:07:15 dillon Exp $ */ #include @@ -199,6 +199,11 @@ cputimer_intr_hard(int signo) #endif +/* + * clock interrupt. + * + * NOTE: frame is a struct intrframe pointer. + */ static void cputimer_intr(void *dummy, void *frame) @@ -219,12 +224,12 @@ cputimer_intr(void *dummy, void *frame) lwkt_send_ipiq3(gscan, (ipifunc3_t)systimer_intr, &sysclock_count, 0); } else { - systimer_intr(&sysclock_count, 0, NULL); + systimer_intr(&sysclock_count, 0, frame); } } #else if (TAILQ_FIRST(&gd->gd_systimerq) != NULL) - systimer_intr(&sysclock_count, 0, NULL); + systimer_intr(&sysclock_count, 0, frame); #endif } -- 2.41.0