Annotation of src/sys/compat/linux/arch/i386/linux_machdep.c, Revision 1.20
1.20 ! mycroft 1: /* $NetBSD: linux_machdep.c,v 1.19 1995/09/19 22:56:37 thorpej Exp $ */
1.1 fvdl 2:
3: /*
4: * Copyright (c) 1995 Frank van der Linden
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed for the NetBSD Project
18: * by Frank van der Linden
19: * 4. The name of the author may not be used to endorse or promote products
20: * derived from this software without specific prior written permission
21: *
22: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32: */
33:
34: #include <sys/param.h>
35: #include <sys/systm.h>
36: #include <sys/signalvar.h>
37: #include <sys/kernel.h>
38: #include <sys/map.h>
39: #include <sys/proc.h>
40: #include <sys/user.h>
41: #include <sys/buf.h>
42: #include <sys/reboot.h>
43: #include <sys/conf.h>
44: #include <sys/file.h>
45: #include <sys/callout.h>
46: #include <sys/malloc.h>
47: #include <sys/mbuf.h>
48: #include <sys/msgbuf.h>
49: #include <sys/mount.h>
50: #include <sys/vnode.h>
51: #include <sys/device.h>
52: #include <sys/sysctl.h>
53: #include <sys/syscallargs.h>
1.13 fvdl 54: #include <sys/filedesc.h>
1.7 mycroft 55:
1.1 fvdl 56: #include <compat/linux/linux_types.h>
1.11 mycroft 57: #include <compat/linux/linux_signal.h>
1.1 fvdl 58: #include <compat/linux/linux_syscallargs.h>
1.7 mycroft 59: #include <compat/linux/linux_util.h>
1.1 fvdl 60:
61: #include <machine/cpu.h>
62: #include <machine/cpufunc.h>
63: #include <machine/psl.h>
64: #include <machine/reg.h>
1.7 mycroft 65: #include <machine/segments.h>
1.1 fvdl 66: #include <machine/specialreg.h>
1.7 mycroft 67: #include <machine/sysarch.h>
1.1 fvdl 68: #include <machine/linux_machdep.h>
69:
70: /*
1.13 fvdl 71: * To see whether pcvt is configured (for virtual console ioctl calls).
72: */
73: #include "vt.h"
74: #if NVT > 0
75: #include <arch/i386/isa/pcvt/pcvt_ioctl.h>
76: #endif
77:
78: /*
1.1 fvdl 79: * Deal with some i386-specific things in the Linux emulation code.
80: * This means just signals for now, will include stuff like
81: * I/O map permissions and V86 mode sometime.
82: */
83:
84: /*
85: * Send an interrupt to process.
86: *
87: * Stack is set up to allow sigcode stored
88: * in u. to call routine, followed by kcall
89: * to sigreturn routine below. After sigreturn
90: * resets the signal mask, the stack, and the
91: * frame pointer, it returns to the user
92: * specified pc, psl.
93: */
94:
95: void
96: linux_sendsig(catcher, sig, mask, code)
97: sig_t catcher;
98: int sig, mask;
99: u_long code;
100: {
101: register struct proc *p = curproc;
102: register struct trapframe *tf;
103: struct linux_sigframe *fp, frame;
104: struct sigacts *psp = p->p_sigacts;
105: int oonstack;
106: extern char linux_sigcode[], linux_esigcode[];
107:
1.3 mycroft 108: tf = p->p_md.md_regs;
1.16 mycroft 109: oonstack = psp->ps_sigstk.ss_flags & SS_ONSTACK;
1.1 fvdl 110:
111: /*
112: * Allocate space for the signal handler context.
113: */
114: if ((psp->ps_flags & SAS_ALTSTACK) && !oonstack &&
115: (psp->ps_sigonstack & sigmask(sig))) {
116: fp = (struct linux_sigframe *)(psp->ps_sigstk.ss_base +
117: psp->ps_sigstk.ss_size - sizeof(struct linux_sigframe));
1.16 mycroft 118: psp->ps_sigstk.ss_flags |= SS_ONSTACK;
1.1 fvdl 119: } else {
120: fp = (struct linux_sigframe *)tf->tf_esp - 1;
121: }
122:
1.7 mycroft 123: frame.sf_handler = catcher;
1.12 mycroft 124: frame.sf_sig = bsd_to_linux_sig[sig];
1.1 fvdl 125:
126: /*
127: * Build the signal context to be used by sigreturn.
128: */
1.7 mycroft 129: frame.sf_sc.sc_mask = mask;
1.4 mycroft 130: #ifdef VM86
131: if (tf->tf_eflags & PSL_VM) {
1.7 mycroft 132: frame.sf_sc.sc_gs = tf->tf_vm86_gs;
133: frame.sf_sc.sc_fs = tf->tf_vm86_fs;
134: frame.sf_sc.sc_es = tf->tf_vm86_es;
135: frame.sf_sc.sc_ds = tf->tf_vm86_ds;
1.4 mycroft 136: } else
1.18 fvdl 137: #endif
1.4 mycroft 138: {
1.7 mycroft 139: __asm("movl %%gs,%w0" : "=r" (frame.sf_sc.sc_gs));
140: __asm("movl %%fs,%w0" : "=r" (frame.sf_sc.sc_fs));
141: frame.sf_sc.sc_es = tf->tf_es;
142: frame.sf_sc.sc_ds = tf->tf_ds;
1.4 mycroft 143: }
1.7 mycroft 144: frame.sf_sc.sc_edi = tf->tf_edi;
145: frame.sf_sc.sc_esi = tf->tf_esi;
146: frame.sf_sc.sc_ebp = tf->tf_ebp;
147: frame.sf_sc.sc_ebx = tf->tf_ebx;
148: frame.sf_sc.sc_edx = tf->tf_edx;
149: frame.sf_sc.sc_ecx = tf->tf_ecx;
150: frame.sf_sc.sc_eax = tf->tf_eax;
151: frame.sf_sc.sc_eip = tf->tf_eip;
152: frame.sf_sc.sc_cs = tf->tf_cs;
153: frame.sf_sc.sc_eflags = tf->tf_eflags;
154: frame.sf_sc.sc_esp_at_signal = tf->tf_esp;
155: frame.sf_sc.sc_ss = tf->tf_ss;
156: frame.sf_sc.sc_err = tf->tf_err;
157: frame.sf_sc.sc_trapno = tf->tf_trapno;
1.1 fvdl 158:
159: if (copyout(&frame, fp, sizeof(frame)) != 0) {
160: /*
161: * Process has trashed its stack; give it an illegal
162: * instruction to halt it in its tracks.
163: */
164: sigexit(p, SIGILL);
165: /* NOTREACHED */
166: }
167:
168: /*
169: * Build context to run handler in.
170: */
171: tf->tf_esp = (int)fp;
172: tf->tf_eip = (int)(((char *)PS_STRINGS) -
173: (linux_esigcode - linux_sigcode));
1.3 mycroft 174: #ifdef VM86
1.1 fvdl 175: tf->tf_eflags &= ~PSL_VM;
1.3 mycroft 176: #endif
1.2 christos 177: tf->tf_cs = LSEL(LUCODE_SEL, SEL_UPL);
178: tf->tf_ds = LSEL(LUDATA_SEL, SEL_UPL);
179: tf->tf_es = LSEL(LUDATA_SEL, SEL_UPL);
180: tf->tf_ss = LSEL(LUDATA_SEL, SEL_UPL);
1.1 fvdl 181: }
182:
183: /*
184: * System call to cleanup state after a signal
185: * has been taken. Reset signal mask and
186: * stack state from context left by sendsig (above).
187: * Return to previous pc and psl as specified by
188: * context left by sendsig. Check carefully to
189: * make sure that the user has not modified the
190: * psl to gain improper privileges or to cause
191: * a machine fault.
192: */
193: int
1.20 ! mycroft 194: linux_sys_sigreturn(p, v, retval)
1.1 fvdl 195: struct proc *p;
1.19 thorpej 196: void *v;
197: register_t *retval;
198: {
1.20 ! mycroft 199: struct linux_sys_sigreturn_args /* {
1.1 fvdl 200: syscallarg(struct linux_sigcontext *) scp;
1.19 thorpej 201: } */ *uap = v;
1.1 fvdl 202: struct linux_sigcontext *scp, context;
203: register struct trapframe *tf;
204:
1.3 mycroft 205: tf = p->p_md.md_regs;
1.1 fvdl 206:
207: /*
208: * The trampoline code hands us the context.
209: * It is unsafe to keep track of it ourselves, in the event that a
210: * program jumps out of a signal handler.
211: */
212: scp = SCARG(uap, scp);
213: if (copyin((caddr_t)scp, &context, sizeof(*scp)) != 0)
214: return (EFAULT);
215:
216: /*
217: * Check for security violations.
218: */
1.7 mycroft 219: if (((context.sc_eflags ^ tf->tf_eflags) & PSL_USERSTATIC) != 0 ||
220: ISPL(context.sc_cs) != SEL_UPL)
1.1 fvdl 221: return (EINVAL);
222:
1.16 mycroft 223: p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK;
1.7 mycroft 224: p->p_sigmask = context.sc_mask & ~sigcantmask;
1.1 fvdl 225:
226: /*
227: * Restore signal context.
228: */
1.4 mycroft 229: #ifdef VM86
1.7 mycroft 230: if (context.sc_eflags & PSL_VM) {
231: tf->tf_vm86_gs = context.sc_gs;
232: tf->tf_vm86_fs = context.sc_fs;
233: tf->tf_vm86_es = context.sc_es;
234: tf->tf_vm86_ds = context.sc_ds;
1.4 mycroft 235: } else
236: #endif
237: {
238: /* %fs and %gs were restored by the trampoline. */
1.7 mycroft 239: tf->tf_es = context.sc_es;
240: tf->tf_ds = context.sc_ds;
1.4 mycroft 241: }
1.7 mycroft 242: tf->tf_edi = context.sc_edi;
243: tf->tf_esi = context.sc_esi;
244: tf->tf_ebp = context.sc_ebp;
245: tf->tf_ebx = context.sc_ebx;
246: tf->tf_edx = context.sc_edx;
247: tf->tf_ecx = context.sc_ecx;
248: tf->tf_eax = context.sc_eax;
249: tf->tf_eip = context.sc_eip;
250: tf->tf_cs = context.sc_cs;
251: tf->tf_eflags = context.sc_eflags;
252: tf->tf_esp = context.sc_esp_at_signal;
253: tf->tf_ss = context.sc_ss;
1.1 fvdl 254:
255: return (EJUSTRETURN);
1.6 mycroft 256: }
257:
1.7 mycroft 258: #ifdef USER_LDT
259:
260: int
261: linux_read_ldt(p, uap, retval)
262: struct proc *p;
1.20 ! mycroft 263: struct linux_sys_modify_ldt_args /* {
1.7 mycroft 264: syscallarg(int) func;
265: syscallarg(void *) ptr;
266: syscallarg(size_t) bytecount;
267: } */ *uap;
268: register_t *retval;
269: {
270: struct i386_get_ldt_args gl;
271: int error;
272: caddr_t sg;
273: char *parms;
274:
1.10 christos 275: sg = stackgap_init(p->p_emul);
1.7 mycroft 276:
277: gl.start = 0;
278: gl.desc = SCARG(uap, ptr);
279: gl.num = SCARG(uap, bytecount) / sizeof(union descriptor);
280:
281: parms = stackgap_alloc(&sg, sizeof(gl));
282:
283: if (error = copyout(&gl, parms, sizeof(gl)))
284: return (error);
285:
286: if (error = i386_get_ldt(p, parms, retval))
287: return (error);
288:
289: *retval *= sizeof(union descriptor);
290: return (0);
291: }
292:
293: struct linux_ldt_info {
294: u_int entry_number;
295: u_long base_addr;
296: u_int limit;
297: u_int seg_32bit:1;
298: u_int contents:2;
299: u_int read_exec_only:1;
300: u_int limit_in_pages:1;
301: u_int seg_not_present:1;
302: };
303:
304: int
305: linux_write_ldt(p, uap, retval)
306: struct proc *p;
1.20 ! mycroft 307: struct linux_sys_modify_ldt_args /* {
1.7 mycroft 308: syscallarg(int) func;
309: syscallarg(void *) ptr;
310: syscallarg(size_t) bytecount;
311: } */ *uap;
312: register_t *retval;
313: {
314: struct linux_ldt_info ldt_info;
315: struct segment_descriptor sd;
316: struct i386_set_ldt_args sl;
317: int error;
318: caddr_t sg;
319: char *parms;
320:
321: if (SCARG(uap, bytecount) != sizeof(ldt_info))
322: return (EINVAL);
323: if (error = copyin(SCARG(uap, ptr), &ldt_info, sizeof(ldt_info)))
324: return error;
325: if (ldt_info.contents == 3)
326: return (EINVAL);
327:
1.10 christos 328: sg = stackgap_init(p->p_emul);
1.7 mycroft 329:
330: sd.sd_lobase = ldt_info.base_addr & 0xffffff;
331: sd.sd_hibase = (ldt_info.base_addr >> 24) & 0xff;
332: sd.sd_lolimit = ldt_info.limit & 0xffff;
333: sd.sd_hilimit = (ldt_info.limit >> 16) & 0xf;
334: sd.sd_type =
335: 16 | (ldt_info.contents << 2) | (!ldt_info.read_exec_only << 1);
336: sd.sd_dpl = SEL_UPL;
337: sd.sd_p = !ldt_info.seg_not_present;
338: sd.sd_def32 = ldt_info.seg_32bit;
339: sd.sd_gran = ldt_info.limit_in_pages;
340:
341: sl.start = ldt_info.entry_number;
342: sl.desc = stackgap_alloc(&sg, sizeof(sd));
343: sl.num = 1;
344:
1.8 mycroft 345: #if 0
1.7 mycroft 346: printf("linux_write_ldt: idx=%d, base=%x, limit=%x\n",
347: ldt_info.entry_number, ldt_info.base_addr, ldt_info.limit);
1.8 mycroft 348: #endif
1.7 mycroft 349:
350: parms = stackgap_alloc(&sg, sizeof(sl));
351:
352: if (error = copyout(&sd, sl.desc, sizeof(sd)))
353: return (error);
354: if (error = copyout(&sl, parms, sizeof(sl)))
355: return (error);
356:
357: if (error = i386_set_ldt(p, parms, retval))
358: return (error);
359:
360: *retval = 0;
361: return (0);
362: }
363:
364: #endif /* USER_LDT */
365:
1.6 mycroft 366: int
1.20 ! mycroft 367: linux_sys_modify_ldt(p, v, retval)
1.6 mycroft 368: struct proc *p;
1.19 thorpej 369: void *v;
370: register_t *retval;
371: {
1.20 ! mycroft 372: struct linux_sys_modify_ldt_args /* {
1.6 mycroft 373: syscallarg(int) func;
374: syscallarg(void *) ptr;
375: syscallarg(size_t) bytecount;
1.19 thorpej 376: } */ *uap = v;
1.6 mycroft 377:
378: switch (SCARG(uap, func)) {
1.7 mycroft 379: #ifdef USER_LDT
1.6 mycroft 380: case 0:
1.7 mycroft 381: return (linux_read_ldt(p, uap, retval));
382:
1.6 mycroft 383: case 1:
1.7 mycroft 384: return (linux_write_ldt(p, uap, retval));
385: #endif /* USER_LDT */
386:
1.6 mycroft 387: default:
388: return (ENOSYS);
389: }
1.13 fvdl 390: }
391:
392: /*
393: * XXX Pathetic hack to make svgalib work. This will fake the major
394: * device number of an opened VT so that svgalib likes it. grmbl.
395: * Should probably do it 'wrong the right way' and use a mapping
396: * array for all major device numbers, and map linux_mknod too.
397: */
398: dev_t
399: linux_fakedev(dev)
400: dev_t dev;
401: {
1.20 ! mycroft 402:
1.13 fvdl 403: if (major(dev) == NETBSD_CONS_MAJOR)
1.17 fvdl 404: return makedev(LINUX_CONS_MAJOR, (minor(dev) + 1));
1.13 fvdl 405: return dev;
406: }
407:
408: /*
409: * We come here in a last attempt to satisfy a Linux ioctl() call
410: */
411: int
1.19 thorpej 412: linux_machdepioctl(p, v, retval)
1.13 fvdl 413: struct proc *p;
1.19 thorpej 414: void *v;
415: register_t *retval;
416: {
1.20 ! mycroft 417: struct linux_sys_ioctl_args /* {
1.13 fvdl 418: syscallarg(int) fd;
419: syscallarg(u_long) com;
420: syscallarg(caddr_t) data;
1.19 thorpej 421: } */ *uap = v;
1.20 ! mycroft 422: struct sys_ioctl_args bia, tmparg;
1.15 fvdl 423: u_long com;
424: #if NVT > 0
1.13 fvdl 425: int error, mode;
426: struct vt_mode lvt;
427: caddr_t bvtp, sg;
428: u_int fd;
429: struct file *fp;
430: struct filedesc *fdp;
1.15 fvdl 431: #endif
1.13 fvdl 432:
433: SCARG(&bia, fd) = SCARG(uap, fd);
434: SCARG(&bia, data) = SCARG(uap, data);
435: com = SCARG(uap, com);
436:
437: switch (com) {
438: #if NVT > 0
439: case LINUX_KDGKBMODE:
440: /*
1.14 fvdl 441: * Could be implemented but somehow KDGKBMODE is the
442: * same as KBDGLEDS.
1.13 fvdl 443: */
444: mode = K_XLATE;
445: return copyout(&mode, SCARG(uap, data), sizeof mode);
446: case LINUX_KDSKBMODE:
447: com = KDSKBMODE;
448: if ((unsigned)SCARG(uap, data) == LINUX_K_MEDIUMRAW)
449: SCARG(&bia, data) = (caddr_t)K_RAW;
450: break;
451: case LINUX_KDMKTONE:
452: com = KDMKTONE;
453: break;
454: case LINUX_KDSETMODE:
455: com = KDSETMODE;
456: break;
457: case LINUX_KDENABIO:
458: com = KDENABIO;
459: break;
460: case LINUX_KDDISABIO:
461: com = KDDISABIO;
462: break;
463: case LINUX_KDGETLED:
464: com = KDGETLED;
465: break;
466: case LINUX_KDSETLED:
467: com = KDSETLED;
468: break;
469: case LINUX_VT_OPENQRY:
470: com = VT_OPENQRY;
471: break;
472: case LINUX_VT_GETMODE:
473: SCARG(&bia, com) = VT_GETMODE;
1.20 ! mycroft 474: if ((error = sys_ioctl(p, &bia, retval)))
1.13 fvdl 475: return error;
476: if ((error = copyin(SCARG(uap, data), (caddr_t)&lvt,
477: sizeof (struct vt_mode))))
478: return error;
479: lvt.relsig = bsd_to_linux_sig[lvt.relsig];
480: lvt.acqsig = bsd_to_linux_sig[lvt.acqsig];
481: lvt.frsig = bsd_to_linux_sig[lvt.frsig];
482: return copyout((caddr_t)&lvt, SCARG(uap, data),
483: sizeof (struct vt_mode));
484: case LINUX_VT_SETMODE:
485: com = VT_SETMODE;
486: if ((error = copyin(SCARG(uap, data), (caddr_t)&lvt,
487: sizeof (struct vt_mode))))
488: return error;
489: lvt.relsig = linux_to_bsd_sig[lvt.relsig];
490: lvt.acqsig = linux_to_bsd_sig[lvt.acqsig];
491: lvt.frsig = linux_to_bsd_sig[lvt.frsig];
492: sg = stackgap_init(p->p_emul);
493: bvtp = stackgap_alloc(&sg, sizeof (struct vt_mode));
494: if ((error = copyout(&lvt, bvtp, sizeof (struct vt_mode))))
495: return error;
496: SCARG(&bia, data) = bvtp;
497: break;
498: case LINUX_VT_RELDISP:
499: com = VT_RELDISP;
500: break;
501: case LINUX_VT_ACTIVATE:
502: com = VT_ACTIVATE;
503: break;
504: case LINUX_VT_WAITACTIVE:
505: com = VT_WAITACTIVE;
506: break;
507: #endif
508: default:
509: return EINVAL;
510: }
511: SCARG(&bia, com) = com;
1.20 ! mycroft 512: return sys_ioctl(p, &bia, retval);
1.13 fvdl 513: }
514:
515: /*
516: * Set I/O permissions for a process. Just set the maximum level
517: * right away (ignoring the argument), otherwise we would have
518: * to rely on I/O permission maps, which are not implemented.
519: */
520: int
1.20 ! mycroft 521: linux_sys_iopl(p, v, retval)
1.13 fvdl 522: struct proc *p;
1.19 thorpej 523: void *v;
524: register_t *retval;
525: {
1.20 ! mycroft 526: struct linux_sys_iopl_args /* {
1.13 fvdl 527: syscallarg(int) level;
1.19 thorpej 528: } */ *uap = v;
1.13 fvdl 529: struct trapframe *fp = p->p_md.md_regs;
530:
531: if (suser(p->p_ucred, &p->p_acflag) != 0)
532: return EPERM;
533: fp->tf_eflags |= PSL_IOPL;
534: *retval = 0;
535: return 0;
536: }
537:
538: /*
539: * See above. If a root process tries to set access to an I/O port,
540: * just let it have the whole range.
541: */
542: int
1.20 ! mycroft 543: linux_sys_ioperm(p, v, retval)
1.13 fvdl 544: struct proc *p;
1.19 thorpej 545: void *v;
546: register_t *retval;
547: {
1.20 ! mycroft 548: struct linux_sys_ioperm_args /* {
1.13 fvdl 549: syscallarg(unsigned int) lo;
550: syscallarg(unsigned int) hi;
551: syscallarg(int) val;
1.19 thorpej 552: } */ *uap = v;
1.13 fvdl 553: struct trapframe *fp = p->p_md.md_regs;
554:
555: if (suser(p->p_ucred, &p->p_acflag) != 0)
556: return EPERM;
557: if (SCARG(uap, val))
558: fp->tf_eflags |= PSL_IOPL;
559: *retval = 0;
560: return 0;
1.1 fvdl 561: }
CVSweb <webmaster@jp.NetBSD.org>