vm86.c revision 331722
1/*- 2 * Copyright (c) 1997 Jonathan Lemon 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 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: stable/11/sys/i386/i386/vm86.c 331722 2018-03-29 02:50:57Z eadler $"); 29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/priv.h> 33#include <sys/proc.h> 34#include <sys/lock.h> 35#include <sys/malloc.h> 36#include <sys/mutex.h> 37 38#include <vm/vm.h> 39#include <vm/pmap.h> 40#include <vm/vm_map.h> 41#include <vm/vm_page.h> 42 43#include <machine/md_var.h> 44#include <machine/pcb.h> 45#include <machine/pcb_ext.h> 46#include <machine/psl.h> 47#include <machine/specialreg.h> 48#include <machine/sysarch.h> 49 50extern int vm86pa; 51extern struct pcb *vm86pcb; 52 53static struct mtx vm86_lock; 54 55extern int vm86_bioscall(struct vm86frame *); 56extern void vm86_biosret(struct vm86frame *); 57 58void vm86_prepcall(struct vm86frame *); 59 60struct system_map { 61 int type; 62 vm_offset_t start; 63 vm_offset_t end; 64}; 65 66#define HLT 0xf4 67#define CLI 0xfa 68#define STI 0xfb 69#define PUSHF 0x9c 70#define POPF 0x9d 71#define INTn 0xcd 72#define IRET 0xcf 73#define CALLm 0xff 74#define OPERAND_SIZE_PREFIX 0x66 75#define ADDRESS_SIZE_PREFIX 0x67 76#define PUSH_MASK ~(PSL_VM | PSL_RF | PSL_I) 77#define POP_MASK ~(PSL_VIP | PSL_VIF | PSL_VM | PSL_RF | PSL_IOPL) 78 79static __inline caddr_t 80MAKE_ADDR(u_short sel, u_short off) 81{ 82 return ((caddr_t)((sel << 4) + off)); 83} 84 85static __inline void 86GET_VEC(u_int vec, u_short *sel, u_short *off) 87{ 88 *sel = vec >> 16; 89 *off = vec & 0xffff; 90} 91 92static __inline u_int 93MAKE_VEC(u_short sel, u_short off) 94{ 95 return ((sel << 16) | off); 96} 97 98static __inline void 99PUSH(u_short x, struct vm86frame *vmf) 100{ 101 vmf->vmf_sp -= 2; 102 suword16(MAKE_ADDR(vmf->vmf_ss, vmf->vmf_sp), x); 103} 104 105static __inline void 106PUSHL(u_int x, struct vm86frame *vmf) 107{ 108 vmf->vmf_sp -= 4; 109 suword(MAKE_ADDR(vmf->vmf_ss, vmf->vmf_sp), x); 110} 111 112static __inline u_short 113POP(struct vm86frame *vmf) 114{ 115 u_short x = fuword16(MAKE_ADDR(vmf->vmf_ss, vmf->vmf_sp)); 116 117 vmf->vmf_sp += 2; 118 return (x); 119} 120 121static __inline u_int 122POPL(struct vm86frame *vmf) 123{ 124 u_int x = fuword(MAKE_ADDR(vmf->vmf_ss, vmf->vmf_sp)); 125 126 vmf->vmf_sp += 4; 127 return (x); 128} 129 130int 131vm86_emulate(vmf) 132 struct vm86frame *vmf; 133{ 134 struct vm86_kernel *vm86; 135 caddr_t addr; 136 u_char i_byte; 137 u_int temp_flags; 138 int inc_ip = 1; 139 int retcode = 0; 140 141 /* 142 * pcb_ext contains the address of the extension area, or zero if 143 * the extension is not present. (This check should not be needed, 144 * as we can't enter vm86 mode until we set up an extension area) 145 */ 146 if (curpcb->pcb_ext == 0) 147 return (SIGBUS); 148 vm86 = &curpcb->pcb_ext->ext_vm86; 149 150 if (vmf->vmf_eflags & PSL_T) 151 retcode = SIGTRAP; 152 153 addr = MAKE_ADDR(vmf->vmf_cs, vmf->vmf_ip); 154 i_byte = fubyte(addr); 155 if (i_byte == ADDRESS_SIZE_PREFIX) { 156 i_byte = fubyte(++addr); 157 inc_ip++; 158 } 159 160 if (vm86->vm86_has_vme) { 161 switch (i_byte) { 162 case OPERAND_SIZE_PREFIX: 163 i_byte = fubyte(++addr); 164 inc_ip++; 165 switch (i_byte) { 166 case PUSHF: 167 if (vmf->vmf_eflags & PSL_VIF) 168 PUSHL((vmf->vmf_eflags & PUSH_MASK) 169 | PSL_IOPL | PSL_I, vmf); 170 else 171 PUSHL((vmf->vmf_eflags & PUSH_MASK) 172 | PSL_IOPL, vmf); 173 vmf->vmf_ip += inc_ip; 174 return (retcode); 175 176 case POPF: 177 temp_flags = POPL(vmf) & POP_MASK; 178 vmf->vmf_eflags = (vmf->vmf_eflags & ~POP_MASK) 179 | temp_flags | PSL_VM | PSL_I; 180 vmf->vmf_ip += inc_ip; 181 if (temp_flags & PSL_I) { 182 vmf->vmf_eflags |= PSL_VIF; 183 if (vmf->vmf_eflags & PSL_VIP) 184 break; 185 } else { 186 vmf->vmf_eflags &= ~PSL_VIF; 187 } 188 return (retcode); 189 } 190 break; 191 192 /* VME faults here if VIP is set, but does not set VIF. */ 193 case STI: 194 vmf->vmf_eflags |= PSL_VIF; 195 vmf->vmf_ip += inc_ip; 196 if ((vmf->vmf_eflags & PSL_VIP) == 0) { 197 uprintf("fatal sti\n"); 198 return (SIGKILL); 199 } 200 break; 201 202 /* VME if no redirection support */ 203 case INTn: 204 break; 205 206 /* VME if trying to set PSL_T, or PSL_I when VIP is set */ 207 case POPF: 208 temp_flags = POP(vmf) & POP_MASK; 209 vmf->vmf_flags = (vmf->vmf_flags & ~POP_MASK) 210 | temp_flags | PSL_VM | PSL_I; 211 vmf->vmf_ip += inc_ip; 212 if (temp_flags & PSL_I) { 213 vmf->vmf_eflags |= PSL_VIF; 214 if (vmf->vmf_eflags & PSL_VIP) 215 break; 216 } else { 217 vmf->vmf_eflags &= ~PSL_VIF; 218 } 219 return (retcode); 220 221 /* VME if trying to set PSL_T, or PSL_I when VIP is set */ 222 case IRET: 223 vmf->vmf_ip = POP(vmf); 224 vmf->vmf_cs = POP(vmf); 225 temp_flags = POP(vmf) & POP_MASK; 226 vmf->vmf_flags = (vmf->vmf_flags & ~POP_MASK) 227 | temp_flags | PSL_VM | PSL_I; 228 if (temp_flags & PSL_I) { 229 vmf->vmf_eflags |= PSL_VIF; 230 if (vmf->vmf_eflags & PSL_VIP) 231 break; 232 } else { 233 vmf->vmf_eflags &= ~PSL_VIF; 234 } 235 return (retcode); 236 237 } 238 return (SIGBUS); 239 } 240 241 switch (i_byte) { 242 case OPERAND_SIZE_PREFIX: 243 i_byte = fubyte(++addr); 244 inc_ip++; 245 switch (i_byte) { 246 case PUSHF: 247 if (vm86->vm86_eflags & PSL_VIF) 248 PUSHL((vmf->vmf_flags & PUSH_MASK) 249 | PSL_IOPL | PSL_I, vmf); 250 else 251 PUSHL((vmf->vmf_flags & PUSH_MASK) 252 | PSL_IOPL, vmf); 253 vmf->vmf_ip += inc_ip; 254 return (retcode); 255 256 case POPF: 257 temp_flags = POPL(vmf) & POP_MASK; 258 vmf->vmf_eflags = (vmf->vmf_eflags & ~POP_MASK) 259 | temp_flags | PSL_VM | PSL_I; 260 vmf->vmf_ip += inc_ip; 261 if (temp_flags & PSL_I) { 262 vm86->vm86_eflags |= PSL_VIF; 263 if (vm86->vm86_eflags & PSL_VIP) 264 break; 265 } else { 266 vm86->vm86_eflags &= ~PSL_VIF; 267 } 268 return (retcode); 269 } 270 return (SIGBUS); 271 272 case CLI: 273 vm86->vm86_eflags &= ~PSL_VIF; 274 vmf->vmf_ip += inc_ip; 275 return (retcode); 276 277 case STI: 278 /* if there is a pending interrupt, go to the emulator */ 279 vm86->vm86_eflags |= PSL_VIF; 280 vmf->vmf_ip += inc_ip; 281 if (vm86->vm86_eflags & PSL_VIP) 282 break; 283 return (retcode); 284 285 case PUSHF: 286 if (vm86->vm86_eflags & PSL_VIF) 287 PUSH((vmf->vmf_flags & PUSH_MASK) 288 | PSL_IOPL | PSL_I, vmf); 289 else 290 PUSH((vmf->vmf_flags & PUSH_MASK) | PSL_IOPL, vmf); 291 vmf->vmf_ip += inc_ip; 292 return (retcode); 293 294 case INTn: 295 i_byte = fubyte(addr + 1); 296 if ((vm86->vm86_intmap[i_byte >> 3] & (1 << (i_byte & 7))) != 0) 297 break; 298 if (vm86->vm86_eflags & PSL_VIF) 299 PUSH((vmf->vmf_flags & PUSH_MASK) 300 | PSL_IOPL | PSL_I, vmf); 301 else 302 PUSH((vmf->vmf_flags & PUSH_MASK) | PSL_IOPL, vmf); 303 PUSH(vmf->vmf_cs, vmf); 304 PUSH(vmf->vmf_ip + inc_ip + 1, vmf); /* increment IP */ 305 GET_VEC(fuword((caddr_t)(i_byte * 4)), 306 &vmf->vmf_cs, &vmf->vmf_ip); 307 vmf->vmf_flags &= ~PSL_T; 308 vm86->vm86_eflags &= ~PSL_VIF; 309 return (retcode); 310 311 case IRET: 312 vmf->vmf_ip = POP(vmf); 313 vmf->vmf_cs = POP(vmf); 314 temp_flags = POP(vmf) & POP_MASK; 315 vmf->vmf_flags = (vmf->vmf_flags & ~POP_MASK) 316 | temp_flags | PSL_VM | PSL_I; 317 if (temp_flags & PSL_I) { 318 vm86->vm86_eflags |= PSL_VIF; 319 if (vm86->vm86_eflags & PSL_VIP) 320 break; 321 } else { 322 vm86->vm86_eflags &= ~PSL_VIF; 323 } 324 return (retcode); 325 326 case POPF: 327 temp_flags = POP(vmf) & POP_MASK; 328 vmf->vmf_flags = (vmf->vmf_flags & ~POP_MASK) 329 | temp_flags | PSL_VM | PSL_I; 330 vmf->vmf_ip += inc_ip; 331 if (temp_flags & PSL_I) { 332 vm86->vm86_eflags |= PSL_VIF; 333 if (vm86->vm86_eflags & PSL_VIP) 334 break; 335 } else { 336 vm86->vm86_eflags &= ~PSL_VIF; 337 } 338 return (retcode); 339 } 340 return (SIGBUS); 341} 342 343#define PGTABLE_SIZE ((1024 + 64) * 1024 / PAGE_SIZE) 344#define INTMAP_SIZE 32 345#define IOMAP_SIZE ctob(IOPAGES) 346#define TSS_SIZE \ 347 (sizeof(struct pcb_ext) - sizeof(struct segment_descriptor) + \ 348 INTMAP_SIZE + IOMAP_SIZE + 1) 349 350struct vm86_layout { 351 pt_entry_t vml_pgtbl[PGTABLE_SIZE]; 352 struct pcb vml_pcb; 353 struct pcb_ext vml_ext; 354 char vml_intmap[INTMAP_SIZE]; 355 char vml_iomap[IOMAP_SIZE]; 356 char vml_iomap_trailer; 357}; 358 359void 360vm86_initialize(void) 361{ 362 int i; 363 u_int *addr; 364 struct vm86_layout *vml = (struct vm86_layout *)vm86paddr; 365 struct pcb *pcb; 366 struct pcb_ext *ext; 367 struct soft_segment_descriptor ssd = { 368 0, /* segment base address (overwritten) */ 369 0, /* length (overwritten) */ 370 SDT_SYS386TSS, /* segment type */ 371 0, /* priority level */ 372 1, /* descriptor present */ 373 0, 0, 374 0, /* default 16 size */ 375 0 /* granularity */ 376 }; 377 378 /* 379 * this should be a compile time error, but cpp doesn't grok sizeof(). 380 */ 381 if (sizeof(struct vm86_layout) > ctob(3)) 382 panic("struct vm86_layout exceeds space allocated in locore.s"); 383 384 /* 385 * Below is the memory layout that we use for the vm86 region. 386 * 387 * +--------+ 388 * | | 389 * | | 390 * | page 0 | 391 * | | +--------+ 392 * | | | stack | 393 * +--------+ +--------+ <--------- vm86paddr 394 * | | |Page Tbl| 1M + 64K = 272 entries = 1088 bytes 395 * | | +--------+ 396 * | | | PCB | size: ~240 bytes 397 * | page 1 | |PCB Ext | size: ~140 bytes (includes TSS) 398 * | | +--------+ 399 * | | |int map | 400 * | | +--------+ 401 * +--------+ | | 402 * | page 2 | | I/O | 403 * +--------+ | bitmap | 404 * | page 3 | | | 405 * | | +--------+ 406 * +--------+ 407 */ 408 409 /* 410 * A rudimentary PCB must be installed, in order to get to the 411 * PCB extension area. We use the PCB area as a scratchpad for 412 * data storage, the layout of which is shown below. 413 * 414 * pcb_esi = new PTD entry 0 415 * pcb_ebp = pointer to frame on vm86 stack 416 * pcb_esp = stack frame pointer at time of switch 417 * pcb_ebx = va of vm86 page table 418 * pcb_eip = argument pointer to initial call 419 * pcb_vm86[0] = saved TSS descriptor, word 0 420 * pcb_vm86[1] = saved TSS descriptor, word 1 421 */ 422#define new_ptd pcb_esi 423#define vm86_frame pcb_ebp 424#define pgtable_va pcb_ebx 425 426 pcb = &vml->vml_pcb; 427 ext = &vml->vml_ext; 428 429 mtx_init(&vm86_lock, "vm86 lock", NULL, MTX_DEF); 430 431 bzero(pcb, sizeof(struct pcb)); 432 pcb->new_ptd = vm86pa | PG_V | PG_RW | PG_U; 433 pcb->vm86_frame = vm86paddr - sizeof(struct vm86frame); 434 pcb->pgtable_va = vm86paddr; 435 pcb->pcb_flags = PCB_VM86CALL; 436 pcb->pcb_ext = ext; 437 438 bzero(ext, sizeof(struct pcb_ext)); 439 ext->ext_tss.tss_esp0 = vm86paddr; 440 ext->ext_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL); 441 ext->ext_tss.tss_ioopt = 442 ((u_int)vml->vml_iomap - (u_int)&ext->ext_tss) << 16; 443 ext->ext_iomap = vml->vml_iomap; 444 ext->ext_vm86.vm86_intmap = vml->vml_intmap; 445 446 if (cpu_feature & CPUID_VME) 447 ext->ext_vm86.vm86_has_vme = (rcr4() & CR4_VME ? 1 : 0); 448 449 addr = (u_int *)ext->ext_vm86.vm86_intmap; 450 for (i = 0; i < (INTMAP_SIZE + IOMAP_SIZE) / sizeof(u_int); i++) 451 *addr++ = 0; 452 vml->vml_iomap_trailer = 0xff; 453 454 ssd.ssd_base = (u_int)&ext->ext_tss; 455 ssd.ssd_limit = TSS_SIZE - 1; 456 ssdtosd(&ssd, &ext->ext_tssd); 457 458 vm86pcb = pcb; 459 460#if 0 461 /* 462 * use whatever is leftover of the vm86 page layout as a 463 * message buffer so we can capture early output. 464 */ 465 msgbufinit((vm_offset_t)vm86paddr + sizeof(struct vm86_layout), 466 ctob(3) - sizeof(struct vm86_layout)); 467#endif 468} 469 470vm_offset_t 471vm86_getpage(struct vm86context *vmc, int pagenum) 472{ 473 int i; 474 475 for (i = 0; i < vmc->npages; i++) 476 if (vmc->pmap[i].pte_num == pagenum) 477 return (vmc->pmap[i].kva); 478 return (0); 479} 480 481vm_offset_t 482vm86_addpage(struct vm86context *vmc, int pagenum, vm_offset_t kva) 483{ 484 int i, flags = 0; 485 486 for (i = 0; i < vmc->npages; i++) 487 if (vmc->pmap[i].pte_num == pagenum) 488 goto overlap; 489 490 if (vmc->npages == VM86_PMAPSIZE) 491 goto full; /* XXX grow map? */ 492 493 if (kva == 0) { 494 kva = (vm_offset_t)malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 495 flags = VMAP_MALLOC; 496 } 497 498 i = vmc->npages++; 499 vmc->pmap[i].flags = flags; 500 vmc->pmap[i].kva = kva; 501 vmc->pmap[i].pte_num = pagenum; 502 return (kva); 503overlap: 504 panic("vm86_addpage: overlap"); 505full: 506 panic("vm86_addpage: not enough room"); 507} 508 509/* 510 * called from vm86_bioscall, while in vm86 address space, to finalize setup. 511 */ 512void 513vm86_prepcall(struct vm86frame *vmf) 514{ 515 struct vm86_kernel *vm86; 516 uint32_t *stack; 517 uint8_t *code; 518 519 code = (void *)0xa00; 520 stack = (void *)(0x1000 - 2); /* keep aligned */ 521 if ((vmf->vmf_trapno & PAGE_MASK) <= 0xff) { 522 /* interrupt call requested */ 523 code[0] = INTn; 524 code[1] = vmf->vmf_trapno & 0xff; 525 code[2] = HLT; 526 vmf->vmf_ip = (uintptr_t)code; 527 vmf->vmf_cs = 0; 528 } else { 529 code[0] = HLT; 530 stack--; 531 stack[0] = MAKE_VEC(0, (uintptr_t)code); 532 } 533 vmf->vmf_sp = (uintptr_t)stack; 534 vmf->vmf_ss = 0; 535 vmf->kernel_fs = vmf->kernel_es = vmf->kernel_ds = 0; 536 vmf->vmf_eflags = PSL_VIF | PSL_VM | PSL_USER; 537 538 vm86 = &curpcb->pcb_ext->ext_vm86; 539 if (!vm86->vm86_has_vme) 540 vm86->vm86_eflags = vmf->vmf_eflags; /* save VIF, VIP */ 541} 542 543/* 544 * vm86 trap handler; determines whether routine succeeded or not. 545 * Called while in vm86 space, returns to calling process. 546 */ 547void 548vm86_trap(struct vm86frame *vmf) 549{ 550 caddr_t addr; 551 552 /* "should not happen" */ 553 if ((vmf->vmf_eflags & PSL_VM) == 0) 554 panic("vm86_trap called, but not in vm86 mode"); 555 556 addr = MAKE_ADDR(vmf->vmf_cs, vmf->vmf_ip); 557 if (*(u_char *)addr == HLT) 558 vmf->vmf_trapno = vmf->vmf_eflags & PSL_C; 559 else 560 vmf->vmf_trapno = vmf->vmf_trapno << 16; 561 562 vm86_biosret(vmf); 563} 564 565int 566vm86_intcall(int intnum, struct vm86frame *vmf) 567{ 568 int retval; 569 570 if (intnum < 0 || intnum > 0xff) 571 return (EINVAL); 572 573 vmf->vmf_trapno = intnum; 574 mtx_lock(&vm86_lock); 575 critical_enter(); 576 retval = vm86_bioscall(vmf); 577 critical_exit(); 578 mtx_unlock(&vm86_lock); 579 return (retval); 580} 581 582/* 583 * struct vm86context contains the page table to use when making 584 * vm86 calls. If intnum is a valid interrupt number (0-255), then 585 * the "interrupt trampoline" will be used, otherwise we use the 586 * caller's cs:ip routine. 587 */ 588int 589vm86_datacall(intnum, vmf, vmc) 590 int intnum; 591 struct vm86frame *vmf; 592 struct vm86context *vmc; 593{ 594 pt_entry_t *pte = (pt_entry_t *)vm86paddr; 595 vm_paddr_t page; 596 int i, entry, retval; 597 598 mtx_lock(&vm86_lock); 599 for (i = 0; i < vmc->npages; i++) { 600 page = vtophys(vmc->pmap[i].kva & PG_FRAME); 601 entry = vmc->pmap[i].pte_num; 602 vmc->pmap[i].old_pte = pte[entry]; 603 pte[entry] = page | PG_V | PG_RW | PG_U; 604 pmap_invalidate_page(kernel_pmap, vmc->pmap[i].kva); 605 } 606 607 vmf->vmf_trapno = intnum; 608 critical_enter(); 609 retval = vm86_bioscall(vmf); 610 critical_exit(); 611 612 for (i = 0; i < vmc->npages; i++) { 613 entry = vmc->pmap[i].pte_num; 614 pte[entry] = vmc->pmap[i].old_pte; 615 pmap_invalidate_page(kernel_pmap, vmc->pmap[i].kva); 616 } 617 mtx_unlock(&vm86_lock); 618 619 return (retval); 620} 621 622vm_offset_t 623vm86_getaddr(struct vm86context *vmc, u_short sel, u_short off) 624{ 625 int i, page; 626 vm_offset_t addr; 627 628 addr = (vm_offset_t)MAKE_ADDR(sel, off); 629 page = addr >> PAGE_SHIFT; 630 for (i = 0; i < vmc->npages; i++) 631 if (page == vmc->pmap[i].pte_num) 632 return (vmc->pmap[i].kva + (addr & PAGE_MASK)); 633 return (0); 634} 635 636int 637vm86_getptr(vmc, kva, sel, off) 638 struct vm86context *vmc; 639 vm_offset_t kva; 640 u_short *sel; 641 u_short *off; 642{ 643 int i; 644 645 for (i = 0; i < vmc->npages; i++) 646 if (kva >= vmc->pmap[i].kva && 647 kva < vmc->pmap[i].kva + PAGE_SIZE) { 648 *off = kva - vmc->pmap[i].kva; 649 *sel = vmc->pmap[i].pte_num << 8; 650 return (1); 651 } 652 return (0); 653} 654 655int 656vm86_sysarch(td, args) 657 struct thread *td; 658 char *args; 659{ 660 int error = 0; 661 struct i386_vm86_args ua; 662 struct vm86_kernel *vm86; 663 664 if ((error = copyin(args, &ua, sizeof(struct i386_vm86_args))) != 0) 665 return (error); 666 667 if (td->td_pcb->pcb_ext == 0) 668 if ((error = i386_extend_pcb(td)) != 0) 669 return (error); 670 vm86 = &td->td_pcb->pcb_ext->ext_vm86; 671 672 switch (ua.sub_op) { 673 case VM86_INIT: { 674 struct vm86_init_args sa; 675 676 if ((error = copyin(ua.sub_args, &sa, sizeof(sa))) != 0) 677 return (error); 678 if (cpu_feature & CPUID_VME) 679 vm86->vm86_has_vme = (rcr4() & CR4_VME ? 1 : 0); 680 else 681 vm86->vm86_has_vme = 0; 682 vm86->vm86_inited = 1; 683 vm86->vm86_debug = sa.debug; 684 bcopy(&sa.int_map, vm86->vm86_intmap, 32); 685 } 686 break; 687 688#if 0 689 case VM86_SET_VME: { 690 struct vm86_vme_args sa; 691 692 if ((cpu_feature & CPUID_VME) == 0) 693 return (ENODEV); 694 695 if (error = copyin(ua.sub_args, &sa, sizeof(sa))) 696 return (error); 697 if (sa.state) 698 load_cr4(rcr4() | CR4_VME); 699 else 700 load_cr4(rcr4() & ~CR4_VME); 701 } 702 break; 703#endif 704 705 case VM86_GET_VME: { 706 struct vm86_vme_args sa; 707 708 sa.state = (rcr4() & CR4_VME ? 1 : 0); 709 error = copyout(&sa, ua.sub_args, sizeof(sa)); 710 } 711 break; 712 713 case VM86_INTCALL: { 714 struct vm86_intcall_args sa; 715 716 if ((error = priv_check(td, PRIV_VM86_INTCALL))) 717 return (error); 718 if ((error = copyin(ua.sub_args, &sa, sizeof(sa)))) 719 return (error); 720 if ((error = vm86_intcall(sa.intnum, &sa.vmf))) 721 return (error); 722 error = copyout(&sa, ua.sub_args, sizeof(sa)); 723 } 724 break; 725 726 default: 727 error = EINVAL; 728 } 729 return (error); 730} 731