linux_machdep.c revision 1.55 1 /* $NetBSD: linux_machdep.c,v 1.55 2000/12/18 14:47:38 fvdl 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 struct ioctl_pt pt;
619
620 fd = SCARG(uap, fd);
621 SCARG(&bia, fd) = fd;
622 SCARG(&bia, data) = SCARG(uap, data);
623 com = SCARG(uap, com);
624
625 fdp = p->p_fd;
626
627 if ((u_int)fd >= fdp->fd_nfiles ||
628 (fp = fdp->fd_ofiles[fd]) == NULL ||
629 (fp->f_iflags & FIF_WANTCLOSE) != 0)
630 return (EBADF);
631
632 switch (com) {
633 #if (NWSDISPLAY > 0)
634 case LINUX_KDGKBMODE:
635 com = KDGKBMODE;
636 break;
637 case LINUX_KDSKBMODE:
638 com = KDSKBMODE;
639 if ((unsigned)SCARG(uap, data) == LINUX_K_MEDIUMRAW)
640 SCARG(&bia, data) = (caddr_t)K_RAW;
641 break;
642 case LINUX_KDMKTONE:
643 com = KDMKTONE;
644 break;
645 case LINUX_KDSETMODE:
646 com = KDSETMODE;
647 break;
648 case LINUX_KDENABIO:
649 com = KDENABIO;
650 break;
651 case LINUX_KDDISABIO:
652 com = KDDISABIO;
653 break;
654 case LINUX_KDGETLED:
655 com = KDGETLED;
656 break;
657 case LINUX_KDSETLED:
658 com = KDSETLED;
659 break;
660 case LINUX_VT_OPENQRY:
661 com = VT_OPENQRY;
662 break;
663 case LINUX_VT_GETMODE:
664 SCARG(&bia, com) = VT_GETMODE;
665 if ((error = sys_ioctl(p, &bia, retval)))
666 return error;
667 if ((error = copyin(SCARG(uap, data), (caddr_t)&lvt,
668 sizeof (struct vt_mode))))
669 return error;
670 lvt.relsig = native_to_linux_sig[lvt.relsig];
671 lvt.acqsig = native_to_linux_sig[lvt.acqsig];
672 lvt.frsig = native_to_linux_sig[lvt.frsig];
673 return copyout((caddr_t)&lvt, SCARG(uap, data),
674 sizeof (struct vt_mode));
675 case LINUX_VT_SETMODE:
676 com = VT_SETMODE;
677 if ((error = copyin(SCARG(uap, data), (caddr_t)&lvt,
678 sizeof (struct vt_mode))))
679 return error;
680 lvt.relsig = linux_to_native_sig[lvt.relsig];
681 lvt.acqsig = linux_to_native_sig[lvt.acqsig];
682 lvt.frsig = linux_to_native_sig[lvt.frsig];
683 sg = stackgap_init(p->p_emul);
684 bvtp = stackgap_alloc(&sg, sizeof (struct vt_mode));
685 if ((error = copyout(&lvt, bvtp, sizeof (struct vt_mode))))
686 return error;
687 SCARG(&bia, data) = bvtp;
688 break;
689 case LINUX_VT_DISALLOCATE:
690 /* XXX should use WSDISPLAYIO_DELSCREEN */
691 return 0;
692 case LINUX_VT_RELDISP:
693 com = VT_RELDISP;
694 break;
695 case LINUX_VT_ACTIVATE:
696 com = VT_ACTIVATE;
697 break;
698 case LINUX_VT_WAITACTIVE:
699 com = VT_WAITACTIVE;
700 break;
701 case LINUX_VT_GETSTATE:
702 com = VT_GETSTATE;
703 break;
704 case LINUX_KDGKBTYPE:
705 /* This is what Linux does. */
706 return (subyte(SCARG(uap, data), KB_101));
707 case LINUX_KDGKBENT:
708 /*
709 * The Linux KDGKBENT ioctl is different from the
710 * SYSV original. So we handle it in machdep code.
711 * XXX We should use keyboard mapping information
712 * from wsdisplay, but this would be expensive.
713 */
714 if ((error = copyin(SCARG(uap, data), &kbe,
715 sizeof(struct kbentry))))
716 return (error);
717 if (kbe.kb_table >= sizeof(linux_keytabs) / sizeof(u_short *)
718 || kbe.kb_index >= NR_KEYS)
719 return (EINVAL);
720 kbe.kb_value = linux_keytabs[kbe.kb_table][kbe.kb_index];
721 return (copyout(&kbe, SCARG(uap, data),
722 sizeof(struct kbentry)));
723 #endif
724 case LINUX_HDIO_GETGEO:
725 case LINUX_HDIO_GETGEO_BIG:
726 /*
727 * Try to mimic Linux behaviour: return the BIOS geometry
728 * if possible (extending its # of cylinders if it's beyond
729 * the 1023 limit), fall back to the MI geometry (i.e.
730 * the real geometry) if not found, by returning an
731 * error. See common/linux_hdio.c
732 */
733 FILE_USE(fp);
734 bip = fd2biosinfo(p, fp);
735 ioctlf = fp->f_ops->fo_ioctl;
736 error = ioctlf(fp, DIOCGDEFLABEL, (caddr_t)&label, p);
737 error1 = ioctlf(fp, DIOCGPART, (caddr_t)&partp, p);
738 FILE_UNUSE(fp, p);
739 if (error != 0 && error1 != 0)
740 return error1;
741 labp = error != 0 ? &label : partp.disklab;
742 start = error1 != 0 ? partp.part->p_offset : 0;
743 if (bip != NULL && bip->bi_head != 0 && bip->bi_sec != 0
744 && bip->bi_cyl != 0) {
745 heads = bip->bi_head;
746 sectors = bip->bi_sec;
747 cylinders = bip->bi_cyl;
748 biostotal = heads * sectors * cylinders;
749 realtotal = labp->d_ntracks * labp->d_nsectors *
750 labp->d_ncylinders;
751 if (realtotal > biostotal)
752 cylinders = realtotal / (heads * sectors);
753 } else {
754 heads = labp->d_ntracks;
755 cylinders = labp->d_ncylinders;
756 sectors = labp->d_nsectors;
757 }
758 if (com == LINUX_HDIO_GETGEO) {
759 hdg.start = start;
760 hdg.heads = heads;
761 hdg.cylinders = cylinders;
762 hdg.sectors = sectors;
763 return copyout(&hdg, SCARG(uap, data), sizeof hdg);
764 } else {
765 hdg_big.start = start;
766 hdg_big.heads = heads;
767 hdg_big.cylinders = cylinders;
768 hdg_big.sectors = sectors;
769 return copyout(&hdg_big, SCARG(uap, data),
770 sizeof hdg_big);
771 }
772 return 0;
773
774 default:
775 /*
776 * Unknown to us. If it's on a device, just pass it through
777 * using PTIOCLINUX, the device itself might be able to
778 * make some sense of it.
779 */
780 FILE_USE(fp);
781 ioctlf = fp->f_ops->fo_ioctl;
782 pt.com = SCARG(uap, com);
783 pt.data = SCARG(uap, data);
784 error = ioctlf(fp, PTIOCLINUX, (caddr_t)&pt, p);
785 FILE_UNUSE(fp, p);
786
787 if (error == EINVAL)
788 printf("linux_machdepioctl: invalid ioctl %08lx\n",
789 com);
790 return error;
791 }
792 SCARG(&bia, com) = com;
793 return sys_ioctl(p, &bia, retval);
794 }
795
796 /*
797 * Set I/O permissions for a process. Just set the maximum level
798 * right away (ignoring the argument), otherwise we would have
799 * to rely on I/O permission maps, which are not implemented.
800 */
801 int
802 linux_sys_iopl(p, v, retval)
803 struct proc *p;
804 void *v;
805 register_t *retval;
806 {
807 #if 0
808 struct linux_sys_iopl_args /* {
809 syscallarg(int) level;
810 } */ *uap = v;
811 #endif
812 struct trapframe *fp = p->p_md.md_regs;
813
814 if (suser(p->p_ucred, &p->p_acflag) != 0)
815 return EPERM;
816 fp->tf_eflags |= PSL_IOPL;
817 *retval = 0;
818 return 0;
819 }
820
821 /*
822 * See above. If a root process tries to set access to an I/O port,
823 * just let it have the whole range.
824 */
825 int
826 linux_sys_ioperm(p, v, retval)
827 struct proc *p;
828 void *v;
829 register_t *retval;
830 {
831 struct linux_sys_ioperm_args /* {
832 syscallarg(unsigned int) lo;
833 syscallarg(unsigned int) hi;
834 syscallarg(int) val;
835 } */ *uap = v;
836 struct trapframe *fp = p->p_md.md_regs;
837
838 if (suser(p->p_ucred, &p->p_acflag) != 0)
839 return EPERM;
840 if (SCARG(uap, val))
841 fp->tf_eflags |= PSL_IOPL;
842 *retval = 0;
843 return 0;
844 }
845