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