vm86.c revision 308418
12061Sjkh/*- 250479Speter * Copyright (c) 1997 Jonathan Lemon 32061Sjkh * All rights reserved. 438666Sjb * 532427Sjb * Redistribution and use in source and binary forms, with or without 6111131Sru * modification, are permitted provided that the following conditions 7111131Sru * are met: 838666Sjb * 1. Redistributions of source code must retain the above copyright 938666Sjb * notice, this list of conditions and the following disclaimer. 1038666Sjb * 2. Redistributions in binary form must reproduce the above copyright 1138666Sjb * notice, this list of conditions and the following disclaimer in the 1264049Salex * documentation and/or other materials provided with the distribution. 1364049Salex * 14116679Ssimokawa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1566071Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16116679Ssimokawa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1773504Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1838666Sjb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1932427Sjb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2038666Sjb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21108451Sschweikh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2238666Sjb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2338666Sjb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2438666Sjb * SUCH DAMAGE. 2538666Sjb */ 2617308Speter 2791606Skeramida#include <sys/cdefs.h> 2819175Sbde__FBSDID("$FreeBSD: stable/11/sys/i386/i386/vm86.c 308418 2016-11-07 12:10:17Z kib $"); 2996205Sjwd 3096205Sjwd#include <sys/param.h> 3138042Sbde#include <sys/systm.h> 3296205Sjwd#include <sys/priv.h> 3396205Sjwd#include <sys/proc.h> 3438042Sbde#include <sys/lock.h> 3596205Sjwd#include <sys/malloc.h> 3696205Sjwd#include <sys/mutex.h> 3717308Speter 3896205Sjwd#include <vm/vm.h> 3996205Sjwd#include <vm/pmap.h> 4017308Speter#include <vm/vm_map.h> 4196205Sjwd#include <vm/vm_page.h> 4296205Sjwd 4396205Sjwd#include <machine/md_var.h> 4496205Sjwd#include <machine/pcb.h> 4596205Sjwd#include <machine/pcb_ext.h> 4696205Sjwd#include <machine/psl.h> 4796205Sjwd#include <machine/specialreg.h> 4896205Sjwd#include <machine/sysarch.h> 4996205Sjwd 5096205Sjwdextern int vm86pa; 5196205Sjwdextern struct pcb *vm86pcb; 5296205Sjwd 5398775Sdillonstatic struct mtx vm86_lock; 5498723Sdillon 5598723Sdillonextern int vm86_bioscall(struct vm86frame *); 5698723Sdillonextern void vm86_biosret(struct vm86frame *); 5798723Sdillon 5838666Sjbvoid vm86_prepcall(struct vm86frame *); 5938666Sjb 6017308Speterstruct system_map { 61123311Speter int type; 62123311Speter vm_offset_t start; 63123311Speter vm_offset_t end; 64123311Speter}; 6595509Sru 6695793Sru#define HLT 0xf4 67116679Ssimokawa#define CLI 0xfa 68120760Sru#define STI 0xfb 69116679Ssimokawa#define PUSHF 0x9c 70123311Speter#define POPF 0x9d 71123311Speter#define INTn 0xcd 72123311Speter#define IRET 0xcf 732061Sjkh#define CALLm 0xff 7497769Sru#define OPERAND_SIZE_PREFIX 0x66 7597252Sru#define ADDRESS_SIZE_PREFIX 0x67 76119579Sru#define PUSH_MASK ~(PSL_VM | PSL_RF | PSL_I) 7797252Sru#define POP_MASK ~(PSL_VIP | PSL_VIF | PSL_VM | PSL_RF | PSL_IOPL) 7895730Sru 7995793Srustatic __inline caddr_t 80111617SruMAKE_ADDR(u_short sel, u_short off) 8195730Sru{ 82116679Ssimokawa return ((caddr_t)((sel << 4) + off)); 8395730Sru} 84116679Ssimokawa 8595730Srustatic __inline void 86110035SruGET_VEC(u_int vec, u_short *sel, u_short *off) 87107516Sru{ 88110035Sru *sel = vec >> 16; 89117234Sru *off = vec & 0xffff; 90110035Sru} 91117229Sru 92117234Srustatic __inline u_int 9354324SmarcelMAKE_VEC(u_short sel, u_short off) 9417308Speter{ 95119519Smarcel return ((sel << 16) | off); 96119519Smarcel} 97119519Smarcel 98119519Smarcelstatic __inline void 99119519SmarcelPUSH(u_short x, struct vm86frame *vmf) 100119519Smarcel{ 101119579Sru vmf->vmf_sp -= 2; 102119519Smarcel suword16(MAKE_ADDR(vmf->vmf_ss, vmf->vmf_sp), x); 103119519Smarcel} 104119519Smarcel 105119519Smarcelstatic __inline void 106119519SmarcelPUSHL(u_int x, struct vm86frame *vmf) 107126024Sgad{ 108126024Sgad vmf->vmf_sp -= 4; 109126024Sgad suword(MAKE_ADDR(vmf->vmf_ss, vmf->vmf_sp), x); 110126024Sgad} 111126024Sgad 112126024Sgadstatic __inline u_short 113126024SgadPOP(struct vm86frame *vmf) 114126024Sgad{ 115126024Sgad u_short x = fuword16(MAKE_ADDR(vmf->vmf_ss, vmf->vmf_sp)); 116126024Sgad 117126024Sgad vmf->vmf_sp += 2; 118126024Sgad return (x); 119126024Sgad} 120126024Sgad 121126024Sgadstatic __inline u_int 122126024SgadPOPL(struct vm86frame *vmf) 123126024Sgad{ 124126024Sgad u_int x = fuword(MAKE_ADDR(vmf->vmf_ss, vmf->vmf_sp)); 125126024Sgad 126126024Sgad vmf->vmf_sp += 4; 127126024Sgad return (x); 128126024Sgad} 129126024Sgad 130126024Sgadint 131126024Sgadvm86_emulate(vmf) 132126024Sgad struct vm86frame *vmf; 133126024Sgad{ 134126024Sgad struct vm86_kernel *vm86; 135125885Sgad caddr_t addr; 136125885Sgad u_char i_byte; 13738666Sjb u_int temp_flags; 13817308Speter int inc_ip = 1; 139119519Smarcel int retcode = 0; 140119579Sru 14138666Sjb /* 142110035Sru * pcb_ext contains the address of the extension area, or zero if 1432302Spaul * the extension is not present. (This check should not be needed, 14439206Sjkh * as we can't enter vm86 mode until we set up an extension area) 14539206Sjkh */ 14639206Sjkh if (curpcb->pcb_ext == 0) 14773349Sru return (SIGBUS); 14817308Speter vm86 = &curpcb->pcb_ext->ext_vm86; 14954324Smarcel 15054324Smarcel if (vmf->vmf_eflags & PSL_T) 15154324Smarcel retcode = SIGTRAP; 15254324Smarcel 15354324Smarcel addr = MAKE_ADDR(vmf->vmf_cs, vmf->vmf_ip); 15454324Smarcel i_byte = fubyte(addr); 15554324Smarcel if (i_byte == ADDRESS_SIZE_PREFIX) { 156118531Sru i_byte = fubyte(++addr); 15754324Smarcel inc_ip++; 15854324Smarcel } 15954324Smarcel 16054324Smarcel if (vm86->vm86_has_vme) { 16154324Smarcel switch (i_byte) { 16254324Smarcel case OPERAND_SIZE_PREFIX: 163110035Sru i_byte = fubyte(++addr); 16454324Smarcel inc_ip++; 165110035Sru switch (i_byte) { 166110035Sru case PUSHF: 16754324Smarcel if (vmf->vmf_eflags & PSL_VIF) 16854324Smarcel PUSHL((vmf->vmf_eflags & PUSH_MASK) 16954324Smarcel | PSL_IOPL | PSL_I, vmf); 17054324Smarcel else 17154324Smarcel PUSHL((vmf->vmf_eflags & PUSH_MASK) 172110035Sru | PSL_IOPL, vmf); 17354324Smarcel vmf->vmf_ip += inc_ip; 17454324Smarcel return (retcode); 17554324Smarcel 176118531Sru case POPF: 177118531Sru temp_flags = POPL(vmf) & POP_MASK; 17854324Smarcel vmf->vmf_eflags = (vmf->vmf_eflags & ~POP_MASK) 17954324Smarcel | temp_flags | PSL_VM | PSL_I; 18054324Smarcel vmf->vmf_ip += inc_ip; 18195730Sru if (temp_flags & PSL_I) { 18295730Sru vmf->vmf_eflags |= PSL_VIF; 18395730Sru if (vmf->vmf_eflags & PSL_VIP) 18495730Sru break; 18595730Sru } else { 18695730Sru vmf->vmf_eflags &= ~PSL_VIF; 18795730Sru } 18838666Sjb return (retcode); 189107374Sru } 19017308Speter break; 19155678Smarcel 192110035Sru /* VME faults here if VIP is set, but does not set VIF. */ 193117793Sru case STI: 194110035Sru vmf->vmf_eflags |= PSL_VIF; 195110035Sru vmf->vmf_ip += inc_ip; 196110035Sru if ((vmf->vmf_eflags & PSL_VIP) == 0) { 1972061Sjkh uprintf("fatal sti\n"); 19817308Speter return (SIGKILL); 199107516Sru } 200107374Sru break; 20155678Smarcel 202107516Sru /* VME if no redirection support */ 203107516Sru case INTn: 204107516Sru break; 205107516Sru 206107516Sru /* VME if trying to set PSL_T, or PSL_I when VIP is set */ 207107516Sru case POPF: 208107516Sru temp_flags = POP(vmf) & POP_MASK; 209107516Sru vmf->vmf_flags = (vmf->vmf_flags & ~POP_MASK) 210122204Skris | temp_flags | PSL_VM | PSL_I; 21155678Smarcel vmf->vmf_ip += inc_ip; 21255678Smarcel if (temp_flags & PSL_I) { 213116696Sru vmf->vmf_eflags |= PSL_VIF; 21455678Smarcel if (vmf->vmf_eflags & PSL_VIP) 21555678Smarcel break; 216107516Sru } else { 217107516Sru vmf->vmf_eflags &= ~PSL_VIF; 218107516Sru } 219107516Sru return (retcode); 22055678Smarcel 22155678Smarcel /* VME if trying to set PSL_T, or PSL_I when VIP is set */ 222111131Sru case IRET: 223111131Sru vmf->vmf_ip = POP(vmf); 224111131Sru vmf->vmf_cs = POP(vmf); 225111131Sru temp_flags = POP(vmf) & POP_MASK; 226111131Sru vmf->vmf_flags = (vmf->vmf_flags & ~POP_MASK) 227111131Sru | temp_flags | PSL_VM | PSL_I; 228111131Sru if (temp_flags & PSL_I) { 229103985Sphk vmf->vmf_eflags |= PSL_VIF; 230103985Sphk if (vmf->vmf_eflags & PSL_VIP) 231103985Sphk break; 232103985Sphk } else { 233111089Sphk vmf->vmf_eflags &= ~PSL_VIF; 234111131Sru } 235111131Sru return (retcode); 236111131Sru 237111131Sru } 238111131Sru return (SIGBUS); 239111131Sru } 240111131Sru 241111131Sru switch (i_byte) { 242111131Sru case OPERAND_SIZE_PREFIX: 243111133Sru i_byte = fubyte(++addr); 244103985Sphk inc_ip++; 245111131Sru switch (i_byte) { 246111131Sru case PUSHF: 247103985Sphk if (vm86->vm86_eflags & PSL_VIF) 248111131Sru PUSHL((vmf->vmf_flags & PUSH_MASK) 249103985Sphk | PSL_IOPL | PSL_I, vmf); 250118531Sru else 251118531Sru PUSHL((vmf->vmf_flags & PUSH_MASK) 252103985Sphk | PSL_IOPL, vmf); 253103985Sphk vmf->vmf_ip += inc_ip; 254111131Sru return (retcode); 255111131Sru 256103985Sphk case POPF: 257103985Sphk temp_flags = POPL(vmf) & POP_MASK; 258111131Sru vmf->vmf_eflags = (vmf->vmf_eflags & ~POP_MASK) 259111131Sru | temp_flags | PSL_VM | PSL_I; 260111131Sru vmf->vmf_ip += inc_ip; 261111131Sru if (temp_flags & PSL_I) { 262111131Sru vm86->vm86_eflags |= PSL_VIF; 263103985Sphk 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_spare[0] = saved TSS descriptor, word 0 420 * pcb_space[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