MFi386: revisions 1.544 and 1.545.
This commit is contained in:
parent
1f1e884a91
commit
4b8d81b418
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user