summaryrefslogtreecommitdiffstats
path: root/sys/pc98
diff options
context:
space:
mode:
authornyan <nyan@FreeBSD.org>2002-10-26 15:44:06 +0000
committernyan <nyan@FreeBSD.org>2002-10-26 15:44:06 +0000
commited378291663a4220caa0ab98bb28e13bb68f0cf7 (patch)
treee10660ee13d4eb28477e5335277ca6165c243419 /sys/pc98
parent0fc7234ce3c73b2147218f31cd2ab0c31ce62826 (diff)
downloadFreeBSD-src-ed378291663a4220caa0ab98bb28e13bb68f0cf7.zip
FreeBSD-src-ed378291663a4220caa0ab98bb28e13bb68f0cf7.tar.gz
MFi386: revisions 1.544 and 1.545.
Diffstat (limited to 'sys/pc98')
-rw-r--r--sys/pc98/i386/machdep.c360
-rw-r--r--sys/pc98/pc98/machdep.c360
2 files changed, 640 insertions, 80 deletions
diff --git a/sys/pc98/i386/machdep.c b/sys/pc98/i386/machdep.c
index 15ebaee..9031235 100644
--- a/sys/pc98/i386/machdep.c
+++ b/sys/pc98/i386/machdep.c
@@ -182,6 +182,10 @@ int cold = 1;
#ifdef COMPAT_43
static void osendsig(sig_t catcher, int sig, sigset_t *mask, u_long code);
#endif
+#ifdef COMPAT_FREEBSD4
+static void freebsd4_sendsig(sig_t catcher, int sig, sigset_t *mask,
+ u_long code);
+#endif
static int
sysctl_hw_physmem(SYSCTL_HANDLER_ARGS)
@@ -306,8 +310,7 @@ osendsig(catcher, sig, mask, code)
sigset_t *mask;
u_long code;
{
- struct osigframe sf;
- struct osigframe *fp;
+ struct osigframe sf, *fp;
struct proc *p;
struct thread *td;
struct sigacts *psp;
@@ -428,6 +431,129 @@ osendsig(catcher, sig, mask, code)
}
#endif /* COMPAT_43 */
+#ifdef COMPAT_FREEBSD4
+static void
+freebsd4_sendsig(catcher, sig, mask, code)
+ sig_t catcher;
+ int sig;
+ sigset_t *mask;
+ u_long code;
+{
+ struct sigframe4 sf, *sfp;
+ struct proc *p;
+ struct thread *td;
+ struct sigacts *psp;
+ struct trapframe *regs;
+ int oonstack;
+
+ td = curthread;
+ p = td->td_proc;
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ psp = p->p_sigacts;
+ regs = td->td_frame;
+ oonstack = sigonstack(regs->tf_esp);
+
+ /* Save user context. */
+ bzero(&sf, sizeof(sf));
+ sf.sf_uc.uc_sigmask = *mask;
+ sf.sf_uc.uc_stack = p->p_sigstk;
+ sf.sf_uc.uc_stack.ss_flags = (p->p_flag & P_ALTSTACK)
+ ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE;
+ sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0;
+ sf.sf_uc.uc_mcontext.mc_gs = rgs();
+ bcopy(regs, &sf.sf_uc.uc_mcontext.mc_fs, sizeof(*regs));
+
+ /* Allocate space for the signal handler context. */
+ if ((p->p_flag & P_ALTSTACK) != 0 && !oonstack &&
+ SIGISMEMBER(psp->ps_sigonstack, sig)) {
+ sfp = (struct sigframe4 *)(p->p_sigstk.ss_sp +
+ p->p_sigstk.ss_size - sizeof(struct sigframe4));
+#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
+ p->p_sigstk.ss_flags |= SS_ONSTACK;
+#endif
+ } else
+ sfp = (struct sigframe4 *)regs->tf_esp - 1;
+ PROC_UNLOCK(p);
+
+ /* Translate the signal if appropriate. */
+ if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize)
+ sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
+
+ /* Build the argument list for the signal handler. */
+ sf.sf_signum = sig;
+ sf.sf_ucontext = (register_t)&sfp->sf_uc;
+ PROC_LOCK(p);
+ if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) {
+ /* Signal handler installed with SA_SIGINFO. */
+ sf.sf_siginfo = (register_t)&sfp->sf_si;
+ sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher;
+
+ /* Fill in POSIX parts */
+ sf.sf_si.si_signo = sig;
+ sf.sf_si.si_code = code;
+ sf.sf_si.si_addr = (void *)regs->tf_err;
+ sf.sf_si.si_pid = p->p_pid;
+ sf.sf_si.si_uid = p->p_ucred->cr_uid;
+ } else {
+ /* Old FreeBSD-style arguments. */
+ sf.sf_siginfo = code;
+ sf.sf_addr = regs->tf_err;
+ sf.sf_ahu.sf_handler = catcher;
+ }
+ PROC_UNLOCK(p);
+
+ /*
+ * If we're a vm86 process, we want to save the segment registers.
+ * We also change eflags to be our emulated eflags, not the actual
+ * eflags.
+ */
+ if (regs->tf_eflags & PSL_VM) {
+ struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
+ struct vm86_kernel *vm86 = &td->td_pcb->pcb_ext->ext_vm86;
+
+ sf.sf_uc.uc_mcontext.mc_gs = tf->tf_vm86_gs;
+ sf.sf_uc.uc_mcontext.mc_fs = tf->tf_vm86_fs;
+ sf.sf_uc.uc_mcontext.mc_es = tf->tf_vm86_es;
+ sf.sf_uc.uc_mcontext.mc_ds = tf->tf_vm86_ds;
+
+ if (vm86->vm86_has_vme == 0)
+ sf.sf_uc.uc_mcontext.mc_eflags =
+ (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) |
+ (vm86->vm86_eflags & (PSL_VIF | PSL_VIP));
+
+ /*
+ * Clear PSL_NT to inhibit T_TSSFLT faults on return from
+ * syscalls made by the signal handler. This just avoids
+ * wasting time for our lazy fixup of such faults. PSL_NT
+ * does nothing in vm86 mode, but vm86 programs can set it
+ * almost legitimately in probes for old cpu types.
+ */
+ tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_VIF | PSL_VIP);
+ }
+
+ /*
+ * Copy the sigframe out to the user's stack.
+ */
+ if (copyout(&sf, sfp, sizeof(*sfp)) != 0) {
+#ifdef DEBUG
+ printf("process %ld has trashed its stack\n", (long)p->p_pid);
+#endif
+ PROC_LOCK(p);
+ sigexit(td, SIGILL);
+ }
+
+ regs->tf_esp = (int)sfp;
+ regs->tf_eip = PS_STRINGS - szfreebsd4_sigcode;
+ regs->tf_eflags &= ~PSL_T;
+ regs->tf_cs = _ucodesel;
+ regs->tf_ds = _udatasel;
+ regs->tf_es = _udatasel;
+ regs->tf_fs = _udatasel;
+ regs->tf_ss = _udatasel;
+ PROC_LOCK(p);
+}
+#endif /* COMPAT_FREEBSD4 */
+
void
sendsig(catcher, sig, mask, code)
sig_t catcher;
@@ -435,18 +561,23 @@ sendsig(catcher, sig, mask, code)
sigset_t *mask;
u_long code;
{
- struct sigframe sf;
+ struct sigframe sf, *sfp;
struct proc *p;
struct thread *td;
struct sigacts *psp;
struct trapframe *regs;
- struct sigframe *sfp;
int oonstack;
td = curthread;
p = td->td_proc;
PROC_LOCK_ASSERT(p, MA_OWNED);
psp = p->p_sigacts;
+#ifdef COMPAT_FREEBSD4
+ if (SIGISMEMBER(psp->ps_freebsd4, sig)) {
+ freebsd4_sendsig(catcher, sig, mask, code);
+ return;
+ }
+#endif
#ifdef COMPAT_43
if (SIGISMEMBER(psp->ps_osigset, sig)) {
osendsig(catcher, sig, mask, code);
@@ -570,6 +701,7 @@ sendsig(catcher, sig, mask, code)
*
* MPSAFE
*/
+#ifdef COMPAT_43
int
osigreturn(td, uap)
struct thread *td;
@@ -577,7 +709,6 @@ osigreturn(td, uap)
struct osigcontext *sigcntxp;
} */ *uap;
{
-#ifdef COMPAT_43
struct osigcontext sc;
struct trapframe *regs;
struct osigcontext *scp;
@@ -682,10 +813,116 @@ osigreturn(td, uap)
signotify(p);
PROC_UNLOCK(p);
return (EJUSTRETURN);
-#else /* !COMPAT_43 */
- return (ENOSYS);
+}
#endif /* COMPAT_43 */
+
+#ifdef COMPAT_FREEBSD4
+/*
+ * MPSAFE
+ */
+int
+freebsd4_sigreturn(td, uap)
+ struct thread *td;
+ struct freebsd4_sigreturn_args /* {
+ const ucontext4 *sigcntxp;
+ } */ *uap;
+{
+ struct ucontext4 uc;
+ struct proc *p = td->td_proc;
+ struct trapframe *regs;
+ const struct ucontext4 *ucp;
+ int cs, eflags, error;
+
+ error = copyin(uap->sigcntxp, &uc, sizeof(uc));
+ if (error != 0)
+ return (error);
+ ucp = &uc;
+ regs = td->td_frame;
+ eflags = ucp->uc_mcontext.mc_eflags;
+ if (eflags & PSL_VM) {
+ struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
+ struct vm86_kernel *vm86;
+
+ /*
+ * if pcb_ext == 0 or vm86_inited == 0, the user hasn't
+ * set up the vm86 area, and we can't enter vm86 mode.
+ */
+ if (td->td_pcb->pcb_ext == 0)
+ return (EINVAL);
+ vm86 = &td->td_pcb->pcb_ext->ext_vm86;
+ if (vm86->vm86_inited == 0)
+ return (EINVAL);
+
+ /* Go back to user mode if both flags are set. */
+ if ((eflags & PSL_VIP) && (eflags & PSL_VIF))
+ trapsignal(p, SIGBUS, 0);
+
+ if (vm86->vm86_has_vme) {
+ eflags = (tf->tf_eflags & ~VME_USERCHANGE) |
+ (eflags & VME_USERCHANGE) | PSL_VM;
+ } else {
+ vm86->vm86_eflags = eflags; /* save VIF, VIP */
+ eflags = (tf->tf_eflags & ~VM_USERCHANGE) |
+ (eflags & VM_USERCHANGE) | PSL_VM;
+ }
+ bcopy(&ucp->uc_mcontext.mc_fs, tf, sizeof(struct trapframe));
+ tf->tf_eflags = eflags;
+ tf->tf_vm86_ds = tf->tf_ds;
+ tf->tf_vm86_es = tf->tf_es;
+ tf->tf_vm86_fs = tf->tf_fs;
+ tf->tf_vm86_gs = ucp->uc_mcontext.mc_gs;
+ tf->tf_ds = _udatasel;
+ tf->tf_es = _udatasel;
+ tf->tf_fs = _udatasel;
+ } else {
+ /*
+ * Don't allow users to change privileged or reserved flags.
+ */
+ /*
+ * XXX do allow users to change the privileged flag PSL_RF.
+ * The cpu sets PSL_RF in tf_eflags for faults. Debuggers
+ * should sometimes set it there too. tf_eflags is kept in
+ * the signal context during signal handling and there is no
+ * other place to remember it, so the PSL_RF bit may be
+ * corrupted by the signal handler without us knowing.
+ * Corruption of the PSL_RF bit at worst causes one more or
+ * one less debugger trap, so allowing it is fairly harmless.
+ */
+ if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) {
+ printf("freebsd4_sigreturn: eflags = 0x%x\n", eflags);
+ return (EINVAL);
+ }
+
+ /*
+ * Don't allow users to load a valid privileged %cs. Let the
+ * hardware check for invalid selectors, excess privilege in
+ * other selectors, invalid %eip's and invalid %esp's.
+ */
+ cs = ucp->uc_mcontext.mc_cs;
+ if (!CS_SECURE(cs)) {
+ printf("freebsd4_sigreturn: cs = 0x%x\n", cs);
+ trapsignal(p, SIGBUS, T_PROTFLT);
+ return (EINVAL);
+ }
+
+ bcopy(&ucp->uc_mcontext.mc_fs, regs, sizeof(*regs));
+ }
+
+ PROC_LOCK(p);
+#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
+ if (ucp->uc_mcontext.mc_onstack & 1)
+ p->p_sigstk.ss_flags |= SS_ONSTACK;
+ else
+ p->p_sigstk.ss_flags &= ~SS_ONSTACK;
+#endif
+
+ p->p_sigmask = ucp->uc_sigmask;
+ SIG_CANTMASK(p->p_sigmask);
+ signotify(p);
+ PROC_UNLOCK(p);
+ return (EJUSTRETURN);
}
+#endif /* COMPAT_FREEBSD4 */
/*
* MPSAFE
@@ -1290,19 +1527,20 @@ sdtossd(sd, ssd)
static void
getmemsize(int first)
{
- int i, physmap_idx, pa_indx;
- u_int basemem, extmem;
#ifdef PC98
- int pg_n;
- u_int under16;
+ int i, physmap_idx, pa_indx, pg_n;
+ u_int basemem, extmem, under16;
+ vm_offset_t pa, physmap[PHYSMAP_SIZE];
+ pt_entry_t *pte;
+ char *cp;
#else
+ int i, physmap_idx, pa_indx;
+ u_int basemem, extmem;
struct vm86frame vmf;
struct vm86context vmc;
-#endif
vm_offset_t pa, physmap[PHYSMAP_SIZE];
pt_entry_t *pte;
char *cp;
-#ifndef PC98
struct bios_smap *smap;
#endif
@@ -1321,20 +1559,12 @@ getmemsize(int first)
break;
}
}
-#else
- bzero(&vmf, sizeof(struct vm86frame));
-#endif
bzero(physmap, sizeof(physmap));
/*
* Perform "base memory" related probes & setup
*/
-#ifdef PC98
under16 = pc98_getmemsize(&basemem, &extmem);
-#else
- vm86_intcall(0x12, &vmf);
- basemem = vmf.vmf_ax;
-#endif
if (basemem > 640) {
printf("Preposterous BIOS basemem of %uK, truncating to 640K\n",
basemem);
@@ -1373,7 +1603,12 @@ getmemsize(int first)
for (i = basemem / 4; i < 160; i++)
pte[i] = (i << PAGE_SHIFT) | PG_V | PG_RW | PG_U;
-#ifndef PC98
+#else /* PC98 */
+
+ bzero(&vmf, sizeof(struct vm86frame));
+ bzero(physmap, sizeof(physmap));
+ basemem = 0;
+
/*
* map page 1 R/W into the kernel page table so we can use it
* as a buffer. The kernel will unmap this page later.
@@ -1441,6 +1676,60 @@ getmemsize(int first)
next_run: ;
} while (vmf.vmf_ebx != 0);
+ /*
+ * Perform "base memory" related probes & setup
+ */
+ for (i = 0; i <= physmap_idx; i += 2) {
+ if (physmap[i] == 0x00000000) {
+ basemem = physmap[i + 1] / 1024;
+ break;
+ }
+ }
+
+ /* Fall back to the old compatibility function for base memory */
+ if (basemem == 0) {
+ vm86_intcall(0x12, &vmf);
+ basemem = vmf.vmf_ax;
+ }
+
+ if (basemem > 640) {
+ printf("Preposterous BIOS basemem of %uK, truncating to 640K\n",
+ basemem);
+ basemem = 640;
+ }
+
+ /*
+ * XXX if biosbasemem is now < 640, there is a `hole'
+ * between the end of base memory and the start of
+ * ISA memory. The hole may be empty or it may
+ * contain BIOS code or data. Map it read/write so
+ * that the BIOS can write to it. (Memory from 0 to
+ * the physical end of the kernel is mapped read-only
+ * to begin with and then parts of it are remapped.
+ * The parts that aren't remapped form holes that
+ * remain read-only and are unused by the kernel.
+ * The base memory area is below the physical end of
+ * the kernel and right now forms a read-only hole.
+ * The part of it from PAGE_SIZE to
+ * (trunc_page(biosbasemem * 1024) - 1) will be
+ * remapped and used by the kernel later.)
+ *
+ * This code is similar to the code used in
+ * pmap_mapdev, but since no memory needs to be
+ * allocated we simply change the mapping.
+ */
+ for (pa = trunc_page(basemem * 1024);
+ pa < ISA_HOLE_START; pa += PAGE_SIZE)
+ pmap_kenter(KERNBASE + pa, pa);
+
+ /*
+ * if basemem != 640, map pages r/w into vm86 page table so
+ * that the bios can scribble on it.
+ */
+ pte = (pt_entry_t *)vm86paddr;
+ for (i = basemem / 4; i < 160; i++)
+ pte[i] = (i << PAGE_SHIFT) | PG_V | PG_RW | PG_U;
+
if (physmap[1] != 0)
goto physmap_done;
@@ -1475,7 +1764,7 @@ next_run: ;
*/
if ((extmem > 15 * 1024) && (extmem < 16 * 1024))
extmem = 15 * 1024;
-#endif
+#endif /* PC98 */
physmap[0] = 0;
physmap[1] = basemem * 1024;
@@ -2221,7 +2510,7 @@ get_fpcontext(struct thread *td, mcontext_t *mcp)
#ifndef DEV_NPX
mcp->mc_fpformat = _MC_FPFMT_NODEV;
mcp->mc_ownedfp = _MC_FPOWNED_NONE;
-#else /* DEV_NPX */
+#else
union savefpu *addr;
/*
@@ -2251,9 +2540,8 @@ get_fpcontext(struct thread *td, mcontext_t *mcp)
bcopy(addr, &mcp->mc_fpstate, sizeof(mcp->mc_fpstate));
bzero(&mcp->mc_spare2, sizeof(mcp->mc_spare2));
}
- bcopy(&mcp->mc_fpstate, &td->td_pcb->pcb_save, sizeof(mcp->mc_fpstate));
mcp->mc_fpformat = npxformat();
-#endif /* !DEV_NPX */
+#endif
}
static int
@@ -2263,7 +2551,10 @@ set_fpcontext(struct thread *td, const mcontext_t *mcp)
if (mcp->mc_fpformat == _MC_FPFMT_NODEV)
return (0);
- if (mcp->mc_ownedfp == _MC_FPOWNED_NONE)
+ else if (mcp->mc_fpformat != _MC_FPFMT_387 &&
+ mcp->mc_fpformat != _MC_FPFMT_XMM)
+ return (EINVAL);
+ else if (mcp->mc_ownedfp == _MC_FPOWNED_NONE)
/* We don't care what state is left in the FPU or PCB. */
fpstate_drop(td);
else if (mcp->mc_ownedfp == _MC_FPOWNED_FPU ||
@@ -2286,25 +2577,14 @@ set_fpcontext(struct thread *td, const mcontext_t *mcp)
* be called with interrupts disabled.
*/
npxsetregs(td, addr);
+#endif
/*
* Don't bother putting things back where they were in the
* misaligned case, since we know that the caller won't use
* them again.
*/
- } else {
- /*
- * There is no valid FPU state in *mcp, so use the saved
- * state in the PCB if there is one. XXX the test for
- * whether there is one seems to be quite broken. We
- * forcibly drop the state in sendsig().
- */
- if ((td->td_pcb->pcb_flags & PCB_NPXINITDONE) != 0)
- npxsetregs(td, &td->td_pcb->pcb_save);
-#endif
-#if !defined(COMPAT_FREEBSD4) && !defined(COMPAT_43)
+ } else
return (EINVAL);
-#endif
- }
return (0);
}
diff --git a/sys/pc98/pc98/machdep.c b/sys/pc98/pc98/machdep.c
index 15ebaee..9031235 100644
--- a/sys/pc98/pc98/machdep.c
+++ b/sys/pc98/pc98/machdep.c
@@ -182,6 +182,10 @@ int cold = 1;
#ifdef COMPAT_43
static void osendsig(sig_t catcher, int sig, sigset_t *mask, u_long code);
#endif
+#ifdef COMPAT_FREEBSD4
+static void freebsd4_sendsig(sig_t catcher, int sig, sigset_t *mask,
+ u_long code);
+#endif
static int
sysctl_hw_physmem(SYSCTL_HANDLER_ARGS)
@@ -306,8 +310,7 @@ osendsig(catcher, sig, mask, code)
sigset_t *mask;
u_long code;
{
- struct osigframe sf;
- struct osigframe *fp;
+ struct osigframe sf, *fp;
struct proc *p;
struct thread *td;
struct sigacts *psp;
@@ -428,6 +431,129 @@ osendsig(catcher, sig, mask, code)
}
#endif /* COMPAT_43 */
+#ifdef COMPAT_FREEBSD4
+static void
+freebsd4_sendsig(catcher, sig, mask, code)
+ sig_t catcher;
+ int sig;
+ sigset_t *mask;
+ u_long code;
+{
+ struct sigframe4 sf, *sfp;
+ struct proc *p;
+ struct thread *td;
+ struct sigacts *psp;
+ struct trapframe *regs;
+ int oonstack;
+
+ td = curthread;
+ p = td->td_proc;
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ psp = p->p_sigacts;
+ regs = td->td_frame;
+ oonstack = sigonstack(regs->tf_esp);
+
+ /* Save user context. */
+ bzero(&sf, sizeof(sf));
+ sf.sf_uc.uc_sigmask = *mask;
+ sf.sf_uc.uc_stack = p->p_sigstk;
+ sf.sf_uc.uc_stack.ss_flags = (p->p_flag & P_ALTSTACK)
+ ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE;
+ sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0;
+ sf.sf_uc.uc_mcontext.mc_gs = rgs();
+ bcopy(regs, &sf.sf_uc.uc_mcontext.mc_fs, sizeof(*regs));
+
+ /* Allocate space for the signal handler context. */
+ if ((p->p_flag & P_ALTSTACK) != 0 && !oonstack &&
+ SIGISMEMBER(psp->ps_sigonstack, sig)) {
+ sfp = (struct sigframe4 *)(p->p_sigstk.ss_sp +
+ p->p_sigstk.ss_size - sizeof(struct sigframe4));
+#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
+ p->p_sigstk.ss_flags |= SS_ONSTACK;
+#endif
+ } else
+ sfp = (struct sigframe4 *)regs->tf_esp - 1;
+ PROC_UNLOCK(p);
+
+ /* Translate the signal if appropriate. */
+ if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize)
+ sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
+
+ /* Build the argument list for the signal handler. */
+ sf.sf_signum = sig;
+ sf.sf_ucontext = (register_t)&sfp->sf_uc;
+ PROC_LOCK(p);
+ if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) {
+ /* Signal handler installed with SA_SIGINFO. */
+ sf.sf_siginfo = (register_t)&sfp->sf_si;
+ sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher;
+
+ /* Fill in POSIX parts */
+ sf.sf_si.si_signo = sig;
+ sf.sf_si.si_code = code;
+ sf.sf_si.si_addr = (void *)regs->tf_err;
+ sf.sf_si.si_pid = p->p_pid;
+ sf.sf_si.si_uid = p->p_ucred->cr_uid;
+ } else {
+ /* Old FreeBSD-style arguments. */
+ sf.sf_siginfo = code;
+ sf.sf_addr = regs->tf_err;
+ sf.sf_ahu.sf_handler = catcher;
+ }
+ PROC_UNLOCK(p);
+
+ /*
+ * If we're a vm86 process, we want to save the segment registers.
+ * We also change eflags to be our emulated eflags, not the actual
+ * eflags.
+ */
+ if (regs->tf_eflags & PSL_VM) {
+ struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
+ struct vm86_kernel *vm86 = &td->td_pcb->pcb_ext->ext_vm86;
+
+ sf.sf_uc.uc_mcontext.mc_gs = tf->tf_vm86_gs;
+ sf.sf_uc.uc_mcontext.mc_fs = tf->tf_vm86_fs;
+ sf.sf_uc.uc_mcontext.mc_es = tf->tf_vm86_es;
+ sf.sf_uc.uc_mcontext.mc_ds = tf->tf_vm86_ds;
+
+ if (vm86->vm86_has_vme == 0)
+ sf.sf_uc.uc_mcontext.mc_eflags =
+ (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) |
+ (vm86->vm86_eflags & (PSL_VIF | PSL_VIP));
+
+ /*
+ * Clear PSL_NT to inhibit T_TSSFLT faults on return from
+ * syscalls made by the signal handler. This just avoids
+ * wasting time for our lazy fixup of such faults. PSL_NT
+ * does nothing in vm86 mode, but vm86 programs can set it
+ * almost legitimately in probes for old cpu types.
+ */
+ tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_VIF | PSL_VIP);
+ }
+
+ /*
+ * Copy the sigframe out to the user's stack.
+ */
+ if (copyout(&sf, sfp, sizeof(*sfp)) != 0) {
+#ifdef DEBUG
+ printf("process %ld has trashed its stack\n", (long)p->p_pid);
+#endif
+ PROC_LOCK(p);
+ sigexit(td, SIGILL);
+ }
+
+ regs->tf_esp = (int)sfp;
+ regs->tf_eip = PS_STRINGS - szfreebsd4_sigcode;
+ regs->tf_eflags &= ~PSL_T;
+ regs->tf_cs = _ucodesel;
+ regs->tf_ds = _udatasel;
+ regs->tf_es = _udatasel;
+ regs->tf_fs = _udatasel;
+ regs->tf_ss = _udatasel;
+ PROC_LOCK(p);
+}
+#endif /* COMPAT_FREEBSD4 */
+
void
sendsig(catcher, sig, mask, code)
sig_t catcher;
@@ -435,18 +561,23 @@ sendsig(catcher, sig, mask, code)
sigset_t *mask;
u_long code;
{
- struct sigframe sf;
+ struct sigframe sf, *sfp;
struct proc *p;
struct thread *td;
struct sigacts *psp;
struct trapframe *regs;
- struct sigframe *sfp;
int oonstack;
td = curthread;
p = td->td_proc;
PROC_LOCK_ASSERT(p, MA_OWNED);
psp = p->p_sigacts;
+#ifdef COMPAT_FREEBSD4
+ if (SIGISMEMBER(psp->ps_freebsd4, sig)) {
+ freebsd4_sendsig(catcher, sig, mask, code);
+ return;
+ }
+#endif
#ifdef COMPAT_43
if (SIGISMEMBER(psp->ps_osigset, sig)) {
osendsig(catcher, sig, mask, code);
@@ -570,6 +701,7 @@ sendsig(catcher, sig, mask, code)
*
* MPSAFE
*/
+#ifdef COMPAT_43
int
osigreturn(td, uap)
struct thread *td;
@@ -577,7 +709,6 @@ osigreturn(td, uap)
struct osigcontext *sigcntxp;
} */ *uap;
{
-#ifdef COMPAT_43
struct osigcontext sc;
struct trapframe *regs;
struct osigcontext *scp;
@@ -682,10 +813,116 @@ osigreturn(td, uap)
signotify(p);
PROC_UNLOCK(p);
return (EJUSTRETURN);
-#else /* !COMPAT_43 */
- return (ENOSYS);
+}
#endif /* COMPAT_43 */
+
+#ifdef COMPAT_FREEBSD4
+/*
+ * MPSAFE
+ */
+int
+freebsd4_sigreturn(td, uap)
+ struct thread *td;
+ struct freebsd4_sigreturn_args /* {
+ const ucontext4 *sigcntxp;
+ } */ *uap;
+{
+ struct ucontext4 uc;
+ struct proc *p = td->td_proc;
+ struct trapframe *regs;
+ const struct ucontext4 *ucp;
+ int cs, eflags, error;
+
+ error = copyin(uap->sigcntxp, &uc, sizeof(uc));
+ if (error != 0)
+ return (error);
+ ucp = &uc;
+ regs = td->td_frame;
+ eflags = ucp->uc_mcontext.mc_eflags;
+ if (eflags & PSL_VM) {
+ struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
+ struct vm86_kernel *vm86;
+
+ /*
+ * if pcb_ext == 0 or vm86_inited == 0, the user hasn't
+ * set up the vm86 area, and we can't enter vm86 mode.
+ */
+ if (td->td_pcb->pcb_ext == 0)
+ return (EINVAL);
+ vm86 = &td->td_pcb->pcb_ext->ext_vm86;
+ if (vm86->vm86_inited == 0)
+ return (EINVAL);
+
+ /* Go back to user mode if both flags are set. */
+ if ((eflags & PSL_VIP) && (eflags & PSL_VIF))
+ trapsignal(p, SIGBUS, 0);
+
+ if (vm86->vm86_has_vme) {
+ eflags = (tf->tf_eflags & ~VME_USERCHANGE) |
+ (eflags & VME_USERCHANGE) | PSL_VM;
+ } else {
+ vm86->vm86_eflags = eflags; /* save VIF, VIP */
+ eflags = (tf->tf_eflags & ~VM_USERCHANGE) |
+ (eflags & VM_USERCHANGE) | PSL_VM;
+ }
+ bcopy(&ucp->uc_mcontext.mc_fs, tf, sizeof(struct trapframe));
+ tf->tf_eflags = eflags;
+ tf->tf_vm86_ds = tf->tf_ds;
+ tf->tf_vm86_es = tf->tf_es;
+ tf->tf_vm86_fs = tf->tf_fs;
+ tf->tf_vm86_gs = ucp->uc_mcontext.mc_gs;
+ tf->tf_ds = _udatasel;
+ tf->tf_es = _udatasel;
+ tf->tf_fs = _udatasel;
+ } else {
+ /*
+ * Don't allow users to change privileged or reserved flags.
+ */
+ /*
+ * XXX do allow users to change the privileged flag PSL_RF.
+ * The cpu sets PSL_RF in tf_eflags for faults. Debuggers
+ * should sometimes set it there too. tf_eflags is kept in
+ * the signal context during signal handling and there is no
+ * other place to remember it, so the PSL_RF bit may be
+ * corrupted by the signal handler without us knowing.
+ * Corruption of the PSL_RF bit at worst causes one more or
+ * one less debugger trap, so allowing it is fairly harmless.
+ */
+ if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) {
+ printf("freebsd4_sigreturn: eflags = 0x%x\n", eflags);
+ return (EINVAL);
+ }
+
+ /*
+ * Don't allow users to load a valid privileged %cs. Let the
+ * hardware check for invalid selectors, excess privilege in
+ * other selectors, invalid %eip's and invalid %esp's.
+ */
+ cs = ucp->uc_mcontext.mc_cs;
+ if (!CS_SECURE(cs)) {
+ printf("freebsd4_sigreturn: cs = 0x%x\n", cs);
+ trapsignal(p, SIGBUS, T_PROTFLT);
+ return (EINVAL);
+ }
+
+ bcopy(&ucp->uc_mcontext.mc_fs, regs, sizeof(*regs));
+ }
+
+ PROC_LOCK(p);
+#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
+ if (ucp->uc_mcontext.mc_onstack & 1)
+ p->p_sigstk.ss_flags |= SS_ONSTACK;
+ else
+ p->p_sigstk.ss_flags &= ~SS_ONSTACK;
+#endif
+
+ p->p_sigmask = ucp->uc_sigmask;
+ SIG_CANTMASK(p->p_sigmask);
+ signotify(p);
+ PROC_UNLOCK(p);
+ return (EJUSTRETURN);
}
+#endif /* COMPAT_FREEBSD4 */
/*
* MPSAFE
@@ -1290,19 +1527,20 @@ sdtossd(sd, ssd)
static void
getmemsize(int first)
{
- int i, physmap_idx, pa_indx;
- u_int basemem, extmem;
#ifdef PC98
- int pg_n;
- u_int under16;
+ int i, physmap_idx, pa_indx, pg_n;
+ u_int basemem, extmem, under16;
+ vm_offset_t pa, physmap[PHYSMAP_SIZE];
+ pt_entry_t *pte;
+ char *cp;
#else
+ int i, physmap_idx, pa_indx;
+ u_int basemem, extmem;
struct vm86frame vmf;
struct vm86context vmc;
-#endif
vm_offset_t pa, physmap[PHYSMAP_SIZE];
pt_entry_t *pte;
char *cp;
-#ifndef PC98
struct bios_smap *smap;
#endif
@@ -1321,20 +1559,12 @@ getmemsize(int first)
break;
}
}
-#else
- bzero(&vmf, sizeof(struct vm86frame));
-#endif
bzero(physmap, sizeof(physmap));
/*
* Perform "base memory" related probes & setup
*/
-#ifdef PC98
under16 = pc98_getmemsize(&basemem, &extmem);
-#else
- vm86_intcall(0x12, &vmf);
- basemem = vmf.vmf_ax;
-#endif
if (basemem > 640) {
printf("Preposterous BIOS basemem of %uK, truncating to 640K\n",
basemem);
@@ -1373,7 +1603,12 @@ getmemsize(int first)
for (i = basemem / 4; i < 160; i++)
pte[i] = (i << PAGE_SHIFT) | PG_V | PG_RW | PG_U;
-#ifndef PC98
+#else /* PC98 */
+
+ bzero(&vmf, sizeof(struct vm86frame));
+ bzero(physmap, sizeof(physmap));
+ basemem = 0;
+
/*
* map page 1 R/W into the kernel page table so we can use it
* as a buffer. The kernel will unmap this page later.
@@ -1441,6 +1676,60 @@ getmemsize(int first)
next_run: ;
} while (vmf.vmf_ebx != 0);
+ /*
+ * Perform "base memory" related probes & setup
+ */
+ for (i = 0; i <= physmap_idx; i += 2) {
+ if (physmap[i] == 0x00000000) {
+ basemem = physmap[i + 1] / 1024;
+ break;
+ }
+ }
+
+ /* Fall back to the old compatibility function for base memory */
+ if (basemem == 0) {
+ vm86_intcall(0x12, &vmf);
+ basemem = vmf.vmf_ax;
+ }
+
+ if (basemem > 640) {
+ printf("Preposterous BIOS basemem of %uK, truncating to 640K\n",
+ basemem);
+ basemem = 640;
+ }
+
+ /*
+ * XXX if biosbasemem is now < 640, there is a `hole'
+ * between the end of base memory and the start of
+ * ISA memory. The hole may be empty or it may
+ * contain BIOS code or data. Map it read/write so
+ * that the BIOS can write to it. (Memory from 0 to
+ * the physical end of the kernel is mapped read-only
+ * to begin with and then parts of it are remapped.
+ * The parts that aren't remapped form holes that
+ * remain read-only and are unused by the kernel.
+ * The base memory area is below the physical end of
+ * the kernel and right now forms a read-only hole.
+ * The part of it from PAGE_SIZE to
+ * (trunc_page(biosbasemem * 1024) - 1) will be
+ * remapped and used by the kernel later.)
+ *
+ * This code is similar to the code used in
+ * pmap_mapdev, but since no memory needs to be
+ * allocated we simply change the mapping.
+ */
+ for (pa = trunc_page(basemem * 1024);
+ pa < ISA_HOLE_START; pa += PAGE_SIZE)
+ pmap_kenter(KERNBASE + pa, pa);
+
+ /*
+ * if basemem != 640, map pages r/w into vm86 page table so
+ * that the bios can scribble on it.
+ */
+ pte = (pt_entry_t *)vm86paddr;
+ for (i = basemem / 4; i < 160; i++)
+ pte[i] = (i << PAGE_SHIFT) | PG_V | PG_RW | PG_U;
+
if (physmap[1] != 0)
goto physmap_done;
@@ -1475,7 +1764,7 @@ next_run: ;
*/
if ((extmem > 15 * 1024) && (extmem < 16 * 1024))
extmem = 15 * 1024;
-#endif
+#endif /* PC98 */
physmap[0] = 0;
physmap[1] = basemem * 1024;
@@ -2221,7 +2510,7 @@ get_fpcontext(struct thread *td, mcontext_t *mcp)
#ifndef DEV_NPX
mcp->mc_fpformat = _MC_FPFMT_NODEV;
mcp->mc_ownedfp = _MC_FPOWNED_NONE;
-#else /* DEV_NPX */
+#else
union savefpu *addr;
/*
@@ -2251,9 +2540,8 @@ get_fpcontext(struct thread *td, mcontext_t *mcp)
bcopy(addr, &mcp->mc_fpstate, sizeof(mcp->mc_fpstate));
bzero(&mcp->mc_spare2, sizeof(mcp->mc_spare2));
}
- bcopy(&mcp->mc_fpstate, &td->td_pcb->pcb_save, sizeof(mcp->mc_fpstate));
mcp->mc_fpformat = npxformat();
-#endif /* !DEV_NPX */
+#endif
}
static int
@@ -2263,7 +2551,10 @@ set_fpcontext(struct thread *td, const mcontext_t *mcp)
if (mcp->mc_fpformat == _MC_FPFMT_NODEV)
return (0);
- if (mcp->mc_ownedfp == _MC_FPOWNED_NONE)
+ else if (mcp->mc_fpformat != _MC_FPFMT_387 &&
+ mcp->mc_fpformat != _MC_FPFMT_XMM)
+ return (EINVAL);
+ else if (mcp->mc_ownedfp == _MC_FPOWNED_NONE)
/* We don't care what state is left in the FPU or PCB. */
fpstate_drop(td);
else if (mcp->mc_ownedfp == _MC_FPOWNED_FPU ||
@@ -2286,25 +2577,14 @@ set_fpcontext(struct thread *td, const mcontext_t *mcp)
* be called with interrupts disabled.
*/
npxsetregs(td, addr);
+#endif
/*
* Don't bother putting things back where they were in the
* misaligned case, since we know that the caller won't use
* them again.
*/
- } else {
- /*
- * There is no valid FPU state in *mcp, so use the saved
- * state in the PCB if there is one. XXX the test for
- * whether there is one seems to be quite broken. We
- * forcibly drop the state in sendsig().
- */
- if ((td->td_pcb->pcb_flags & PCB_NPXINITDONE) != 0)
- npxsetregs(td, &td->td_pcb->pcb_save);
-#endif
-#if !defined(COMPAT_FREEBSD4) && !defined(COMPAT_43)
+ } else
return (EINVAL);
-#endif
- }
return (0);
}
OpenPOWER on IntegriCloud