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