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