Changeset View
Changeset View
Standalone View
Standalone View
sys/i386/i386/vm86.c
Show First 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | |||||
#define INTn 0xcd | #define INTn 0xcd | ||||
#define IRET 0xcf | #define IRET 0xcf | ||||
#define CALLm 0xff | #define CALLm 0xff | ||||
#define OPERAND_SIZE_PREFIX 0x66 | #define OPERAND_SIZE_PREFIX 0x66 | ||||
#define ADDRESS_SIZE_PREFIX 0x67 | #define ADDRESS_SIZE_PREFIX 0x67 | ||||
#define PUSH_MASK ~(PSL_VM | PSL_RF | PSL_I) | #define PUSH_MASK ~(PSL_VM | PSL_RF | PSL_I) | ||||
#define POP_MASK ~(PSL_VIP | PSL_VIF | PSL_VM | PSL_RF | PSL_IOPL) | #define POP_MASK ~(PSL_VIP | PSL_VIF | PSL_VM | PSL_RF | PSL_IOPL) | ||||
static int | |||||
vm86_suword16(volatile void *base, int word) | |||||
{ | |||||
if (curthread->td_critnest != 0) { | |||||
*(volatile uint16_t *)base = word; | |||||
return (0); | |||||
} | |||||
return (suword16(base, word)); | |||||
} | |||||
static int | |||||
vm86_suword(volatile void *base, long word) | |||||
{ | |||||
if (curthread->td_critnest != 0) { | |||||
*(volatile long *)base = word; | |||||
return (0); | |||||
} | |||||
return (suword(base, word)); | |||||
} | |||||
static int | |||||
vm86_fubyte(volatile const void *base) | |||||
{ | |||||
if (curthread->td_critnest != 0) | |||||
return (*(volatile const u_char *)base); | |||||
return (fubyte(base)); | |||||
} | |||||
static int | |||||
vm86_fuword16(volatile const void *base) | |||||
{ | |||||
if (curthread->td_critnest != 0) | |||||
return (*(volatile const uint16_t *)base); | |||||
return (fuword16(base)); | |||||
} | |||||
static long | |||||
vm86_fuword(volatile const void *base) | |||||
{ | |||||
if (curthread->td_critnest != 0) | |||||
return (*(volatile const long *)base); | |||||
return (fuword(base)); | |||||
} | |||||
static __inline caddr_t | static __inline caddr_t | ||||
MAKE_ADDR(u_short sel, u_short off) | MAKE_ADDR(u_short sel, u_short off) | ||||
{ | { | ||||
return ((caddr_t)((sel << 4) + off)); | return ((caddr_t)((sel << 4) + off)); | ||||
} | } | ||||
static __inline void | static __inline void | ||||
GET_VEC(u_int vec, u_short *sel, u_short *off) | GET_VEC(u_int vec, u_short *sel, u_short *off) | ||||
{ | { | ||||
*sel = vec >> 16; | *sel = vec >> 16; | ||||
*off = vec & 0xffff; | *off = vec & 0xffff; | ||||
} | } | ||||
static __inline u_int | static __inline u_int | ||||
MAKE_VEC(u_short sel, u_short off) | MAKE_VEC(u_short sel, u_short off) | ||||
{ | { | ||||
return ((sel << 16) | off); | return ((sel << 16) | off); | ||||
} | } | ||||
static __inline void | static __inline void | ||||
PUSH(u_short x, struct vm86frame *vmf) | PUSH(u_short x, struct vm86frame *vmf) | ||||
{ | { | ||||
vmf->vmf_sp -= 2; | vmf->vmf_sp -= 2; | ||||
suword16(MAKE_ADDR(vmf->vmf_ss, vmf->vmf_sp), x); | vm86_suword16(MAKE_ADDR(vmf->vmf_ss, vmf->vmf_sp), x); | ||||
} | } | ||||
static __inline void | static __inline void | ||||
PUSHL(u_int x, struct vm86frame *vmf) | PUSHL(u_int x, struct vm86frame *vmf) | ||||
{ | { | ||||
vmf->vmf_sp -= 4; | vmf->vmf_sp -= 4; | ||||
suword(MAKE_ADDR(vmf->vmf_ss, vmf->vmf_sp), x); | vm86_suword(MAKE_ADDR(vmf->vmf_ss, vmf->vmf_sp), x); | ||||
} | } | ||||
static __inline u_short | static __inline u_short | ||||
POP(struct vm86frame *vmf) | POP(struct vm86frame *vmf) | ||||
{ | { | ||||
u_short x = fuword16(MAKE_ADDR(vmf->vmf_ss, vmf->vmf_sp)); | u_short x = vm86_fuword16(MAKE_ADDR(vmf->vmf_ss, vmf->vmf_sp)); | ||||
vmf->vmf_sp += 2; | vmf->vmf_sp += 2; | ||||
return (x); | return (x); | ||||
} | } | ||||
static __inline u_int | static __inline u_int | ||||
POPL(struct vm86frame *vmf) | POPL(struct vm86frame *vmf) | ||||
{ | { | ||||
u_int x = fuword(MAKE_ADDR(vmf->vmf_ss, vmf->vmf_sp)); | u_int x = vm86_fuword(MAKE_ADDR(vmf->vmf_ss, vmf->vmf_sp)); | ||||
vmf->vmf_sp += 4; | vmf->vmf_sp += 4; | ||||
return (x); | return (x); | ||||
} | } | ||||
int | int | ||||
vm86_emulate(struct vm86frame *vmf) | vm86_emulate(struct vm86frame *vmf) | ||||
{ | { | ||||
Show All 12 Lines | vm86_emulate(struct vm86frame *vmf) | ||||
if (curpcb->pcb_ext == 0) | if (curpcb->pcb_ext == 0) | ||||
return (SIGBUS); | return (SIGBUS); | ||||
vm86 = &curpcb->pcb_ext->ext_vm86; | vm86 = &curpcb->pcb_ext->ext_vm86; | ||||
if (vmf->vmf_eflags & PSL_T) | if (vmf->vmf_eflags & PSL_T) | ||||
retcode = SIGTRAP; | retcode = SIGTRAP; | ||||
addr = MAKE_ADDR(vmf->vmf_cs, vmf->vmf_ip); | addr = MAKE_ADDR(vmf->vmf_cs, vmf->vmf_ip); | ||||
i_byte = fubyte(addr); | i_byte = vm86_fubyte(addr); | ||||
if (i_byte == ADDRESS_SIZE_PREFIX) { | if (i_byte == ADDRESS_SIZE_PREFIX) { | ||||
i_byte = fubyte(++addr); | i_byte = vm86_fubyte(++addr); | ||||
inc_ip++; | inc_ip++; | ||||
} | } | ||||
if (vm86->vm86_has_vme) { | if (vm86->vm86_has_vme) { | ||||
switch (i_byte) { | switch (i_byte) { | ||||
case OPERAND_SIZE_PREFIX: | case OPERAND_SIZE_PREFIX: | ||||
i_byte = fubyte(++addr); | i_byte = vm86_fubyte(++addr); | ||||
inc_ip++; | inc_ip++; | ||||
switch (i_byte) { | switch (i_byte) { | ||||
case PUSHF: | case PUSHF: | ||||
if (vmf->vmf_eflags & PSL_VIF) | if (vmf->vmf_eflags & PSL_VIF) | ||||
PUSHL((vmf->vmf_eflags & PUSH_MASK) | PUSHL((vmf->vmf_eflags & PUSH_MASK) | ||||
| PSL_IOPL | PSL_I, vmf); | | PSL_IOPL | PSL_I, vmf); | ||||
else | else | ||||
PUSHL((vmf->vmf_eflags & PUSH_MASK) | PUSHL((vmf->vmf_eflags & PUSH_MASK) | ||||
▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | case IRET: | ||||
return (retcode); | return (retcode); | ||||
} | } | ||||
return (SIGBUS); | return (SIGBUS); | ||||
} | } | ||||
switch (i_byte) { | switch (i_byte) { | ||||
case OPERAND_SIZE_PREFIX: | case OPERAND_SIZE_PREFIX: | ||||
i_byte = fubyte(++addr); | i_byte = vm86_fubyte(++addr); | ||||
inc_ip++; | inc_ip++; | ||||
switch (i_byte) { | switch (i_byte) { | ||||
case PUSHF: | case PUSHF: | ||||
if (vm86->vm86_eflags & PSL_VIF) | if (vm86->vm86_eflags & PSL_VIF) | ||||
PUSHL((vmf->vmf_flags & PUSH_MASK) | PUSHL((vmf->vmf_flags & PUSH_MASK) | ||||
| PSL_IOPL | PSL_I, vmf); | | PSL_IOPL | PSL_I, vmf); | ||||
else | else | ||||
PUSHL((vmf->vmf_flags & PUSH_MASK) | PUSHL((vmf->vmf_flags & PUSH_MASK) | ||||
Show All 35 Lines | if (vm86->vm86_eflags & PSL_VIF) | ||||
PUSH((vmf->vmf_flags & PUSH_MASK) | PUSH((vmf->vmf_flags & PUSH_MASK) | ||||
| PSL_IOPL | PSL_I, vmf); | | PSL_IOPL | PSL_I, vmf); | ||||
else | else | ||||
PUSH((vmf->vmf_flags & PUSH_MASK) | PSL_IOPL, vmf); | PUSH((vmf->vmf_flags & PUSH_MASK) | PSL_IOPL, vmf); | ||||
vmf->vmf_ip += inc_ip; | vmf->vmf_ip += inc_ip; | ||||
return (retcode); | return (retcode); | ||||
case INTn: | case INTn: | ||||
i_byte = fubyte(addr + 1); | i_byte = vm86_fubyte(addr + 1); | ||||
if ((vm86->vm86_intmap[i_byte >> 3] & (1 << (i_byte & 7))) != 0) | if ((vm86->vm86_intmap[i_byte >> 3] & (1 << (i_byte & 7))) != 0) | ||||
break; | break; | ||||
if (vm86->vm86_eflags & PSL_VIF) | if (vm86->vm86_eflags & PSL_VIF) | ||||
PUSH((vmf->vmf_flags & PUSH_MASK) | PUSH((vmf->vmf_flags & PUSH_MASK) | ||||
| PSL_IOPL | PSL_I, vmf); | | PSL_IOPL | PSL_I, vmf); | ||||
else | else | ||||
PUSH((vmf->vmf_flags & PUSH_MASK) | PSL_IOPL, vmf); | PUSH((vmf->vmf_flags & PUSH_MASK) | PSL_IOPL, vmf); | ||||
PUSH(vmf->vmf_cs, vmf); | PUSH(vmf->vmf_cs, vmf); | ||||
PUSH(vmf->vmf_ip + inc_ip + 1, vmf); /* increment IP */ | PUSH(vmf->vmf_ip + inc_ip + 1, vmf); /* increment IP */ | ||||
GET_VEC(fuword((caddr_t)(i_byte * 4)), | GET_VEC(vm86_fuword((caddr_t)(i_byte * 4)), | ||||
&vmf->vmf_cs, &vmf->vmf_ip); | &vmf->vmf_cs, &vmf->vmf_ip); | ||||
vmf->vmf_flags &= ~PSL_T; | vmf->vmf_flags &= ~PSL_T; | ||||
vm86->vm86_eflags &= ~PSL_VIF; | vm86->vm86_eflags &= ~PSL_VIF; | ||||
return (retcode); | return (retcode); | ||||
case IRET: | case IRET: | ||||
vmf->vmf_ip = POP(vmf); | vmf->vmf_ip = POP(vmf); | ||||
vmf->vmf_cs = POP(vmf); | vmf->vmf_cs = POP(vmf); | ||||
▲ Show 20 Lines • Show All 228 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* vm86 trap handler; determines whether routine succeeded or not. | * vm86 trap handler; determines whether routine succeeded or not. | ||||
* Called while in vm86 space, returns to calling process. | * Called while in vm86 space, returns to calling process. | ||||
*/ | */ | ||||
void | void | ||||
vm86_trap(struct vm86frame *vmf) | vm86_trap(struct vm86frame *vmf) | ||||
{ | { | ||||
void (*p)(struct vm86frame *); | |||||
caddr_t addr; | caddr_t addr; | ||||
/* "should not happen" */ | /* "should not happen" */ | ||||
if ((vmf->vmf_eflags & PSL_VM) == 0) | if ((vmf->vmf_eflags & PSL_VM) == 0) | ||||
panic("vm86_trap called, but not in vm86 mode"); | panic("vm86_trap called, but not in vm86 mode"); | ||||
addr = MAKE_ADDR(vmf->vmf_cs, vmf->vmf_ip); | addr = MAKE_ADDR(vmf->vmf_cs, vmf->vmf_ip); | ||||
if (*(u_char *)addr == HLT) | if (*(u_char *)addr == HLT) | ||||
vmf->vmf_trapno = vmf->vmf_eflags & PSL_C; | vmf->vmf_trapno = vmf->vmf_eflags & PSL_C; | ||||
else | else | ||||
vmf->vmf_trapno = vmf->vmf_trapno << 16; | vmf->vmf_trapno = vmf->vmf_trapno << 16; | ||||
vm86_biosret(vmf); | p = (void (*)(struct vm86frame *))((uintptr_t)vm86_biosret + | ||||
setidt_disp); | |||||
p(vmf); | |||||
} | } | ||||
int | int | ||||
vm86_intcall(int intnum, struct vm86frame *vmf) | vm86_intcall(int intnum, struct vm86frame *vmf) | ||||
{ | { | ||||
int (*p)(struct vm86frame *); | |||||
int retval; | int retval; | ||||
if (intnum < 0 || intnum > 0xff) | if (intnum < 0 || intnum > 0xff) | ||||
return (EINVAL); | return (EINVAL); | ||||
vmf->vmf_trapno = intnum; | vmf->vmf_trapno = intnum; | ||||
p = (int (*)(struct vm86frame *))((uintptr_t)vm86_bioscall + | |||||
setidt_disp); | |||||
mtx_lock(&vm86_lock); | mtx_lock(&vm86_lock); | ||||
critical_enter(); | critical_enter(); | ||||
retval = vm86_bioscall(vmf); | retval = p(vmf); | ||||
critical_exit(); | critical_exit(); | ||||
mtx_unlock(&vm86_lock); | mtx_unlock(&vm86_lock); | ||||
return (retval); | return (retval); | ||||
} | } | ||||
/* | /* | ||||
* struct vm86context contains the page table to use when making | * struct vm86context contains the page table to use when making | ||||
* vm86 calls. If intnum is a valid interrupt number (0-255), then | * vm86 calls. If intnum is a valid interrupt number (0-255), then | ||||
* the "interrupt trampoline" will be used, otherwise we use the | * the "interrupt trampoline" will be used, otherwise we use the | ||||
* caller's cs:ip routine. | * caller's cs:ip routine. | ||||
*/ | */ | ||||
int | int | ||||
vm86_datacall(int intnum, struct vm86frame *vmf, struct vm86context *vmc) | vm86_datacall(int intnum, struct vm86frame *vmf, struct vm86context *vmc) | ||||
{ | { | ||||
pt_entry_t *pte = (pt_entry_t *)vm86paddr; | pt_entry_t *pte; | ||||
int (*p)(struct vm86frame *); | |||||
vm_paddr_t page; | vm_paddr_t page; | ||||
int i, entry, retval; | int i, entry, retval; | ||||
pte = (pt_entry_t *)vm86paddr; | |||||
mtx_lock(&vm86_lock); | mtx_lock(&vm86_lock); | ||||
for (i = 0; i < vmc->npages; i++) { | for (i = 0; i < vmc->npages; i++) { | ||||
page = vtophys(vmc->pmap[i].kva & PG_FRAME); | page = vtophys(vmc->pmap[i].kva & PG_FRAME); | ||||
entry = vmc->pmap[i].pte_num; | entry = vmc->pmap[i].pte_num; | ||||
vmc->pmap[i].old_pte = pte[entry]; | vmc->pmap[i].old_pte = pte[entry]; | ||||
pte[entry] = page | PG_V | PG_RW | PG_U; | pte[entry] = page | PG_V | PG_RW | PG_U; | ||||
pmap_invalidate_page(kernel_pmap, vmc->pmap[i].kva); | pmap_invalidate_page(kernel_pmap, vmc->pmap[i].kva); | ||||
} | } | ||||
vmf->vmf_trapno = intnum; | vmf->vmf_trapno = intnum; | ||||
p = (int (*)(struct vm86frame *))((uintptr_t)vm86_bioscall + | |||||
setidt_disp); | |||||
critical_enter(); | critical_enter(); | ||||
retval = vm86_bioscall(vmf); | retval = p(vmf); | ||||
critical_exit(); | critical_exit(); | ||||
for (i = 0; i < vmc->npages; i++) { | for (i = 0; i < vmc->npages; i++) { | ||||
entry = vmc->pmap[i].pte_num; | entry = vmc->pmap[i].pte_num; | ||||
pte[entry] = vmc->pmap[i].old_pte; | pte[entry] = vmc->pmap[i].old_pte; | ||||
pmap_invalidate_page(kernel_pmap, vmc->pmap[i].kva); | pmap_invalidate_page(kernel_pmap, vmc->pmap[i].kva); | ||||
} | } | ||||
mtx_unlock(&vm86_lock); | mtx_unlock(&vm86_lock); | ||||
▲ Show 20 Lines • Show All 108 Lines • Show Last 20 Lines |