linux_machdep.c revision 1.47.2.2 1 /* $NetBSD: linux_machdep.c,v 1.47.2.2 2000/12/08 09:08:22 bouyer 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 #if defined(KERNEL) && !defined(_LKM)
40 #include "opt_vm86.h"
41 #include "opt_user_ldt.h"
42 #endif
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/signalvar.h>
47 #include <sys/kernel.h>
48 #include <sys/map.h>
49 #include <sys/proc.h>
50 #include <sys/user.h>
51 #include <sys/buf.h>
52 #include <sys/reboot.h>
53 #include <sys/conf.h>
54 #include <sys/exec.h>
55 #include <sys/file.h>
56 #include <sys/callout.h>
57 #include <sys/malloc.h>
58 #include <sys/mbuf.h>
59 #include <sys/msgbuf.h>
60 #include <sys/mount.h>
61 #include <sys/vnode.h>
62 #include <sys/device.h>
63 #include <sys/syscallargs.h>
64 #include <sys/filedesc.h>
65 #include <sys/exec_elf.h>
66
67 #include <compat/linux/common/linux_types.h>
68 #include <compat/linux/common/linux_signal.h>
69 #include <compat/linux/common/linux_util.h>
70 #include <compat/linux/common/linux_ioctl.h>
71 #include <compat/linux/common/linux_exec.h>
72 #include <compat/linux/common/linux_machdep.h>
73
74 #include <compat/linux/linux_syscallargs.h>
75
76 #include <machine/cpu.h>
77 #include <machine/cpufunc.h>
78 #include <machine/psl.h>
79 #include <machine/reg.h>
80 #include <machine/segments.h>
81 #include <machine/specialreg.h>
82 #include <machine/sysarch.h>
83 #include <machine/vm86.h>
84 #include <machine/vmparam.h>
85
86 /*
87 * To see whether wscons is configured (for virtual console ioctl calls).
88 */
89 #if defined(_KERNEL) && !defined(_LKM)
90 #include "wsdisplay.h"
91 #endif
92 #if (NWSDISPLAY > 0)
93 #include <sys/ioctl.h>
94 #include <dev/wscons/wsdisplay_usl_io.h>
95 #if defined(_KERNEL) && !defined(_LKM)
96 #include "opt_xserver.h"
97 #endif
98 #endif
99
100 #ifdef USER_LDT
101 #include <machine/cpu.h>
102 int linux_read_ldt __P((struct proc *, struct linux_sys_modify_ldt_args *,
103 register_t *));
104 int linux_write_ldt __P((struct proc *, struct linux_sys_modify_ldt_args *,
105 register_t *));
106 #endif
107
108 /*
109 * Deal with some i386-specific things in the Linux emulation code.
110 */
111
112 void
113 linux_setregs(p, epp, stack)
114 struct proc *p;
115 struct exec_package *epp;
116 u_long stack;
117 {
118 struct pcb *pcb = &p->p_addr->u_pcb;
119
120 setregs(p, epp, stack);
121 pcb->pcb_savefpu.sv_env.en_cw = __Linux_NPXCW__;
122 }
123
124 /*
125 * Send an interrupt to process.
126 *
127 * Stack is set up to allow sigcode stored
128 * in u. to call routine, followed by kcall
129 * to sigreturn routine below. After sigreturn
130 * resets the signal mask, the stack, and the
131 * frame pointer, it returns to the user
132 * specified pc, psl.
133 */
134
135 void
136 linux_sendsig(catcher, sig, mask, code)
137 sig_t catcher;
138 int sig;
139 sigset_t *mask;
140 u_long code;
141 {
142 struct proc *p = curproc;
143 struct trapframe *tf;
144 struct linux_sigframe *fp, frame;
145 struct sigacts *psp = p->p_sigacts;
146
147 tf = p->p_md.md_regs;
148
149 /* Allocate space for the signal handler context. */
150 /* XXX Linux doesn't support the signal stack. */
151 fp = (struct linux_sigframe *)tf->tf_esp;
152 fp--;
153
154 /* Build stack frame for signal trampoline. */
155 frame.sf_handler = catcher;
156 frame.sf_sig = native_to_linux_sig[sig];
157
158 /* Save register context. */
159 #ifdef VM86
160 if (tf->tf_eflags & PSL_VM) {
161 frame.sf_sc.sc_gs = tf->tf_vm86_gs;
162 frame.sf_sc.sc_fs = tf->tf_vm86_fs;
163 frame.sf_sc.sc_es = tf->tf_vm86_es;
164 frame.sf_sc.sc_ds = tf->tf_vm86_ds;
165 frame.sf_sc.sc_eflags = get_vflags(p);
166 } else
167 #endif
168 {
169 __asm("movl %%gs,%w0" : "=r" (frame.sf_sc.sc_gs));
170 __asm("movl %%fs,%w0" : "=r" (frame.sf_sc.sc_fs));
171 frame.sf_sc.sc_es = tf->tf_es;
172 frame.sf_sc.sc_ds = tf->tf_ds;
173 frame.sf_sc.sc_eflags = tf->tf_eflags;
174 }
175 frame.sf_sc.sc_edi = tf->tf_edi;
176 frame.sf_sc.sc_esi = tf->tf_esi;
177 frame.sf_sc.sc_ebp = tf->tf_ebp;
178 frame.sf_sc.sc_ebx = tf->tf_ebx;
179 frame.sf_sc.sc_edx = tf->tf_edx;
180 frame.sf_sc.sc_ecx = tf->tf_ecx;
181 frame.sf_sc.sc_eax = tf->tf_eax;
182 frame.sf_sc.sc_eip = tf->tf_eip;
183 frame.sf_sc.sc_cs = tf->tf_cs;
184 frame.sf_sc.sc_esp_at_signal = tf->tf_esp;
185 frame.sf_sc.sc_ss = tf->tf_ss;
186 frame.sf_sc.sc_err = tf->tf_err;
187 frame.sf_sc.sc_trapno = tf->tf_trapno;
188
189 /* Save signal stack. */
190 /* XXX Linux doesn't support the signal stack. */
191
192 /* Save signal mask. */
193 native_to_linux_old_sigset(mask, &frame.sf_sc.sc_mask);
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)psp->ps_sigcode;
210 tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL);
211 tf->tf_eflags &= ~(PSL_T|PSL_VM|PSL_AC);
212 tf->tf_esp = (int)fp;
213 tf->tf_ss = GSEL(GUDATA_SEL, SEL_UPL);
214
215 /* Remember that we're now on the signal stack. */
216 /* XXX Linux doesn't support the signal stack. */
217 }
218
219 /*
220 * System call to cleanup state after a signal
221 * has been taken. Reset signal mask and
222 * stack state from context left by sendsig (above).
223 * Return to previous pc and psl as specified by
224 * context left by sendsig. Check carefully to
225 * make sure that the user has not modified the
226 * psl to gain improper privileges or to cause
227 * a machine fault.
228 */
229 int
230 linux_sys_rt_sigreturn(p, v, retval)
231 struct proc *p;
232 void *v;
233 register_t *retval;
234 {
235 /* XXX XAX write me */
236 return(ENOSYS);
237 }
238
239 int
240 linux_sys_sigreturn(p, v, retval)
241 struct proc *p;
242 void *v;
243 register_t *retval;
244 {
245 struct linux_sys_sigreturn_args /* {
246 syscallarg(struct linux_sigcontext *) scp;
247 } */ *uap = v;
248 struct linux_sigcontext *scp, context;
249 struct trapframe *tf;
250 sigset_t mask;
251
252 /*
253 * The trampoline code hands us the context.
254 * It is unsafe to keep track of it ourselves, in the event that a
255 * program jumps out of a signal handler.
256 */
257 scp = SCARG(uap, scp);
258 if (copyin((caddr_t)scp, &context, sizeof(*scp)) != 0)
259 return (EFAULT);
260
261 /* Restore register context. */
262 tf = p->p_md.md_regs;
263 #ifdef VM86
264 if (context.sc_eflags & PSL_VM) {
265 tf->tf_vm86_gs = context.sc_gs;
266 tf->tf_vm86_fs = context.sc_fs;
267 tf->tf_vm86_es = context.sc_es;
268 tf->tf_vm86_ds = context.sc_ds;
269 set_vflags(p, context.sc_eflags);
270 } else
271 #endif
272 {
273 /*
274 * Check for security violations. If we're returning to
275 * protected mode, the CPU will validate the segment registers
276 * automatically and generate a trap on violations. We handle
277 * the trap, rather than doing all of the checking here.
278 */
279 if (((context.sc_eflags ^ tf->tf_eflags) & PSL_USERSTATIC) != 0 ||
280 !USERMODE(context.sc_cs, context.sc_eflags))
281 return (EINVAL);
282
283 /* %fs and %gs were restored by the trampoline. */
284 tf->tf_es = context.sc_es;
285 tf->tf_ds = context.sc_ds;
286 tf->tf_eflags = context.sc_eflags;
287 }
288 tf->tf_edi = context.sc_edi;
289 tf->tf_esi = context.sc_esi;
290 tf->tf_ebp = context.sc_ebp;
291 tf->tf_ebx = context.sc_ebx;
292 tf->tf_edx = context.sc_edx;
293 tf->tf_ecx = context.sc_ecx;
294 tf->tf_eax = context.sc_eax;
295 tf->tf_eip = context.sc_eip;
296 tf->tf_cs = context.sc_cs;
297 tf->tf_esp = context.sc_esp_at_signal;
298 tf->tf_ss = context.sc_ss;
299
300 /* Restore signal stack. */
301 p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK;
302
303 /* Restore signal mask. */
304 linux_old_to_native_sigset(&context.sc_mask, &mask);
305 (void) sigprocmask1(p, SIG_SETMASK, &mask, 0);
306
307 return (EJUSTRETURN);
308 }
309
310 #ifdef USER_LDT
311
312 int
313 linux_read_ldt(p, uap, retval)
314 struct proc *p;
315 struct linux_sys_modify_ldt_args /* {
316 syscallarg(int) func;
317 syscallarg(void *) ptr;
318 syscallarg(size_t) bytecount;
319 } */ *uap;
320 register_t *retval;
321 {
322 struct i386_get_ldt_args gl;
323 int error;
324 caddr_t sg;
325 char *parms;
326
327 sg = stackgap_init(p->p_emul);
328
329 gl.start = 0;
330 gl.desc = SCARG(uap, ptr);
331 gl.num = SCARG(uap, bytecount) / sizeof(union descriptor);
332
333 parms = stackgap_alloc(&sg, sizeof(gl));
334
335 if ((error = copyout(&gl, parms, sizeof(gl))) != 0)
336 return (error);
337
338 if ((error = i386_get_ldt(p, parms, retval)) != 0)
339 return (error);
340
341 *retval *= sizeof(union descriptor);
342 return (0);
343 }
344
345 struct linux_ldt_info {
346 u_int entry_number;
347 u_long base_addr;
348 u_int limit;
349 u_int seg_32bit:1;
350 u_int contents:2;
351 u_int read_exec_only:1;
352 u_int limit_in_pages:1;
353 u_int seg_not_present:1;
354 };
355
356 int
357 linux_write_ldt(p, uap, retval)
358 struct proc *p;
359 struct linux_sys_modify_ldt_args /* {
360 syscallarg(int) func;
361 syscallarg(void *) ptr;
362 syscallarg(size_t) bytecount;
363 } */ *uap;
364 register_t *retval;
365 {
366 struct linux_ldt_info ldt_info;
367 struct segment_descriptor sd;
368 struct i386_set_ldt_args sl;
369 int error;
370 caddr_t sg;
371 char *parms;
372
373 if (SCARG(uap, bytecount) != sizeof(ldt_info))
374 return (EINVAL);
375 if ((error = copyin(SCARG(uap, ptr), &ldt_info, sizeof(ldt_info))) != 0)
376 return error;
377 if (ldt_info.contents == 3)
378 return (EINVAL);
379
380 sg = stackgap_init(p->p_emul);
381
382 sd.sd_lobase = ldt_info.base_addr & 0xffffff;
383 sd.sd_hibase = (ldt_info.base_addr >> 24) & 0xff;
384 sd.sd_lolimit = ldt_info.limit & 0xffff;
385 sd.sd_hilimit = (ldt_info.limit >> 16) & 0xf;
386 sd.sd_type =
387 16 | (ldt_info.contents << 2) | (!ldt_info.read_exec_only << 1);
388 sd.sd_dpl = SEL_UPL;
389 sd.sd_p = !ldt_info.seg_not_present;
390 sd.sd_def32 = ldt_info.seg_32bit;
391 sd.sd_gran = ldt_info.limit_in_pages;
392
393 sl.start = ldt_info.entry_number;
394 sl.desc = stackgap_alloc(&sg, sizeof(sd));
395 sl.num = 1;
396
397 #if 0
398 printf("linux_write_ldt: idx=%d, base=%x, limit=%x\n",
399 ldt_info.entry_number, ldt_info.base_addr, ldt_info.limit);
400 #endif
401
402 parms = stackgap_alloc(&sg, sizeof(sl));
403
404 if ((error = copyout(&sd, sl.desc, sizeof(sd))) != 0)
405 return (error);
406 if ((error = copyout(&sl, parms, sizeof(sl))) != 0)
407 return (error);
408
409 if ((error = i386_set_ldt(p, parms, retval)) != 0)
410 return (error);
411
412 *retval = 0;
413 return (0);
414 }
415
416 #endif /* USER_LDT */
417
418 int
419 linux_sys_modify_ldt(p, v, retval)
420 struct proc *p;
421 void *v;
422 register_t *retval;
423 {
424 struct linux_sys_modify_ldt_args /* {
425 syscallarg(int) func;
426 syscallarg(void *) ptr;
427 syscallarg(size_t) bytecount;
428 } */ *uap = v;
429
430 switch (SCARG(uap, func)) {
431 #ifdef USER_LDT
432 case 0:
433 return (linux_read_ldt(p, uap, retval));
434
435 case 1:
436 return (linux_write_ldt(p, uap, retval));
437 #endif /* USER_LDT */
438
439 default:
440 return (ENOSYS);
441 }
442 }
443
444 /*
445 * XXX Pathetic hack to make svgalib work. This will fake the major
446 * device number of an opened VT so that svgalib likes it. grmbl.
447 * Should probably do it 'wrong the right way' and use a mapping
448 * array for all major device numbers, and map linux_mknod too.
449 */
450 dev_t
451 linux_fakedev(dev)
452 dev_t dev;
453 {
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)
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 (NWSDISPLAY > 0)
558 int error;
559 struct vt_mode lvt;
560 caddr_t bvtp, sg;
561 struct kbentry kbe;
562 #endif
563
564 SCARG(&bia, fd) = SCARG(uap, fd);
565 SCARG(&bia, data) = SCARG(uap, data);
566 com = SCARG(uap, com);
567
568 switch (com) {
569 #if (NWSDISPLAY > 0)
570 case LINUX_KDGKBMODE:
571 com = KDGKBMODE;
572 break;
573 case LINUX_KDSKBMODE:
574 com = KDSKBMODE;
575 if ((unsigned)SCARG(uap, data) == LINUX_K_MEDIUMRAW)
576 SCARG(&bia, data) = (caddr_t)K_RAW;
577 break;
578 case LINUX_KDMKTONE:
579 com = KDMKTONE;
580 break;
581 case LINUX_KDSETMODE:
582 com = KDSETMODE;
583 break;
584 case LINUX_KDENABIO:
585 com = KDENABIO;
586 break;
587 case LINUX_KDDISABIO:
588 com = KDDISABIO;
589 break;
590 case LINUX_KDGETLED:
591 com = KDGETLED;
592 break;
593 case LINUX_KDSETLED:
594 com = KDSETLED;
595 break;
596 case LINUX_VT_OPENQRY:
597 com = VT_OPENQRY;
598 break;
599 case LINUX_VT_GETMODE:
600 SCARG(&bia, com) = VT_GETMODE;
601 if ((error = sys_ioctl(p, &bia, retval)))
602 return error;
603 if ((error = copyin(SCARG(uap, data), (caddr_t)&lvt,
604 sizeof (struct vt_mode))))
605 return error;
606 lvt.relsig = native_to_linux_sig[lvt.relsig];
607 lvt.acqsig = native_to_linux_sig[lvt.acqsig];
608 lvt.frsig = native_to_linux_sig[lvt.frsig];
609 return copyout((caddr_t)&lvt, SCARG(uap, data),
610 sizeof (struct vt_mode));
611 case LINUX_VT_SETMODE:
612 com = VT_SETMODE;
613 if ((error = copyin(SCARG(uap, data), (caddr_t)&lvt,
614 sizeof (struct vt_mode))))
615 return error;
616 lvt.relsig = linux_to_native_sig[lvt.relsig];
617 lvt.acqsig = linux_to_native_sig[lvt.acqsig];
618 lvt.frsig = linux_to_native_sig[lvt.frsig];
619 sg = stackgap_init(p->p_emul);
620 bvtp = stackgap_alloc(&sg, sizeof (struct vt_mode));
621 if ((error = copyout(&lvt, bvtp, sizeof (struct vt_mode))))
622 return error;
623 SCARG(&bia, data) = bvtp;
624 break;
625 case LINUX_VT_RELDISP:
626 com = VT_RELDISP;
627 break;
628 case LINUX_VT_ACTIVATE:
629 com = VT_ACTIVATE;
630 break;
631 case LINUX_VT_WAITACTIVE:
632 com = VT_WAITACTIVE;
633 break;
634 case LINUX_VT_GETSTATE:
635 com = VT_GETSTATE;
636 break;
637 case LINUX_KDGKBTYPE:
638 /* This is what Linux does. */
639 return (subyte(SCARG(uap, data), KB_101));
640 case LINUX_KDGKBENT:
641 /*
642 * The Linux KDGKBENT ioctl is different from the
643 * SYSV original. So we handle it in machdep code.
644 * XXX We should use keyboard mapping information
645 * from wsdisplay, but this would be expensive.
646 */
647 if ((error = copyin(SCARG(uap, data), &kbe,
648 sizeof(struct kbentry))))
649 return (error);
650 if (kbe.kb_table >= sizeof(linux_keytabs) / sizeof(u_short *)
651 || kbe.kb_index >= NR_KEYS)
652 return (EINVAL);
653 kbe.kb_value = linux_keytabs[kbe.kb_table][kbe.kb_index];
654 return (copyout(&kbe, SCARG(uap, data),
655 sizeof(struct kbentry)));
656 #endif
657 default:
658 printf("linux_machdepioctl: invalid ioctl %08lx\n", com);
659 return EINVAL;
660 }
661 SCARG(&bia, com) = com;
662 return sys_ioctl(p, &bia, retval);
663 }
664
665 /*
666 * Set I/O permissions for a process. Just set the maximum level
667 * right away (ignoring the argument), otherwise we would have
668 * to rely on I/O permission maps, which are not implemented.
669 */
670 int
671 linux_sys_iopl(p, v, retval)
672 struct proc *p;
673 void *v;
674 register_t *retval;
675 {
676 #if 0
677 struct linux_sys_iopl_args /* {
678 syscallarg(int) level;
679 } */ *uap = v;
680 #endif
681 struct trapframe *fp = p->p_md.md_regs;
682
683 if (suser(p->p_ucred, &p->p_acflag) != 0)
684 return EPERM;
685 fp->tf_eflags |= PSL_IOPL;
686 *retval = 0;
687 return 0;
688 }
689
690 /*
691 * See above. If a root process tries to set access to an I/O port,
692 * just let it have the whole range.
693 */
694 int
695 linux_sys_ioperm(p, v, retval)
696 struct proc *p;
697 void *v;
698 register_t *retval;
699 {
700 struct linux_sys_ioperm_args /* {
701 syscallarg(unsigned int) lo;
702 syscallarg(unsigned int) hi;
703 syscallarg(int) val;
704 } */ *uap = v;
705 struct trapframe *fp = p->p_md.md_regs;
706
707 if (suser(p->p_ucred, &p->p_acflag) != 0)
708 return EPERM;
709 if (SCARG(uap, val))
710 fp->tf_eflags |= PSL_IOPL;
711 *retval = 0;
712 return 0;
713 }
714