sys_machdep.c (fb919e4d5a2c1baca52ac70d1064f140fffdda71) sys_machdep.c (df4d012b9afa5064c159349b7b4d7e178f57319e)
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

--- 54 unchanged lines hidden (view full) ---

63#define SIZE_FROM_LARGEST_LD(num) (NEW_MAX_LD(num) << 3)
64
65
66
67static int i386_get_ldt __P((struct proc *, char *));
68static int i386_set_ldt __P((struct proc *, char *));
69static int i386_get_ioperm __P((struct proc *, char *));
70static int i386_set_ioperm __P((struct proc *, char *));
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

--- 54 unchanged lines hidden (view full) ---

63#define SIZE_FROM_LARGEST_LD(num) (NEW_MAX_LD(num) << 3)
64
65
66
67static int i386_get_ldt __P((struct proc *, char *));
68static int i386_set_ldt __P((struct proc *, char *));
69static int i386_get_ioperm __P((struct proc *, char *));
70static int i386_set_ioperm __P((struct proc *, char *));
71int i386_extend_pcb __P((struct proc *));
72
73#ifndef _SYS_SYSPROTO_H_
74struct sysarch_args {
75 int op;
76 char *parms;
77};
78#endif
79

--- 43 unchanged lines hidden (view full) ---

123 0, 0,
124 0, /* default 32 size */
125 0 /* granularity */
126 };
127
128 ext = (struct pcb_ext *)kmem_alloc(kernel_map, ctob(IOPAGES+1));
129 if (ext == 0)
130 return (ENOMEM);
71
72#ifndef _SYS_SYSPROTO_H_
73struct sysarch_args {
74 int op;
75 char *parms;
76};
77#endif
78

--- 43 unchanged lines hidden (view full) ---

122 0, 0,
123 0, /* default 32 size */
124 0 /* granularity */
125 };
126
127 ext = (struct pcb_ext *)kmem_alloc(kernel_map, ctob(IOPAGES+1));
128 if (ext == 0)
129 return (ENOMEM);
131 p->p_addr->u_pcb.pcb_ext = ext;
132 bzero(ext, sizeof(struct pcb_ext));
133 ext->ext_tss.tss_esp0 = (unsigned)p->p_addr + ctob(UPAGES) - 16;
134 ext->ext_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL);
135 /*
136 * The last byte of the i/o map must be followed by an 0xff byte.
137 * We arbitrarily allocate 16 bytes here, to keep the starting
138 * address on a doubleword boundary.
139 */

--- 5 unchanged lines hidden (view full) ---

145
146 addr = (u_long *)ext->ext_vm86.vm86_intmap;
147 for (i = 0; i < (ctob(IOPAGES) + 32 + 16) / sizeof(u_long); i++)
148 *addr++ = ~0;
149
150 ssd.ssd_base = (unsigned)&ext->ext_tss;
151 ssd.ssd_limit -= ((unsigned)&ext->ext_tss - (unsigned)ext);
152 ssdtosd(&ssd, &ext->ext_tssd);
130 bzero(ext, sizeof(struct pcb_ext));
131 ext->ext_tss.tss_esp0 = (unsigned)p->p_addr + ctob(UPAGES) - 16;
132 ext->ext_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL);
133 /*
134 * The last byte of the i/o map must be followed by an 0xff byte.
135 * We arbitrarily allocate 16 bytes here, to keep the starting
136 * address on a doubleword boundary.
137 */

--- 5 unchanged lines hidden (view full) ---

