linux_machdep.c revision 1.62.2.5 1 /* $NetBSD: linux_machdep.c,v 1.62.2.5 2002/02/28 04:12:49 nathanw Exp $ */
2
3 /*-
4 * Copyright (c) 1995, 2000 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 <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: linux_machdep.c,v 1.62.2.5 2002/02/28 04:12:49 nathanw Exp $");
41
42 #if defined(_KERNEL_OPT)
43 #include "opt_vm86.h"
44 #include "opt_user_ldt.h"
45 #endif
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/signalvar.h>
50 #include <sys/kernel.h>
51 #include <sys/map.h>
52 #include <sys/lwp.h>
53 #include <sys/proc.h>
54 #include <sys/user.h>
55 #include <sys/buf.h>
56 #include <sys/reboot.h>
57 #include <sys/conf.h>
58 #include <sys/exec.h>
59 #include <sys/file.h>
60 #include <sys/callout.h>
61 #include <sys/malloc.h>
62 #include <sys/mbuf.h>
63 #include <sys/msgbuf.h>
64 #include <sys/mount.h>
65 #include <sys/vnode.h>
66 #include <sys/device.h>
67 #include <sys/syscallargs.h>
68 #include <sys/filedesc.h>
69 #include <sys/exec_elf.h>
70 #include <sys/disklabel.h>
71 #include <sys/ioctl.h>
72 #include <miscfs/specfs/specdev.h>
73
74 #include <compat/linux/common/linux_types.h>
75 #include <compat/linux/common/linux_signal.h>
76 #include <compat/linux/common/linux_util.h>
77 #include <compat/linux/common/linux_ioctl.h>
78 #include <compat/linux/common/linux_hdio.h>
79 #include <compat/linux/common/linux_exec.h>
80 #include <compat/linux/common/linux_machdep.h>
81
82 #include <compat/linux/linux_syscallargs.h>
83
84 #include <machine/cpu.h>
85 #include <machine/cpufunc.h>
86 #include <machine/psl.h>
87 #include <machine/reg.h>
88 #include <machine/segments.h>
89 #include <machine/specialreg.h>
90 #include <machine/sysarch.h>
91 #include <machine/vm86.h>
92 #include <machine/vmparam.h>
93
94 /*
95 * To see whether wscons is configured (for virtual console ioctl calls).
96 */
97 #if defined(_KERNEL_OPT)
98 #include "wsdisplay.h"
99 #endif
100 #if (NWSDISPLAY > 0)
101 #include <dev/wscons/wsconsio.h>
102 #include <dev/wscons/wsdisplay_usl_io.h>
103 #if defined(_KERNEL_OPT)
104 #include "opt_xserver.h"
105 #endif
106 #endif
107
108 #ifdef USER_LDT
109 #include <machine/cpu.h>
110 int linux_read_ldt __P((struct lwp *, struct linux_sys_modify_ldt_args *,
111 register_t *));
112 int linux_write_ldt __P((struct lwp *, struct linux_sys_modify_ldt_args *,
113 register_t *));
114 #endif
115
116 static struct biosdisk_info *fd2biosinfo __P((struct proc *, struct file *));
117 extern struct disklist *i386_alldisks;
118 extern const char *findblkname __P((int));
119
120 /*
121 * Deal with some i386-specific things in the Linux emulation code.
122 */
123
124 void
125 linux_setregs(l, epp, stack)
126 struct lwp *l;
127 struct exec_package *epp;
128 u_long stack;
129 {
130 struct pcb *pcb = &l->l_addr->u_pcb;
131
132 setregs(l, epp, stack);
133 if (i386_use_fxsave)
134 pcb->pcb_savefpu.sv_xmm.sv_env.en_cw = __Linux_NPXCW__;
135 else
136 pcb->pcb_savefpu.sv_87.sv_env.en_cw = __Linux_NPXCW__;
137 }
138
139 /*
140 * Send an interrupt to process.
141 *
142 * Stack is set up to allow sigcode stored
143 * in u. to call routine, followed by kcall
144 * to sigreturn routine below. After sigreturn
145 * resets the signal mask, the stack, and the
146 * frame pointer, it returns to the user
147 * specified pc, psl.
148 */
149
150 void
151 linux_sendsig(catcher, sig, mask, code)
152 sig_t catcher;
153 int sig;
154 sigset_t *mask;
155 u_long code;
156 {
157 struct lwp *l = curproc;
158 struct proc *p = l->l_proc;
159 struct trapframe *tf;
160 struct linux_sigframe *fp, frame;
161 int onstack;
162
163 tf = l->l_md.md_regs;
164 /* Do we need to jump onto the signal stack? */
165 onstack =
166 (p->p_sigctx.ps_sigstk.ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 &&
167 (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0;
168
169 /* Allocate space for the signal handler context. */
170 if (onstack)
171 fp = (struct linux_sigframe *)((caddr_t)p->p_sigctx.ps_sigstk.ss_sp +
172 p->p_sigctx.ps_sigstk.ss_size);
173 else
174 fp = (struct linux_sigframe *)tf->tf_esp;
175 fp--;
176
177 /* Build stack frame for signal trampoline. */
178 frame.sf_handler = catcher;
179 frame.sf_sig = native_to_linux_sig[sig];
180
181 /* Save register context. */
182 #ifdef VM86
183 if (tf->tf_eflags & PSL_VM) {
184 frame.sf_sc.sc_gs = tf->tf_vm86_gs;
185 frame.sf_sc.sc_fs = tf->tf_vm86_fs;
186 frame.sf_sc.sc_es = tf->tf_vm86_es;
187 frame.sf_sc.sc_ds = tf->tf_vm86_ds;
188 frame.sf_sc.sc_eflags = get_vflags(l);
189 } else
190 #endif
191 {
192 frame.sf_sc.sc_gs = tf->tf_gs;
193 frame.sf_sc.sc_fs = tf->tf_fs;
194 frame.sf_sc.sc_es = tf->tf_es;
195 frame.sf_sc.sc_ds = tf->tf_ds;
196 frame.sf_sc.sc_eflags = tf->tf_eflags;
197 }
198 frame.sf_sc.sc_edi = tf->tf_edi;
199 frame.sf_sc.sc_esi = tf->tf_esi;
200 frame.sf_sc.sc_ebp = tf->tf_ebp;
201 frame.sf_sc.sc_ebx = tf->tf_ebx;
202 frame.sf_sc.sc_edx = tf->tf_edx;
203 frame.sf_sc.sc_ecx = tf->tf_ecx;
204 frame.sf_sc.sc_eax = tf->tf_eax;
205 frame.sf_sc.sc_eip = tf->tf_eip;
206 frame.sf_sc.sc_cs = tf->tf_cs;
207 frame.sf_sc.sc_esp_at_signal = tf->tf_esp;
208 frame.sf_sc.sc_ss = tf->tf_ss;
209 frame.sf_sc.sc_err = tf->tf_err;
210 frame.sf_sc.sc_trapno = tf->tf_trapno;
211 frame.sf_sc.sc_cr2 = p->p_addr->u_pcb.pcb_cr2;
212
213 /* Save signal stack. */
214 /* Linux doesn't save the onstack flag in sigframe */
215
216 /* Save signal mask. */
217 native_to_linux_old_sigset(&frame.sf_sc.sc_mask, mask);
218
219 if (copyout(&frame, fp, sizeof(frame)) != 0) {
220 /*
221 * Process has trashed its stack; give it an illegal
222 * instruction to halt it in its tracks.
223 */
224 sigexit(l, SIGILL);
225 /* NOTREACHED */
226 }
227
228 /*
229 * Build context to run handler in.
230 */
231 tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL);
232 tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL);
233 tf->tf_eip = (int)p->p_sigctx.ps_sigcode;
234 tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL);
235 tf->tf_eflags &= ~(PSL_T|PSL_VM|PSL_AC);
236 tf->tf_esp = (int)fp;
237 tf->tf_ss = GSEL(GUDATA_SEL, SEL_UPL);
238
239 /* Remember that we're now on the signal stack. */
240 if (onstack)
241 p->p_sigctx.ps_sigstk.ss_flags |= SS_ONSTACK;
242 }
243
244 /*
245 * System call to cleanup state after a signal
246 * has been taken. Reset signal mask and
247 * stack state from context left by sendsig (above).
248 * Return to previous pc and psl as specified by
249 * context left by sendsig. Check carefully to
250 * make sure that the user has not modified the
251 * psl to gain improper privileges or to cause
252 * a machine fault.
253 */
254 int
255 linux_sys_rt_sigreturn(l, v, retval)
256 struct lwp *l;
257 void *v;
258 register_t *retval;
259 {
260 /* XXX XAX write me */
261 return(ENOSYS);
262 }
263
264 int
265 linux_sys_sigreturn(l, v, retval)
266 struct lwp *l;
267 void *v;
268 register_t *retval;
269 {
270 struct linux_sys_sigreturn_args /* {
271 syscallarg(struct linux_sigcontext *) scp;
272 } */ *uap = v;
273 struct proc *p = l->l_proc;
274 struct linux_sigcontext *scp, context;
275 struct trapframe *tf;
276 sigset_t mask;
277 ssize_t ss_gap;
278
279 /*
280 * The trampoline code hands us the context.
281 * It is unsafe to keep track of it ourselves, in the event that a
282 * program jumps out of a signal handler.
283 */
284 scp = SCARG(uap, scp);
285 if (copyin((caddr_t)scp, &context, sizeof(*scp)) != 0)
286 return (EFAULT);
287
288 /* Restore register context. */
289 tf = l->l_md.md_regs;
290 #ifdef VM86
291 if (context.sc_eflags & PSL_VM) {
292 tf->tf_vm86_gs = context.sc_gs;
293 tf->tf_vm86_fs = context.sc_fs;
294 tf->tf_vm86_es = context.sc_es;
295 tf->tf_vm86_ds = context.sc_ds;
296 set_vflags(l, context.sc_eflags);
297 } else
298 #endif
299 {
300 /*
301 * Check for security violations. If we're returning to
302 * protected mode, the CPU will validate the segment registers
303 * automatically and generate a trap on violations. We handle
304 * the trap, rather than doing all of the checking here.
305 */
306 if (((context.sc_eflags ^ tf->tf_eflags) & PSL_USERSTATIC) != 0 ||
307 !USERMODE(context.sc_cs, context.sc_eflags))
308 return (EINVAL);
309
310 /* %fs and %gs were restored by the trampoline. */
311 tf->tf_es = context.sc_es;
312 tf->tf_ds = context.sc_ds;
313 tf->tf_eflags = context.sc_eflags;
314 }
315 tf->tf_edi = context.sc_edi;
316 tf->tf_esi = context.sc_esi;
317 tf->tf_ebp = context.sc_ebp;
318 tf->tf_ebx = context.sc_ebx;
319 tf->tf_edx = context.sc_edx;
320 tf->tf_ecx = context.sc_ecx;
321 tf->tf_eax = context.sc_eax;
322 tf->tf_eip = context.sc_eip;
323 tf->tf_cs = context.sc_cs;
324 tf->tf_esp = context.sc_esp_at_signal;
325 tf->tf_ss = context.sc_ss;
326
327 /* Restore signal stack. */
328 /*
329 * Linux really does it this way; it doesn't have space in sigframe
330 * to save the onstack flag.
331 */
332 ss_gap = (ssize_t)
333 ((caddr_t) context.sc_esp_at_signal - (caddr_t) p->p_sigctx.ps_sigstk.ss_sp);
334 if (ss_gap >= 0 && ss_gap < p->p_sigctx.ps_sigstk.ss_size)
335 p->p_sigctx.ps_sigstk.ss_flags |= SS_ONSTACK;
336 else
337 p->p_sigctx.ps_sigstk.ss_flags &= ~SS_ONSTACK;
338
339 /* Restore signal mask. */
340 linux_old_to_native_sigset(&mask, &context.sc_mask);
341 (void) sigprocmask1(p, SIG_SETMASK, &mask, 0);
342
343 return (EJUSTRETURN);
344 }
345
346 #ifdef USER_LDT
347
348 int
349 linux_read_ldt(l, uap, retval)
350 struct lwp *l;
351 struct linux_sys_modify_ldt_args /* {
352 syscallarg(int) func;
353 syscallarg(void *) ptr;
354 syscallarg(size_t) bytecount;
355 } */ *uap;
356 register_t *retval;
357 {
358 struct proc *p = l->l_proc;
359 struct i386_get_ldt_args gl;
360 int error;
361 caddr_t sg;
362 char *parms;
363
364 sg = stackgap_init(p->p_emul);
365
366 gl.start = 0;
367 gl.desc = SCARG(uap, ptr);
368 gl.num = SCARG(uap, bytecount) / sizeof(union descriptor);
369
370 parms = stackgap_alloc(&sg, sizeof(gl));
371
372 if ((error = copyout(&gl, parms, sizeof(gl))) != 0)
373 return (error);
374
375 if ((error = i386_get_ldt(l, parms, retval)) != 0)
376 return (error);
377
378 *retval *= sizeof(union descriptor);
379 return (0);
380 }
381
382 struct linux_ldt_info {
383 u_int entry_number;
384 u_long base_addr;
385 u_int limit;
386 u_int seg_32bit:1;
387 u_int contents:2;
388 u_int read_exec_only:1;
389 u_int limit_in_pages:1;
390 u_int seg_not_present:1;
391 };
392
393 int
394 linux_write_ldt(l, uap, retval)
395 struct lwp *l;
396 struct linux_sys_modify_ldt_args /* {
397 syscallarg(int) func;
398 syscallarg(void *) ptr;
399 syscallarg(size_t) bytecount;
400 } */ *uap;
401 register_t *retval;
402 {
403 struct proc *p = l->l_proc;
404 struct linux_ldt_info ldt_info;
405 struct segment_descriptor sd;
406 struct i386_set_ldt_args sl;
407 int error;
408 caddr_t sg;
409 char *parms;
410
411 if (SCARG(uap, bytecount) != sizeof(ldt_info))
412 return (EINVAL);
413 if ((error = copyin(SCARG(uap, ptr), &ldt_info, sizeof(ldt_info))) != 0)
414 return error;
415 if (ldt_info.contents == 3)
416 return (EINVAL);
417
418 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
419 /* this means you should zero the ldt */
420 (void)memset(&sd, 0, sizeof(sd));
421 } else {
422 sd.sd_lobase = ldt_info.base_addr & 0xffffff;
423 sd.sd_hibase = (ldt_info.base_addr >> 24) & 0xff;
424 sd.sd_lolimit = ldt_info.limit & 0xffff;
425 sd.sd_hilimit = (ldt_info.limit >> 16) & 0xf;
426 sd.sd_type = 16 | (ldt_info.contents << 2) |
427 (!ldt_info.read_exec_only << 1);
428 sd.sd_dpl = SEL_UPL;
429 sd.sd_p = !ldt_info.seg_not_present;
430 sd.sd_def32 = ldt_info.seg_32bit;
431 sd.sd_gran = ldt_info.limit_in_pages;
432 }
433 sg = stackgap_init(p->p_emul);
434 sl.start = ldt_info.entry_number;
435 sl.desc = stackgap_alloc(&sg, sizeof(sd));
436 sl.num = 1;
437
438 #if 0
439 printf("linux_write_ldt: idx=%d, base=%x, limit=%x\n",
440 ldt_info.entry_number, ldt_info.base_addr, ldt_info.limit);
441 #endif
442
443 parms = stackgap_alloc(&sg, sizeof(sl));
444
445 if ((error = copyout(&sd, sl.desc, sizeof(sd))) != 0)
446 return (error);
447 if ((error = copyout(&sl, parms, sizeof(sl))) != 0)
448 return (error);
449
450 if ((error = i386_set_ldt(l, parms, retval)) != 0)
451 return (error);
452
453 *retval = 0;
454 return (0);
455 }
456
457 #endif /* USER_LDT */
458
459 int
460 linux_sys_modify_ldt(l, v, retval)
461 struct lwp *l;
462 void *v;
463 register_t *retval;
464 {
465 struct linux_sys_modify_ldt_args /* {
466 syscallarg(int) func;
467 syscallarg(void *) ptr;
468 syscallarg(size_t) bytecount;
469 } */ *uap = v;
470
471 switch (SCARG(uap, func)) {
472 #ifdef USER_LDT
473 case 0:
474 return (linux_read_ldt(l, uap, retval));
475
476 case 1:
477 return (linux_write_ldt(l, uap, retval));
478 #endif /* USER_LDT */
479
480 default:
481 return (ENOSYS);
482 }
483 }
484
485 /*
486 * XXX Pathetic hack to make svgalib work. This will fake the major
487 * device number of an opened VT so that svgalib likes it. grmbl.
488 * Should probably do it 'wrong the right way' and use a mapping
489 * array for all major device numbers, and map linux_mknod too.
490 */
491 dev_t
492 linux_fakedev(dev, raw)
493 dev_t dev;
494 int raw;
495 {
496 if (raw) {
497 #if (NWSDISPLAY > 0)
498 if (major(dev) == NETBSD_WSCONS_MAJOR)
499 return makedev(LINUX_CONS_MAJOR, (minor(dev) + 1));
500 #endif
501 return 0;
502 } else {
503 return dev;
504 }
505 }
506
507 #if (NWSDISPLAY > 0)
508 /*
509 * That's not complete, but enough to get an X server running.
510 */
511 #define NR_KEYS 128
512 static const u_short plain_map[NR_KEYS] = {
513 0x0200, 0x001b, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036,
514 0x0037, 0x0038, 0x0039, 0x0030, 0x002d, 0x003d, 0x007f, 0x0009,
515 0x0b71, 0x0b77, 0x0b65, 0x0b72, 0x0b74, 0x0b79, 0x0b75, 0x0b69,
516 0x0b6f, 0x0b70, 0x005b, 0x005d, 0x0201, 0x0702, 0x0b61, 0x0b73,
517 0x0b64, 0x0b66, 0x0b67, 0x0b68, 0x0b6a, 0x0b6b, 0x0b6c, 0x003b,
518 0x0027, 0x0060, 0x0700, 0x005c, 0x0b7a, 0x0b78, 0x0b63, 0x0b76,
519 0x0b62, 0x0b6e, 0x0b6d, 0x002c, 0x002e, 0x002f, 0x0700, 0x030c,
520 0x0703, 0x0020, 0x0207, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104,
521 0x0105, 0x0106, 0x0107, 0x0108, 0x0109, 0x0208, 0x0209, 0x0307,
522 0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
523 0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x003c, 0x010a,
524 0x010b, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
525 0x030e, 0x0702, 0x030d, 0x001c, 0x0701, 0x0205, 0x0114, 0x0603,
526 0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
527 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
528 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
529 }, shift_map[NR_KEYS] = {
530 0x0200, 0x001b, 0x0021, 0x0040, 0x0023, 0x0024, 0x0025, 0x005e,
531 0x0026, 0x002a, 0x0028, 0x0029, 0x005f, 0x002b, 0x007f, 0x0009,
532 0x0b51, 0x0b57, 0x0b45, 0x0b52, 0x0b54, 0x0b59, 0x0b55, 0x0b49,
533 0x0b4f, 0x0b50, 0x007b, 0x007d, 0x0201, 0x0702, 0x0b41, 0x0b53,
534 0x0b44, 0x0b46, 0x0b47, 0x0b48, 0x0b4a, 0x0b4b, 0x0b4c, 0x003a,
535 0x0022, 0x007e, 0x0700, 0x007c, 0x0b5a, 0x0b58, 0x0b43, 0x0b56,
536 0x0b42, 0x0b4e, 0x0b4d, 0x003c, 0x003e, 0x003f, 0x0700, 0x030c,
537 0x0703, 0x0020, 0x0207, 0x010a, 0x010b, 0x010c, 0x010d, 0x010e,
538 0x010f, 0x0110, 0x0111, 0x0112, 0x0113, 0x0213, 0x0203, 0x0307,
539 0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
540 0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x003e, 0x010a,
541 0x010b, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
542 0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
543 0x020b, 0x0601, 0x0602, 0x0117, 0x0600, 0x020a, 0x0115, 0x0116,
544 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
545 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
546 }, altgr_map[NR_KEYS] = {
547 0x0200, 0x0200, 0x0200, 0x0040, 0x0200, 0x0024, 0x0200, 0x0200,
548 0x007b, 0x005b, 0x005d, 0x007d, 0x005c, 0x0200, 0x0200, 0x0200,
549 0x0b71, 0x0b77, 0x0918, 0x0b72, 0x0b74, 0x0b79, 0x0b75, 0x0b69,
550 0x0b6f, 0x0b70, 0x0200, 0x007e, 0x0201, 0x0702, 0x0914, 0x0b73,
551 0x0917, 0x0919, 0x0b67, 0x0b68, 0x0b6a, 0x0b6b, 0x0b6c, 0x0200,
552 0x0200, 0x0200, 0x0700, 0x0200, 0x0b7a, 0x0b78, 0x0916, 0x0b76,
553 0x0915, 0x0b6e, 0x0b6d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
554 0x0703, 0x0200, 0x0207, 0x050c, 0x050d, 0x050e, 0x050f, 0x0510,
555 0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0208, 0x0202, 0x0911,
556 0x0912, 0x0913, 0x030b, 0x090e, 0x090f, 0x0910, 0x030a, 0x090b,
557 0x090c, 0x090d, 0x090a, 0x0310, 0x0206, 0x0200, 0x007c, 0x0516,
558 0x0517, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
559 0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
560 0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
561 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
562 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
563 }, ctrl_map[NR_KEYS] = {
564 0x0200, 0x0200, 0x0200, 0x0000, 0x001b, 0x001c, 0x001d, 0x001e,
565 0x001f, 0x007f, 0x0200, 0x0200, 0x001f, 0x0200, 0x0008, 0x0200,
566 0x0011, 0x0017, 0x0005, 0x0012, 0x0014, 0x0019, 0x0015, 0x0009,
567 0x000f, 0x0010, 0x001b, 0x001d, 0x0201, 0x0702, 0x0001, 0x0013,
568 0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b, 0x000c, 0x0200,
569 0x0007, 0x0000, 0x0700, 0x001c, 0x001a, 0x0018, 0x0003, 0x0016,
570 0x0002, 0x000e, 0x000d, 0x0200, 0x020e, 0x007f, 0x0700, 0x030c,
571 0x0703, 0x0000, 0x0207, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104,
572 0x0105, 0x0106, 0x0107, 0x0108, 0x0109, 0x0208, 0x0204, 0x0307,
573 0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
574 0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x0200, 0x010a,
575 0x010b, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
576 0x030e, 0x0702, 0x030d, 0x001c, 0x0701, 0x0205, 0x0114, 0x0603,
577 0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
578 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
579 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
580 };
581
582 const u_short * const linux_keytabs[] = {
583 plain_map, shift_map, altgr_map, altgr_map, ctrl_map
584 };
585 #endif
586
587 static struct biosdisk_info *
588 fd2biosinfo(p, fp)
589 struct proc *p;
590 struct file *fp;
591 {
592 struct vnode *vp;
593 const char *blkname;
594 char diskname[16];
595 int i;
596 struct nativedisk_info *nip;
597 struct disklist *dl = i386_alldisks;
598
599 if (fp->f_type != DTYPE_VNODE)
600 return NULL;
601 vp = (struct vnode *)fp->f_data;
602
603 if (vp->v_type != VBLK)
604 return NULL;
605
606 blkname = findblkname(major(vp->v_rdev));
607 snprintf(diskname, sizeof diskname, "%s%u", blkname,
608 DISKUNIT(vp->v_rdev));
609
610 for (i = 0; i < dl->dl_nnativedisks; i++) {
611 nip = &dl->dl_nativedisks[i];
612 if (strcmp(diskname, nip->ni_devname))
613 continue;
614 if (nip->ni_nmatches != 0)
615 return &dl->dl_biosdisks[nip->ni_biosmatches[0]];
616 }
617
618 return NULL;
619 }
620
621
622 /*
623 * We come here in a last attempt to satisfy a Linux ioctl() call
624 */
625 int
626 linux_machdepioctl(p, v, retval)
627 struct proc *p;
628 void *v;
629 register_t *retval;
630 {
631 struct linux_sys_ioctl_args /* {
632 syscallarg(int) fd;
633 syscallarg(u_long) com;
634 syscallarg(caddr_t) data;
635 } */ *uap = v;
636 struct sys_ioctl_args bia;
637 u_long com;
638 int error, error1;
639 #if (NWSDISPLAY > 0)
640 struct vt_mode lvt;
641 caddr_t bvtp, sg;
642 struct kbentry kbe;
643 #endif
644 struct linux_hd_geometry hdg;
645 struct linux_hd_big_geometry hdg_big;
646 struct biosdisk_info *bip;
647 struct filedesc *fdp;
648 struct file *fp;
649 int fd;
650 struct disklabel label, *labp;
651 struct partinfo partp;
652 int (*ioctlf) __P((struct file *, u_long, caddr_t, struct proc *));
653 u_long start, biostotal, realtotal;
654 u_char heads, sectors;
655 u_int cylinders;
656 struct ioctl_pt pt;
657
658 fd = SCARG(uap, fd);
659 SCARG(&bia, fd) = fd;
660 SCARG(&bia, data) = SCARG(uap, data);
661 com = SCARG(uap, com);
662
663 fdp = p->p_fd;
664
665 if ((fp = fd_getfile(fdp, fd)) == NULL)
666 return (EBADF);
667
668 switch (com) {
669 #if (NWSDISPLAY > 0)
670 case LINUX_KDGKBMODE:
671 com = KDGKBMODE;
672 break;
673 case LINUX_KDSKBMODE:
674 com = KDSKBMODE;
675 if ((unsigned)SCARG(uap, data) == LINUX_K_MEDIUMRAW)
676 SCARG(&bia, data) = (caddr_t)K_RAW;
677 break;
678 case LINUX_KIOCSOUND:
679 SCARG(&bia, data) =
680 (caddr_t)(((unsigned long)SCARG(&bia, data)) & 0xffff);
681 /* fall through */
682 case LINUX_KDMKTONE:
683 com = KDMKTONE;
684 break;
685 case LINUX_KDSETMODE:
686 com = KDSETMODE;
687 break;
688 case LINUX_KDGETMODE:
689 /* KD_* values are equal to the wscons numbers */
690 com = WSDISPLAYIO_GMODE;
691 break;
692 case LINUX_KDENABIO:
693 com = KDENABIO;
694 break;
695 case LINUX_KDDISABIO:
696 com = KDDISABIO;
697 break;
698 case LINUX_KDGETLED:
699 com = KDGETLED;
700 break;
701 case LINUX_KDSETLED:
702 com = KDSETLED;
703 break;
704 case LINUX_VT_OPENQRY:
705 com = VT_OPENQRY;
706 break;
707 case LINUX_VT_GETMODE:
708 SCARG(&bia, com) = VT_GETMODE;
709 /* XXX NJWLWP */
710 if ((error = sys_ioctl(curproc, &bia, retval)))
711 return error;
712 if ((error = copyin(SCARG(uap, data), (caddr_t)&lvt,
713 sizeof (struct vt_mode))))
714 return error;
715 lvt.relsig = native_to_linux_sig[lvt.relsig];
716 lvt.acqsig = native_to_linux_sig[lvt.acqsig];
717 lvt.frsig = native_to_linux_sig[lvt.frsig];
718 return copyout((caddr_t)&lvt, SCARG(uap, data),
719 sizeof (struct vt_mode));
720 case LINUX_VT_SETMODE:
721 com = VT_SETMODE;
722 if ((error = copyin(SCARG(uap, data), (caddr_t)&lvt,
723 sizeof (struct vt_mode))))
724 return error;
725 lvt.relsig = linux_to_native_sig[lvt.relsig];
726 lvt.acqsig = linux_to_native_sig[lvt.acqsig];
727 lvt.frsig = linux_to_native_sig[lvt.frsig];
728 sg = stackgap_init(p->p_emul);
729 bvtp = stackgap_alloc(&sg, sizeof (struct vt_mode));
730 if ((error = copyout(&lvt, bvtp, sizeof (struct vt_mode))))
731 return error;
732 SCARG(&bia, data) = bvtp;
733 break;
734 case LINUX_VT_DISALLOCATE:
735 /* XXX should use WSDISPLAYIO_DELSCREEN */
736 return 0;
737 case LINUX_VT_RELDISP:
738 com = VT_RELDISP;
739 break;
740 case LINUX_VT_ACTIVATE:
741 com = VT_ACTIVATE;
742 break;
743 case LINUX_VT_WAITACTIVE:
744 com = VT_WAITACTIVE;
745 break;
746 case LINUX_VT_GETSTATE:
747 com = VT_GETSTATE;
748 break;
749 case LINUX_KDGKBTYPE:
750 /* This is what Linux does. */
751 return (subyte(SCARG(uap, data), KB_101));
752 case LINUX_KDGKBENT:
753 /*
754 * The Linux KDGKBENT ioctl is different from the
755 * SYSV original. So we handle it in machdep code.
756 * XXX We should use keyboard mapping information
757 * from wsdisplay, but this would be expensive.
758 */
759 if ((error = copyin(SCARG(uap, data), &kbe,
760 sizeof(struct kbentry))))
761 return (error);
762 if (kbe.kb_table >= sizeof(linux_keytabs) / sizeof(u_short *)
763 || kbe.kb_index >= NR_KEYS)
764 return (EINVAL);
765 kbe.kb_value = linux_keytabs[kbe.kb_table][kbe.kb_index];
766 return (copyout(&kbe, SCARG(uap, data),
767 sizeof(struct kbentry)));
768 #endif
769 case LINUX_HDIO_GETGEO:
770 case LINUX_HDIO_GETGEO_BIG:
771 /*
772 * Try to mimic Linux behaviour: return the BIOS geometry
773 * if possible (extending its # of cylinders if it's beyond
774 * the 1023 limit), fall back to the MI geometry (i.e.
775 * the real geometry) if not found, by returning an
776 * error. See common/linux_hdio.c
777 */
778 FILE_USE(fp);
779 bip = fd2biosinfo(p, fp);
780 ioctlf = fp->f_ops->fo_ioctl;
781 error = ioctlf(fp, DIOCGDEFLABEL, (caddr_t)&label, p);
782 error1 = ioctlf(fp, DIOCGPART, (caddr_t)&partp, p);
783 FILE_UNUSE(fp, p);
784 if (error != 0 && error1 != 0)
785 return error1;
786 labp = error != 0 ? &label : partp.disklab;
787 start = error1 != 0 ? partp.part->p_offset : 0;
788 if (bip != NULL && bip->bi_head != 0 && bip->bi_sec != 0
789 && bip->bi_cyl != 0) {
790 heads = bip->bi_head;
791 sectors = bip->bi_sec;
792 cylinders = bip->bi_cyl;
793 biostotal = heads * sectors * cylinders;
794 realtotal = labp->d_ntracks * labp->d_nsectors *
795 labp->d_ncylinders;
796 if (realtotal > biostotal)
797 cylinders = realtotal / (heads * sectors);
798 } else {
799 heads = labp->d_ntracks;
800 cylinders = labp->d_ncylinders;
801 sectors = labp->d_nsectors;
802 }
803 if (com == LINUX_HDIO_GETGEO) {
804 hdg.start = start;
805 hdg.heads = heads;
806 hdg.cylinders = cylinders;
807 hdg.sectors = sectors;
808 return copyout(&hdg, SCARG(uap, data), sizeof hdg);
809 } else {
810 hdg_big.start = start;
811 hdg_big.heads = heads;
812 hdg_big.cylinders = cylinders;
813 hdg_big.sectors = sectors;
814 return copyout(&hdg_big, SCARG(uap, data),
815 sizeof hdg_big);
816 }
817 return 0;
818
819 default:
820 /*
821 * Unknown to us. If it's on a device, just pass it through
822 * using PTIOCLINUX, the device itself might be able to
823 * make some sense of it.
824 * XXX hack: if the function returns EJUSTRETURN,
825 * it has stuffed a sysctl return value in pt.data.
826 */
827 FILE_USE(fp);
828 ioctlf = fp->f_ops->fo_ioctl;
829 pt.com = SCARG(uap, com);
830 pt.data = SCARG(uap, data);
831 error = ioctlf(fp, PTIOCLINUX, (caddr_t)&pt, p);
832 FILE_UNUSE(fp, p);
833 if (error == EJUSTRETURN) {
834 retval[0] = (register_t)pt.data;
835 error = 0;
836 }
837
838 if (error == ENOTTY)
839 printf("linux_machdepioctl: invalid ioctl %08lx\n",
840 com);
841 return error;
842 }
843 SCARG(&bia, com) = com;
844 /* XXX NJWLWP */
845 return sys_ioctl(curproc, &bia, retval);
846 }
847
848 /*
849 * Set I/O permissions for a process. Just set the maximum level
850 * right away (ignoring the argument), otherwise we would have
851 * to rely on I/O permission maps, which are not implemented.
852 */
853 int
854 linux_sys_iopl(l, v, retval)
855 struct lwp *l;
856 void *v;
857 register_t *retval;
858 {
859 #if 0
860 struct linux_sys_iopl_args /* {
861 syscallarg(int) level;
862 } */ *uap = v;
863 #endif
864 struct proc *p = l->l_proc;
865 struct trapframe *fp = l->l_md.md_regs;
866
867 if (suser(p->p_ucred, &p->p_acflag) != 0)
868 return EPERM;
869 fp->tf_eflags |= PSL_IOPL;
870 *retval = 0;
871 return 0;
872 }
873
874 /*
875 * See above. If a root process tries to set access to an I/O port,
876 * just let it have the whole range.
877 */
878 int
879 linux_sys_ioperm(l, v, retval)
880 struct lwp *l;
881 void *v;
882 register_t *retval;
883 {
884 struct linux_sys_ioperm_args /* {
885 syscallarg(unsigned int) lo;
886 syscallarg(unsigned int) hi;
887 syscallarg(int) val;
888 } */ *uap = v;
889 struct proc *p = l->l_proc;
890 struct trapframe *fp = l->l_md.md_regs;
891
892 if (suser(p->p_ucred, &p->p_acflag) != 0)
893 return EPERM;
894 if (SCARG(uap, val))
895 fp->tf_eflags |= PSL_IOPL;
896 *retval = 0;
897 return 0;
898 }
899