MFi386: revisions 1.544 and 1.545.

This commit is contained in:
Yoshihiro Takahashi 2002-10-26 15:44:06 +00:00
parent 1f1e884a91
commit 4b8d81b418
2 changed files with 648 additions and 88 deletions

View File

@ -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 */
}
#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;
#else
struct vm86frame vmf;
struct vm86context vmc;
#endif
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;
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);
}

View File

@ -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 */
}
#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;
#else
struct vm86frame vmf;
struct vm86context vmc;
#endif
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;
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);
}