Changeset View
Changeset View
Standalone View
Standalone View
sys/i386/i386/vm86.c
Show First 20 Lines • Show All 391 Lines • ▼ Show 20 Lines | |||||
#define PGTABLE_SIZE ((1024 + 64) * 1024 / PAGE_SIZE) | #define PGTABLE_SIZE ((1024 + 64) * 1024 / PAGE_SIZE) | ||||
#define INTMAP_SIZE 32 | #define INTMAP_SIZE 32 | ||||
#define IOMAP_SIZE ctob(IOPAGES) | #define IOMAP_SIZE ctob(IOPAGES) | ||||
#define TSS_SIZE \ | #define TSS_SIZE \ | ||||
(sizeof(struct pcb_ext) - sizeof(struct segment_descriptor) + \ | (sizeof(struct pcb_ext) - sizeof(struct segment_descriptor) + \ | ||||
INTMAP_SIZE + IOMAP_SIZE + 1) | INTMAP_SIZE + IOMAP_SIZE + 1) | ||||
struct vm86_layout { | struct vm86_layout_pae { | ||||
pt_entry_t vml_pgtbl[PGTABLE_SIZE]; | uint64_t vml_pgtbl[PGTABLE_SIZE]; | ||||
struct pcb vml_pcb; | struct pcb vml_pcb; | ||||
struct pcb_ext vml_ext; | struct pcb_ext vml_ext; | ||||
char vml_intmap[INTMAP_SIZE]; | char vml_intmap[INTMAP_SIZE]; | ||||
char vml_iomap[IOMAP_SIZE]; | char vml_iomap[IOMAP_SIZE]; | ||||
char vml_iomap_trailer; | char vml_iomap_trailer; | ||||
}; | }; | ||||
void | struct vm86_layout_nopae { | ||||
vm86_initialize(void) | uint32_t vml_pgtbl[PGTABLE_SIZE]; | ||||
struct pcb vml_pcb; | |||||
struct pcb_ext vml_ext; | |||||
char vml_intmap[INTMAP_SIZE]; | |||||
char vml_iomap[IOMAP_SIZE]; | |||||
char vml_iomap_trailer; | |||||
}; | |||||
_Static_assert(sizeof(struct vm86_layout_pae) <= ctob(3), | |||||
"struct vm86_layout_pae exceeds space allocated in locore.s"); | |||||
_Static_assert(sizeof(struct vm86_layout_nopae) <= ctob(3), | |||||
"struct vm86_layout_nopae exceeds space allocated in locore.s"); | |||||
static void | |||||
vm86_initialize_pae(void) | |||||
{ | { | ||||
int i; | int i; | ||||
u_int *addr; | u_int *addr; | ||||
struct vm86_layout *vml = (struct vm86_layout *)vm86paddr; | struct vm86_layout_pae *vml; | ||||
struct pcb *pcb; | struct pcb *pcb; | ||||
struct pcb_ext *ext; | struct pcb_ext *ext; | ||||
struct soft_segment_descriptor ssd = { | struct soft_segment_descriptor ssd = { | ||||
0, /* segment base address (overwritten) */ | 0, /* segment base address (overwritten) */ | ||||
0, /* length (overwritten) */ | 0, /* length (overwritten) */ | ||||
SDT_SYS386TSS, /* segment type */ | SDT_SYS386TSS, /* segment type */ | ||||
0, /* priority level */ | 0, /* priority level */ | ||||
1, /* descriptor present */ | 1, /* descriptor present */ | ||||
0, 0, | 0, 0, | ||||
0, /* default 16 size */ | 0, /* default 16 size */ | ||||
0 /* granularity */ | 0 /* granularity */ | ||||
}; | }; | ||||
/* | /* | ||||
* this should be a compile time error, but cpp doesn't grok sizeof(). | |||||
*/ | |||||
if (sizeof(struct vm86_layout) > ctob(3)) | |||||
panic("struct vm86_layout exceeds space allocated in locore.s"); | |||||
/* | |||||
* Below is the memory layout that we use for the vm86 region. | * Below is the memory layout that we use for the vm86 region. | ||||
* | * | ||||
* +--------+ | * +--------+ | ||||
* | | | * | | | ||||
* | | | * | | | ||||
* | page 0 | | * | page 0 | | ||||
* | | +--------+ | * | | +--------+ | ||||
* | | | stack | | * | | | stack | | ||||
Show All 25 Lines | vm86_initialize_pae(void) | ||||
* pcb_eip = argument pointer to initial call | * pcb_eip = argument pointer to initial call | ||||
* pcb_vm86[0] = saved TSS descriptor, word 0 | * pcb_vm86[0] = saved TSS descriptor, word 0 | ||||
* pcb_vm86[1] = saved TSS descriptor, word 1 | * pcb_vm86[1] = saved TSS descriptor, word 1 | ||||
*/ | */ | ||||
#define new_ptd pcb_esi | #define new_ptd pcb_esi | ||||
#define vm86_frame pcb_ebp | #define vm86_frame pcb_ebp | ||||
#define pgtable_va pcb_ebx | #define pgtable_va pcb_ebx | ||||
vml = (struct vm86_layout_pae *)vm86paddr; | |||||
pcb = &vml->vml_pcb; | pcb = &vml->vml_pcb; | ||||
ext = &vml->vml_ext; | ext = &vml->vml_ext; | ||||
mtx_init(&vm86_lock, "vm86 lock", NULL, MTX_DEF); | mtx_init(&vm86_lock, "vm86 lock", NULL, MTX_DEF); | ||||
bzero(pcb, sizeof(struct pcb)); | bzero(pcb, sizeof(struct pcb)); | ||||
pcb->new_ptd = vm86pa | PG_V | PG_RW | PG_U; | pcb->new_ptd = vm86pa | PG_V | PG_RW | PG_U; | ||||
pcb->vm86_frame = vm86paddr - sizeof(struct vm86frame); | pcb->vm86_frame = vm86paddr - sizeof(struct vm86frame); | ||||
pcb->pgtable_va = vm86paddr; | pcb->pgtable_va = vm86paddr; | ||||
pcb->pcb_flags = PCB_VM86CALL; | pcb->pcb_flags = PCB_VM86CALL; | ||||
pcb->pcb_ext = ext; | pcb->pcb_ext = ext; | ||||
bzero(ext, sizeof(struct pcb_ext)); | bzero(ext, sizeof(struct pcb_ext)); | ||||
ext->ext_tss.tss_esp0 = vm86paddr; | ext->ext_tss.tss_esp0 = vm86paddr; | ||||
ext->ext_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL); | ext->ext_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL); | ||||
ext->ext_tss.tss_ioopt = | ext->ext_tss.tss_ioopt = | ||||
((u_int)vml->vml_iomap - (u_int)&ext->ext_tss) << 16; | ((u_int)vml->vml_iomap - (u_int)&ext->ext_tss) << 16; | ||||
ext->ext_iomap = vml->vml_iomap; | ext->ext_iomap = vml->vml_iomap; | ||||
ext->ext_vm86.vm86_intmap = vml->vml_intmap; | ext->ext_vm86.vm86_intmap = vml->vml_intmap; | ||||
if (cpu_feature & CPUID_VME) | if (cpu_feature & CPUID_VME) | ||||
ext->ext_vm86.vm86_has_vme = (rcr4() & CR4_VME ? 1 : 0); | ext->ext_vm86.vm86_has_vme = (rcr4() & CR4_VME ? 1 : 0); | ||||
addr = (u_int *)ext->ext_vm86.vm86_intmap; | addr = (u_int *)ext->ext_vm86.vm86_intmap; | ||||
for (i = 0; i < (INTMAP_SIZE + IOMAP_SIZE) / sizeof(u_int); i++) | for (i = 0; i < (INTMAP_SIZE + IOMAP_SIZE) / sizeof(u_int); i++) | ||||
*addr++ = 0; | *addr++ = 0; | ||||
vml->vml_iomap_trailer = 0xff; | vml->vml_iomap_trailer = 0xff; | ||||
ssd.ssd_base = (u_int)&ext->ext_tss; | ssd.ssd_base = (u_int)&ext->ext_tss; | ||||
ssd.ssd_limit = TSS_SIZE - 1; | ssd.ssd_limit = TSS_SIZE - 1; | ||||
ssdtosd(&ssd, &ext->ext_tssd); | ssdtosd(&ssd, &ext->ext_tssd); | ||||
vm86pcb = pcb; | vm86pcb = pcb; | ||||
#if 0 | #if 0 | ||||
/* | /* | ||||
* use whatever is leftover of the vm86 page layout as a | * use whatever is leftover of the vm86 page layout as a | ||||
* message buffer so we can capture early output. | * message buffer so we can capture early output. | ||||
*/ | */ | ||||
msgbufinit((vm_offset_t)vm86paddr + sizeof(struct vm86_layout), | msgbufinit((vm_offset_t)vm86paddr + sizeof(struct vm86_layout), | ||||
ctob(3) - sizeof(struct vm86_layout)); | ctob(3) - sizeof(struct vm86_layout)); | ||||
#endif | #endif | ||||
} | } | ||||
static void | |||||
vm86_initialize_nopae(void) | |||||
{ | |||||
int i; | |||||
u_int *addr; | |||||
struct vm86_layout_nopae *vml; | |||||
struct pcb *pcb; | |||||
struct pcb_ext *ext; | |||||
struct soft_segment_descriptor ssd = { | |||||
0, /* segment base address (overwritten) */ | |||||
0, /* length (overwritten) */ | |||||
SDT_SYS386TSS, /* segment type */ | |||||
0, /* priority level */ | |||||
1, /* descriptor present */ | |||||
0, 0, | |||||
0, /* default 16 size */ | |||||
0 /* granularity */ | |||||
}; | |||||
vml = (struct vm86_layout_nopae *)vm86paddr; | |||||
pcb = &vml->vml_pcb; | |||||
ext = &vml->vml_ext; | |||||
mtx_init(&vm86_lock, "vm86 lock", NULL, MTX_DEF); | |||||
bzero(pcb, sizeof(struct pcb)); | |||||
pcb->new_ptd = vm86pa | PG_V | PG_RW | PG_U; | |||||
pcb->vm86_frame = vm86paddr - sizeof(struct vm86frame); | |||||
pcb->pgtable_va = vm86paddr; | |||||
pcb->pcb_flags = PCB_VM86CALL; | |||||
pcb->pcb_ext = ext; | |||||
bzero(ext, sizeof(struct pcb_ext)); | |||||
ext->ext_tss.tss_esp0 = vm86paddr; | |||||
ext->ext_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL); | |||||
ext->ext_tss.tss_ioopt = | |||||
((u_int)vml->vml_iomap - (u_int)&ext->ext_tss) << 16; | |||||
ext->ext_iomap = vml->vml_iomap; | |||||
ext->ext_vm86.vm86_intmap = vml->vml_intmap; | |||||
if (cpu_feature & CPUID_VME) | |||||
ext->ext_vm86.vm86_has_vme = (rcr4() & CR4_VME ? 1 : 0); | |||||
addr = (u_int *)ext->ext_vm86.vm86_intmap; | |||||
for (i = 0; i < (INTMAP_SIZE + IOMAP_SIZE) / sizeof(u_int); i++) | |||||
*addr++ = 0; | |||||
vml->vml_iomap_trailer = 0xff; | |||||
ssd.ssd_base = (u_int)&ext->ext_tss; | |||||
ssd.ssd_limit = TSS_SIZE - 1; | |||||
ssdtosd(&ssd, &ext->ext_tssd); | |||||
vm86pcb = pcb; | |||||
#if 0 | |||||
/* | |||||
* use whatever is leftover of the vm86 page layout as a | |||||
* message buffer so we can capture early output. | |||||
*/ | |||||
msgbufinit((vm_offset_t)vm86paddr + sizeof(struct vm86_layout), | |||||
ctob(3) - sizeof(struct vm86_layout)); | |||||
#endif | |||||
} | |||||
void | |||||
vm86_initialize(void) | |||||
{ | |||||
if (pae_mode) | |||||
vm86_initialize_pae(); | |||||
else | |||||
vm86_initialize_nopae(); | |||||
} | |||||
vm_offset_t | vm_offset_t | ||||
vm86_getpage(struct vm86context *vmc, int pagenum) | vm86_getpage(struct vm86context *vmc, int pagenum) | ||||
{ | { | ||||
int i; | int i; | ||||
for (i = 0; i < vmc->npages; i++) | for (i = 0; i < vmc->npages; i++) | ||||
if (vmc->pmap[i].pte_num == pagenum) | if (vmc->pmap[i].pte_num == pagenum) | ||||
return (vmc->pmap[i].kva); | return (vmc->pmap[i].kva); | ||||
▲ Show 20 Lines • Show All 111 Lines • ▼ Show 20 Lines | |||||
* 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; | uint64_t *pte_pae; | ||||
uint32_t *pte_nopae; | |||||
int (*p)(struct vm86frame *); | 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); | ||||
if (pae_mode) { | |||||
pte_pae = (uint64_t *)vm86paddr; | |||||
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_PAE); | ||||
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_pae[entry]; | ||||
pte[entry] = page | PG_V | PG_RW | PG_U; | pte_pae[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); | ||||
} | } | ||||
} else { | |||||
pte_nopae = (uint32_t *)vm86paddr; | |||||
for (i = 0; i < vmc->npages; i++) { | |||||
page = vtophys(vmc->pmap[i].kva & PG_FRAME_NOPAE); | |||||
entry = vmc->pmap[i].pte_num; | |||||
vmc->pmap[i].old_pte = pte_nopae[entry]; | |||||
pte_nopae[entry] = page | PG_V | PG_RW | PG_U; | |||||
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 + | p = (int (*)(struct vm86frame *))((uintptr_t)vm86_bioscall + | ||||
setidt_disp); | setidt_disp); | ||||
critical_enter(); | critical_enter(); | ||||
retval = p(vmf); | retval = p(vmf); | ||||
critical_exit(); | critical_exit(); | ||||
if (pae_mode) { | |||||
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_pae[entry] = vmc->pmap[i].old_pte; | ||||
pmap_invalidate_page(kernel_pmap, vmc->pmap[i].kva); | pmap_invalidate_page(kernel_pmap, vmc->pmap[i].kva); | ||||
} | |||||
} else { | |||||
for (i = 0; i < vmc->npages; i++) { | |||||
entry = vmc->pmap[i].pte_num; | |||||
pte_nopae[entry] = vmc->pmap[i].old_pte; | |||||
pmap_invalidate_page(kernel_pmap, vmc->pmap[i].kva); | |||||
} | |||||
} | } | ||||
mtx_unlock(&vm86_lock); | mtx_unlock(&vm86_lock); | ||||
return (retval); | return (retval); | ||||
} | } | ||||
vm_offset_t | vm_offset_t | ||||
vm86_getaddr(struct vm86context *vmc, u_short sel, u_short off) | vm86_getaddr(struct vm86context *vmc, u_short sel, u_short off) | ||||
▲ Show 20 Lines • Show All 102 Lines • Show Last 20 Lines |