143
144 addr = (u_long *)ext->ext_vm86.vm86_intmap;
145 for (i = 0; i < (ctob(IOPAGES) + 32 + 16) / sizeof(u_long); i++)
146 *addr++ = ~0;
147
148 ssd.ssd_base = (unsigned)&ext->ext_tss;
149 ssd.ssd_limit -= ((unsigned)&ext->ext_tss - (unsigned)ext);
150 ssdtosd(&ssd, &ext->ext_tssd);
151
152 KASSERT(p == curproc, ("giving a TSS to non-curproc"));
153 KASSERT(p->p_addr->u_pcb.pcb_ext == 0, ("already have a TSS!"));
154 mtx_lock_spin(&sched_lock);
155 p->p_addr->u_pcb.pcb_ext = ext;
153
154 /* switch to the new TSS after syscall completes */
156
157 /* switch to the new TSS after syscall completes */
155 /*
156 * XXX: The sched_lock here needs to be over a slightly larger area.
157 * I have patches to more properly lock accesses to process ldt's
158 * and tss's that still need to be reviewed, but this keeps us from
159 * panic'ing on the mtx_assert() in need_resched() for the time being.
160 */
161 mtx_lock_spin(&sched_lock);
162 need_resched(p);
163 mtx_unlock_spin(&sched_lock);
164
165 return 0;
166}
167
168static int
169i386_set_ioperm(p, args)

--- 79 unchanged lines hidden (view full) ---

249void
250set_user_ldt(struct pcb *pcb)
251{
252 struct pcb_ldt *pcb_ldt;
253
254 if (pcb != PCPU_GET(curpcb))
255 return;
256
158 need_resched(p);
159 mtx_unlock_spin(&sched_lock);
160
161 return 0;
162}
163
164static int
165i386_set_ioperm(p, args)

--- 79 unchanged lines hidden (view full) ---

