Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/compat/linux/arch/i386/linux_machdep.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/compat/linux/arch/i386/linux_machdep.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.62 retrieving revision 1.62.2.8 diff -u -p -r1.62 -r1.62.2.8 --- src/sys/compat/linux/arch/i386/linux_machdep.c 2001/01/26 19:41:52 1.62 +++ src/sys/compat/linux/arch/i386/linux_machdep.c 2002/04/17 00:04:57 1.62.2.8 @@ -1,4 +1,4 @@ -/* $NetBSD: linux_machdep.c,v 1.62 2001/01/26 19:41:52 manu Exp $ */ +/* $NetBSD: linux_machdep.c,v 1.62.2.8 2002/04/17 00:04:57 nathanw Exp $ */ /*- * Copyright (c) 1995, 2000 The NetBSD Foundation, Inc. @@ -36,7 +36,10 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#if defined(KERNEL) && !defined(_LKM) +#include +__KERNEL_RCSID(0, "$NetBSD: linux_machdep.c,v 1.62.2.8 2002/04/17 00:04:57 nathanw Exp $"); + +#if defined(_KERNEL_OPT) #include "opt_vm86.h" #include "opt_user_ldt.h" #endif @@ -46,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -90,25 +94,31 @@ /* * To see whether wscons is configured (for virtual console ioctl calls). */ -#if defined(_KERNEL) && !defined(_LKM) +#if defined(_KERNEL_OPT) #include "wsdisplay.h" #endif #if (NWSDISPLAY > 0) #include #include -#if defined(_KERNEL) && !defined(_LKM) +#if defined(_KERNEL_OPT) #include "opt_xserver.h" #endif #endif #ifdef USER_LDT #include -int linux_read_ldt __P((struct proc *, struct linux_sys_modify_ldt_args *, +int linux_read_ldt __P((struct lwp *, struct linux_sys_modify_ldt_args *, register_t *)); -int linux_write_ldt __P((struct proc *, struct linux_sys_modify_ldt_args *, +int linux_write_ldt __P((struct lwp *, struct linux_sys_modify_ldt_args *, register_t *)); #endif +#ifdef DEBUG_LINUX +#define DPRINTF(a) uprintf a +#else +#define DPRINTF(a) +#endif + static struct biosdisk_info *fd2biosinfo __P((struct proc *, struct file *)); extern struct disklist *i386_alldisks; extern const char *findblkname __P((int)); @@ -118,15 +128,50 @@ extern const char *findblkname __P((int) */ void -linux_setregs(p, epp, stack) - struct proc *p; +linux_setregs(l, epp, stack) + struct lwp *l; struct exec_package *epp; u_long stack; { - struct pcb *pcb = &p->p_addr->u_pcb; + struct pcb *pcb = &l->l_addr->u_pcb; + struct trapframe *tf; + +#if NNPX > 0 + /* If we were using the FPU, forget about it. */ + if (npxproc == l) + npxdrop(); +#endif + +#ifdef USER_LDT + pmap_ldt_cleanup(l); +#endif - setregs(p, epp, stack); - pcb->pcb_savefpu.sv_env.en_cw = __Linux_NPXCW__; + l->l_md.md_flags &= ~MDP_USEDFPU; + pcb->pcb_flags = 0; + + if (i386_use_fxsave) { + pcb->pcb_savefpu.sv_xmm.sv_env.en_cw = __Linux_NPXCW__; + pcb->pcb_savefpu.sv_xmm.sv_env.en_mxcsr = __INITIAL_MXCSR__; + } else + pcb->pcb_savefpu.sv_87.sv_env.en_cw = __Linux_NPXCW__; + + tf = l->l_md.md_regs; + tf->tf_gs = GSEL(GUDATA_SEL, SEL_UPL); + tf->tf_fs = GSEL(GUDATA_SEL, SEL_UPL); + tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL); + tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL); + tf->tf_edi = 0; + tf->tf_esi = 0; + tf->tf_ebp = 0; + tf->tf_ebx = (int)l->l_proc->p_psstr; + tf->tf_edx = 0; + tf->tf_ecx = 0; + tf->tf_eax = 0; + tf->tf_eip = epp->ep_entry; + tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL); + tf->tf_eflags = PSL_USERSET; + tf->tf_esp = stack; + tf->tf_ss = GSEL(GUDATA_SEL, SEL_UPL); } /* @@ -147,20 +192,29 @@ linux_sendsig(catcher, sig, mask, code) sigset_t *mask; u_long code; { - struct proc *p = curproc; + struct lwp *l = curproc; + struct proc *p = l->l_proc; struct trapframe *tf; struct linux_sigframe *fp, frame; + int onstack; - tf = p->p_md.md_regs; + tf = l->l_md.md_regs; + /* Do we need to jump onto the signal stack? */ + onstack = + (p->p_sigctx.ps_sigstk.ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 && + (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0; /* Allocate space for the signal handler context. */ - /* XXX Linux doesn't support the signal stack. */ - fp = (struct linux_sigframe *)tf->tf_esp; + if (onstack) + fp = (struct linux_sigframe *)((caddr_t)p->p_sigctx.ps_sigstk.ss_sp + + p->p_sigctx.ps_sigstk.ss_size); + else + fp = (struct linux_sigframe *)tf->tf_esp; fp--; /* Build stack frame for signal trampoline. */ frame.sf_handler = catcher; - frame.sf_sig = native_to_linux_sig[sig]; + frame.sf_sig = native_to_linux_signo[sig]; /* Save register context. */ #ifdef VM86 @@ -169,12 +223,12 @@ linux_sendsig(catcher, sig, mask, code) frame.sf_sc.sc_fs = tf->tf_vm86_fs; frame.sf_sc.sc_es = tf->tf_vm86_es; frame.sf_sc.sc_ds = tf->tf_vm86_ds; - frame.sf_sc.sc_eflags = get_vflags(p); + frame.sf_sc.sc_eflags = get_vflags(l); } else #endif { - __asm("movl %%gs,%w0" : "=r" (frame.sf_sc.sc_gs)); - __asm("movl %%fs,%w0" : "=r" (frame.sf_sc.sc_fs)); + frame.sf_sc.sc_gs = tf->tf_gs; + frame.sf_sc.sc_fs = tf->tf_fs; frame.sf_sc.sc_es = tf->tf_es; frame.sf_sc.sc_ds = tf->tf_ds; frame.sf_sc.sc_eflags = tf->tf_eflags; @@ -192,25 +246,28 @@ linux_sendsig(catcher, sig, mask, code) frame.sf_sc.sc_ss = tf->tf_ss; frame.sf_sc.sc_err = tf->tf_err; frame.sf_sc.sc_trapno = tf->tf_trapno; + frame.sf_sc.sc_cr2 = l->l_addr->u_pcb.pcb_cr2; /* Save signal stack. */ - /* XXX Linux doesn't support the signal stack. */ + /* Linux doesn't save the onstack flag in sigframe */ /* Save signal mask. */ - native_to_linux_old_sigset(mask, &frame.sf_sc.sc_mask); + native_to_linux_old_sigset(&frame.sf_sc.sc_mask, mask); if (copyout(&frame, fp, sizeof(frame)) != 0) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ - sigexit(p, SIGILL); + sigexit(l, SIGILL); /* NOTREACHED */ } /* * Build context to run handler in. */ + tf->tf_gs = GSEL(GUDATA_SEL, SEL_UPL); + tf->tf_fs = GSEL(GUDATA_SEL, SEL_UPL); tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL); tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL); tf->tf_eip = (int)p->p_sigctx.ps_sigcode; @@ -220,7 +277,8 @@ linux_sendsig(catcher, sig, mask, code) tf->tf_ss = GSEL(GUDATA_SEL, SEL_UPL); /* Remember that we're now on the signal stack. */ - /* XXX Linux doesn't support the signal stack. */ + if (onstack) + p->p_sigctx.ps_sigstk.ss_flags |= SS_ONSTACK; } /* @@ -234,8 +292,8 @@ linux_sendsig(catcher, sig, mask, code) * a machine fault. */ int -linux_sys_rt_sigreturn(p, v, retval) - struct proc *p; +linux_sys_rt_sigreturn(l, v, retval) + struct lwp *l; void *v; register_t *retval; { @@ -244,17 +302,19 @@ linux_sys_rt_sigreturn(p, v, retval) } int -linux_sys_sigreturn(p, v, retval) - struct proc *p; +linux_sys_sigreturn(l, v, retval) + struct lwp *l; void *v; register_t *retval; { struct linux_sys_sigreturn_args /* { syscallarg(struct linux_sigcontext *) scp; } */ *uap = v; + struct proc *p = l->l_proc; struct linux_sigcontext *scp, context; struct trapframe *tf; sigset_t mask; + ssize_t ss_gap; /* * The trampoline code hands us the context. @@ -266,14 +326,14 @@ linux_sys_sigreturn(p, v, retval) return (EFAULT); /* Restore register context. */ - tf = p->p_md.md_regs; + tf = l->l_md.md_regs; #ifdef VM86 if (context.sc_eflags & PSL_VM) { tf->tf_vm86_gs = context.sc_gs; tf->tf_vm86_fs = context.sc_fs; tf->tf_vm86_es = context.sc_es; tf->tf_vm86_ds = context.sc_ds; - set_vflags(p, context.sc_eflags); + set_vflags(l, context.sc_eflags); } else #endif { @@ -287,7 +347,8 @@ linux_sys_sigreturn(p, v, retval) !USERMODE(context.sc_cs, context.sc_eflags)) return (EINVAL); - /* %fs and %gs were restored by the trampoline. */ + tf->tf_gs = context.sc_gs; + tf->tf_fs = context.sc_fs; tf->tf_es = context.sc_es; tf->tf_ds = context.sc_ds; tf->tf_eflags = context.sc_eflags; @@ -305,10 +366,19 @@ linux_sys_sigreturn(p, v, retval) tf->tf_ss = context.sc_ss; /* Restore signal stack. */ - p->p_sigctx.ps_sigstk.ss_flags &= ~SS_ONSTACK; + /* + * Linux really does it this way; it doesn't have space in sigframe + * to save the onstack flag. + */ + ss_gap = (ssize_t) + ((caddr_t) context.sc_esp_at_signal - (caddr_t) p->p_sigctx.ps_sigstk.ss_sp); + if (ss_gap >= 0 && ss_gap < p->p_sigctx.ps_sigstk.ss_size) + p->p_sigctx.ps_sigstk.ss_flags |= SS_ONSTACK; + else + p->p_sigctx.ps_sigstk.ss_flags &= ~SS_ONSTACK; /* Restore signal mask. */ - linux_old_to_native_sigset(&context.sc_mask, &mask); + linux_old_to_native_sigset(&mask, &context.sc_mask); (void) sigprocmask1(p, SIG_SETMASK, &mask, 0); return (EJUSTRETURN); @@ -317,8 +387,8 @@ linux_sys_sigreturn(p, v, retval) #ifdef USER_LDT int -linux_read_ldt(p, uap, retval) - struct proc *p; +linux_read_ldt(l, uap, retval) + struct lwp *l; struct linux_sys_modify_ldt_args /* { syscallarg(int) func; syscallarg(void *) ptr; @@ -326,23 +396,25 @@ linux_read_ldt(p, uap, retval) } */ *uap; register_t *retval; { + struct proc *p = l->l_proc; struct i386_get_ldt_args gl; int error; caddr_t sg; char *parms; - sg = stackgap_init(p->p_emul); + DPRINTF(("linux_read_ldt!")); + sg = stackgap_init(p, 0); gl.start = 0; gl.desc = SCARG(uap, ptr); gl.num = SCARG(uap, bytecount) / sizeof(union descriptor); - parms = stackgap_alloc(&sg, sizeof(gl)); + parms = stackgap_alloc(p, &sg, sizeof(gl)); if ((error = copyout(&gl, parms, sizeof(gl))) != 0) return (error); - if ((error = i386_get_ldt(p, parms, retval)) != 0) + if ((error = i386_get_ldt(l, parms, retval)) != 0) return (error); *retval *= sizeof(union descriptor); @@ -358,11 +430,12 @@ struct linux_ldt_info { u_int read_exec_only:1; u_int limit_in_pages:1; u_int seg_not_present:1; + u_int useable:1; }; int -linux_write_ldt(p, uap, retval) - struct proc *p; +linux_write_ldt(l, uap, retval) + struct lwp *l; struct linux_sys_modify_ldt_args /* { syscallarg(int) func; syscallarg(void *) ptr; @@ -370,50 +443,68 @@ linux_write_ldt(p, uap, retval) } */ *uap; register_t *retval; { + struct proc *p = l->l_proc; struct linux_ldt_info ldt_info; struct segment_descriptor sd; struct i386_set_ldt_args sl; int error; caddr_t sg; char *parms; + int oldmode = (int)retval[0]; + DPRINTF(("linux_write_ldt %d\n", oldmode)); if (SCARG(uap, bytecount) != sizeof(ldt_info)) return (EINVAL); if ((error = copyin(SCARG(uap, ptr), &ldt_info, sizeof(ldt_info))) != 0) return error; - if (ldt_info.contents == 3) + if (ldt_info.entry_number >= 8192) return (EINVAL); + if (ldt_info.contents == 3) { + if (oldmode) + return (EINVAL); + if (ldt_info.seg_not_present) + return (EINVAL); + } - sg = stackgap_init(p->p_emul); - - sd.sd_lobase = ldt_info.base_addr & 0xffffff; - sd.sd_hibase = (ldt_info.base_addr >> 24) & 0xff; - sd.sd_lolimit = ldt_info.limit & 0xffff; - sd.sd_hilimit = (ldt_info.limit >> 16) & 0xf; - sd.sd_type = - 16 | (ldt_info.contents << 2) | (!ldt_info.read_exec_only << 1); - sd.sd_dpl = SEL_UPL; - sd.sd_p = !ldt_info.seg_not_present; - sd.sd_def32 = ldt_info.seg_32bit; - sd.sd_gran = ldt_info.limit_in_pages; - + if (ldt_info.base_addr == 0 && ldt_info.limit == 0 && + (oldmode || (ldt_info.contents == 0 && + ldt_info.read_exec_only == 1 && ldt_info.seg_32bit == 0 && + ldt_info.limit_in_pages == 0 && ldt_info.seg_not_present == 1 && + ldt_info.useable == 0))) { + /* this means you should zero the ldt */ + (void)memset(&sd, 0, sizeof(sd)); + } else { + sd.sd_lobase = ldt_info.base_addr & 0xffffff; + sd.sd_hibase = (ldt_info.base_addr >> 24) & 0xff; + sd.sd_lolimit = ldt_info.limit & 0xffff; + sd.sd_hilimit = (ldt_info.limit >> 16) & 0xf; + sd.sd_type = 16 | (ldt_info.contents << 2) | + (!ldt_info.read_exec_only << 1); + sd.sd_dpl = SEL_UPL; + sd.sd_p = !ldt_info.seg_not_present; + sd.sd_def32 = ldt_info.seg_32bit; + sd.sd_gran = ldt_info.limit_in_pages; + if (!oldmode) + sd.sd_xx = ldt_info.useable; + else + sd.sd_xx = 0; + } + sg = stackgap_init(p, 0); sl.start = ldt_info.entry_number; - sl.desc = stackgap_alloc(&sg, sizeof(sd)); + sl.desc = stackgap_alloc(p, &sg, sizeof(sd)); sl.num = 1; -#if 0 - printf("linux_write_ldt: idx=%d, base=%x, limit=%x\n", - ldt_info.entry_number, ldt_info.base_addr, ldt_info.limit); -#endif + DPRINTF(("linux_write_ldt: idx=%d, base=0x%lx, limit=0x%x\n", + ldt_info.entry_number, ldt_info.base_addr, ldt_info.limit)); - parms = stackgap_alloc(&sg, sizeof(sl)); + parms = stackgap_alloc(p, &sg, sizeof(sl)); if ((error = copyout(&sd, sl.desc, sizeof(sd))) != 0) return (error); if ((error = copyout(&sl, parms, sizeof(sl))) != 0) return (error); - if ((error = i386_set_ldt(p, parms, retval)) != 0) + if ((error = i386_set_ldt(l, parms, retval)) != 0) return (error); *retval = 0; @@ -423,8 +514,8 @@ linux_write_ldt(p, uap, retval) #endif /* USER_LDT */ int -linux_sys_modify_ldt(p, v, retval) - struct proc *p; +linux_sys_modify_ldt(l, v, retval) + struct lwp *l; void *v; register_t *retval; { @@ -437,10 +528,19 @@ linux_sys_modify_ldt(p, v, retval) switch (SCARG(uap, func)) { #ifdef USER_LDT case 0: - return (linux_read_ldt(p, uap, retval)); - + return linux_read_ldt(l, uap, retval); case 1: - return (linux_write_ldt(p, uap, retval)); + retval[0] = 1; + return linux_write_ldt(l, uap, retval); + case 2: +#ifdef notyet + return (linux_read_default_ldt(l, uap, retval); +#else + return (ENOSYS); +#endif + case 0x11: + retval[0] = 0; + return linux_write_ldt(l, uap, retval); #endif /* USER_LDT */ default: @@ -455,14 +555,19 @@ linux_sys_modify_ldt(p, v, retval) * array for all major device numbers, and map linux_mknod too. */ dev_t -linux_fakedev(dev) +linux_fakedev(dev, raw) dev_t dev; + int raw; { + if (raw) { #if (NWSDISPLAY > 0) - if (major(dev) == NETBSD_WSCONS_MAJOR) - return makedev(LINUX_CONS_MAJOR, (minor(dev) + 1)); + if (major(dev) == NETBSD_WSCONS_MAJOR) + return makedev(LINUX_CONS_MAJOR, (minor(dev) + 1)); #endif - return dev; + return 0; + } else { + return dev; + } } #if (NWSDISPLAY > 0) @@ -623,9 +728,7 @@ linux_machdepioctl(p, v, retval) fdp = p->p_fd; - if ((u_int)fd >= fdp->fd_nfiles || - (fp = fdp->fd_ofiles[fd]) == NULL || - (fp->f_iflags & FIF_WANTCLOSE) != 0) + if ((fp = fd_getfile(fdp, fd)) == NULL) return (EBADF); switch (com) { @@ -669,14 +772,15 @@ linux_machdepioctl(p, v, retval) break; case LINUX_VT_GETMODE: SCARG(&bia, com) = VT_GETMODE; - if ((error = sys_ioctl(p, &bia, retval))) + /* XXX NJWLWP */ + if ((error = sys_ioctl(curproc, &bia, retval))) return error; if ((error = copyin(SCARG(uap, data), (caddr_t)&lvt, sizeof (struct vt_mode)))) return error; - lvt.relsig = native_to_linux_sig[lvt.relsig]; - lvt.acqsig = native_to_linux_sig[lvt.acqsig]; - lvt.frsig = native_to_linux_sig[lvt.frsig]; + lvt.relsig = native_to_linux_signo[lvt.relsig]; + lvt.acqsig = native_to_linux_signo[lvt.acqsig]; + lvt.frsig = native_to_linux_signo[lvt.frsig]; return copyout((caddr_t)&lvt, SCARG(uap, data), sizeof (struct vt_mode)); case LINUX_VT_SETMODE: @@ -684,11 +788,11 @@ linux_machdepioctl(p, v, retval) if ((error = copyin(SCARG(uap, data), (caddr_t)&lvt, sizeof (struct vt_mode)))) return error; - lvt.relsig = linux_to_native_sig[lvt.relsig]; - lvt.acqsig = linux_to_native_sig[lvt.acqsig]; - lvt.frsig = linux_to_native_sig[lvt.frsig]; - sg = stackgap_init(p->p_emul); - bvtp = stackgap_alloc(&sg, sizeof (struct vt_mode)); + lvt.relsig = linux_to_native_signo[lvt.relsig]; + lvt.acqsig = linux_to_native_signo[lvt.acqsig]; + lvt.frsig = linux_to_native_signo[lvt.frsig]; + sg = stackgap_init(p, 0); + bvtp = stackgap_alloc(p, &sg, sizeof (struct vt_mode)); if ((error = copyout(&lvt, bvtp, sizeof (struct vt_mode)))) return error; SCARG(&bia, data) = bvtp; @@ -798,12 +902,13 @@ linux_machdepioctl(p, v, retval) } if (error == ENOTTY) - printf("linux_machdepioctl: invalid ioctl %08lx\n", - com); + DPRINTF(("linux_machdepioctl: invalid ioctl %08lx\n", + com)); return error; } SCARG(&bia, com) = com; - return sys_ioctl(p, &bia, retval); + /* XXX NJWLWP */ + return sys_ioctl(curproc, &bia, retval); } /* @@ -812,8 +917,8 @@ linux_machdepioctl(p, v, retval) * to rely on I/O permission maps, which are not implemented. */ int -linux_sys_iopl(p, v, retval) - struct proc *p; +linux_sys_iopl(l, v, retval) + struct lwp *l; void *v; register_t *retval; { @@ -822,7 +927,8 @@ linux_sys_iopl(p, v, retval) syscallarg(int) level; } */ *uap = v; #endif - struct trapframe *fp = p->p_md.md_regs; + struct proc *p = l->l_proc; + struct trapframe *fp = l->l_md.md_regs; if (suser(p->p_ucred, &p->p_acflag) != 0) return EPERM; @@ -836,8 +942,8 @@ linux_sys_iopl(p, v, retval) * just let it have the whole range. */ int -linux_sys_ioperm(p, v, retval) - struct proc *p; +linux_sys_ioperm(l, v, retval) + struct lwp *l; void *v; register_t *retval; { @@ -846,7 +952,8 @@ linux_sys_ioperm(p, v, retval) syscallarg(unsigned int) hi; syscallarg(int) val; } */ *uap = v; - struct trapframe *fp = p->p_md.md_regs; + struct proc *p = l->l_proc; + struct trapframe *fp = l->l_md.md_regs; if (suser(p->p_ucred, &p->p_acflag) != 0) return EPERM;