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} |