linux_machdep.c revision 1.41 1 /* $NetBSD: linux_machdep.c,v 1.41 1998/06/11 22:26:13 drochner Exp $ */
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 "opt_vm86.h"
35 #include "opt_user_ldt.h"
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/signalvar.h>
40 #include <sys/kernel.h>
41 #include <sys/map.h>
42 #include <sys/proc.h>
43 #include <sys/user.h>
44 #include <sys/buf.h>
45 #include <sys/reboot.h>
46 #include <sys/conf.h>
47 #include <sys/exec.h>
48 #include <sys/file.h>
49 #include <sys/callout.h>
50 #include <sys/malloc.h>
51 #include <sys/mbuf.h>
52 #include <sys/msgbuf.h>
53 #include <sys/mount.h>
54 #include <sys/vnode.h>
55 #include <sys/device.h>
56 #include <sys/syscallargs.h>
57 #include <sys/filedesc.h>
58 #include <sys/exec_elf.h>
59
60 #include <compat/linux/linux_types.h>
61 #include <compat/linux/linux_signal.h>
62 #include <compat/linux/linux_syscallargs.h>
63 #include <compat/linux/linux_util.h>
64 #include <compat/linux/linux_ioctl.h>
65 #include <compat/linux/linux_exec.h>
66
67 #include <machine/cpu.h>
68 #include <machine/cpufunc.h>
69 #include <machine/psl.h>
70 #include <machine/reg.h>
71 #include <machine/segments.h>
72 #include <machine/specialreg.h>
73 #include <machine/sysarch.h>
74 #include <machine/vm86.h>
75 #include <machine/vmparam.h>
76 #include <machine/linux_machdep.h>
77
78 /*
79 * To see whether pcvt is configured (for virtual console ioctl calls).
80 */
81 #ifndef NVT
82 #include "vt.h"
83 #endif
84 #if NVT > 0
85 #include <arch/i386/isa/pcvt/pcvt_ioctl.h>
86 #endif
87
88 #include "wsdisplay.h"
89 #if (NWSDISPLAY > 0)
90 #include <sys/ioctl.h>
91 #include <dev/wscons/wsdisplay_usl_io.h>
92 #include "opt_xserver.h"
93 #endif
94
95 #ifdef USER_LDT
96 #include <machine/cpu.h>
97 int linux_read_ldt __P((struct proc *, struct linux_sys_modify_ldt_args *,
98 register_t *));
99 int linux_write_ldt __P((struct proc *, struct linux_sys_modify_ldt_args *,
100 register_t *));
101 #endif
102
103 /*
104 * Deal with some i386-specific things in the Linux emulation code.
105 */
106
107 void
108 linux_setregs(p, epp, stack)
109 struct proc *p;
110 struct exec_package *epp;
111 u_long stack;
112 {
113 register struct pcb *pcb = &p->p_addr->u_pcb;
114
115 pcb->pcb_savefpu.sv_env.en_cw = __Linux_NPXCW__;
116 setregs(p, epp, stack);
117 }
118
119 /*
120 * Send an interrupt to process.
121 *
122 * Stack is set up to allow sigcode stored
123 * in u. to call routine, followed by kcall
124 * to sigreturn routine below. After sigreturn
125 * resets the signal mask, the stack, and the
126 * frame pointer, it returns to the user
127 * specified pc, psl.
128 */
129
130 void
131 linux_sendsig(catcher, sig, mask, code)
132 sig_t catcher;
133 int sig, mask;
134 u_long code;
135 {
136 register struct proc *p = curproc;
137 register struct trapframe *tf;
138 struct linux_sigframe *fp, frame;
139 struct sigacts *psp = p->p_sigacts;
140 int oonstack;
141 extern char linux_sigcode[], linux_esigcode[];
142
143 tf = p->p_md.md_regs;
144 oonstack = psp->ps_sigstk.ss_flags & SS_ONSTACK;
145
146 /*
147 * Allocate space for the signal handler context.
148 */
149 if ((psp->ps_flags & SAS_ALTSTACK) && !oonstack &&
150 (psp->ps_sigonstack & sigmask(sig))) {
151 fp = (struct linux_sigframe *)((caddr_t)psp->ps_sigstk.ss_sp +
152 psp->ps_sigstk.ss_size - sizeof(struct linux_sigframe));
153 psp->ps_sigstk.ss_flags |= SS_ONSTACK;
154 } else {
155 fp = (struct linux_sigframe *)tf->tf_esp - 1;
156 }
157
158 frame.sf_handler = catcher;
159 frame.sf_sig = bsd_to_linux_sig[sig];
160
161 /*
162 * Build the signal context to be used by sigreturn.
163 */
164 frame.sf_sc.sc_mask = mask;
165 #ifdef VM86
166 if (tf->tf_eflags & PSL_VM) {
167 frame.sf_sc.sc_gs = tf->tf_vm86_gs;
168 frame.sf_sc.sc_fs = tf->tf_vm86_fs;
169 frame.sf_sc.sc_es = tf->tf_vm86_es;
170 frame.sf_sc.sc_ds = tf->tf_vm86_ds;
171 frame.sf_sc.sc_eflags = get_vflags(p);
172 } else
173 #endif
174 {
175 __asm("movl %%gs,%w0" : "=r" (frame.sf_sc.sc_gs));
176 __asm("movl %%fs,%w0" : "=r" (frame.sf_sc.sc_fs));
177 frame.sf_sc.sc_es = tf->tf_es;
178 frame.sf_sc.sc_ds = tf->tf_ds;
179 frame.sf_sc.sc_eflags = tf->tf_eflags;
180 }
181 frame.sf_sc.sc_edi = tf->tf_edi;
182 frame.sf_sc.sc_esi = tf->tf_esi;
183 frame.sf_sc.sc_ebp = tf->tf_ebp;
184 frame.sf_sc.sc_ebx = tf->tf_ebx;
185 frame.sf_sc.sc_edx = tf->tf_edx;
186 frame.sf_sc.sc_ecx = tf->tf_ecx;
187 frame.sf_sc.sc_eax = tf->tf_eax;
188 frame.sf_sc.sc_eip = tf->tf_eip;
189 frame.sf_sc.sc_cs = tf->tf_cs;
190 frame.sf_sc.sc_esp_at_signal = tf->tf_esp;
191 frame.sf_sc.sc_ss = tf->tf_ss;
192 frame.sf_sc.sc_err = tf->tf_err;
193 frame.sf_sc.sc_trapno = tf->tf_trapno;
194
195 if (copyout(&frame, fp, sizeof(frame)) != 0) {
196 /*
197 * Process has trashed its stack; give it an illegal
198 * instruction to halt it in its tracks.
199 */
200 sigexit(p, SIGILL);
201 /* NOTREACHED */
202 }
203
204 /*
205 * Build context to run handler in.
206 */
207 tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL);
208 tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL);
209 tf->tf_eip = (int)(((char *)PS_STRINGS) -
210 (linux_esigcode - linux_sigcode));
211 tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL);
212 tf->tf_eflags &= ~(PSL_T|PSL_VM|PSL_AC);
213 tf->tf_esp = (int)fp;
214 tf->tf_ss = GSEL(GUDATA_SEL, SEL_UPL);
215 }
216
217 /*
218 * System call to cleanup state after a signal
219 * has been taken. Reset signal mask and
220 * stack state from context left by sendsig (above).
221 * Return to previous pc and psl as specified by
222 * context left by sendsig. Check carefully to
223 * make sure that the user has not modified the
224 * psl to gain improper privileges or to cause
225 * a machine fault.
226 */
227 int
228 linux_sys_sigreturn(p, v, retval)
229 struct proc *p;
230 void *v;
231 register_t *retval;
232 {
233 struct linux_sys_sigreturn_args /* {
234 syscallarg(struct linux_sigcontext *) scp;
235 } */ *uap = v;
236 struct linux_sigcontext *scp, context;
237 register struct trapframe *tf;
238
239 tf = p->p_md.md_regs;
240
241 /*
242 * The trampoline code hands us the context.
243 * It is unsafe to keep track of it ourselves, in the event that a
244 * program jumps out of a signal handler.
245 */
246 scp = SCARG(uap, scp);
247 if (copyin((caddr_t)scp, &context, sizeof(*scp)) != 0)
248 return (EFAULT);
249
250 /*
251 * Restore signal context.
252 */
253 #ifdef VM86
254 if (context.sc_eflags & PSL_VM) {
255 tf->tf_vm86_gs = context.sc_gs;
256 tf->tf_vm86_fs = context.sc_fs;
257 tf->tf_vm86_es = context.sc_es;
258 tf->tf_vm86_ds = context.sc_ds;
259 set_vflags(p, context.sc_eflags);
260 } else
261 #endif
262 {
263 /*
264 * Check for security violations. If we're returning to
265 * protected mode, the CPU will validate the segment registers
266 * automatically and generate a trap on violations. We handle
267 * the trap, rather than doing all of the checking here.
268 */
269 if (((context.sc_eflags ^ tf->tf_eflags) & PSL_USERSTATIC) != 0 ||
270 !USERMODE(context.sc_cs, context.sc_eflags))
271 return (EINVAL);
272
273 /* %fs and %gs were restored by the trampoline. */
274 tf->tf_es = context.sc_es;
275 tf->tf_ds = context.sc_ds;
276 tf->tf_eflags = context.sc_eflags;
277 }
278 tf->tf_edi = context.sc_edi;
279 tf->tf_esi = context.sc_esi;
280 tf->tf_ebp = context.sc_ebp;
281 tf->tf_ebx = context.sc_ebx;
282 tf->tf_edx = context.sc_edx;
283 tf->tf_ecx = context.sc_ecx;
284 tf->tf_eax = context.sc_eax;
285 tf->tf_eip = context.sc_eip;
286 tf->tf_cs = context.sc_cs;
287 tf->tf_esp = context.sc_esp_at_signal;
288 tf->tf_ss = context.sc_ss;
289
290 p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK;
291 p->p_sigmask = context.sc_mask & ~sigcantmask;
292
293 return (EJUSTRETURN);
294 }
295
296 #ifdef USER_LDT
297
298 int
299 linux_read_ldt(p, uap, retval)
300 struct proc *p;
301 struct linux_sys_modify_ldt_args /* {
302 syscallarg(int) func;
303 syscallarg(void *) ptr;
304 syscallarg(size_t) bytecount;
305 } */ *uap;
306 register_t *retval;
307 {
308 struct i386_get_ldt_args gl;
309 int error;
310 caddr_t sg;
311 char *parms;
312
313 sg = stackgap_init(p->p_emul);
314
315 gl.start = 0;
316 gl.desc = SCARG(uap, ptr);
317 gl.num = SCARG(uap, bytecount) / sizeof(union descriptor);
318
319 parms = stackgap_alloc(&sg, sizeof(gl));
320
321 if ((error = copyout(&gl, parms, sizeof(gl))) != 0)
322 return (error);
323
324 if ((error = i386_get_ldt(p, parms, retval)) != 0)
325 return (error);
326
327 *retval *= sizeof(union descriptor);
328 return (0);
329 }
330
331 struct linux_ldt_info {
332 u_int entry_number;
333 u_long base_addr;
334 u_int limit;
335 u_int seg_32bit:1;
336 u_int contents:2;
337 u_int read_exec_only:1;
338 u_int limit_in_pages:1;
339 u_int seg_not_present:1;
340 };
341
342 int
343 linux_write_ldt(p, uap, retval)
344 struct proc *p;
345 struct linux_sys_modify_ldt_args /* {
346 syscallarg(int) func;
347 syscallarg(void *) ptr;
348 syscallarg(size_t) bytecount;
349 } */ *uap;
350 register_t *retval;
351 {
352 struct linux_ldt_info ldt_info;
353 struct segment_descriptor sd;
354 struct i386_set_ldt_args sl;
355 int error;
356 caddr_t sg;
357 char *parms;
358
359 if (SCARG(uap, bytecount) != sizeof(ldt_info))
360 return (EINVAL);
361 if ((error = copyin(SCARG(uap, ptr), &ldt_info, sizeof(ldt_info))) != 0)
362 return error;
363 if (ldt_info.contents == 3)
364 return (EINVAL);
365
366 sg = stackgap_init(p->p_emul);
367
368 sd.sd_lobase = ldt_info.base_addr & 0xffffff;
369 sd.sd_hibase = (ldt_info.base_addr >> 24) & 0xff;
370 sd.sd_lolimit = ldt_info.limit & 0xffff;
371 sd.sd_hilimit = (ldt_info.limit >> 16) & 0xf;
372 sd.sd_type =
373 16 | (ldt_info.contents << 2) | (!ldt_info.read_exec_only << 1);
374 sd.sd_dpl = SEL_UPL;
375 sd.sd_p = !ldt_info.seg_not_present;
376 sd.sd_def32 = ldt_info.seg_32bit;
377 sd.sd_gran = ldt_info.limit_in_pages;
378
379 sl.start = ldt_info.entry_number;
380 sl.desc = stackgap_alloc(&sg, sizeof(sd));
381 sl.num = 1;
382
383 #if 0
384 printf("linux_write_ldt: idx=%d, base=%x, limit=%x\n",
385 ldt_info.entry_number, ldt_info.base_addr, ldt_info.limit);
386 #endif
387
388 parms = stackgap_alloc(&sg, sizeof(sl));
389
390 if ((error = copyout(&sd, sl.desc, sizeof(sd))) != 0)
391 return (error);
392 if ((error = copyout(&sl, parms, sizeof(sl))) != 0)
393 return (error);
394
395 if ((error = i386_set_ldt(p, parms, retval)) != 0)
396 return (error);
397
398 *retval = 0;
399 return (0);
400 }
401
402 #endif /* USER_LDT */
403
404 int
405 linux_sys_modify_ldt(p, v, retval)
406 struct proc *p;
407 void *v;
408 register_t *retval;
409 {
410 struct linux_sys_modify_ldt_args /* {
411 syscallarg(int) func;
412 syscallarg(void *) ptr;
413 syscallarg(size_t) bytecount;
414 } */ *uap = v;
415
416 switch (SCARG(uap, func)) {
417 #ifdef USER_LDT
418 case 0:
419 return (linux_read_ldt(p, uap, retval));
420
421 case 1:
422 return (linux_write_ldt(p, uap, retval));
423 #endif /* USER_LDT */
424
425 default:
426 return (ENOSYS);
427 }
428 }
429
430 /*
431 * XXX Pathetic hack to make svgalib work. This will fake the major
432 * device number of an opened VT so that svgalib likes it. grmbl.
433 * Should probably do it 'wrong the right way' and use a mapping
434 * array for all major device numbers, and map linux_mknod too.
435 */
436 dev_t
437 linux_fakedev(dev)
438 dev_t dev;
439 {
440 #if (NVT > 0)
441 if (major(dev) == NETBSD_PCCONS_MAJOR)
442 return makedev(LINUX_CONS_MAJOR, (minor(dev) + 1));
443 #endif
444 #if (NWSDISPLAY > 0)
445 if (major(dev) == NETBSD_WSCONS_MAJOR)
446 return makedev(LINUX_CONS_MAJOR, (minor(dev) + 1));
447 #endif
448 return dev;
449 }
450
451 #if (NWSDISPLAY > 0) && defined(XSERVER)
452 /*
453 * That's not complete, but enough to get an X server running.
454 */
455 #define NR_KEYS 128
456 static u_short plain_map[NR_KEYS] = {
457 0x0200, 0x001b, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036,
458 0x0037, 0x0038, 0x0039, 0x0030, 0x002d, 0x003d, 0x007f, 0x0009,
459 0x0b71, 0x0b77, 0x0b65, 0x0b72, 0x0b74, 0x0b79, 0x0b75, 0x0b69,
460 0x0b6f, 0x0b70, 0x005b, 0x005d, 0x0201, 0x0702, 0x0b61, 0x0b73,
461 0x0b64, 0x0b66, 0x0b67, 0x0b68, 0x0b6a, 0x0b6b, 0x0b6c, 0x003b,
462 0x0027, 0x0060, 0x0700, 0x005c, 0x0b7a, 0x0b78, 0x0b63, 0x0b76,
463 0x0b62, 0x0b6e, 0x0b6d, 0x002c, 0x002e, 0x002f, 0x0700, 0x030c,
464 0x0703, 0x0020, 0x0207, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104,
465 0x0105, 0x0106, 0x0107, 0x0108, 0x0109, 0x0208, 0x0209, 0x0307,
466 0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
467 0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x003c, 0x010a,
468 0x010b, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
469 0x030e, 0x0702, 0x030d, 0x001c, 0x0701, 0x0205, 0x0114, 0x0603,
470 0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
471 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
472 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
473 }, shift_map[NR_KEYS] = {
474 0x0200, 0x001b, 0x0021, 0x0040, 0x0023, 0x0024, 0x0025, 0x005e,
475 0x0026, 0x002a, 0x0028, 0x0029, 0x005f, 0x002b, 0x007f, 0x0009,
476 0x0b51, 0x0b57, 0x0b45, 0x0b52, 0x0b54, 0x0b59, 0x0b55, 0x0b49,
477 0x0b4f, 0x0b50, 0x007b, 0x007d, 0x0201, 0x0702, 0x0b41, 0x0b53,
478 0x0b44, 0x0b46, 0x0b47, 0x0b48, 0x0b4a, 0x0b4b, 0x0b4c, 0x003a,
479 0x0022, 0x007e, 0x0700, 0x007c, 0x0b5a, 0x0b58, 0x0b43, 0x0b56,
480 0x0b42, 0x0b4e, 0x0b4d, 0x003c, 0x003e, 0x003f, 0x0700, 0x030c,
481 0x0703, 0x0020, 0x0207, 0x010a, 0x010b, 0x010c, 0x010d, 0x010e,
482 0x010f, 0x0110, 0x0111, 0x0112, 0x0113, 0x0213, 0x0203, 0x0307,
483 0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
484 0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x003e, 0x010a,
485 0x010b, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
486 0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
487 0x020b, 0x0601, 0x0602, 0x0117, 0x0600, 0x020a, 0x0115, 0x0116,
488 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
489 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
490 }, altgr_map[NR_KEYS] = {
491 0x0200, 0x0200, 0x0200, 0x0040, 0x0200, 0x0024, 0x0200, 0x0200,
492 0x007b, 0x005b, 0x005d, 0x007d, 0x005c, 0x0200, 0x0200, 0x0200,
493 0x0b71, 0x0b77, 0x0918, 0x0b72, 0x0b74, 0x0b79, 0x0b75, 0x0b69,
494 0x0b6f, 0x0b70, 0x0200, 0x007e, 0x0201, 0x0702, 0x0914, 0x0b73,
495 0x0917, 0x0919, 0x0b67, 0x0b68, 0x0b6a, 0x0b6b, 0x0b6c, 0x0200,
496 0x0200, 0x0200, 0x0700, 0x0200, 0x0b7a, 0x0b78, 0x0916, 0x0b76,
497 0x0915, 0x0b6e, 0x0b6d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
498 0x0703, 0x0200, 0x0207, 0x050c, 0x050d, 0x050e, 0x050f, 0x0510,
499 0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0208, 0x0202, 0x0911,
500 0x0912, 0x0913, 0x030b, 0x090e, 0x090f, 0x0910, 0x030a, 0x090b,
501 0x090c, 0x090d, 0x090a, 0x0310, 0x0206, 0x0200, 0x007c, 0x0516,
502 0x0517, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
503 0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
504 0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
505 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
506 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
507 }, ctrl_map[NR_KEYS] = {
508 0x0200, 0x0200, 0x0200, 0x0000, 0x001b, 0x001c, 0x001d, 0x001e,
509 0x001f, 0x007f, 0x0200, 0x0200, 0x001f, 0x0200, 0x0008, 0x0200,
510 0x0011, 0x0017, 0x0005, 0x0012, 0x0014, 0x0019, 0x0015, 0x0009,
511 0x000f, 0x0010, 0x001b, 0x001d, 0x0201, 0x0702, 0x0001, 0x0013,
512 0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b, 0x000c, 0x0200,
513 0x0007, 0x0000, 0x0700, 0x001c, 0x001a, 0x0018, 0x0003, 0x0016,
514 0x0002, 0x000e, 0x000d, 0x0200, 0x020e, 0x007f, 0x0700, 0x030c,
515 0x0703, 0x0000, 0x0207, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104,
516 0x0105, 0x0106, 0x0107, 0x0108, 0x0109, 0x0208, 0x0204, 0x0307,
517 0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
518 0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x0200, 0x010a,
519 0x010b, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
520 0x030e, 0x0702, 0x030d, 0x001c, 0x0701, 0x0205, 0x0114, 0x0603,
521 0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
522 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
523 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
524 };
525
526 u_short *linux_keytabs[] = {
527 plain_map, shift_map, altgr_map, altgr_map, ctrl_map
528 };
529 #endif
530
531 /*
532 * We come here in a last attempt to satisfy a Linux ioctl() call
533 */
534 int
535 linux_machdepioctl(p, v, retval)
536 struct proc *p;
537 void *v;
538 register_t *retval;
539 {
540 struct linux_sys_ioctl_args /* {
541 syscallarg(int) fd;
542 syscallarg(u_long) com;
543 syscallarg(caddr_t) data;
544 } */ *uap = v;
545 struct sys_ioctl_args bia;
546 u_long com;
547 #if (NVT > 0) || (NWSDISPLAY > 0)
548 int error;
549 struct vt_mode lvt;
550 caddr_t bvtp, sg;
551 #endif
552 #if (NWSDISPLAY > 0) && defined(XSERVER)
553 struct kbentry kbe;
554 #endif
555
556 SCARG(&bia, fd) = SCARG(uap, fd);
557 SCARG(&bia, data) = SCARG(uap, data);
558 com = SCARG(uap, com);
559
560 switch (com) {
561 #if (NVT > 0) || (NWSDISPLAY > 0)
562 case LINUX_KDGKBMODE:
563 com = KDGKBMODE;
564 break;
565 case LINUX_KDSKBMODE:
566 com = KDSKBMODE;
567 if ((unsigned)SCARG(uap, data) == LINUX_K_MEDIUMRAW)
568 SCARG(&bia, data) = (caddr_t)K_RAW;
569 break;
570 case LINUX_KDMKTONE:
571 com = KDMKTONE;
572 break;
573 case LINUX_KDSETMODE:
574 com = KDSETMODE;
575 break;
576 case LINUX_KDENABIO:
577 com = KDENABIO;
578 break;
579 case LINUX_KDDISABIO:
580 com = KDDISABIO;
581 break;
582 case LINUX_KDGETLED:
583 com = KDGETLED;
584 break;
585 case LINUX_KDSETLED:
586 com = KDSETLED;
587 break;
588 case LINUX_VT_OPENQRY:
589 com = VT_OPENQRY;
590 break;
591 case LINUX_VT_GETMODE:
592 SCARG(&bia, com) = VT_GETMODE;
593 if ((error = sys_ioctl(p, &bia, retval)))
594 return error;
595 if ((error = copyin(SCARG(uap, data), (caddr_t)&lvt,
596 sizeof (struct vt_mode))))
597 return error;
598 lvt.relsig = bsd_to_linux_sig[lvt.relsig];
599 lvt.acqsig = bsd_to_linux_sig[lvt.acqsig];
600 lvt.frsig = bsd_to_linux_sig[lvt.frsig];
601 return copyout((caddr_t)&lvt, SCARG(uap, data),
602 sizeof (struct vt_mode));
603 case LINUX_VT_SETMODE:
604 com = VT_SETMODE;
605 if ((error = copyin(SCARG(uap, data), (caddr_t)&lvt,
606 sizeof (struct vt_mode))))
607 return error;
608 lvt.relsig = linux_to_bsd_sig[lvt.relsig];
609 lvt.acqsig = linux_to_bsd_sig[lvt.acqsig];
610 lvt.frsig = linux_to_bsd_sig[lvt.frsig];
611 sg = stackgap_init(p->p_emul);
612 bvtp = stackgap_alloc(&sg, sizeof (struct vt_mode));
613 if ((error = copyout(&lvt, bvtp, sizeof (struct vt_mode))))
614 return error;
615 SCARG(&bia, data) = bvtp;
616 break;
617 case LINUX_VT_RELDISP:
618 com = VT_RELDISP;
619 break;
620 case LINUX_VT_ACTIVATE:
621 com = VT_ACTIVATE;
622 break;
623 case LINUX_VT_WAITACTIVE:
624 com = VT_WAITACTIVE;
625 break;
626 #endif
627 #if (NWSDISPLAY > 0)
628 case LINUX_VT_GETSTATE:
629 com = VT_GETSTATE;
630 break;
631 #ifdef XSERVER
632 case LINUX_KDGKBTYPE:
633 /* This is what Linux does. */
634 return (subyte(SCARG(uap, data), KB_101));
635 case LINUX_KDGKBENT:
636 /*
637 * The Linux KDGKBENT ioctl is different from the
638 * SYSV original. So we handle it in machdep code.
639 * XXX We should use keyboard mapping information
640 * from wsdisplay, but this would be expensive.
641 */
642 if ((error = copyin(SCARG(uap, data), &kbe,
643 sizeof(struct kbentry))))
644 return (error);
645 if (kbe.kb_table >= sizeof(linux_keytabs) / sizeof(u_short *)
646 || kbe.kb_index >= NR_KEYS)
647 return (EINVAL);
648 kbe.kb_value = linux_keytabs[kbe.kb_table][kbe.kb_index];
649 return (copyout(&kbe, SCARG(uap, data),
650 sizeof(struct kbentry)));
651 #endif
652 #endif
653 default:
654 printf("linux_machdepioctl: invalid ioctl %08lx\n", com);
655 return EINVAL;
656 }
657 SCARG(&bia, com) = com;
658 return sys_ioctl(p, &bia, retval);
659 }
660
661 /*
662 * Set I/O permissions for a process. Just set the maximum level
663 * right away (ignoring the argument), otherwise we would have
664 * to rely on I/O permission maps, which are not implemented.
665 */
666 int
667 linux_sys_iopl(p, v, retval)
668 struct proc *p;
669 void *v;
670 register_t *retval;
671 {
672 #if 0
673 struct linux_sys_iopl_args /* {
674 syscallarg(int) level;
675 } */ *uap = v;
676 #endif
677 struct trapframe *fp = p->p_md.md_regs;
678
679 if (suser(p->p_ucred, &p->p_acflag) != 0)
680 return EPERM;
681 fp->tf_eflags |= PSL_IOPL;
682 *retval = 0;
683 return 0;
684 }
685
686 /*
687 * See above. If a root process tries to set access to an I/O port,
688 * just let it have the whole range.
689 */
690 int
691 linux_sys_ioperm(p, v, retval)
692 struct proc *p;
693 void *v;
694 register_t *retval;
695 {
696 struct linux_sys_ioperm_args /* {
697 syscallarg(unsigned int) lo;
698 syscallarg(unsigned int) hi;
699 syscallarg(int) val;
700 } */ *uap = v;
701 struct trapframe *fp = p->p_md.md_regs;
702
703 if (suser(p->p_ucred, &p->p_acflag) != 0)
704 return EPERM;
705 if (SCARG(uap, val))
706 fp->tf_eflags |= PSL_IOPL;
707 *retval = 0;
708 return 0;
709 }
710