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