127998Sdyson/*- 227998Sdyson * Copyright (c) 1997 Jonathan Lemon 327998Sdyson * All rights reserved. 427998Sdyson * 527998Sdyson * Redistribution and use in source and binary forms, with or without 627998Sdyson * modification, are permitted provided that the following conditions 727998Sdyson * are met: 827998Sdyson * 1. Redistributions of source code must retain the above copyright 927998Sdyson * notice, this list of conditions and the following disclaimer. 1027998Sdyson * 2. Redistributions in binary form must reproduce the above copyright 1127998Sdyson * notice, this list of conditions and the following disclaimer in the 1227998Sdyson * documentation and/or other materials provided with the distribution. 1327998Sdyson * 1427998Sdyson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1527998Sdyson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1627998Sdyson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1727998Sdyson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1827998Sdyson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1927998Sdyson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2027998Sdyson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2127998Sdyson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2227998Sdyson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2327998Sdyson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2427998Sdyson * SUCH DAMAGE. 2527998Sdyson */ 2627998Sdyson 27115683Sobrien#include <sys/cdefs.h> 28115683Sobrien__FBSDID("$FreeBSD$"); 29115683Sobrien 3027998Sdyson#include <sys/param.h> 3127998Sdyson#include <sys/systm.h> 32164033Srwatson#include <sys/priv.h> 3327998Sdyson#include <sys/proc.h> 3427998Sdyson#include <sys/lock.h> 3539786Sache#include <sys/malloc.h> 3667355Sjhb#include <sys/mutex.h> 3727998Sdyson 3827998Sdyson#include <vm/vm.h> 3927998Sdyson#include <vm/pmap.h> 4027998Sdyson#include <vm/vm_map.h> 4127998Sdyson#include <vm/vm_page.h> 4227998Sdyson 4330275Speter#include <machine/md_var.h> 44138129Sdas#include <machine/pcb.h> 45138129Sdas#include <machine/pcb_ext.h> 4627998Sdyson#include <machine/psl.h> 4727998Sdyson#include <machine/specialreg.h> 4850816Sluoqi#include <machine/sysarch.h> 4927998Sdyson 5047678Sjlemonextern int vm86pa; 5134840Sjlemonextern struct pcb *vm86pcb; 5227998Sdyson 5379995Sjlemonstatic struct mtx vm86_lock; 5466691Sjhb 5534840Sjlemonextern int vm86_bioscall(struct vm86frame *); 5634840Sjlemonextern void vm86_biosret(struct vm86frame *); 5734840Sjlemon 58165302Skmacyvoid vm86_prepcall(struct vm86frame *); 5947678Sjlemon 6047678Sjlemonstruct system_map { 6147678Sjlemon int type; 6247678Sjlemon vm_offset_t start; 6347678Sjlemon vm_offset_t end; 6447678Sjlemon}; 6547678Sjlemon 6634840Sjlemon#define HLT 0xf4 6727998Sdyson#define CLI 0xfa 6827998Sdyson#define STI 0xfb 6927998Sdyson#define PUSHF 0x9c 7027998Sdyson#define POPF 0x9d 7127998Sdyson#define INTn 0xcd 7227998Sdyson#define IRET 0xcf 7334840Sjlemon#define CALLm 0xff 7427998Sdyson#define OPERAND_SIZE_PREFIX 0x66 7527998Sdyson#define ADDRESS_SIZE_PREFIX 0x67 7627998Sdyson#define PUSH_MASK ~(PSL_VM | PSL_RF | PSL_I) 7727998Sdyson#define POP_MASK ~(PSL_VIP | PSL_VIF | PSL_VM | PSL_RF | PSL_IOPL) 7827998Sdyson 7935210Sbdestatic __inline caddr_t 8027998SdysonMAKE_ADDR(u_short sel, u_short off) 8127998Sdyson{ 8227998Sdyson return ((caddr_t)((sel << 4) + off)); 8327998Sdyson} 8427998Sdyson 8535210Sbdestatic __inline void 8639755SbdeGET_VEC(u_int vec, u_short *sel, u_short *off) 8727998Sdyson{ 8827998Sdyson *sel = vec >> 16; 8927998Sdyson *off = vec & 0xffff; 9027998Sdyson} 9127998Sdyson 9239755Sbdestatic __inline u_int 9327998SdysonMAKE_VEC(u_short sel, u_short off) 9427998Sdyson{ 9527998Sdyson return ((sel << 16) | off); 9627998Sdyson} 9727998Sdyson 9835210Sbdestatic __inline void 9927998SdysonPUSH(u_short x, struct vm86frame *vmf) 10027998Sdyson{ 10127998Sdyson vmf->vmf_sp -= 2; 10298482Speter suword16(MAKE_ADDR(vmf->vmf_ss, vmf->vmf_sp), x); 10327998Sdyson} 10427998Sdyson 10535210Sbdestatic __inline void 10639755SbdePUSHL(u_int x, struct vm86frame *vmf) 10727998Sdyson{ 10827998Sdyson vmf->vmf_sp -= 4; 10927998Sdyson suword(MAKE_ADDR(vmf->vmf_ss, vmf->vmf_sp), x); 11027998Sdyson} 11127998Sdyson 11235210Sbdestatic __inline u_short 11327998SdysonPOP(struct vm86frame *vmf) 11427998Sdyson{ 11598482Speter u_short x = fuword16(MAKE_ADDR(vmf->vmf_ss, vmf->vmf_sp)); 11627998Sdyson 11727998Sdyson vmf->vmf_sp += 2; 11827998Sdyson return (x); 11927998Sdyson} 12027998Sdyson 12139755Sbdestatic __inline u_int 12227998SdysonPOPL(struct vm86frame *vmf) 12327998Sdyson{ 12439755Sbde u_int x = fuword(MAKE_ADDR(vmf->vmf_ss, vmf->vmf_sp)); 12527998Sdyson 12627998Sdyson vmf->vmf_sp += 4; 12727998Sdyson return (x); 12827998Sdyson} 12927998Sdyson 13027998Sdysonint 13128872Sjlemonvm86_emulate(vmf) 13227998Sdyson struct vm86frame *vmf; 13327998Sdyson{ 13427998Sdyson struct vm86_kernel *vm86; 13527998Sdyson caddr_t addr; 13627998Sdyson u_char i_byte; 13739755Sbde u_int temp_flags; 13827998Sdyson int inc_ip = 1; 13927998Sdyson int retcode = 0; 14027998Sdyson 14127998Sdyson /* 14227998Sdyson * pcb_ext contains the address of the extension area, or zero if 14327998Sdyson * the extension is not present. (This check should not be needed, 14427998Sdyson * as we can't enter vm86 mode until we set up an extension area) 14527998Sdyson */ 146238792Skib if (curpcb->pcb_ext == 0) 14727998Sdyson return (SIGBUS); 148238792Skib vm86 = &curpcb->pcb_ext->ext_vm86; 14927998Sdyson 15027998Sdyson if (vmf->vmf_eflags & PSL_T) 15127998Sdyson retcode = SIGTRAP; 15227998Sdyson 15327998Sdyson addr = MAKE_ADDR(vmf->vmf_cs, vmf->vmf_ip); 15427998Sdyson i_byte = fubyte(addr); 15527998Sdyson if (i_byte == ADDRESS_SIZE_PREFIX) { 15627998Sdyson i_byte = fubyte(++addr); 15727998Sdyson inc_ip++; 15827998Sdyson } 15927998Sdyson 16027998Sdyson if (vm86->vm86_has_vme) { 16127998Sdyson switch (i_byte) { 16227998Sdyson case OPERAND_SIZE_PREFIX: 16327998Sdyson i_byte = fubyte(++addr); 16427998Sdyson inc_ip++; 16527998Sdyson switch (i_byte) { 16627998Sdyson case PUSHF: 16727998Sdyson if (vmf->vmf_eflags & PSL_VIF) 16827998Sdyson PUSHL((vmf->vmf_eflags & PUSH_MASK) 16927998Sdyson | PSL_IOPL | PSL_I, vmf); 17027998Sdyson else 17127998Sdyson PUSHL((vmf->vmf_eflags & PUSH_MASK) 17227998Sdyson | PSL_IOPL, vmf); 17327998Sdyson vmf->vmf_ip += inc_ip; 17427998Sdyson return (0); 17527998Sdyson 17627998Sdyson case POPF: 17727998Sdyson temp_flags = POPL(vmf) & POP_MASK; 17827998Sdyson vmf->vmf_eflags = (vmf->vmf_eflags & ~POP_MASK) 17927998Sdyson | temp_flags | PSL_VM | PSL_I; 18027998Sdyson vmf->vmf_ip += inc_ip; 18127998Sdyson if (temp_flags & PSL_I) { 18227998Sdyson vmf->vmf_eflags |= PSL_VIF; 18327998Sdyson if (vmf->vmf_eflags & PSL_VIP) 18427998Sdyson break; 18527998Sdyson } else { 18627998Sdyson vmf->vmf_eflags &= ~PSL_VIF; 18727998Sdyson } 18827998Sdyson return (0); 18927998Sdyson } 19027998Sdyson break; 19127998Sdyson 19227998Sdyson /* VME faults here if VIP is set, but does not set VIF. */ 19327998Sdyson case STI: 19427998Sdyson vmf->vmf_eflags |= PSL_VIF; 19527998Sdyson vmf->vmf_ip += inc_ip; 19627998Sdyson if ((vmf->vmf_eflags & PSL_VIP) == 0) { 19727998Sdyson uprintf("fatal sti\n"); 19827998Sdyson return (SIGKILL); 19927998Sdyson } 20027998Sdyson break; 20127998Sdyson 20227998Sdyson /* VME if no redirection support */ 20327998Sdyson case INTn: 20427998Sdyson break; 20527998Sdyson 20627998Sdyson /* VME if trying to set PSL_TF, or PSL_I when VIP is set */ 20727998Sdyson case POPF: 20827998Sdyson temp_flags = POP(vmf) & POP_MASK; 20927998Sdyson vmf->vmf_flags = (vmf->vmf_flags & ~POP_MASK) 21027998Sdyson | temp_flags | PSL_VM | PSL_I; 21127998Sdyson vmf->vmf_ip += inc_ip; 21227998Sdyson if (temp_flags & PSL_I) { 21327998Sdyson vmf->vmf_eflags |= PSL_VIF; 21427998Sdyson if (vmf->vmf_eflags & PSL_VIP) 21527998Sdyson break; 21627998Sdyson } else { 21727998Sdyson vmf->vmf_eflags &= ~PSL_VIF; 21827998Sdyson } 21927998Sdyson return (retcode); 22027998Sdyson 22127998Sdyson /* VME if trying to set PSL_TF, or PSL_I when VIP is set */ 22227998Sdyson case IRET: 22327998Sdyson vmf->vmf_ip = POP(vmf); 22427998Sdyson vmf->vmf_cs = POP(vmf); 22527998Sdyson temp_flags = POP(vmf) & POP_MASK; 22627998Sdyson vmf->vmf_flags = (vmf->vmf_flags & ~POP_MASK) 22727998Sdyson | temp_flags | PSL_VM | PSL_I; 22827998Sdyson if (temp_flags & PSL_I) { 22927998Sdyson vmf->vmf_eflags |= PSL_VIF; 23027998Sdyson if (vmf->vmf_eflags & PSL_VIP) 23127998Sdyson break; 23227998Sdyson } else { 23327998Sdyson vmf->vmf_eflags &= ~PSL_VIF; 23427998Sdyson } 23527998Sdyson return (retcode); 23627998Sdyson 23727998Sdyson } 23827998Sdyson return (SIGBUS); 23927998Sdyson } 24027998Sdyson 24127998Sdyson switch (i_byte) { 24227998Sdyson case OPERAND_SIZE_PREFIX: 24327998Sdyson i_byte = fubyte(++addr); 24427998Sdyson inc_ip++; 24527998Sdyson switch (i_byte) { 24627998Sdyson case PUSHF: 24727998Sdyson if (vm86->vm86_eflags & PSL_VIF) 24827998Sdyson PUSHL((vmf->vmf_flags & PUSH_MASK) 24927998Sdyson | PSL_IOPL | PSL_I, vmf); 25027998Sdyson else 25127998Sdyson PUSHL((vmf->vmf_flags & PUSH_MASK) 25227998Sdyson | PSL_IOPL, vmf); 25327998Sdyson vmf->vmf_ip += inc_ip; 25427998Sdyson return (retcode); 25527998Sdyson 25627998Sdyson case POPF: 25727998Sdyson temp_flags = POPL(vmf) & POP_MASK; 25827998Sdyson vmf->vmf_eflags = (vmf->vmf_eflags & ~POP_MASK) 25927998Sdyson | temp_flags | PSL_VM | PSL_I; 26027998Sdyson vmf->vmf_ip += inc_ip; 26127998Sdyson if (temp_flags & PSL_I) { 26227998Sdyson vm86->vm86_eflags |= PSL_VIF; 26327998Sdyson if (vm86->vm86_eflags & PSL_VIP) 26427998Sdyson break; 26527998Sdyson } else { 26627998Sdyson vm86->vm86_eflags &= ~PSL_VIF; 26727998Sdyson } 26827998Sdyson return (retcode); 26927998Sdyson } 27027998Sdyson return (SIGBUS); 27127998Sdyson 27227998Sdyson case CLI: 27327998Sdyson vm86->vm86_eflags &= ~PSL_VIF; 27427998Sdyson vmf->vmf_ip += inc_ip; 27527998Sdyson return (retcode); 27627998Sdyson 27727998Sdyson case STI: 27827998Sdyson /* if there is a pending interrupt, go to the emulator */ 27927998Sdyson vm86->vm86_eflags |= PSL_VIF; 28027998Sdyson vmf->vmf_ip += inc_ip; 28127998Sdyson if (vm86->vm86_eflags & PSL_VIP) 28227998Sdyson break; 28327998Sdyson return (retcode); 28427998Sdyson 28527998Sdyson case PUSHF: 28627998Sdyson if (vm86->vm86_eflags & PSL_VIF) 28727998Sdyson PUSH((vmf->vmf_flags & PUSH_MASK) 28827998Sdyson | PSL_IOPL | PSL_I, vmf); 28927998Sdyson else 29027998Sdyson PUSH((vmf->vmf_flags & PUSH_MASK) | PSL_IOPL, vmf); 29127998Sdyson vmf->vmf_ip += inc_ip; 29227998Sdyson return (retcode); 29327998Sdyson 29427998Sdyson case INTn: 29527998Sdyson i_byte = fubyte(addr + 1); 29627998Sdyson if ((vm86->vm86_intmap[i_byte >> 3] & (1 << (i_byte & 7))) != 0) 29727998Sdyson break; 29827998Sdyson if (vm86->vm86_eflags & PSL_VIF) 29927998Sdyson PUSH((vmf->vmf_flags & PUSH_MASK) 30027998Sdyson | PSL_IOPL | PSL_I, vmf); 30127998Sdyson else 30227998Sdyson PUSH((vmf->vmf_flags & PUSH_MASK) | PSL_IOPL, vmf); 30327998Sdyson PUSH(vmf->vmf_cs, vmf); 30427998Sdyson PUSH(vmf->vmf_ip + inc_ip + 1, vmf); /* increment IP */ 30527998Sdyson GET_VEC(fuword((caddr_t)(i_byte * 4)), 30627998Sdyson &vmf->vmf_cs, &vmf->vmf_ip); 30727998Sdyson vmf->vmf_flags &= ~PSL_T; 30827998Sdyson vm86->vm86_eflags &= ~PSL_VIF; 30927998Sdyson return (retcode); 31027998Sdyson 31127998Sdyson case IRET: 31227998Sdyson vmf->vmf_ip = POP(vmf); 31327998Sdyson vmf->vmf_cs = POP(vmf); 31427998Sdyson temp_flags = POP(vmf) & POP_MASK; 31527998Sdyson vmf->vmf_flags = (vmf->vmf_flags & ~POP_MASK) 31627998Sdyson | temp_flags | PSL_VM | PSL_I; 31727998Sdyson if (temp_flags & PSL_I) { 31827998Sdyson vm86->vm86_eflags |= PSL_VIF; 31927998Sdyson if (vm86->vm86_eflags & PSL_VIP) 32027998Sdyson break; 32127998Sdyson } else { 32227998Sdyson vm86->vm86_eflags &= ~PSL_VIF; 32327998Sdyson } 32427998Sdyson return (retcode); 32527998Sdyson 32627998Sdyson case POPF: 32727998Sdyson temp_flags = POP(vmf) & POP_MASK; 32827998Sdyson vmf->vmf_flags = (vmf->vmf_flags & ~POP_MASK) 32927998Sdyson | temp_flags | PSL_VM | PSL_I; 33027998Sdyson vmf->vmf_ip += inc_ip; 33127998Sdyson if (temp_flags & PSL_I) { 33227998Sdyson vm86->vm86_eflags |= PSL_VIF; 33327998Sdyson if (vm86->vm86_eflags & PSL_VIP) 33427998Sdyson break; 33527998Sdyson } else { 33627998Sdyson vm86->vm86_eflags &= ~PSL_VIF; 33727998Sdyson } 33827998Sdyson return (retcode); 33927998Sdyson } 34027998Sdyson return (SIGBUS); 34127998Sdyson} 34227998Sdyson 34337889Sjlemon#define PGTABLE_SIZE ((1024 + 64) * 1024 / PAGE_SIZE) 34437889Sjlemon#define INTMAP_SIZE 32 34537889Sjlemon#define IOMAP_SIZE ctob(IOPAGES) 34637889Sjlemon#define TSS_SIZE \ 34737889Sjlemon (sizeof(struct pcb_ext) - sizeof(struct segment_descriptor) + \ 34837889Sjlemon INTMAP_SIZE + IOMAP_SIZE + 1) 34937889Sjlemon 35037889Sjlemonstruct vm86_layout { 35137889Sjlemon pt_entry_t vml_pgtbl[PGTABLE_SIZE]; 35237889Sjlemon struct pcb vml_pcb; 35337889Sjlemon struct pcb_ext vml_ext; 35437889Sjlemon char vml_intmap[INTMAP_SIZE]; 35537889Sjlemon char vml_iomap[IOMAP_SIZE]; 35637889Sjlemon char vml_iomap_trailer; 35737889Sjlemon}; 35837889Sjlemon 35947678Sjlemonvoid 36034840Sjlemonvm86_initialize(void) 36134840Sjlemon{ 36237889Sjlemon int i; 36339755Sbde u_int *addr; 36437889Sjlemon struct vm86_layout *vml = (struct vm86_layout *)vm86paddr; 36534840Sjlemon struct pcb *pcb; 36634840Sjlemon struct pcb_ext *ext; 36734840Sjlemon struct soft_segment_descriptor ssd = { 36834840Sjlemon 0, /* segment base address (overwritten) */ 36937889Sjlemon 0, /* length (overwritten) */ 37034840Sjlemon SDT_SYS386TSS, /* segment type */ 37134840Sjlemon 0, /* priority level */ 37234840Sjlemon 1, /* descriptor present */ 37334840Sjlemon 0, 0, 37437889Sjlemon 0, /* default 16 size */ 37534840Sjlemon 0 /* granularity */ 37634840Sjlemon }; 37734840Sjlemon 37834840Sjlemon /* 37937889Sjlemon * this should be a compile time error, but cpp doesn't grok sizeof(). 38037889Sjlemon */ 38137889Sjlemon if (sizeof(struct vm86_layout) > ctob(3)) 38237889Sjlemon panic("struct vm86_layout exceeds space allocated in locore.s"); 38337889Sjlemon 38437889Sjlemon /* 38534840Sjlemon * Below is the memory layout that we use for the vm86 region. 38634840Sjlemon * 38737889Sjlemon * +--------+ 38837889Sjlemon * | | 38937889Sjlemon * | | 39037889Sjlemon * | page 0 | 39137889Sjlemon * | | +--------+ 39237889Sjlemon * | | | stack | 39337889Sjlemon * +--------+ +--------+ <--------- vm86paddr 39434840Sjlemon * | | |Page Tbl| 1M + 64K = 272 entries = 1088 bytes 39534840Sjlemon * | | +--------+ 39634840Sjlemon * | | | PCB | size: ~240 bytes 39737889Sjlemon * | page 1 | |PCB Ext | size: ~140 bytes (includes TSS) 39834840Sjlemon * | | +--------+ 39937889Sjlemon * | | |int map | 40034840Sjlemon * | | +--------+ 40134840Sjlemon * +--------+ | | 40234840Sjlemon * | page 2 | | I/O | 40334840Sjlemon * +--------+ | bitmap | 40434840Sjlemon * | page 3 | | | 40537889Sjlemon * | | +--------+ 40637889Sjlemon * +--------+ 40734840Sjlemon */ 40834840Sjlemon 40934840Sjlemon /* 41034840Sjlemon * A rudimentary PCB must be installed, in order to get to the 41134840Sjlemon * PCB extension area. We use the PCB area as a scratchpad for 41234840Sjlemon * data storage, the layout of which is shown below. 41334840Sjlemon * 41434840Sjlemon * pcb_esi = new PTD entry 0 41534840Sjlemon * pcb_ebp = pointer to frame on vm86 stack 41634840Sjlemon * pcb_esp = stack frame pointer at time of switch 41734840Sjlemon * pcb_ebx = va of vm86 page table 41834840Sjlemon * pcb_eip = argument pointer to initial call 41946129Sluoqi * pcb_spare[0] = saved TSS descriptor, word 0 42046129Sluoqi * pcb_space[1] = saved TSS descriptor, word 1 42134840Sjlemon */ 42237889Sjlemon#define new_ptd pcb_esi 42337889Sjlemon#define vm86_frame pcb_ebp 42437889Sjlemon#define pgtable_va pcb_ebx 42534840Sjlemon 42637889Sjlemon pcb = &vml->vml_pcb; 42737889Sjlemon ext = &vml->vml_ext; 42834840Sjlemon 429106607Sdavidxu mtx_init(&vm86_lock, "vm86 lock", NULL, MTX_DEF); 43066691Sjhb 43137889Sjlemon bzero(pcb, sizeof(struct pcb)); 43237889Sjlemon pcb->new_ptd = vm86pa | PG_V | PG_RW | PG_U; 43337889Sjlemon pcb->vm86_frame = vm86paddr - sizeof(struct vm86frame); 43437889Sjlemon pcb->pgtable_va = vm86paddr; 435106542Sdavidxu pcb->pcb_flags = PCB_VM86CALL; 43634840Sjlemon pcb->pcb_ext = ext; 43734840Sjlemon 43834840Sjlemon bzero(ext, sizeof(struct pcb_ext)); 43937889Sjlemon ext->ext_tss.tss_esp0 = vm86paddr; 44034840Sjlemon ext->ext_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL); 44134840Sjlemon ext->ext_tss.tss_ioopt = 44237889Sjlemon ((u_int)vml->vml_iomap - (u_int)&ext->ext_tss) << 16; 44337889Sjlemon ext->ext_iomap = vml->vml_iomap; 44437889Sjlemon ext->ext_vm86.vm86_intmap = vml->vml_intmap; 44534840Sjlemon 44634879Sjlemon if (cpu_feature & CPUID_VME) 44734879Sjlemon ext->ext_vm86.vm86_has_vme = (rcr4() & CR4_VME ? 1 : 0); 44834840Sjlemon 44939755Sbde addr = (u_int *)ext->ext_vm86.vm86_intmap; 45039755Sbde for (i = 0; i < (INTMAP_SIZE + IOMAP_SIZE) / sizeof(u_int); i++) 45134840Sjlemon *addr++ = 0; 45237889Sjlemon vml->vml_iomap_trailer = 0xff; 45334840Sjlemon 45434840Sjlemon ssd.ssd_base = (u_int)&ext->ext_tss; 45537889Sjlemon ssd.ssd_limit = TSS_SIZE - 1; 45634840Sjlemon ssdtosd(&ssd, &ext->ext_tssd); 45734840Sjlemon 45834840Sjlemon vm86pcb = pcb; 45947678Sjlemon 46047688Sjlemon#if 0 46147678Sjlemon /* 46247678Sjlemon * use whatever is leftover of the vm86 page layout as a 46347678Sjlemon * message buffer so we can capture early output. 46447678Sjlemon */ 46547678Sjlemon msgbufinit((vm_offset_t)vm86paddr + sizeof(struct vm86_layout), 46647678Sjlemon ctob(3) - sizeof(struct vm86_layout)); 46747688Sjlemon#endif 46834840Sjlemon} 46934840Sjlemon 47044845Sjlemonvm_offset_t 47144845Sjlemonvm86_getpage(struct vm86context *vmc, int pagenum) 47244845Sjlemon{ 47344845Sjlemon int i; 47444845Sjlemon 47544845Sjlemon for (i = 0; i < vmc->npages; i++) 47644845Sjlemon if (vmc->pmap[i].pte_num == pagenum) 47744845Sjlemon return (vmc->pmap[i].kva); 47844845Sjlemon return (0); 47944845Sjlemon} 48044845Sjlemon 48144845Sjlemonvm_offset_t 48244845Sjlemonvm86_addpage(struct vm86context *vmc, int pagenum, vm_offset_t kva) 48344845Sjlemon{ 48444845Sjlemon int i, flags = 0; 48544845Sjlemon 48644845Sjlemon for (i = 0; i < vmc->npages; i++) 48744845Sjlemon if (vmc->pmap[i].pte_num == pagenum) 48899864Speter goto overlap; 48944845Sjlemon 49044845Sjlemon if (vmc->npages == VM86_PMAPSIZE) 49199864Speter goto full; /* XXX grow map? */ 49244845Sjlemon 49344845Sjlemon if (kva == 0) { 494111119Simp kva = (vm_offset_t)malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 49544845Sjlemon flags = VMAP_MALLOC; 49644845Sjlemon } 49744845Sjlemon 49844845Sjlemon i = vmc->npages++; 49944845Sjlemon vmc->pmap[i].flags = flags; 50044845Sjlemon vmc->pmap[i].kva = kva; 50144845Sjlemon vmc->pmap[i].pte_num = pagenum; 50244845Sjlemon return (kva); 50399864Speteroverlap: 50499864Speter panic("vm86_addpage: overlap"); 50599864Speterfull: 50699864Speter panic("vm86_addpage: not enough room"); 50744845Sjlemon} 50844845Sjlemon 50934840Sjlemon/* 51034840Sjlemon * called from vm86_bioscall, while in vm86 address space, to finalize setup. 51134840Sjlemon */ 51234840Sjlemonvoid 513165302Skmacyvm86_prepcall(struct vm86frame *vmf) 51434840Sjlemon{ 515165302Skmacy struct vm86_kernel *vm86; 516234350Sjkim uint32_t *stack; 517234350Sjkim uint8_t *code; 51834840Sjlemon 519234350Sjkim code = (void *)0xa00; 520234350Sjkim stack = (void *)(0x1000 - 2); /* keep aligned */ 521165302Skmacy if ((vmf->vmf_trapno & PAGE_MASK) <= 0xff) { 52234840Sjlemon /* interrupt call requested */ 523234350Sjkim code[0] = INTn; 524234350Sjkim code[1] = vmf->vmf_trapno & 0xff; 525234350Sjkim code[2] = HLT; 526234350Sjkim vmf->vmf_ip = (uintptr_t)code; 527165302Skmacy vmf->vmf_cs = 0; 528234350Sjkim } else { 529234350Sjkim code[0] = HLT; 530234350Sjkim stack--; 531234350Sjkim stack[0] = MAKE_VEC(0, (uintptr_t)code); 53234840Sjlemon } 533234350Sjkim vmf->vmf_sp = (uintptr_t)stack; 534234350Sjkim vmf->vmf_ss = 0; 535165302Skmacy vmf->kernel_fs = vmf->kernel_es = vmf->kernel_ds = 0; 536165302Skmacy vmf->vmf_eflags = PSL_VIF | PSL_VM | PSL_USER; 537165302Skmacy 538238792Skib vm86 = &curpcb->pcb_ext->ext_vm86; 539165302Skmacy if (!vm86->vm86_has_vme) 540165302Skmacy vm86->vm86_eflags = vmf->vmf_eflags; /* save VIF, VIP */ 54134840Sjlemon} 54234840Sjlemon 54334840Sjlemon/* 54434840Sjlemon * vm86 trap handler; determines whether routine succeeded or not. 54534840Sjlemon * Called while in vm86 space, returns to calling process. 54634840Sjlemon */ 54734840Sjlemonvoid 54834840Sjlemonvm86_trap(struct vm86frame *vmf) 54934840Sjlemon{ 55034840Sjlemon caddr_t addr; 55134840Sjlemon 55234840Sjlemon /* "should not happen" */ 55334840Sjlemon if ((vmf->vmf_eflags & PSL_VM) == 0) 55434840Sjlemon panic("vm86_trap called, but not in vm86 mode"); 55534840Sjlemon 55634840Sjlemon addr = MAKE_ADDR(vmf->vmf_cs, vmf->vmf_ip); 55734840Sjlemon if (*(u_char *)addr == HLT) 55834840Sjlemon vmf->vmf_trapno = vmf->vmf_eflags & PSL_C; 55934840Sjlemon else 56034840Sjlemon vmf->vmf_trapno = vmf->vmf_trapno << 16; 56134840Sjlemon 56234840Sjlemon vm86_biosret(vmf); 56334840Sjlemon} 56434840Sjlemon 56527998Sdysonint 56634840Sjlemonvm86_intcall(int intnum, struct vm86frame *vmf) 56734840Sjlemon{ 56866691Sjhb int retval; 56966691Sjhb 57034840Sjlemon if (intnum < 0 || intnum > 0xff) 57134840Sjlemon return (EINVAL); 57234840Sjlemon 57334840Sjlemon vmf->vmf_trapno = intnum; 574106607Sdavidxu mtx_lock(&vm86_lock); 575106607Sdavidxu critical_enter(); 57666691Sjhb retval = vm86_bioscall(vmf); 577106607Sdavidxu critical_exit(); 578106607Sdavidxu mtx_unlock(&vm86_lock); 57966691Sjhb return (retval); 58034840Sjlemon} 58134840Sjlemon 58234840Sjlemon/* 58344845Sjlemon * struct vm86context contains the page table to use when making 58444845Sjlemon * vm86 calls. If intnum is a valid interrupt number (0-255), then 58544845Sjlemon * the "interrupt trampoline" will be used, otherwise we use the 58644845Sjlemon * caller's cs:ip routine. 58734840Sjlemon */ 58834840Sjlemonint 58944845Sjlemonvm86_datacall(intnum, vmf, vmc) 59034840Sjlemon int intnum; 59134840Sjlemon struct vm86frame *vmf; 59244845Sjlemon struct vm86context *vmc; 59334840Sjlemon{ 59486485Speter pt_entry_t *pte = (pt_entry_t *)vm86paddr; 595112569Sjake vm_paddr_t page; 59644845Sjlemon int i, entry, retval; 59734840Sjlemon 598106607Sdavidxu mtx_lock(&vm86_lock); 59944845Sjlemon for (i = 0; i < vmc->npages; i++) { 60044845Sjlemon page = vtophys(vmc->pmap[i].kva & PG_FRAME); 60144845Sjlemon entry = vmc->pmap[i].pte_num; 60244845Sjlemon vmc->pmap[i].old_pte = pte[entry]; 60344845Sjlemon pte[entry] = page | PG_V | PG_RW | PG_U; 60499862Speter pmap_invalidate_page(kernel_pmap, vmc->pmap[i].kva); 60544845Sjlemon } 60639786Sache 60744845Sjlemon vmf->vmf_trapno = intnum; 608106609Sdavidxu critical_enter(); 60944845Sjlemon retval = vm86_bioscall(vmf); 610106609Sdavidxu critical_exit(); 61144845Sjlemon 61244845Sjlemon for (i = 0; i < vmc->npages; i++) { 61344845Sjlemon entry = vmc->pmap[i].pte_num; 61444845Sjlemon pte[entry] = vmc->pmap[i].old_pte; 61599862Speter pmap_invalidate_page(kernel_pmap, vmc->pmap[i].kva); 61639786Sache } 617106607Sdavidxu mtx_unlock(&vm86_lock); 61839786Sache 61944845Sjlemon return (retval); 62044845Sjlemon} 62139786Sache 62244845Sjlemonvm_offset_t 623189004Srdivackyvm86_getaddr(struct vm86context *vmc, u_short sel, u_short off) 62444845Sjlemon{ 62544845Sjlemon int i, page; 62644845Sjlemon vm_offset_t addr; 62739786Sache 62844845Sjlemon addr = (vm_offset_t)MAKE_ADDR(sel, off); 62944845Sjlemon page = addr >> PAGE_SHIFT; 63044845Sjlemon for (i = 0; i < vmc->npages; i++) 63144845Sjlemon if (page == vmc->pmap[i].pte_num) 63244845Sjlemon return (vmc->pmap[i].kva + (addr & PAGE_MASK)); 63344845Sjlemon return (0); 63434840Sjlemon} 63534840Sjlemon 63634840Sjlemonint 63744845Sjlemonvm86_getptr(vmc, kva, sel, off) 63844845Sjlemon struct vm86context *vmc; 63944845Sjlemon vm_offset_t kva; 64044845Sjlemon u_short *sel; 64144845Sjlemon u_short *off; 64234840Sjlemon{ 64344845Sjlemon int i; 64434840Sjlemon 64544845Sjlemon for (i = 0; i < vmc->npages; i++) 64644845Sjlemon if (kva >= vmc->pmap[i].kva && 64744845Sjlemon kva < vmc->pmap[i].kva + PAGE_SIZE) { 64844845Sjlemon *off = kva - vmc->pmap[i].kva; 64944845Sjlemon *sel = vmc->pmap[i].pte_num << 8; 65044845Sjlemon return (1); 65144845Sjlemon } 65244845Sjlemon return (0); 65334840Sjlemon} 65444845Sjlemon 65534840Sjlemonint 65683366Sjulianvm86_sysarch(td, args) 65783366Sjulian struct thread *td; 65827998Sdyson char *args; 65927998Sdyson{ 66027998Sdyson int error = 0; 66127998Sdyson struct i386_vm86_args ua; 66227998Sdyson struct vm86_kernel *vm86; 66327998Sdyson 66443314Sdillon if ((error = copyin(args, &ua, sizeof(struct i386_vm86_args))) != 0) 66527998Sdyson return (error); 66627998Sdyson 66783366Sjulian if (td->td_pcb->pcb_ext == 0) 66883366Sjulian if ((error = i386_extend_pcb(td)) != 0) 66927998Sdyson return (error); 67083366Sjulian vm86 = &td->td_pcb->pcb_ext->ext_vm86; 67127998Sdyson 67227998Sdyson switch (ua.sub_op) { 67327998Sdyson case VM86_INIT: { 67427998Sdyson struct vm86_init_args sa; 67527998Sdyson 67643314Sdillon if ((error = copyin(ua.sub_args, &sa, sizeof(sa))) != 0) 67727998Sdyson return (error); 67827998Sdyson if (cpu_feature & CPUID_VME) 67927998Sdyson vm86->vm86_has_vme = (rcr4() & CR4_VME ? 1 : 0); 68027998Sdyson else 68127998Sdyson vm86->vm86_has_vme = 0; 68227998Sdyson vm86->vm86_inited = 1; 68327998Sdyson vm86->vm86_debug = sa.debug; 68427998Sdyson bcopy(&sa.int_map, vm86->vm86_intmap, 32); 68527998Sdyson } 68627998Sdyson break; 68727998Sdyson 68827998Sdyson#if 0 68927998Sdyson case VM86_SET_VME: { 69027998Sdyson struct vm86_vme_args sa; 69127998Sdyson 69227998Sdyson if ((cpu_feature & CPUID_VME) == 0) 69327998Sdyson return (ENODEV); 69427998Sdyson 69527998Sdyson if (error = copyin(ua.sub_args, &sa, sizeof(sa))) 69627998Sdyson return (error); 69727998Sdyson if (sa.state) 69827998Sdyson load_cr4(rcr4() | CR4_VME); 69927998Sdyson else 70027998Sdyson load_cr4(rcr4() & ~CR4_VME); 70127998Sdyson } 70227998Sdyson break; 70327998Sdyson#endif 70427998Sdyson 70527998Sdyson case VM86_GET_VME: { 70627998Sdyson struct vm86_vme_args sa; 70727998Sdyson 70827998Sdyson sa.state = (rcr4() & CR4_VME ? 1 : 0); 70927998Sdyson error = copyout(&sa, ua.sub_args, sizeof(sa)); 71027998Sdyson } 71127998Sdyson break; 71227998Sdyson 71334840Sjlemon case VM86_INTCALL: { 71434840Sjlemon struct vm86_intcall_args sa; 71534840Sjlemon 716164033Srwatson if ((error = priv_check(td, PRIV_VM86_INTCALL))) 71766053Sjlemon return (error); 71868404Smsmith if ((error = copyin(ua.sub_args, &sa, sizeof(sa)))) 71934840Sjlemon return (error); 72068404Smsmith if ((error = vm86_intcall(sa.intnum, &sa.vmf))) 72134840Sjlemon return (error); 72234840Sjlemon error = copyout(&sa, ua.sub_args, sizeof(sa)); 72334840Sjlemon } 72434840Sjlemon break; 72534840Sjlemon 72627998Sdyson default: 72727998Sdyson error = EINVAL; 72827998Sdyson } 72927998Sdyson return (error); 73027998Sdyson} 731