245void
246set_user_ldt(struct pcb *pcb)
247{
248 struct pcb_ldt *pcb_ldt;
249
250 if (pcb != PCPU_GET(curpcb))
251 return;
252
253 mtx_lock_spin(&sched_lock);
257 pcb_ldt = pcb->pcb_ldt;
258#ifdef SMP
259 gdt[PCPU_GET(cpuid) * NGDT + GUSERLDT_SEL].sd = pcb_ldt->ldt_sd;
260#else
261 gdt[GUSERLDT_SEL].sd = pcb_ldt->ldt_sd;
262#endif
263 lldt(GSEL(GUSERLDT_SEL, SEL_KPL));
264 PCPU_SET(currentldt, GSEL(GUSERLDT_SEL, SEL_KPL));
254 pcb_ldt = pcb->pcb_ldt;
255#ifdef SMP
256 gdt[PCPU_GET(cpuid) * NGDT + GUSERLDT_SEL].sd = pcb_ldt->ldt_sd;
257#else
258 gdt[GUSERLDT_SEL].sd = pcb_ldt->ldt_sd;
259#endif
260 lldt(GSEL(GUSERLDT_SEL, SEL_KPL));
261 PCPU_SET(currentldt, GSEL(GUSERLDT_SEL, SEL_KPL));
262 mtx_unlock_spin(&sched_lock);
265}
266
263}
264
265/*
266 * Must be called with either sched_lock free or held but not recursed.
267 * If it does not return NULL, it will return with it owned.
268 */
267struct pcb_ldt *
268user_ldt_alloc(struct pcb *pcb, int len)
269{
270 struct pcb_ldt *pcb_ldt, *new_ldt;
271
269struct pcb_ldt *
270user_ldt_alloc(struct pcb *pcb, int len)
271{
272 struct pcb_ldt *pcb_ldt, *new_ldt;
273
274 if (mtx_owned(&sched_lock))
275 mtx_unlock_spin(&sched_lock);
276 mtx_assert(&sched_lock, MA_NOTOWNED);
272 MALLOC(new_ldt, struct pcb_ldt *, sizeof(struct pcb_ldt),
273 M_SUBPROC, M_WAITOK);
277 MALLOC(new_ldt, struct pcb_ldt *, sizeof(struct pcb_ldt),
278 M_SUBPROC, M_WAITOK);
274 if (new_ldt == NULL)
275 return NULL;
276
277 new_ldt->ldt_len = len = NEW_MAX_LD(len);
278 new_ldt->ldt_base = (caddr_t)kmem_alloc(kernel_map,
279 len * sizeof(union descriptor));
280 if (new_ldt->ldt_base == NULL) {
281 FREE(new_ldt, M_SUBPROC);
282 return NULL;
283 }
284 new_ldt->ldt_refcnt = 1;
285 new_ldt->ldt_active = 0;
286
279
280 new_ldt->ldt_len = len = NEW_MAX_LD(len);
281 new_ldt->ldt_base = (caddr_t)kmem_alloc(kernel_map,
282 len * sizeof(union descriptor));
283 if (new_ldt->ldt_base == NULL) {
284 FREE(new_ldt, M_SUBPROC);
285 return NULL;
286 }
287 new_ldt->ldt_refcnt = 1;
288 new_ldt->ldt_active = 0;
289
290 mtx_lock_spin(&sched_lock);
287 gdt_segs[GUSERLDT_SEL].ssd_base = (unsigned)new_ldt->ldt_base;
288 gdt_segs[GUSERLDT_SEL].ssd_limit = len * sizeof(union descriptor) - 1;
289 ssdtosd(&gdt_segs[GUSERLDT_SEL], &new_ldt->ldt_sd);
290
291 if ((pcb_ldt = pcb->pcb_ldt)) {
292 if (len > pcb_ldt->ldt_len)
293 len = pcb_ldt->ldt_len;
294 bcopy(pcb_ldt->ldt_base, new_ldt->ldt_base,
295 len * sizeof(union descriptor));
296 } else {
297 bcopy(ldt, new_ldt->ldt_base, sizeof(ldt));
298 }
299 return new_ldt;
300}
301
291 gdt_segs[GUSERLDT_SEL].ssd_base = (unsigned)new_ldt->ldt_base;
292 gdt_segs[GUSERLDT_SEL].ssd_limit = len * sizeof(union descriptor) - 1;
293 ssdtosd(&gdt_segs[GUSERLDT_SEL], &new_ldt->ldt_sd);
294
295 if ((pcb_ldt = pcb->pcb_ldt)) {
296 if (len > pcb_ldt->ldt_len)
297 len = pcb_ldt->ldt_len;
298 bcopy(pcb_ldt->ldt_base, new_ldt->ldt_base,
299 len * sizeof(union descriptor));
300 } else {
301 bcopy(ldt, new_ldt->ldt_base, sizeof(ldt));
302 }
303 return new_ldt;
304}
305
306/*
307 * Must be called either with sched_lock free or held but not recursed.
308 * If pcb->pcb_ldt is not NULL, it will return with sched_lock released.
309 */
302void
303user_ldt_free(struct pcb *pcb)
304{
305 struct pcb_ldt *pcb_ldt = pcb->pcb_ldt;
306
307 if (pcb_ldt == NULL)
308 return;
309
310void
311user_ldt_free(struct pcb *pcb)
312{
313 struct pcb_ldt *pcb_ldt = pcb->pcb_ldt;
314
315 if (pcb_ldt == NULL)
316 return;
317
318 if (!mtx_owned(&sched_lock))
319 mtx_lock_spin(&sched_lock);
320 mtx_assert(&sched_lock, MA_OWNED | MA_NOTRECURSED);
310 if (pcb == PCPU_GET(curpcb)) {
311 lldt(_default_ldt);
312 PCPU_SET(currentldt, _default_ldt);
313 }
314
321 if (pcb == PCPU_GET(curpcb)) {
322 lldt(_default_ldt);
323 PCPU_SET(currentldt, _default_ldt);
324 }
325
326 pcb->pcb_ldt = NULL;
315 if (--pcb_ldt->ldt_refcnt == 0) {
327 if (--pcb_ldt->ldt_refcnt == 0) {
328 mtx_unlock_spin(&sched_lock);
316 kmem_free(kernel_map, (vm_offset_t)pcb_ldt->ldt_base,
317 pcb_ldt->ldt_len * sizeof(union descriptor));
318 FREE(pcb_ldt, M_SUBPROC);
329 kmem_free(kernel_map, (vm_offset_t)pcb_ldt->ldt_base,
330 pcb_ldt->ldt_len * sizeof(union descriptor));
331 FREE(pcb_ldt, M_SUBPROC);
319 }
320 pcb->pcb_ldt = NULL;
332 } else
333 mtx_unlock_spin(&sched_lock);
321}
322
323static int
324i386_get_ldt(p, args)
325 struct proc *p;
326 char *args;
327{
328 int error = 0;
329 struct pcb *pcb = &p->p_addr->u_pcb;
330 struct pcb_ldt *pcb_ldt = pcb->pcb_ldt;
331 int nldt, num;
332 union descriptor *lp;
334}
335
336static int
337i386_get_ldt(p, args)
338 struct proc *p;
339 char *args;
340{
341 int error = 0;
342 struct pcb *pcb = &p->p_addr->u_pcb;
343 struct pcb_ldt *pcb_ldt = pcb->pcb_ldt;
344 int nldt, num;
345 union descriptor *lp;
333 int s;
334 struct i386_ldt_args ua, *uap = &ua;
335
336 if ((error = copyin(args, uap, sizeof(struct i386_ldt_args))) < 0)
337 return(error);
338
339#ifdef DEBUG
340 printf("i386_get_ldt: start=%d num=%d descs=%p\n",
341 uap->start, uap->num, (void *)uap->descs);
342#endif
343
344 /* verify range of LDTs exist */
345 if ((uap->start < 0) || (uap->num <= 0))
346 return(EINVAL);
347
346 struct i386_ldt_args ua, *uap = &ua;
347
348 if ((error = copyin(args, uap, sizeof(struct i386_ldt_args))) < 0)
349 return(error);
350
351#ifdef DEBUG
352 printf("i386_get_ldt: start=%d num=%d descs=%p\n",
353 uap->start, uap->num, (void *)uap->descs);
354#endif
355
356 /* verify range of LDTs exist */
357 if ((uap->start < 0) || (uap->num <= 0))
358 return(EINVAL);
359
348 s = splhigh();
349
350 if (pcb_ldt) {
351 nldt = pcb_ldt->ldt_len;
352 num = min(uap->num, nldt);
353 lp = &((union descriptor *)(pcb_ldt->ldt_base))[uap->start];
354 } else {
355 nldt = sizeof(ldt)/sizeof(ldt[0]);
356 num = min(uap->num, nldt);
357 lp = &ldt[uap->start];
358 }
360 if (pcb_ldt) {
361 nldt = pcb_ldt->ldt_len;
362 num = min(uap->num, nldt);
363 lp = &((union descriptor *)(pcb_ldt->ldt_base))[uap->start];
364 } else {
365 nldt = sizeof(ldt)/sizeof(ldt[0]);
366 num = min(uap->num, nldt);
367 lp = &ldt[uap->start];
368 }
359 if (uap->start > nldt) {
360 splx(s);
369 if (uap->start > nldt)
361 return(EINVAL);
370 return(EINVAL);
362 }
363
364 error = copyout(lp, uap->descs, num * sizeof(union descriptor));
365 if (!error)
366 p->p_retval[0] = num;
367
371
372 error = copyout(lp, uap->descs, num * sizeof(union descriptor));
373 if (!error)
374 p->p_retval[0] = num;
375
368 splx(s);
369 return(error);
370}
371
372static int
373i386_set_ldt(p, args)
374 struct proc *p;
375 char *args;
376{
377 int error = 0, i, n;
378 int largest_ld;
379 struct pcb *pcb = &p->p_addr->u_pcb;
380 struct pcb_ldt *pcb_ldt = pcb->pcb_ldt;
376 return(error);
377}
378
379static int
380i386_set_ldt(p, args)
381 struct proc *p;
382 char *args;
383{
384 int error = 0, i, n;
385 int largest_ld;
386 struct pcb *pcb = &p->p_addr->u_pcb;
387 struct pcb_ldt *pcb_ldt = pcb->pcb_ldt;
381 int s;
382 struct i386_ldt_args ua, *uap = &ua;
388 struct i386_ldt_args ua, *uap = &ua;
389 caddr_t old_ldt_base;
390 int old_ldt_len;
391 critical_t savecrit;
383
384 if ((error = copyin(args, uap, sizeof(struct i386_ldt_args))) < 0)
385 return(error);
386
387#ifdef DEBUG
388 printf("i386_set_ldt: start=%d num=%d descs=%p\n",
389 uap->start, uap->num, (void *)uap->descs);
390#endif

--- 9 unchanged lines hidden (view full) ---

400 return(EINVAL);
401
402 /* allocate user ldt */
403 if (!pcb_ldt || largest_ld >= pcb_ldt->ldt_len) {
404 struct pcb_ldt *new_ldt = user_ldt_alloc(pcb, largest_ld);
405 if (new_ldt == NULL)
406 return ENOMEM;
407 if (pcb_ldt) {
392
393 if ((error = copyin(args, uap, sizeof(struct i386_ldt_args))) < 0)
394 return(error);
395
396#ifdef DEBUG
397 printf("i386_set_ldt: start=%d num=%d descs=%p\n",
398 uap->start, uap->num, (void *)uap->descs);
399#endif

--- 9 unchanged lines hidden (view full) ---

409 return(EINVAL);
410
411 /* allocate user ldt */
412 if (!pcb_ldt || largest_ld >= pcb_ldt->ldt_len) {
413 struct pcb_ldt *new_ldt = user_ldt_alloc(pcb, largest_ld);
414 if (new_ldt == NULL)
415 return ENOMEM;
416 if (pcb_ldt) {
417 old_ldt_base = pcb_ldt->ldt_base;
418 old_ldt_len = pcb_ldt->ldt_len;
408 pcb_ldt->ldt_sd = new_ldt->ldt_sd;
419 pcb_ldt->ldt_sd = new_ldt->ldt_sd;
409 kmem_free(kernel_map, (vm_offset_t)pcb_ldt->ldt_base,
410 pcb_ldt->ldt_len * sizeof(union descriptor));
411 pcb_ldt->ldt_base = new_ldt->ldt_base;
412 pcb_ldt->ldt_len = new_ldt->ldt_len;
420 pcb_ldt->ldt_base = new_ldt->ldt_base;
421 pcb_ldt->ldt_len = new_ldt->ldt_len;
422 mtx_unlock_spin(&sched_lock);
423 kmem_free(kernel_map, (vm_offset_t)old_ldt_base,
424 old_ldt_len * sizeof(union descriptor));
413 FREE(new_ldt, M_SUBPROC);
425 FREE(new_ldt, M_SUBPROC);
414 } else
426 } else {
415 pcb->pcb_ldt = pcb_ldt = new_ldt;
427 pcb->pcb_ldt = pcb_ldt = new_ldt;
428 mtx_unlock_spin(&sched_lock);
429 }
416#ifdef SMP
417 /* signal other cpus to reload ldt */
418 smp_rendezvous(NULL, (void (*)(void *))set_user_ldt, NULL, pcb);
419#else
420 set_user_ldt(pcb);
421#endif
422 }
423

--- 24 unchanged lines hidden (view full) ---

448 case SDT_SYS386TGT: /* system 386 trap gate */
449 case SDT_SYS286CGT: /* system 286 call gate */
450 case SDT_SYS386CGT: /* system 386 call gate */
451 /* I can't think of any reason to allow a user proc
452 * to create a segment of these types. They are
453 * for OS use only.
454 */
455 return EACCES;
430#ifdef SMP
431 /* signal other cpus to reload ldt */
432 smp_rendezvous(NULL, (void (*)(void *))set_user_ldt, NULL, pcb);
433#else
434 set_user_ldt(pcb);
435#endif
436 }
437

--- 24 unchanged lines hidden (view full) ---

462 case SDT_SYS386TGT: /* system 386 trap gate */
463 case SDT_SYS286CGT: /* system 286 call gate */
464 case SDT_SYS386CGT: /* system 386 call gate */
465 /* I can't think of any reason to allow a user proc
466 * to create a segment of these types. They are
467 * for OS use only.
468 */
469 return EACCES;
470 /*NOTREACHED*/
456
457 /* memory segment types */
458 case SDT_MEMEC: /* memory execute only conforming */
459 case SDT_MEMEAC: /* memory execute only accessed conforming */
460 case SDT_MEMERC: /* memory execute read conforming */
461 case SDT_MEMERAC: /* memory execute read accessed conforming */
462 /* Must be "present" if executable and conforming. */
471
472 /* memory segment types */
473 case SDT_MEMEC: /* memory execute only conforming */
474 case SDT_MEMEAC: /* memory execute only accessed conforming */
475 case SDT_MEMERC: /* memory execute read conforming */
476 case SDT_MEMERAC: /* memory execute read accessed conforming */
477 /* Must be "present" if executable and conforming. */
463 if (desc.sd.sd_p == 0)
464 return (EACCES);
478 if (desc.sd.sd_p == 0)
479 return (EACCES);
465 break;
466 case SDT_MEMRO: /* memory read only */
467 case SDT_MEMROA: /* memory read only accessed */
468 case SDT_MEMRW: /* memory read write */
469 case SDT_MEMRWA: /* memory read write accessed */
470 case SDT_MEMROD: /* memory read only expand dwn limit */
471 case SDT_MEMRODA: /* memory read only expand dwn lim accessed */
472 case SDT_MEMRWD: /* memory read write expand dwn limit */

--- 8 unchanged lines hidden (view full) ---

481 /*NOTREACHED*/
482 }
483
484 /* Only user (ring-3) descriptors may be present. */
485 if ((desc.sd.sd_p != 0) && (desc.sd.sd_dpl != SEL_UPL))
486 return (EACCES);
487 }
488
480 break;
481 case SDT_MEMRO: /* memory read only */
482 case SDT_MEMROA: /* memory read only accessed */
483 case SDT_MEMRW: /* memory read write */
484 case SDT_MEMRWA: /* memory read write accessed */
485 case SDT_MEMROD: /* memory read only expand dwn limit */
486 case SDT_MEMRODA: /* memory read only expand dwn lim accessed */
487 case SDT_MEMRWD: /* memory read write expand dwn limit */

--- 8 unchanged lines hidden (view full) ---

496 /*NOTREACHED*/
497 }
498
499 /* Only user (ring-3) descriptors may be present. */
500 if ((desc.sd.sd_p != 0) && (desc.sd.sd_dpl != SEL_UPL))
501 return (EACCES);
502 }
503
489 s = splhigh();
490
491 /* Fill in range */
504 /* Fill in range */
505 savecrit = critical_enter();
492 error = copyin(uap->descs,
506 error = copyin(uap->descs,
493 &((union descriptor *)(pcb_ldt->ldt_base))[uap->start],
494 uap->num * sizeof(union descriptor));
507 &((union descriptor *)(pcb_ldt->ldt_base))[uap->start],
508 uap->num * sizeof(union descriptor));
495 if (!error)
496 p->p_retval[0] = uap->start;
509 if (!error)
510 p->p_retval[0] = uap->start;
511 critical_exit(savecrit);
497
512
498 splx(s);
499 return(error);
500}
513 return(error);
514}