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