sys_machdep.c (114029) | sys_machdep.c (114349) |
---|---|
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 --- 17 unchanged lines hidden (view full) --- 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 | 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 --- 17 unchanged lines hidden (view full) --- 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: head/sys/amd64/amd64/sys_machdep.c 114029 2003-04-25 20:04:02Z jhb $ | 34 * $FreeBSD: head/sys/amd64/amd64/sys_machdep.c 114349 2003-05-01 01:05:25Z peter $ |
35 * 36 */ 37 | 35 * 36 */ 37 |
38#include "opt_kstack_pages.h" 39#include "opt_mac.h" 40 | |
41#include <sys/param.h> 42#include <sys/systm.h> 43#include <sys/lock.h> | 38#include <sys/param.h> 39#include <sys/systm.h> 40#include <sys/lock.h> |
44#include <sys/mac.h> 45#include <sys/malloc.h> 46#include <sys/mutex.h> | |
47#include <sys/proc.h> | 41#include <sys/proc.h> |
48#include <sys/smp.h> | |
49#include <sys/sysproto.h> | 42#include <sys/sysproto.h> |
50#include <sys/user.h> | |
51 | 43 |
52#include <vm/vm.h> 53#include <vm/pmap.h> 54#include <vm/vm_map.h> 55#include <vm/vm_extern.h> 56 57#include <machine/cpu.h> 58#include <machine/pcb_ext.h> /* pcb.h included by sys/user.h */ 59#include <machine/proc.h> 60#include <machine/sysarch.h> 61 62#include <vm/vm_kern.h> /* for kernel_map */ 63 64#define MAX_LD 8192 65#define LD_PER_PAGE 512 66#define NEW_MAX_LD(num) ((num + LD_PER_PAGE) & ~(LD_PER_PAGE-1)) 67#define SIZE_FROM_LARGEST_LD(num) (NEW_MAX_LD(num) << 3) 68 69 70 71static int i386_get_ldt(struct thread *, char *); 72static int i386_set_ldt(struct thread *, char *); 73static int i386_get_ioperm(struct thread *, char *); 74static int i386_set_ioperm(struct thread *, char *); 75#ifdef SMP 76static void set_user_ldt_rv(struct thread *); 77#endif 78 | |
79#ifndef _SYS_SYSPROTO_H_ 80struct sysarch_args { 81 int op; 82 char *parms; 83}; 84#endif 85 86int 87sysarch(td, uap) 88 struct thread *td; 89 register struct sysarch_args *uap; 90{ 91 int error; 92 | 44#ifndef _SYS_SYSPROTO_H_ 45struct sysarch_args { 46 int op; 47 char *parms; 48}; 49#endif 50 51int 52sysarch(td, uap) 53 struct thread *td; 54 register struct sysarch_args *uap; 55{ 56 int error; 57 |
93 mtx_lock(&Giant); | |
94 switch(uap->op) { | 58 switch(uap->op) { |
95 case I386_GET_LDT: 96 error = i386_get_ldt(td, uap->parms); 97 break; 98 99 case I386_SET_LDT: 100 error = i386_set_ldt(td, uap->parms); 101 break; 102 case I386_GET_IOPERM: 103 error = i386_get_ioperm(td, uap->parms); 104 break; 105 case I386_SET_IOPERM: 106 error = i386_set_ioperm(td, uap->parms); 107 break; 108 case I386_VM86: 109 error = vm86_sysarch(td, uap->parms); 110 break; | |
111 default: 112 error = EINVAL; 113 break; 114 } | 59 default: 60 error = EINVAL; 61 break; 62 } |
115 mtx_unlock(&Giant); | |
116 return (error); 117} | 63 return (error); 64} |
118 119int 120i386_extend_pcb(struct thread *td) 121{ 122 int i, offset; 123 u_long *addr; 124 struct pcb_ext *ext; 125 struct soft_segment_descriptor ssd = { 126 0, /* segment base address (overwritten) */ 127 ctob(IOPAGES + 1) - 1, /* length */ 128 SDT_SYS386TSS, /* segment type */ 129 0, /* priority level */ 130 1, /* descriptor present */ 131 0, 0, 132 0, /* default 32 size */ 133 0 /* granularity */ 134 }; 135 136 if (td->td_proc->p_flag & P_THREADED) 137 return (EINVAL); /* XXXKSE */ 138/* XXXKSE All the code below only works in 1:1 needs changing */ 139 ext = (struct pcb_ext *)kmem_alloc(kernel_map, ctob(IOPAGES+1)); 140 if (ext == 0) 141 return (ENOMEM); 142 bzero(ext, sizeof(struct pcb_ext)); 143 /* -16 is so we can convert a trapframe into vm86trapframe inplace */ 144 ext->ext_tss.tss_esp0 = td->td_kstack + ctob(KSTACK_PAGES) - 145 sizeof(struct pcb) - 16; 146 ext->ext_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL); 147 /* 148 * The last byte of the i/o map must be followed by an 0xff byte. 149 * We arbitrarily allocate 16 bytes here, to keep the starting 150 * address on a doubleword boundary. 151 */ 152 offset = PAGE_SIZE - 16; 153 ext->ext_tss.tss_ioopt = 154 (offset - ((unsigned)&ext->ext_tss - (unsigned)ext)) << 16; 155 ext->ext_iomap = (caddr_t)ext + offset; 156 ext->ext_vm86.vm86_intmap = (caddr_t)ext + offset - 32; 157 158 addr = (u_long *)ext->ext_vm86.vm86_intmap; 159 for (i = 0; i < (ctob(IOPAGES) + 32 + 16) / sizeof(u_long); i++) 160 *addr++ = ~0; 161 162 ssd.ssd_base = (unsigned)&ext->ext_tss; 163 ssd.ssd_limit -= ((unsigned)&ext->ext_tss - (unsigned)ext); 164 ssdtosd(&ssd, &ext->ext_tssd); 165 166 KASSERT(td->td_proc == curthread->td_proc, ("giving TSS to !curproc")); 167 KASSERT(td->td_pcb->pcb_ext == 0, ("already have a TSS!")); 168 mtx_lock_spin(&sched_lock); 169 td->td_pcb->pcb_ext = ext; 170 171 /* switch to the new TSS after syscall completes */ 172 td->td_flags |= TDF_NEEDRESCHED; 173 mtx_unlock_spin(&sched_lock); 174 175 return 0; 176} 177 178static int 179i386_set_ioperm(td, args) 180 struct thread *td; 181 char *args; 182{ 183 int i, error; 184 struct i386_ioperm_args ua; 185 char *iomap; 186 187 if ((error = copyin(args, &ua, sizeof(struct i386_ioperm_args))) != 0) 188 return (error); 189 190#ifdef MAC 191 if ((error = mac_check_sysarch_ioperm(td->td_ucred)) != 0) 192 return (error); 193#endif 194 if ((error = suser(td)) != 0) 195 return (error); 196 if ((error = securelevel_gt(td->td_ucred, 0)) != 0) 197 return (error); 198 /* 199 * XXX 200 * While this is restricted to root, we should probably figure out 201 * whether any other driver is using this i/o address, as so not to 202 * cause confusion. This probably requires a global 'usage registry'. 203 */ 204 205 if (td->td_pcb->pcb_ext == 0) 206 if ((error = i386_extend_pcb(td)) != 0) 207 return (error); 208 iomap = (char *)td->td_pcb->pcb_ext->ext_iomap; 209 210 if (ua.start + ua.length > IOPAGES * PAGE_SIZE * NBBY) 211 return (EINVAL); 212 213 for (i = ua.start; i < ua.start + ua.length; i++) { 214 if (ua.enable) 215 iomap[i >> 3] &= ~(1 << (i & 7)); 216 else 217 iomap[i >> 3] |= (1 << (i & 7)); 218 } 219 return (error); 220} 221 222static int 223i386_get_ioperm(td, args) 224 struct thread *td; 225 char *args; 226{ 227 int i, state, error; 228 struct i386_ioperm_args ua; 229 char *iomap; 230 231 if ((error = copyin(args, &ua, sizeof(struct i386_ioperm_args))) != 0) 232 return (error); 233 if (ua.start >= IOPAGES * PAGE_SIZE * NBBY) 234 return (EINVAL); 235 236 if (td->td_pcb->pcb_ext == 0) { 237 ua.length = 0; 238 goto done; 239 } 240 241 iomap = (char *)td->td_pcb->pcb_ext->ext_iomap; 242 243 i = ua.start; 244 state = (iomap[i >> 3] >> (i & 7)) & 1; 245 ua.enable = !state; 246 ua.length = 1; 247 248 for (i = ua.start + 1; i < IOPAGES * PAGE_SIZE * NBBY; i++) { 249 if (state != ((iomap[i >> 3] >> (i & 7)) & 1)) 250 break; 251 ua.length++; 252 } 253 254done: 255 error = copyout(&ua, args, sizeof(struct i386_ioperm_args)); 256 return (error); 257} 258 259/* 260 * Update the GDT entry pointing to the LDT to point to the LDT of the 261 * current process. 262 * 263 * This must be called with sched_lock held. Unfortunately, we can't use a 264 * mtx_assert() here because cpu_switch() calls this function after changing 265 * curproc but before sched_lock's owner is updated in mi_switch(). 266 */ 267void 268set_user_ldt(struct mdproc *mdp) 269{ 270 struct proc_ldt *pldt; 271 272 pldt = mdp->md_ldt; 273#ifdef SMP 274 gdt[PCPU_GET(cpuid) * NGDT + GUSERLDT_SEL].sd = pldt->ldt_sd; 275#else 276 gdt[GUSERLDT_SEL].sd = pldt->ldt_sd; 277#endif 278 lldt(GSEL(GUSERLDT_SEL, SEL_KPL)); 279 PCPU_SET(currentldt, GSEL(GUSERLDT_SEL, SEL_KPL)); 280} 281 282#ifdef SMP 283static void 284set_user_ldt_rv(struct thread *td) 285{ 286 287 if (td->td_proc != curthread->td_proc) 288 return; 289 290 mtx_lock_spin(&sched_lock); 291 set_user_ldt(&td->td_proc->p_md); 292 mtx_unlock_spin(&sched_lock); 293} 294#endif 295 296/* 297 * Must be called with either sched_lock free or held but not recursed. 298 * If it does not return NULL, it will return with it owned. 299 */ 300struct proc_ldt * 301user_ldt_alloc(struct mdproc *mdp, int len) 302{ 303 struct proc_ldt *pldt, *new_ldt; 304 305 if (mtx_owned(&sched_lock)) 306 mtx_unlock_spin(&sched_lock); 307 mtx_assert(&sched_lock, MA_NOTOWNED); 308 MALLOC(new_ldt, struct proc_ldt *, sizeof(struct proc_ldt), 309 M_SUBPROC, M_WAITOK); 310 311 new_ldt->ldt_len = len = NEW_MAX_LD(len); 312 new_ldt->ldt_base = (caddr_t)kmem_alloc(kernel_map, 313 len * sizeof(union descriptor)); 314 if (new_ldt->ldt_base == NULL) { 315 FREE(new_ldt, M_SUBPROC); 316 return NULL; 317 } 318 new_ldt->ldt_refcnt = 1; 319 new_ldt->ldt_active = 0; 320 321 mtx_lock_spin(&sched_lock); 322 gdt_segs[GUSERLDT_SEL].ssd_base = (unsigned)new_ldt->ldt_base; 323 gdt_segs[GUSERLDT_SEL].ssd_limit = len * sizeof(union descriptor) - 1; 324 ssdtosd(&gdt_segs[GUSERLDT_SEL], &new_ldt->ldt_sd); 325 326 if ((pldt = mdp->md_ldt)) { 327 if (len > pldt->ldt_len) 328 len = pldt->ldt_len; 329 bcopy(pldt->ldt_base, new_ldt->ldt_base, 330 len * sizeof(union descriptor)); 331 } else { 332 bcopy(ldt, new_ldt->ldt_base, sizeof(ldt)); 333 } 334 return new_ldt; 335} 336 337/* 338 * Must be called either with sched_lock free or held but not recursed. 339 * If md_ldt is not NULL, it will return with sched_lock released. 340 */ 341void 342user_ldt_free(struct thread *td) 343{ 344 struct mdproc *mdp = &td->td_proc->p_md; 345 struct proc_ldt *pldt = mdp->md_ldt; 346 347 if (pldt == NULL) 348 return; 349 350 if (!mtx_owned(&sched_lock)) 351 mtx_lock_spin(&sched_lock); 352 mtx_assert(&sched_lock, MA_OWNED | MA_NOTRECURSED); 353 if (td == PCPU_GET(curthread)) { 354 lldt(_default_ldt); 355 PCPU_SET(currentldt, _default_ldt); 356 } 357 358 mdp->md_ldt = NULL; 359 if (--pldt->ldt_refcnt == 0) { 360 mtx_unlock_spin(&sched_lock); 361 kmem_free(kernel_map, (vm_offset_t)pldt->ldt_base, 362 pldt->ldt_len * sizeof(union descriptor)); 363 FREE(pldt, M_SUBPROC); 364 } else 365 mtx_unlock_spin(&sched_lock); 366} 367 368static int 369i386_get_ldt(td, args) 370 struct thread *td; 371 char *args; 372{ 373 int error = 0; 374 struct proc_ldt *pldt = td->td_proc->p_md.md_ldt; 375 int nldt, num; 376 union descriptor *lp; 377 struct i386_ldt_args ua, *uap = &ua; 378 379 if ((error = copyin(args, uap, sizeof(struct i386_ldt_args))) < 0) 380 return(error); 381 382#ifdef DEBUG 383 printf("i386_get_ldt: start=%d num=%d descs=%p\n", 384 uap->start, uap->num, (void *)uap->descs); 385#endif 386 387 /* verify range of LDTs exist */ 388 if ((uap->start < 0) || (uap->num <= 0)) 389 return(EINVAL); 390 391 if (pldt) { 392 nldt = pldt->ldt_len; 393 num = min(uap->num, nldt); 394 lp = &((union descriptor *)(pldt->ldt_base))[uap->start]; 395 } else { 396 nldt = sizeof(ldt)/sizeof(ldt[0]); 397 num = min(uap->num, nldt); 398 lp = &ldt[uap->start]; 399 } 400 if (uap->start + num > nldt) 401 return(EINVAL); 402 403 error = copyout(lp, uap->descs, num * sizeof(union descriptor)); 404 if (!error) 405 td->td_retval[0] = num; 406 407 return(error); 408} 409 410static int 411i386_set_ldt(td, args) 412 struct thread *td; 413 char *args; 414{ 415 int error = 0, i, n; 416 int largest_ld; 417 struct mdproc *mdp = &td->td_proc->p_md; 418 struct proc_ldt *pldt = mdp->md_ldt; 419 struct i386_ldt_args ua, *uap = &ua; 420 union descriptor *descs; 421 caddr_t old_ldt_base; 422 int descs_size, old_ldt_len; 423 register_t savecrit; 424 425 if ((error = copyin(args, uap, sizeof(struct i386_ldt_args))) < 0) 426 return(error); 427 428#ifdef DEBUG 429 printf("i386_set_ldt: start=%d num=%d descs=%p\n", 430 uap->start, uap->num, (void *)uap->descs); 431#endif 432 433 /* verify range of descriptors to modify */ 434 if ((uap->start < 0) || (uap->start >= MAX_LD) || (uap->num < 0) || 435 (uap->num > MAX_LD)) 436 { 437 return(EINVAL); 438 } 439 largest_ld = uap->start + uap->num - 1; 440 if (largest_ld >= MAX_LD) 441 return(EINVAL); 442 443 /* allocate user ldt */ 444 if (!pldt || largest_ld >= pldt->ldt_len) { 445 struct proc_ldt *new_ldt = user_ldt_alloc(mdp, largest_ld); 446 if (new_ldt == NULL) 447 return ENOMEM; 448 if (pldt) { 449 old_ldt_base = pldt->ldt_base; 450 old_ldt_len = pldt->ldt_len; 451 pldt->ldt_sd = new_ldt->ldt_sd; 452 pldt->ldt_base = new_ldt->ldt_base; 453 pldt->ldt_len = new_ldt->ldt_len; 454 mtx_unlock_spin(&sched_lock); 455 kmem_free(kernel_map, (vm_offset_t)old_ldt_base, 456 old_ldt_len * sizeof(union descriptor)); 457 FREE(new_ldt, M_SUBPROC); 458#ifndef SMP 459 mtx_lock_spin(&sched_lock); 460#endif 461 } else { 462 mdp->md_ldt = pldt = new_ldt; 463#ifdef SMP 464 mtx_unlock_spin(&sched_lock); 465#endif 466 } 467#ifdef SMP 468 /* signal other cpus to reload ldt */ 469 smp_rendezvous(NULL, (void (*)(void *))set_user_ldt_rv, 470 NULL, td); 471#else 472 set_user_ldt(mdp); 473 mtx_unlock_spin(&sched_lock); 474#endif 475 } 476 477 descs_size = uap->num * sizeof(union descriptor); 478 descs = (union descriptor *)kmem_alloc(kernel_map, descs_size); 479 if (descs == NULL) 480 return (ENOMEM); 481 error = copyin(&uap->descs[0], descs, descs_size); 482 if (error) { 483 kmem_free(kernel_map, (vm_offset_t)descs, descs_size); 484 return (error); 485 } 486 /* Check descriptors for access violations */ 487 for (i = 0, n = uap->start; i < uap->num; i++, n++) { 488 union descriptor *dp; 489 dp = &descs[i]; 490 491 switch (dp->sd.sd_type) { 492 case SDT_SYSNULL: /* system null */ 493 dp->sd.sd_p = 0; 494 break; 495 case SDT_SYS286TSS: /* system 286 TSS available */ 496 case SDT_SYSLDT: /* system local descriptor table */ 497 case SDT_SYS286BSY: /* system 286 TSS busy */ 498 case SDT_SYSTASKGT: /* system task gate */ 499 case SDT_SYS286IGT: /* system 286 interrupt gate */ 500 case SDT_SYS286TGT: /* system 286 trap gate */ 501 case SDT_SYSNULL2: /* undefined by Intel */ 502 case SDT_SYS386TSS: /* system 386 TSS available */ 503 case SDT_SYSNULL3: /* undefined by Intel */ 504 case SDT_SYS386BSY: /* system 386 TSS busy */ 505 case SDT_SYSNULL4: /* undefined by Intel */ 506 case SDT_SYS386IGT: /* system 386 interrupt gate */ 507 case SDT_SYS386TGT: /* system 386 trap gate */ 508 case SDT_SYS286CGT: /* system 286 call gate */ 509 case SDT_SYS386CGT: /* system 386 call gate */ 510 /* I can't think of any reason to allow a user proc 511 * to create a segment of these types. They are 512 * for OS use only. 513 */ 514 kmem_free(kernel_map, (vm_offset_t)descs, descs_size); 515 return EACCES; 516 /*NOTREACHED*/ 517 518 /* memory segment types */ 519 case SDT_MEMEC: /* memory execute only conforming */ 520 case SDT_MEMEAC: /* memory execute only accessed conforming */ 521 case SDT_MEMERC: /* memory execute read conforming */ 522 case SDT_MEMERAC: /* memory execute read accessed conforming */ 523 /* Must be "present" if executable and conforming. */ 524 if (dp->sd.sd_p == 0) { 525 kmem_free(kernel_map, (vm_offset_t)descs, 526 descs_size); 527 return (EACCES); 528 } 529 break; 530 case SDT_MEMRO: /* memory read only */ 531 case SDT_MEMROA: /* memory read only accessed */ 532 case SDT_MEMRW: /* memory read write */ 533 case SDT_MEMRWA: /* memory read write accessed */ 534 case SDT_MEMROD: /* memory read only expand dwn limit */ 535 case SDT_MEMRODA: /* memory read only expand dwn lim accessed */ 536 case SDT_MEMRWD: /* memory read write expand dwn limit */ 537 case SDT_MEMRWDA: /* memory read write expand dwn lim acessed */ 538 case SDT_MEME: /* memory execute only */ 539 case SDT_MEMEA: /* memory execute only accessed */ 540 case SDT_MEMER: /* memory execute read */ 541 case SDT_MEMERA: /* memory execute read accessed */ 542 break; 543 default: 544 kmem_free(kernel_map, (vm_offset_t)descs, descs_size); 545 return(EINVAL); 546 /*NOTREACHED*/ 547 } 548 549 /* Only user (ring-3) descriptors may be present. */ 550 if ((dp->sd.sd_p != 0) && (dp->sd.sd_dpl != SEL_UPL)) { 551 kmem_free(kernel_map, (vm_offset_t)descs, descs_size); 552 return (EACCES); 553 } 554 } 555 556 /* Fill in range */ 557 savecrit = intr_disable(); 558 bcopy(descs, 559 &((union descriptor *)(pldt->ldt_base))[uap->start], 560 uap->num * sizeof(union descriptor)); 561 td->td_retval[0] = uap->start; 562 intr_restore(savecrit); 563 kmem_free(kernel_map, (vm_offset_t)descs, descs_size); 564 return (0); 565} | |