kernel - use new td_ucred in numerous places
[dragonfly.git] / sys / platform / pc32 / i386 / sys_machdep.c
CommitLineData
984263bc
MD
1/*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * from: @(#)sys_machdep.c 5.5 (Berkeley) 1/19/91
34 * $FreeBSD: src/sys/i386/i386/sys_machdep.c,v 1.47.2.3 2002/10/07 17:20:00 jhb Exp $
978400d3 35 * $DragonFly: src/sys/platform/pc32/i386/sys_machdep.c,v 1.32 2008/01/06 16:55:53 swildner Exp $
984263bc
MD
36 *
37 */
38
984263bc
MD
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/sysproto.h>
42#include <sys/malloc.h>
85100692 43#include <sys/thread.h>
984263bc 44#include <sys/proc.h>
895c1f85 45#include <sys/priv.h>
cf4e130b 46#include <sys/thread.h>
fc26c9f1 47#include <sys/memrange.h>
984263bc
MD
48
49#include <vm/vm.h>
50#include <sys/lock.h>
51#include <vm/pmap.h>
52#include <vm/vm_map.h>
53#include <vm/vm_extern.h>
54
55#include <sys/user.h>
56
57#include <machine/cpu.h>
984263bc
MD
58#include <machine/pcb_ext.h> /* pcb.h included by sys/user.h */
59#include <machine/sysarch.h>
984263bc 60#include <machine/smp.h>
85100692 61#include <machine/globaldata.h> /* mdcpu */
984263bc
MD
62
63#include <vm/vm_kern.h> /* for kernel_map */
cf4e130b 64#include <sys/thread2.h>
984263bc
MD
65
66#define MAX_LD 8192
67#define LD_PER_PAGE 512
68#define NEW_MAX_LD(num) ((num + LD_PER_PAGE) & ~(LD_PER_PAGE-1))
69#define SIZE_FROM_LARGEST_LD(num) (NEW_MAX_LD(num) << 3)
70
71
72
73f913ca
MD
73static int ki386_get_ldt(struct lwp *, char *, int *);
74static int ki386_set_ldt(struct lwp *, char *, int *);
75static int ki386_get_ioperm(struct lwp *, char *);
76static int ki386_set_ioperm(struct lwp *, char *);
806bf111 77static int check_descs(union descriptor *, int);
065b709a 78int i386_extend_pcb(struct lwp *);
984263bc 79
41c20dac
MD
80/*
81 * sysarch_args(int op, char *params)
3919ced0
MD
82 *
83 * MPALMOSTSAFE
41c20dac 84 */
984263bc 85int
753fd850 86sys_sysarch(struct sysarch_args *uap)
984263bc 87{
065b709a 88 struct lwp *lp = curthread->td_lwp;
984263bc
MD
89 int error = 0;
90
3919ced0
MD
91 get_mplock();
92
984263bc 93 switch(uap->op) {
984263bc 94 case I386_GET_LDT:
73f913ca 95 error = ki386_get_ldt(lp, uap->parms, &uap->sysmsg_result);
984263bc 96 break;
984263bc 97 case I386_SET_LDT:
73f913ca 98 error = ki386_set_ldt(lp, uap->parms, &uap->sysmsg_result);
984263bc 99 break;
984263bc 100 case I386_GET_IOPERM:
73f913ca 101 error = ki386_get_ioperm(lp, uap->parms);
984263bc
MD
102 break;
103 case I386_SET_IOPERM:
73f913ca 104 error = ki386_set_ioperm(lp, uap->parms);
984263bc
MD
105 break;
106 case I386_VM86:
065b709a 107 error = vm86_sysarch(lp, uap->parms);
984263bc
MD
108 break;
109 default:
110 error = EOPNOTSUPP;
111 break;
112 }
3919ced0 113 rel_mplock();
984263bc
MD
114 return (error);
115}
116
117int
065b709a 118i386_extend_pcb(struct lwp *lp)
984263bc
MD
119{
120 int i, offset;
121 u_long *addr;
122 struct pcb_ext *ext;
123 struct soft_segment_descriptor ssd = {
124 0, /* segment base address (overwritten) */
125 ctob(IOPAGES + 1) - 1, /* length */
126 SDT_SYS386TSS, /* segment type */
127 0, /* priority level */
128 1, /* descriptor present */
129 0, 0,
130 0, /* default 32 size */
131 0 /* granularity */
132 };
133
e4846942
MD
134 ext = (struct pcb_ext *)kmem_alloc(&kernel_map, ctob(IOPAGES+1));
135 if (ext == NULL)
984263bc 136 return (ENOMEM);
984263bc 137 bzero(ext, sizeof(struct pcb_ext));
065b709a 138 ext->ext_tss.tss_esp0 = (unsigned)((char *)lp->lwp_thread->td_pcb - 16);
984263bc
MD
139 ext->ext_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL);
140 /*
141 * The last byte of the i/o map must be followed by an 0xff byte.
142 * We arbitrarily allocate 16 bytes here, to keep the starting
143 * address on a doubleword boundary.
144 */
145 offset = PAGE_SIZE - 16;
146 ext->ext_tss.tss_ioopt =
147 (offset - ((unsigned)&ext->ext_tss - (unsigned)ext)) << 16;
148 ext->ext_iomap = (caddr_t)ext + offset;
149 ext->ext_vm86.vm86_intmap = (caddr_t)ext + offset - 32;
150
151 addr = (u_long *)ext->ext_vm86.vm86_intmap;
152 for (i = 0; i < (ctob(IOPAGES) + 32 + 16) / sizeof(u_long); i++)
153 *addr++ = ~0;
154
155 ssd.ssd_base = (unsigned)&ext->ext_tss;
156 ssd.ssd_limit -= ((unsigned)&ext->ext_tss - (unsigned)ext);
157 ssdtosd(&ssd, &ext->ext_tssd);
984263bc 158
df011816
MD
159 /*
160 * Put the new TSS where the switch code can find it. Do
161 * a forced switch to ourself to activate it.
162 */
163 crit_enter();
164 lp->lwp_thread->td_pcb->pcb_ext = ext;
165 lp->lwp_thread->td_switch(lp->lwp_thread);
166 crit_exit();
167
984263bc
MD
168 return 0;
169}
170
171static int
73f913ca 172ki386_set_ioperm(struct lwp *lp, char *args)
984263bc
MD
173{
174 int i, error;
175 struct i386_ioperm_args ua;
176 char *iomap;
177
178 if ((error = copyin(args, &ua, sizeof(struct i386_ioperm_args))) != 0)
179 return (error);
180
9910d07b 181 if ((error = priv_check_cred(lp->lwp_thread->td_ucred, PRIV_ROOT, 0)) != 0)
984263bc
MD
182 return (error);
183 if (securelevel > 0)
184 return (EPERM);
185 /*
186 * XXX
187 * While this is restricted to root, we should probably figure out
188 * whether any other driver is using this i/o address, as so not to
189 * cause confusion. This probably requires a global 'usage registry'.
190 */
191
065b709a
SS
192 if (lp->lwp_thread->td_pcb->pcb_ext == 0)
193 if ((error = i386_extend_pcb(lp)) != 0)
984263bc 194 return (error);
065b709a 195 iomap = (char *)lp->lwp_thread->td_pcb->pcb_ext->ext_iomap;
984263bc
MD
196
197 if (ua.start + ua.length > IOPAGES * PAGE_SIZE * NBBY)
198 return (EINVAL);
199
200 for (i = ua.start; i < ua.start + ua.length; i++) {
201 if (ua.enable)
202 iomap[i >> 3] &= ~(1 << (i & 7));
203 else
204 iomap[i >> 3] |= (1 << (i & 7));
205 }
206 return (error);
207}
208
209static int
73f913ca 210ki386_get_ioperm(struct lwp *lp, char *args)
984263bc
MD
211{
212 int i, state, error;
213 struct i386_ioperm_args ua;
214 char *iomap;
215
216 if ((error = copyin(args, &ua, sizeof(struct i386_ioperm_args))) != 0)
217 return (error);
218 if (ua.start >= IOPAGES * PAGE_SIZE * NBBY)
219 return (EINVAL);
220
065b709a 221 if (lp->lwp_thread->td_pcb->pcb_ext == 0) {
984263bc
MD
222 ua.length = 0;
223 goto done;
224 }
225
065b709a 226 iomap = (char *)lp->lwp_thread->td_pcb->pcb_ext->ext_iomap;
984263bc
MD
227
228 i = ua.start;
229 state = (iomap[i >> 3] >> (i & 7)) & 1;
230 ua.enable = !state;
231 ua.length = 1;
232
233 for (i = ua.start + 1; i < IOPAGES * PAGE_SIZE * NBBY; i++) {
234 if (state != ((iomap[i >> 3] >> (i & 7)) & 1))
235 break;
236 ua.length++;
237 }
238
239done:
240 error = copyout(&ua, args, sizeof(struct i386_ioperm_args));
241 return (error);
242}
243
984263bc 244/*
806bf111
MD
245 * Update the TLS entries for the process. Used by assembly, do not staticize.
246 *
247 * Must be called from a critical section (else an interrupt thread preemption
248 * may cause %gs to fault). Normally called from the low level swtch.s code.
923e4699
MD
249 *
250 * MPSAFE
806bf111
MD
251 */
252void
253set_user_TLS(void)
254{
255 struct thread *td = curthread;
256 int i;
257#ifdef SMP
258 int off = GTLS_START + mycpu->gd_cpuid * NGDT;
259#else
260 const int off = GTLS_START;
261#endif
262 for (i = 0; i < NGTLS; ++i)
4e7c41c5 263 gdt[off + i].sd = td->td_tls.tls[i];
806bf111
MD
264}
265
4e2eba5b 266#ifdef SMP
6819df07
MD
267static
268void
269set_user_ldt_cpusync(struct lwkt_cpusync *cmd)
270{
271 set_user_ldt(cmd->cs_data);
272}
4e2eba5b 273#endif
6819df07 274
806bf111 275/*
984263bc 276 * Update the GDT entry pointing to the LDT to point to the LDT of the
806bf111
MD
277 * current process. Used by assembly, do not staticize.
278 *
279 * Must be called from a critical section (else an interrupt thread preemption
280 * may cause %gs to fault). Normally called from the low level swtch.s code.
984263bc
MD
281 */
282void
283set_user_ldt(struct pcb *pcb)
284{
285 struct pcb_ldt *pcb_ldt;
286
b7c628e4 287 if (pcb != curthread->td_pcb)
984263bc
MD
288 return;
289
290 pcb_ldt = pcb->pcb_ldt;
291#ifdef SMP
7b95be2a 292 gdt[mycpu->gd_cpuid * NGDT + GUSERLDT_SEL].sd = pcb_ldt->ldt_sd;
984263bc
MD
293#else
294 gdt[GUSERLDT_SEL].sd = pcb_ldt->ldt_sd;
295#endif
296 lldt(GSEL(GUSERLDT_SEL, SEL_KPL));
85100692 297 mdcpu->gd_currentldt = GSEL(GUSERLDT_SEL, SEL_KPL);
984263bc
MD
298}
299
300struct pcb_ldt *
301user_ldt_alloc(struct pcb *pcb, int len)
302{
303 struct pcb_ldt *pcb_ldt, *new_ldt;
304
305 MALLOC(new_ldt, struct pcb_ldt *, sizeof(struct pcb_ldt),
306 M_SUBPROC, M_WAITOK);
984263bc
MD
307
308 new_ldt->ldt_len = len = NEW_MAX_LD(len);
e4846942
MD
309 new_ldt->ldt_base = (caddr_t)kmem_alloc(&kernel_map,
310 len * sizeof(union descriptor));
984263bc
MD
311 if (new_ldt->ldt_base == NULL) {
312 FREE(new_ldt, M_SUBPROC);
313 return NULL;
314 }
315 new_ldt->ldt_refcnt = 1;
316 new_ldt->ldt_active = 0;
317
318 gdt_segs[GUSERLDT_SEL].ssd_base = (unsigned)new_ldt->ldt_base;
319 gdt_segs[GUSERLDT_SEL].ssd_limit = len * sizeof(union descriptor) - 1;
320 ssdtosd(&gdt_segs[GUSERLDT_SEL], &new_ldt->ldt_sd);
321
322 if ((pcb_ldt = pcb->pcb_ldt)) {
323 if (len > pcb_ldt->ldt_len)
324 len = pcb_ldt->ldt_len;
325 bcopy(pcb_ldt->ldt_base, new_ldt->ldt_base,
326 len * sizeof(union descriptor));
327 } else {
328 bcopy(ldt, new_ldt->ldt_base, sizeof(ldt));
329 }
330 return new_ldt;
331}
332
333void
334user_ldt_free(struct pcb *pcb)
335{
336 struct pcb_ldt *pcb_ldt = pcb->pcb_ldt;
337
338 if (pcb_ldt == NULL)
339 return;
340
cf4e130b 341 crit_enter();
b7c628e4 342 if (pcb == curthread->td_pcb) {
984263bc 343 lldt(_default_ldt);
85100692 344 mdcpu->gd_currentldt = _default_ldt;
984263bc 345 }
cf4e130b
MD
346 pcb->pcb_ldt = NULL;
347 crit_exit();
984263bc
MD
348
349 if (--pcb_ldt->ldt_refcnt == 0) {
e4846942
MD
350 kmem_free(&kernel_map, (vm_offset_t)pcb_ldt->ldt_base,
351 pcb_ldt->ldt_len * sizeof(union descriptor));
984263bc
MD
352 FREE(pcb_ldt, M_SUBPROC);
353 }
984263bc
MD
354}
355
356static int
73f913ca 357ki386_get_ldt(struct lwp *lwp, char *args, int *res)
984263bc
MD
358{
359 int error = 0;
065b709a 360 struct pcb *pcb = lwp->lwp_thread->td_pcb;
984263bc 361 struct pcb_ldt *pcb_ldt = pcb->pcb_ldt;
6d2edbe1 362 unsigned int nldt, num;
984263bc 363 union descriptor *lp;
984263bc
MD
364 struct i386_ldt_args ua, *uap = &ua;
365
366 if ((error = copyin(args, uap, sizeof(struct i386_ldt_args))) < 0)
367 return(error);
368
369#ifdef DEBUG
26be20a0 370 kprintf("ki386_get_ldt: start=%d num=%d descs=%p\n",
984263bc
MD
371 uap->start, uap->num, (void *)uap->descs);
372#endif
373
9acd5bbb 374 crit_enter();
984263bc
MD
375
376 if (pcb_ldt) {
6d2edbe1 377 nldt = (unsigned int)pcb_ldt->ldt_len;
984263bc
MD
378 num = min(uap->num, nldt);
379 lp = &((union descriptor *)(pcb_ldt->ldt_base))[uap->start];
380 } else {
6d2edbe1 381 nldt = (unsigned int)(sizeof(ldt) / sizeof(ldt[0]));
984263bc
MD
382 num = min(uap->num, nldt);
383 lp = &ldt[uap->start];
384 }
6d2edbe1
MD
385
386 /*
387 * note: uap->(args), num, and nldt are unsigned. nldt and num
388 * are limited in scope, but uap->start can be anything.
389 */
390 if (uap->start > nldt || uap->start + num > nldt) {
9acd5bbb 391 crit_exit();
984263bc
MD
392 return(EINVAL);
393 }
394
395 error = copyout(lp, uap->descs, num * sizeof(union descriptor));
396 if (!error)
90b9818c 397 *res = num;
9acd5bbb 398 crit_exit();
984263bc
MD
399 return(error);
400}
401
402static int
73f913ca 403ki386_set_ldt(struct lwp *lp, char *args, int *res)
984263bc 404{
806bf111 405 int error = 0;
984263bc 406 int largest_ld;
065b709a 407 struct pcb *pcb = lp->lwp_thread->td_pcb;
984263bc
MD
408 struct pcb_ldt *pcb_ldt = pcb->pcb_ldt;
409 union descriptor *descs;
806bf111 410 int descs_size;
984263bc
MD
411 struct i386_ldt_args ua, *uap = &ua;
412
413 if ((error = copyin(args, uap, sizeof(struct i386_ldt_args))) < 0)
414 return(error);
415
416#ifdef DEBUG
26be20a0 417 kprintf("ki386_set_ldt: start=%d num=%d descs=%p\n",
984263bc
MD
418 uap->start, uap->num, (void *)uap->descs);
419#endif
420
421 /* verify range of descriptors to modify */
422 if ((uap->start < 0) || (uap->start >= MAX_LD) || (uap->num < 0) ||
423 (uap->num > MAX_LD))
424 {
425 return(EINVAL);
426 }
427 largest_ld = uap->start + uap->num - 1;
428 if (largest_ld >= MAX_LD)
429 return(EINVAL);
430
431 /* allocate user ldt */
432 if (!pcb_ldt || largest_ld >= pcb_ldt->ldt_len) {
433 struct pcb_ldt *new_ldt = user_ldt_alloc(pcb, largest_ld);
434 if (new_ldt == NULL)
435 return ENOMEM;
436 if (pcb_ldt) {
437 pcb_ldt->ldt_sd = new_ldt->ldt_sd;
e4846942
MD
438 kmem_free(&kernel_map, (vm_offset_t)pcb_ldt->ldt_base,
439 pcb_ldt->ldt_len * sizeof(union descriptor));
984263bc
MD
440 pcb_ldt->ldt_base = new_ldt->ldt_base;
441 pcb_ldt->ldt_len = new_ldt->ldt_len;
442 FREE(new_ldt, M_SUBPROC);
806bf111 443 } else {
984263bc 444 pcb->pcb_ldt = pcb_ldt = new_ldt;
806bf111
MD
445 }
446 /*
447 * Since the LDT may be shared, we must signal other cpus to
448 * reload it. XXX we need to track which cpus might be
449 * using the shared ldt and only signal those.
450 */
984263bc 451#ifdef SMP
6819df07 452 lwkt_cpusync_simple(-1, set_user_ldt_cpusync, pcb);
984263bc
MD
453#else
454 set_user_ldt(pcb);
455#endif
456 }
457
458 descs_size = uap->num * sizeof(union descriptor);
e4846942 459 descs = (union descriptor *)kmem_alloc(&kernel_map, descs_size);
984263bc
MD
460 if (descs == NULL)
461 return (ENOMEM);
462 error = copyin(&uap->descs[0], descs, descs_size);
463 if (error) {
e4846942 464 kmem_free(&kernel_map, (vm_offset_t)descs, descs_size);
984263bc
MD
465 return (error);
466 }
467 /* Check descriptors for access violations */
806bf111
MD
468 error = check_descs(descs, uap->num);
469 if (error) {
e4846942 470 kmem_free(&kernel_map, (vm_offset_t)descs, descs_size);
806bf111
MD
471 return (error);
472 }
473
474 /*
4e7c41c5
MD
475 * Fill in the actual ldt entries. Since %fs or %gs might point to
476 * one of these entries a critical section is required to prevent an
806bf111
MD
477 * interrupt thread from preempting us, switch back, and faulting
478 * on the load of %fs due to a half-formed descriptor.
479 */
480 crit_enter();
481 bcopy(descs,
482 &((union descriptor *)(pcb_ldt->ldt_base))[uap->start],
483 uap->num * sizeof(union descriptor));
484 *res = uap->start;
485
486 crit_exit();
e4846942 487 kmem_free(&kernel_map, (vm_offset_t)descs, descs_size);
806bf111
MD
488 return (0);
489}
490
491static int
492check_descs(union descriptor *descs, int num)
493{
494 int i;
495
496 /* Check descriptors for access violations */
497 for (i = 0; i < num; i++) {
984263bc
MD
498 union descriptor *dp;
499 dp = &descs[i];
500
501 switch (dp->sd.sd_type) {
502 case SDT_SYSNULL: /* system null */
503 dp->sd.sd_p = 0;
504 break;
505 case SDT_SYS286TSS: /* system 286 TSS available */
506 case SDT_SYSLDT: /* system local descriptor table */
507 case SDT_SYS286BSY: /* system 286 TSS busy */
508 case SDT_SYSTASKGT: /* system task gate */
509 case SDT_SYS286IGT: /* system 286 interrupt gate */
510 case SDT_SYS286TGT: /* system 286 trap gate */
511 case SDT_SYSNULL2: /* undefined by Intel */
512 case SDT_SYS386TSS: /* system 386 TSS available */
513 case SDT_SYSNULL3: /* undefined by Intel */
514 case SDT_SYS386BSY: /* system 386 TSS busy */
515 case SDT_SYSNULL4: /* undefined by Intel */
516 case SDT_SYS386IGT: /* system 386 interrupt gate */
517 case SDT_SYS386TGT: /* system 386 trap gate */
518 case SDT_SYS286CGT: /* system 286 call gate */
519 case SDT_SYS386CGT: /* system 386 call gate */
520 /* I can't think of any reason to allow a user proc
521 * to create a segment of these types. They are
522 * for OS use only.
523 */
984263bc
MD
524 return EACCES;
525
526 /* memory segment types */
527 case SDT_MEMEC: /* memory execute only conforming */
528 case SDT_MEMEAC: /* memory execute only accessed conforming */
529 case SDT_MEMERC: /* memory execute read conforming */
530 case SDT_MEMERAC: /* memory execute read accessed conforming */
531 /* Must be "present" if executable and conforming. */
806bf111 532 if (dp->sd.sd_p == 0)
984263bc 533 return (EACCES);
984263bc
MD
534 break;
535 case SDT_MEMRO: /* memory read only */
536 case SDT_MEMROA: /* memory read only accessed */
537 case SDT_MEMRW: /* memory read write */
538 case SDT_MEMRWA: /* memory read write accessed */
539 case SDT_MEMROD: /* memory read only expand dwn limit */
540 case SDT_MEMRODA: /* memory read only expand dwn lim accessed */
541 case SDT_MEMRWD: /* memory read write expand dwn limit */
542 case SDT_MEMRWDA: /* memory read write expand dwn lim acessed */
543 case SDT_MEME: /* memory execute only */
544 case SDT_MEMEA: /* memory execute only accessed */
545 case SDT_MEMER: /* memory execute read */
546 case SDT_MEMERA: /* memory execute read accessed */
547 break;
548 default:
984263bc
MD
549 return(EINVAL);
550 /*NOTREACHED*/
551 }
552
553 /* Only user (ring-3) descriptors may be present. */
806bf111 554 if ((dp->sd.sd_p != 0) && (dp->sd.sd_dpl != SEL_UPL))
984263bc 555 return (EACCES);
984263bc 556 }
984263bc
MD
557 return (0);
558}
fc26c9f1
MD
559
560/*
561 * Called when /dev/io is opened
562 */
563int
564cpu_set_iopl(void)
565{
08f2f1bb 566 curthread->td_lwp->lwp_md.md_regs->tf_eflags |= PSL_IOPL;
fc26c9f1
MD
567 return(0);
568}
569
570/*
571 * Called when /dev/io is closed
572 */
573int
574cpu_clr_iopl(void)
575{
08f2f1bb 576 curthread->td_lwp->lwp_md.md_regs->tf_eflags &= ~PSL_IOPL;
fc26c9f1
MD
577 return(0);
578}
579