]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - 6/sys/i386/i386/sys_machdep.c
merge fix for boot-time hang on centos' xen
[FreeBSD/FreeBSD.git] / 6 / sys / i386 / i386 / sys_machdep.c
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  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  *      from: @(#)sys_machdep.c 5.5 (Berkeley) 1/19/91
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include "opt_kstack_pages.h"
36 #include "opt_mac.h"
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/lock.h>
41 #include <sys/mac.h>
42 #include <sys/malloc.h>
43 #include <sys/mutex.h>
44 #include <sys/proc.h>
45 #include <sys/smp.h>
46 #include <sys/sysproto.h>
47
48 #include <vm/vm.h>
49 #include <vm/pmap.h>
50 #include <vm/vm_map.h>
51 #include <vm/vm_extern.h>
52
53 #include <machine/cpu.h>
54 #include <machine/pcb.h>
55 #include <machine/pcb_ext.h>
56 #include <machine/proc.h>
57 #include <machine/sysarch.h>
58
59 #include <vm/vm_kern.h>         /* for kernel_map */
60
61 #ifdef XEN 
62 #include <machine/xen/xenfunc.h>
63
64 void i386_reset_ldt(struct proc_ldt *pldt); 
65
66 void 
67 i386_reset_ldt(struct proc_ldt *pldt) 
68
69         xen_set_ldt((vm_offset_t)pldt->ldt_base, pldt->ldt_len); 
70
71 #define SEG_VIRT_END  (HYPERVISOR_VIRT_START >> 12) & 0xffff
72 #define SET_DESCRIPTOR(index, sd)  \
73         HYPERVISOR_update_descriptor(vtomach(&PCPU_GET(fsgs_gdt)[index]), *(uint64_t *)&(sd));
74 #else  
75 #define i386_reset_ldt(x)
76 #define SEG_VIRT_END 0xffff
77 #define SET_DESCRIPTOR(index, sd) PCPU_GET(fsgs_gdt)[index] = (sd);
78 #endif
79
80 #define MAX_LD 8192
81 #define LD_PER_PAGE 512
82 #define NEW_MAX_LD(num)  ((num + LD_PER_PAGE) & ~(LD_PER_PAGE-1))
83 #define SIZE_FROM_LARGEST_LD(num) (NEW_MAX_LD(num) << 3)
84
85
86
87 static int i386_set_ldt_data(struct thread *, int start, int num,
88         union descriptor *descs);
89 static int i386_ldt_grow(struct thread *td, int len);
90 #ifdef SMP
91 static void set_user_ldt_rv(struct thread *);
92 #endif
93
94 #ifndef _SYS_SYSPROTO_H_
95 struct sysarch_args {
96         int op;
97         char *parms;
98 };
99 #endif
100
101 int
102 sysarch(td, uap)
103         struct thread *td;
104         register struct sysarch_args *uap;
105 {
106         int error;
107         union descriptor *lp;
108         union {
109                 struct i386_ldt_args largs;
110                 struct i386_ioperm_args iargs;
111         } kargs;
112         uint32_t base;
113         struct segment_descriptor sd, *sdp;
114
115         switch (uap->op) {
116         case I386_GET_IOPERM:
117         case I386_SET_IOPERM:
118                 if ((error = copyin(uap->parms, &kargs.iargs,
119                     sizeof(struct i386_ioperm_args))) != 0)
120                         return (error);
121                 break;
122         case I386_GET_LDT:
123         case I386_SET_LDT:
124                 if ((error = copyin(uap->parms, &kargs.largs,
125                     sizeof(struct i386_ldt_args))) != 0)
126                         return (error);
127                 if (kargs.largs.num > MAX_LD || kargs.largs.num <= 0)
128                         return (EINVAL);
129                 break;
130         default:
131                 break;
132         }
133
134         mtx_lock(&Giant);
135         switch(uap->op) {
136         case I386_GET_LDT:
137                 error = i386_get_ldt(td, &kargs.largs);
138                 break;
139         case I386_SET_LDT:
140                 if (kargs.largs.descs != NULL) {
141                         lp = (union descriptor *)kmem_alloc(kernel_map,
142                             kargs.largs.num * sizeof(union descriptor));
143                         if (lp == NULL) {
144                                 error = ENOMEM;
145                                 break;
146                         }
147                         error = copyin(kargs.largs.descs, lp,
148                             kargs.largs.num * sizeof(union descriptor));
149                         if (error == 0)
150                                 error = i386_set_ldt(td, &kargs.largs, lp);
151                         kmem_free(kernel_map, (vm_offset_t)lp,
152                             kargs.largs.num * sizeof(union descriptor));
153                 } else {
154                         error = i386_set_ldt(td, &kargs.largs, NULL);
155                 }
156                 break;
157         case I386_GET_IOPERM:
158                 error = i386_get_ioperm(td, &kargs.iargs);
159                 if (error == 0)
160                         error = copyout(&kargs.iargs, uap->parms,
161                             sizeof(struct i386_ioperm_args));
162                 break;
163         case I386_SET_IOPERM:
164                 error = i386_set_ioperm(td, &kargs.iargs);
165                 break;
166         case I386_VM86:
167                 error = vm86_sysarch(td, uap->parms);
168                 break;
169         case I386_GET_FSBASE:
170                 sdp = &td->td_pcb->pcb_fsd;
171                 base = sdp->sd_hibase << 24 | sdp->sd_lobase;
172                 error = copyout(&base, uap->parms, sizeof(base));
173                 break;
174         case I386_SET_FSBASE:
175                 error = copyin(uap->parms, &base, sizeof(base));
176                 if (!error) {
177                         /*
178                          * Construct a descriptor and store it in the pcb for
179                          * the next context switch.  Also store it in the gdt
180                          * so that the load of tf_fs into %fs will activate it
181                          * at return to userland.
182                          */
183                         sd.sd_lobase = base & 0xffffff;
184                         sd.sd_hibase = (base >> 24) & 0xff;
185                         sd.sd_lolimit = SEG_VIRT_END; /* 4GB limit, wraps */
186                         sd.sd_hilimit = 0xf;
187                         sd.sd_type  = SDT_MEMRWA;
188                         sd.sd_dpl   = SEL_UPL;
189                         sd.sd_p     = 1;
190                         sd.sd_xx    = 0;
191                         sd.sd_def32 = 1;
192                         sd.sd_gran  = 1;
193                         critical_enter();
194                         td->td_pcb->pcb_fsd = sd;
195                         SET_DESCRIPTOR(0, sd);
196                         critical_exit();
197                         td->td_frame->tf_fs = GSEL(GUFS_SEL, SEL_UPL);
198                 }
199                 break;
200         case I386_GET_GSBASE:
201                 sdp = &td->td_pcb->pcb_gsd;
202                 base = sdp->sd_hibase << 24 | sdp->sd_lobase;
203                 error = copyout(&base, uap->parms, sizeof(base));
204                 break;
205         case I386_SET_GSBASE:
206                 error = copyin(uap->parms, &base, sizeof(base));
207                 if (!error) {
208                         /*
209                          * Construct a descriptor and store it in the pcb for
210                          * the next context switch.  Also store it in the gdt
211                          * because we have to do a load_gs() right now.
212                          */
213                         sd.sd_lobase = base & 0xffffff;
214                         sd.sd_hibase = (base >> 24) & 0xff;
215                         sd.sd_lolimit = SEG_VIRT_END; /* 4GB limit, wraps */
216                         sd.sd_hilimit = 0xf;
217                         sd.sd_type  = SDT_MEMRWA;
218                         sd.sd_dpl   = SEL_UPL;
219                         sd.sd_p     = 1;
220                         sd.sd_xx    = 0;
221                         sd.sd_def32 = 1;
222                         sd.sd_gran  = 1;
223                         critical_enter();
224                         td->td_pcb->pcb_gsd = sd;
225                         SET_DESCRIPTOR(1, sd);
226                         critical_exit();
227                         load_gs(GSEL(GUGS_SEL, SEL_UPL));
228                 }
229                 break;
230         default:
231                 error = EINVAL;
232                 break;
233         }
234         mtx_unlock(&Giant);
235         return (error);
236 }
237
238 int
239 i386_extend_pcb(struct thread *td)
240 {
241         int i, offset;
242         u_long *addr;
243         struct pcb_ext *ext;
244         struct soft_segment_descriptor ssd = {
245                 0,                      /* segment base address (overwritten) */
246                 ctob(IOPAGES + 1) - 1,  /* length */
247                 SDT_SYS386TSS,          /* segment type */
248                 0,                      /* priority level */
249                 1,                      /* descriptor present */
250                 0, 0,
251                 0,                      /* default 32 size */
252                 0                       /* granularity */
253         };
254
255         if (td->td_proc->p_flag & P_SA)
256                 return (EINVAL);                /* XXXKSE */
257 /* XXXKSE  All the code below only works in 1:1   needs changing */
258         ext = (struct pcb_ext *)kmem_alloc(kernel_map, ctob(IOPAGES+1));
259         if (ext == 0)
260                 return (ENOMEM);
261         bzero(ext, sizeof(struct pcb_ext)); 
262         /* -16 is so we can convert a trapframe into vm86trapframe inplace */
263         ext->ext_tss.tss_esp0 = td->td_kstack + ctob(KSTACK_PAGES) -
264             sizeof(struct pcb) - 16;
265         ext->ext_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL);
266         /*
267          * The last byte of the i/o map must be followed by an 0xff byte.
268          * We arbitrarily allocate 16 bytes here, to keep the starting
269          * address on a doubleword boundary.
270          */
271         offset = PAGE_SIZE - 16;
272         ext->ext_tss.tss_ioopt = 
273             (offset - ((unsigned)&ext->ext_tss - (unsigned)ext)) << 16;
274         ext->ext_iomap = (caddr_t)ext + offset;
275         ext->ext_vm86.vm86_intmap = (caddr_t)ext + offset - 32;
276
277         addr = (u_long *)ext->ext_vm86.vm86_intmap;
278         for (i = 0; i < (ctob(IOPAGES) + 32 + 16) / sizeof(u_long); i++)
279                 *addr++ = ~0;
280
281         ssd.ssd_base = (unsigned)&ext->ext_tss;
282         ssd.ssd_limit -= ((unsigned)&ext->ext_tss - (unsigned)ext);
283         ssdtosd(&ssd, &ext->ext_tssd);
284
285         KASSERT(td == curthread, ("giving TSS to !curthread"));
286         KASSERT(td->td_pcb->pcb_ext == 0, ("already have a TSS!"));
287
288         /* Switch to the new TSS. */
289         mtx_lock_spin(&sched_lock);
290         td->td_pcb->pcb_ext = ext;
291         private_tss |= PCPU_GET(cpumask);
292         *PCPU_GET(tss_gdt) = ext->ext_tssd;
293         ltr(GSEL(GPROC0_SEL, SEL_KPL));
294         mtx_unlock_spin(&sched_lock);
295
296         return 0;
297 }
298
299 int
300 i386_set_ioperm(td, uap)
301         struct thread *td;
302         struct i386_ioperm_args *uap;
303 {
304         int i, error;
305         char *iomap;
306
307 #ifdef MAC
308         if ((error = mac_check_sysarch_ioperm(td->td_ucred)) != 0)
309                 return (error);
310 #endif
311         if ((error = suser(td)) != 0)
312                 return (error);
313         if ((error = securelevel_gt(td->td_ucred, 0)) != 0)
314                 return (error);
315         /*
316          * XXX 
317          * While this is restricted to root, we should probably figure out
318          * whether any other driver is using this i/o address, as so not to
319          * cause confusion.  This probably requires a global 'usage registry'.
320          */
321
322         if (td->td_pcb->pcb_ext == 0)
323                 if ((error = i386_extend_pcb(td)) != 0)
324                         return (error);
325         iomap = (char *)td->td_pcb->pcb_ext->ext_iomap;
326
327         if (uap->start + uap->length > IOPAGES * PAGE_SIZE * NBBY)
328                 return (EINVAL);
329
330         for (i = uap->start; i < uap->start + uap->length; i++) {
331                 if (uap->enable)
332                         iomap[i >> 3] &= ~(1 << (i & 7));
333                 else
334                         iomap[i >> 3] |= (1 << (i & 7));
335         }
336         return (error);
337 }
338
339 int
340 i386_get_ioperm(td, uap)
341         struct thread *td;
342         struct i386_ioperm_args *uap;
343 {
344         int i, state;
345         char *iomap;
346
347         if (uap->start >= IOPAGES * PAGE_SIZE * NBBY)
348                 return (EINVAL);
349
350         if (td->td_pcb->pcb_ext == 0) {
351                 uap->length = 0;
352                 goto done;
353         }
354
355         iomap = (char *)td->td_pcb->pcb_ext->ext_iomap;
356
357         i = uap->start;
358         state = (iomap[i >> 3] >> (i & 7)) & 1;
359         uap->enable = !state;
360         uap->length = 1;
361
362         for (i = uap->start + 1; i < IOPAGES * PAGE_SIZE * NBBY; i++) {
363                 if (state != ((iomap[i >> 3] >> (i & 7)) & 1))
364                         break;
365                 uap->length++;
366         }
367
368 done:
369         return (0);
370 }
371
372 /*
373  * Update the GDT entry pointing to the LDT to point to the LDT of the
374  * current process.
375  *
376  * This must be called with sched_lock held.  Unfortunately, we can't use a
377  * mtx_assert() here because cpu_switch() calls this function after changing
378  * curproc but before sched_lock's owner is updated in mi_switch().
379  */   
380 void
381 set_user_ldt(struct mdproc *mdp)
382 {
383         struct proc_ldt *pldt;
384
385         pldt = mdp->md_ldt;
386 #ifdef XEN
387         i386_reset_ldt(pldt);
388         PCPU_SET(currentldt, (int)pldt);
389 #else   
390 #ifdef SMP
391         gdt[PCPU_GET(cpuid) * NGDT + GUSERLDT_SEL].sd = pldt->ldt_sd;
392 #else
393         gdt[GUSERLDT_SEL].sd = pldt->ldt_sd;
394 #endif
395         lldt(GSEL(GUSERLDT_SEL, SEL_KPL));
396         PCPU_SET(currentldt, GSEL(GUSERLDT_SEL, SEL_KPL));
397 #endif /* !XEN */
398 }
399
400 #ifdef SMP
401 static void
402 set_user_ldt_rv(struct thread *td)
403 {
404
405         if (td->td_proc != curthread->td_proc)
406                 return;
407
408         set_user_ldt(&td->td_proc->p_md);
409 }
410 #endif
411
412 #ifdef XEN
413
414 struct proc_ldt * 
415 user_ldt_alloc(struct mdproc *mdp, int len) 
416
417         struct proc_ldt *pldt, *new_ldt; 
418  
419         MALLOC(new_ldt, struct proc_ldt *, sizeof(struct proc_ldt), 
420                 M_SUBPROC, M_WAITOK); 
421  
422         new_ldt->ldt_len = len = NEW_MAX_LD(len); 
423         new_ldt->ldt_base = (caddr_t)kmem_alloc(kernel_map, 
424                 round_page(len * sizeof(union descriptor))); 
425         if (new_ldt->ldt_base == NULL) { 
426                 FREE(new_ldt, M_SUBPROC); 
427                 return NULL; 
428         } 
429         new_ldt->ldt_refcnt = 1; 
430         new_ldt->ldt_active = 0; 
431  
432         if ((pldt = mdp->md_ldt)) { 
433                 if (len > pldt->ldt_len) 
434                         len = pldt->ldt_len; 
435                 bcopy(pldt->ldt_base, new_ldt->ldt_base, 
436                     len * sizeof(union descriptor)); 
437         } else { 
438                 bcopy(ldt, new_ldt->ldt_base, PAGE_SIZE); 
439         } 
440         pmap_map_readonly(kernel_pmap, (vm_offset_t)new_ldt->ldt_base, 
441                           new_ldt->ldt_len*sizeof(union descriptor)); 
442         return new_ldt; 
443
444 #else
445 /*
446  * Must be called with either sched_lock free or held but not recursed.
447  * If it does not return NULL, it will return with it owned.
448  */
449 struct proc_ldt *
450 user_ldt_alloc(struct mdproc *mdp, int len)
451 {
452         struct proc_ldt *pldt, *new_ldt;
453
454         if (mtx_owned(&sched_lock))
455                 mtx_unlock_spin(&sched_lock);
456         mtx_assert(&sched_lock, MA_NOTOWNED);
457         MALLOC(new_ldt, struct proc_ldt *, sizeof(struct proc_ldt),
458                 M_SUBPROC, M_WAITOK);
459
460         new_ldt->ldt_len = len = NEW_MAX_LD(len);
461         new_ldt->ldt_base = (caddr_t)kmem_alloc(kernel_map,
462                 len * sizeof(union descriptor));
463         if (new_ldt->ldt_base == NULL) {
464                 FREE(new_ldt, M_SUBPROC);
465                 return NULL;
466         }
467         new_ldt->ldt_refcnt = 1;
468         new_ldt->ldt_active = 0;
469
470         mtx_lock_spin(&sched_lock);
471         gdt_segs[GUSERLDT_SEL].ssd_base = (unsigned)new_ldt->ldt_base;
472         gdt_segs[GUSERLDT_SEL].ssd_limit = len * sizeof(union descriptor) - 1;
473         ssdtosd(&gdt_segs[GUSERLDT_SEL], &new_ldt->ldt_sd);
474
475         if ((pldt = mdp->md_ldt)) {
476                 if (len > pldt->ldt_len)
477                         len = pldt->ldt_len;
478                 bcopy(pldt->ldt_base, new_ldt->ldt_base,
479                     len * sizeof(union descriptor));
480         } else {
481                 bcopy(ldt, new_ldt->ldt_base, sizeof(ldt));
482         }
483         return new_ldt;
484 }
485 #endif
486
487 /*
488  * Must be called either with sched_lock free or held but not recursed.
489  * If md_ldt is not NULL, it will return with sched_lock released.
490  */
491 void
492 user_ldt_free(struct thread *td)
493 {
494         struct mdproc *mdp = &td->td_proc->p_md;
495         struct proc_ldt *pldt = mdp->md_ldt;
496
497         if (pldt == NULL)
498                 return;
499
500         if (!mtx_owned(&sched_lock))
501                 mtx_lock_spin(&sched_lock);
502         mtx_assert(&sched_lock, MA_OWNED | MA_NOTRECURSED);
503         if (td == PCPU_GET(curthread)) {
504 #ifndef XEN
505                 lldt(_default_ldt);
506 #endif          
507                 PCPU_SET(currentldt, _default_ldt);
508                 i386_reset_ldt((struct proc_ldt *)_default_ldt);
509         }
510
511         mdp->md_ldt = NULL;
512         if (--pldt->ldt_refcnt == 0) {
513                 mtx_unlock_spin(&sched_lock);
514                 kmem_free(kernel_map, (vm_offset_t)pldt->ldt_base,
515                         pldt->ldt_len * sizeof(union descriptor));
516                 FREE(pldt, M_SUBPROC);
517         } else
518                 mtx_unlock_spin(&sched_lock);
519 }
520
521 /*
522  * Note for the authors of compat layers (linux, etc): copyout() in
523  * the function below is not a problem since it presents data in
524  * arch-specific format (i.e. i386-specific in this case), not in
525  * the OS-specific one.
526  */
527 int
528 i386_get_ldt(td, uap)
529         struct thread *td;
530         struct i386_ldt_args *uap;
531 {
532         int error = 0;
533         struct proc_ldt *pldt = td->td_proc->p_md.md_ldt;
534         int nldt, num;
535         union descriptor *lp;
536
537 #ifdef  DEBUG
538         printf("i386_get_ldt: start=%d num=%d descs=%p\n",
539             uap->start, uap->num, (void *)uap->descs);
540 #endif
541
542         if (pldt) {
543                 nldt = pldt->ldt_len;
544                 num = min(uap->num, nldt);
545                 lp = &((union descriptor *)(pldt->ldt_base))[uap->start];
546         } else {
547                 nldt = sizeof(ldt)/sizeof(ldt[0]);
548                 num = min(uap->num, nldt);
549                 lp = &ldt[uap->start];
550         }
551
552         if ((uap->start > (unsigned int)nldt) ||
553             ((unsigned int)num > (unsigned int)nldt) ||
554             ((unsigned int)(uap->start + num) > (unsigned int)nldt))
555                 return(EINVAL);
556
557         error = copyout(lp, uap->descs, num * sizeof(union descriptor));
558         if (!error)
559                 td->td_retval[0] = num;
560
561         return(error);
562 }
563
564 static int ldt_warnings;
565 #define NUM_LDT_WARNINGS 10
566
567 int
568 i386_set_ldt(td, uap, descs)
569         struct thread *td;
570         struct i386_ldt_args *uap;
571         union descriptor *descs;
572 {
573         int error = 0, i;
574         int largest_ld;
575         struct mdproc *mdp = &td->td_proc->p_md;
576         struct proc_ldt *pldt;
577         union descriptor *dp;
578
579 #ifdef  DEBUG
580         printf("i386_set_ldt: start=%d num=%d descs=%p\n",
581             uap->start, uap->num, (void *)uap->descs);
582 #endif
583
584         if (descs == NULL) {
585                 /* Free descriptors */
586                 if (uap->start == 0 && uap->num == 0) {
587                         /*
588                          * Treat this as a special case, so userland needn't
589                          * know magic number NLDT.
590                          */
591                         uap->start = NLDT;
592                         uap->num = MAX_LD - NLDT;
593                 }
594                 if (uap->num <= 0)
595                         return (EINVAL);
596                 mtx_lock_spin(&sched_lock);
597                 pldt = mdp->md_ldt;
598                 if (pldt == NULL || uap->start >= pldt->ldt_len) {
599                         mtx_unlock_spin(&sched_lock);
600                         return (0);
601                 }
602                 largest_ld = uap->start + uap->num;
603                 if (largest_ld > pldt->ldt_len)
604                         largest_ld = pldt->ldt_len;
605                 i = largest_ld - uap->start;
606                 bzero(&((union descriptor *)(pldt->ldt_base))[uap->start],
607                     sizeof(union descriptor) * i);
608                 mtx_unlock_spin(&sched_lock);
609                 return (0);
610         }
611
612         if (!(uap->start == LDT_AUTO_ALLOC && uap->num == 1)) {
613 #ifdef XEN 
614                         load_gs(0);  /* XXX check if we really still need this */
615 #endif 
616                 /* complain a for a while if using old methods */
617                 if (ldt_warnings++ < NUM_LDT_WARNINGS) {
618                         printf("Warning: pid %d used static ldt allocation.\n",
619                             td->td_proc->p_pid);
620                         printf("See the i386_set_ldt man page for more info\n");
621                 }
622                 /* verify range of descriptors to modify */
623                 largest_ld = uap->start + uap->num;
624                 if (uap->start >= MAX_LD ||
625                     uap->num < 0 || largest_ld > MAX_LD) {
626                         return (EINVAL);
627                 }
628         }
629
630         /* Check descriptors for access violations */
631         for (i = 0; i < uap->num; i++) {
632                 dp = &descs[i];
633
634                 switch (dp->sd.sd_type) {
635                 case SDT_SYSNULL:       /* system null */ 
636                         dp->sd.sd_p = 0;
637                         break;
638                 case SDT_SYS286TSS: /* system 286 TSS available */
639                 case SDT_SYSLDT:    /* system local descriptor table */
640                 case SDT_SYS286BSY: /* system 286 TSS busy */
641                 case SDT_SYSTASKGT: /* system task gate */
642                 case SDT_SYS286IGT: /* system 286 interrupt gate */
643                 case SDT_SYS286TGT: /* system 286 trap gate */
644                 case SDT_SYSNULL2:  /* undefined by Intel */ 
645                 case SDT_SYS386TSS: /* system 386 TSS available */
646                 case SDT_SYSNULL3:  /* undefined by Intel */
647                 case SDT_SYS386BSY: /* system 386 TSS busy */
648                 case SDT_SYSNULL4:  /* undefined by Intel */ 
649                 case SDT_SYS386IGT: /* system 386 interrupt gate */
650                 case SDT_SYS386TGT: /* system 386 trap gate */
651                 case SDT_SYS286CGT: /* system 286 call gate */ 
652                 case SDT_SYS386CGT: /* system 386 call gate */
653                         /* I can't think of any reason to allow a user proc
654                          * to create a segment of these types.  They are
655                          * for OS use only.
656                          */
657                         return (EACCES);
658                         /*NOTREACHED*/
659
660                 /* memory segment types */
661                 case SDT_MEMEC:   /* memory execute only conforming */
662                 case SDT_MEMEAC:  /* memory execute only accessed conforming */
663                 case SDT_MEMERC:  /* memory execute read conforming */
664                 case SDT_MEMERAC: /* memory execute read accessed conforming */
665                          /* Must be "present" if executable and conforming. */
666                         if (dp->sd.sd_p == 0)
667                                 return (EACCES);
668                         break;
669                 case SDT_MEMRO:   /* memory read only */
670                 case SDT_MEMROA:  /* memory read only accessed */
671                 case SDT_MEMRW:   /* memory read write */
672                 case SDT_MEMRWA:  /* memory read write accessed */
673                 case SDT_MEMROD:  /* memory read only expand dwn limit */
674                 case SDT_MEMRODA: /* memory read only expand dwn lim accessed */
675                 case SDT_MEMRWD:  /* memory read write expand dwn limit */  
676                 case SDT_MEMRWDA: /* memory read write expand dwn lim acessed */
677                 case SDT_MEME:    /* memory execute only */ 
678                 case SDT_MEMEA:   /* memory execute only accessed */
679                 case SDT_MEMER:   /* memory execute read */
680                 case SDT_MEMERA:  /* memory execute read accessed */
681                         break;
682                 default:
683                         return(EINVAL);
684                         /*NOTREACHED*/
685                 }
686
687                 /* Only user (ring-3) descriptors may be present. */
688                 if ((dp->sd.sd_p != 0) && (dp->sd.sd_dpl != SEL_UPL))
689                         return (EACCES);
690         }
691
692         if (uap->start == LDT_AUTO_ALLOC && uap->num == 1) {
693                 /* Allocate a free slot */
694                 pldt = mdp->md_ldt;
695                 if (pldt == NULL) {
696                         error = i386_ldt_grow(td, NLDT + 1);
697                         if (error)
698                                 return (error);
699                         pldt = mdp->md_ldt;
700                 }
701 again:
702                 mtx_lock_spin(&sched_lock);
703                 /*
704                  * start scanning a bit up to leave room for NVidia and
705                  * Wine, which still user the "Blat" method of allocation.
706                  */
707                 dp = &((union descriptor *)(pldt->ldt_base))[NLDT];
708                 for (i = NLDT; i < pldt->ldt_len; ++i) {
709                         if (dp->sd.sd_type == SDT_SYSNULL)
710                                 break;
711                         dp++;
712                 }
713                 if (i >= pldt->ldt_len) {
714                         mtx_unlock_spin(&sched_lock);
715                         error = i386_ldt_grow(td, pldt->ldt_len+1);
716                         if (error)
717                                 return (error);
718                         goto again;
719                 }
720                 uap->start = i;
721                 error = i386_set_ldt_data(td, i, 1, descs);
722                 mtx_unlock_spin(&sched_lock);
723         } else {
724                 largest_ld = uap->start + uap->num;
725                 error = i386_ldt_grow(td, largest_ld);
726                 if (error == 0) {
727                         mtx_lock_spin(&sched_lock);
728                         error = i386_set_ldt_data(td, uap->start, uap->num,
729                             descs);
730                         mtx_unlock_spin(&sched_lock);
731                 }
732         }
733         if (error == 0)
734                 td->td_retval[0] = uap->start;
735         return (error);
736 }
737
738 #ifdef XEN
739 static int 
740 i386_set_ldt_data(struct thread *td, int start, int num, 
741         union descriptor *descs) 
742
743         struct mdproc *mdp = &td->td_proc->p_md; 
744         struct proc_ldt *pldt = mdp->md_ldt; 
745         int i, error; 
746
747         for (i = 0; i < num; i++) { 
748                 error = HYPERVISOR_update_descriptor(vtomach(&((union descriptor *)(pldt->ldt_base))[start + i]), *(uint64_t *)(descs + i)); 
749                 if (error) 
750                         panic("failed to update ldt: %d", error); 
751         } 
752         return (0); 
753
754 #else
755 static int
756 i386_set_ldt_data(struct thread *td, int start, int num,
757         union descriptor *descs)
758 {
759         struct mdproc *mdp = &td->td_proc->p_md;
760         struct proc_ldt *pldt = mdp->md_ldt;
761
762         mtx_assert(&sched_lock, MA_OWNED);
763
764         /* Fill in range */
765         bcopy(descs,
766             &((union descriptor *)(pldt->ldt_base))[start],
767             num * sizeof(union descriptor));
768         return (0);
769 }
770 #endif
771
772 static int
773 i386_ldt_grow(struct thread *td, int len) 
774 {
775         struct mdproc *mdp = &td->td_proc->p_md;
776         struct proc_ldt *pldt;
777         caddr_t old_ldt_base;
778         int old_ldt_len;
779
780         if (len > MAX_LD)
781                 return (ENOMEM);
782         if (len < NLDT + 1)
783                 len = NLDT + 1;
784
785         /* Allocate a user ldt. */
786         pldt = mdp->md_ldt;
787         if (!pldt || len > pldt->ldt_len) {
788                 struct proc_ldt *new_ldt;
789
790                 new_ldt = user_ldt_alloc(mdp, len);
791                 if (new_ldt == NULL)
792                         return (ENOMEM);
793                 pldt = mdp->md_ldt;
794
795                 /* sched_lock was acquired by user_ldt_alloc. */
796                 if (pldt) {
797                         if (new_ldt->ldt_len > pldt->ldt_len) {
798                                 old_ldt_base = pldt->ldt_base;
799                                 old_ldt_len = pldt->ldt_len;
800                                 pldt->ldt_sd = new_ldt->ldt_sd;
801                                 pldt->ldt_base = new_ldt->ldt_base;
802                                 pldt->ldt_len = new_ldt->ldt_len;
803                                 mtx_unlock_spin(&sched_lock);
804                                 kmem_free(kernel_map, (vm_offset_t)old_ldt_base,
805                                         old_ldt_len * sizeof(union descriptor));
806                                 FREE(new_ldt, M_SUBPROC);
807                                 mtx_lock_spin(&sched_lock);
808                         } else {
809                                 /*
810                                  * If other threads already did the work,
811                                  * do nothing.
812                                  */
813                                 mtx_unlock_spin(&sched_lock);
814                                 kmem_free(kernel_map,
815                                    (vm_offset_t)new_ldt->ldt_base,
816                                    new_ldt->ldt_len * sizeof(union descriptor));
817                                 FREE(new_ldt, M_SUBPROC);
818                                 return (0);
819                         }
820                 } else {
821                         mdp->md_ldt = pldt = new_ldt;
822                 }
823 #ifdef SMP
824                 mtx_unlock_spin(&sched_lock);
825                 /* signal other cpus to reload ldt */
826                 smp_rendezvous(NULL, (void (*)(void *))set_user_ldt_rv,
827                     NULL, td);
828 #else
829                 set_user_ldt(mdp);
830                 mtx_unlock_spin(&sched_lock);
831 #endif
832         }
833         return (0);
834 }