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