Annotation of sys/arch/i386/i386/kvm86.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: kvm86.c,v 1.3 2007/02/20 21:15:01 tom Exp $ */
! 2: /* $NetBSD: kvm86.c,v 1.10 2005/12/26 19:23:59 perry Exp $ */
! 3: /*
! 4: * Copyright (c) 2002
! 5: * Matthias Drochner. All rights reserved.
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions, and the following disclaimer.
! 12: * 2. Redistributions in binary form must reproduce the above copyright
! 13: * notice, this list of conditions and the following disclaimer in the
! 14: * documentation and/or other materials provided with the distribution.
! 15: *
! 16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 17: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 18: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 19: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 20: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 21: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 22: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 23: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 24: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 25: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 26: * SUCH DAMAGE.
! 27: */
! 28: #include <sys/cdefs.h>
! 29:
! 30: #include <sys/param.h>
! 31: #include <sys/systm.h>
! 32: #include <sys/proc.h>
! 33: #include <sys/user.h>
! 34: #include <sys/malloc.h>
! 35: #include <sys/mutex.h>
! 36: #include <sys/simplelock.h>
! 37: #include <uvm/uvm_extern.h>
! 38: #include <uvm/uvm.h>
! 39: #include <machine/pcb.h>
! 40: #include <machine/pte.h>
! 41: #include <machine/pmap.h>
! 42: #include <machine/kvm86.h>
! 43: #include <machine/cpu.h>
! 44:
! 45: /* assembler functions in kvm86call.s */
! 46: extern int kvm86_call(struct trapframe *);
! 47: extern void kvm86_ret(struct trapframe *, int);
! 48:
! 49: #define PGTABLE_SIZE ((1024 + 64) * 1024 / PAGE_SIZE)
! 50:
! 51: struct kvm86_data {
! 52: pt_entry_t pgtbl[PGTABLE_SIZE];
! 53:
! 54: struct segment_descriptor sd;
! 55:
! 56: struct pcb pcb;
! 57: u_long iomap[0x10000/32];
! 58: };
! 59:
! 60: void kvm86_map(struct kvm86_data *, paddr_t, uint32_t);
! 61: void kvm86_mapbios(struct kvm86_data *);
! 62: void kvm86_prepare(struct kvm86_data *vmd);
! 63: /*
! 64: * global VM for BIOS calls
! 65: */
! 66: struct kvm86_data *bioscallvmd;
! 67: /* page for trampoline and stack */
! 68: void *bioscallscratchpage;
! 69: /* where this page is mapped in the vm86 */
! 70: #define BIOSCALLSCRATCHPAGE_VMVA 0x1000
! 71: /* a virtual page to map in vm86 memory temporarily */
! 72: vaddr_t bioscalltmpva;
! 73:
! 74: struct mutex kvm86_mp_mutex;
! 75:
! 76: #define KVM86_IOPL3 /* not strictly necessary, saves a lot of traps */
! 77:
! 78: void
! 79: kvm86_init()
! 80: {
! 81: size_t vmdsize;
! 82: char *buf;
! 83: struct kvm86_data *vmd;
! 84: struct pcb *pcb;
! 85: paddr_t pa;
! 86: int i;
! 87:
! 88: vmdsize = round_page(sizeof(struct kvm86_data)) + PAGE_SIZE;
! 89:
! 90: if ((buf = (char *)uvm_km_zalloc(kernel_map, vmdsize)) == NULL)
! 91: return;
! 92:
! 93: /* first page is stack */
! 94: vmd = (struct kvm86_data *)(buf + PAGE_SIZE);
! 95: pcb = &vmd->pcb;
! 96:
! 97: /*
! 98: * derive pcb and TSS from proc0
! 99: * we want to access all IO ports, so we need a full-size
! 100: * permission bitmap
! 101: * XXX do we really need the pcb or just the TSS?
! 102: */
! 103: memcpy(pcb, &proc0.p_addr->u_pcb, sizeof(struct pcb));
! 104: pcb->pcb_tss.tss_esp0 = (int)vmd;
! 105: pcb->pcb_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL);
! 106: for (i = 0; i < sizeof(vmd->iomap) / 4; i++)
! 107: vmd->iomap[i] = 0;
! 108: pcb->pcb_tss.tss_ioopt =
! 109: ((caddr_t)vmd->iomap - (caddr_t)&pcb->pcb_tss) << 16;
! 110:
! 111: /* setup TSS descriptor (including our iomap) */
! 112: setsegment(&vmd->sd, &pcb->pcb_tss,
! 113: sizeof(struct pcb) + sizeof(vmd->iomap) - 1,
! 114: SDT_SYS386TSS, SEL_KPL, 0, 0);
! 115:
! 116: /* prepare VM for BIOS calls */
! 117: kvm86_mapbios(vmd);
! 118: if ((bioscallscratchpage = (void *)uvm_km_alloc(kernel_map, PAGE_SIZE))
! 119: == 0)
! 120: return;
! 121:
! 122: pmap_extract(pmap_kernel(), (vaddr_t)bioscallscratchpage, &pa);
! 123: kvm86_map(vmd, pa, BIOSCALLSCRATCHPAGE_VMVA);
! 124: bioscallvmd = vmd;
! 125: bioscalltmpva = uvm_km_alloc(kernel_map, PAGE_SIZE);
! 126: mtx_init(&kvm86_mp_mutex, IPL_IPI);
! 127: }
! 128:
! 129: /*
! 130: * XXX pass some stuff to the assembler code
! 131: * XXX this should be done cleanly (in call argument to kvm86_call())
! 132: */
! 133:
! 134: volatile struct pcb *vm86pcb;
! 135: volatile int vm86tssd0, vm86tssd1;
! 136: volatile paddr_t vm86newptd;
! 137: volatile struct trapframe *vm86frame;
! 138: volatile pt_entry_t *vm86pgtableva;
! 139:
! 140: void
! 141: kvm86_prepare(struct kvm86_data *vmd)
! 142: {
! 143: vm86newptd = vtophys((vaddr_t)vmd) | PG_V | PG_RW | PG_U | PG_u;
! 144: vm86pgtableva = vmd->pgtbl;
! 145: vm86frame = (struct trapframe *)vmd - 1;
! 146: vm86pcb = &vmd->pcb;
! 147: vm86tssd0 = *(int*)&vmd->sd;
! 148: vm86tssd1 = *((int*)&vmd->sd + 1);
! 149: }
! 150:
! 151: void
! 152: kvm86_map(struct kvm86_data *vmd, paddr_t pa, uint32_t vmva)
! 153: {
! 154:
! 155: vmd->pgtbl[vmva >> 12] = pa | PG_V | PG_RW | PG_U | PG_u;
! 156: }
! 157:
! 158: void
! 159: kvm86_mapbios(struct kvm86_data *vmd)
! 160: {
! 161: paddr_t pa;
! 162:
! 163: /* map first physical page (vector table, BIOS data) */
! 164: kvm86_map(vmd, 0, 0);
! 165:
! 166: /* map ISA hole */
! 167: for (pa = 0xa0000; pa < 0x100000; pa += PAGE_SIZE)
! 168: kvm86_map(vmd, pa, pa);
! 169: }
! 170:
! 171: void *
! 172: kvm86_bios_addpage(uint32_t vmva)
! 173: {
! 174: void *mem;
! 175: paddr_t pa;
! 176:
! 177: if (bioscallvmd->pgtbl[vmva >> 12]) /* allocated? */
! 178: return (NULL);
! 179:
! 180: if ((mem = (void *)uvm_km_alloc(kernel_map, PAGE_SIZE)) == NULL)
! 181: return (NULL);
! 182:
! 183: pmap_extract(pmap_kernel(), (vaddr_t)mem, &pa);
! 184: kvm86_map(bioscallvmd, pa, vmva);
! 185:
! 186: return (mem);
! 187: }
! 188:
! 189: void
! 190: kvm86_bios_delpage(uint32_t vmva, void *kva)
! 191: {
! 192:
! 193: bioscallvmd->pgtbl[vmva >> 12] = 0;
! 194: uvm_km_free(kernel_map, (vaddr_t)kva, PAGE_SIZE);
! 195: }
! 196:
! 197: size_t
! 198: kvm86_bios_read(u_int32_t vmva, char *buf, size_t len)
! 199: {
! 200: size_t todo, now;
! 201: paddr_t vmpa;
! 202:
! 203: todo = len;
! 204: while (todo > 0) {
! 205: now = min(todo, PAGE_SIZE - (vmva & (PAGE_SIZE - 1)));
! 206:
! 207: if (!bioscallvmd->pgtbl[vmva >> 12])
! 208: break;
! 209: vmpa = bioscallvmd->pgtbl[vmva >> 12] & ~(PAGE_SIZE - 1);
! 210: pmap_kenter_pa(bioscalltmpva, vmpa, VM_PROT_READ);
! 211: pmap_update(pmap_kernel());
! 212:
! 213: memcpy(buf, (void *)(bioscalltmpva + (vmva & (PAGE_SIZE - 1))),
! 214: now);
! 215: buf += now;
! 216: todo -= now;
! 217: vmva += now;
! 218: }
! 219: return (len - todo);
! 220: }
! 221:
! 222: int
! 223: kvm86_bioscall(int intno, struct trapframe *tf)
! 224: {
! 225: static const unsigned char call[] = {
! 226: 0xfa, /* CLI */
! 227: 0xcd, /* INTxx */
! 228: 0,
! 229: 0xfb, /* STI */
! 230: 0xf4 /* HLT */
! 231: };
! 232:
! 233: memcpy(bioscallscratchpage, call, sizeof(call));
! 234: *((unsigned char *)bioscallscratchpage + 2) = intno;
! 235:
! 236: tf->tf_eip = BIOSCALLSCRATCHPAGE_VMVA;
! 237: tf->tf_cs = 0;
! 238: tf->tf_esp = BIOSCALLSCRATCHPAGE_VMVA + PAGE_SIZE - 2;
! 239: tf->tf_ss = 0;
! 240: tf->tf_eflags = PSL_USERSET | PSL_VM;
! 241: #ifdef KVM86_IOPL3
! 242: tf->tf_eflags |= PSL_IOPL;
! 243: #endif
! 244: tf->tf_ds = tf->tf_es = tf->tf_fs = tf->tf_gs = 0;
! 245:
! 246: kvm86_prepare(bioscallvmd); /* XXX */
! 247: return (kvm86_call(tf));
! 248: }
! 249:
! 250: int
! 251: kvm86_simplecall(int no, struct kvm86regs *regs)
! 252: {
! 253: struct trapframe tf;
! 254: int res;
! 255:
! 256: memset(&tf, 0, sizeof(struct trapframe));
! 257: tf.tf_eax = regs->eax;
! 258: tf.tf_ebx = regs->ebx;
! 259: tf.tf_ecx = regs->ecx;
! 260: tf.tf_edx = regs->edx;
! 261: tf.tf_esi = regs->esi;
! 262: tf.tf_edi = regs->edi;
! 263: tf.tf_vm86_es = regs->es;
! 264:
! 265: mtx_enter(&kvm86_mp_mutex);
! 266: res = kvm86_bioscall(no, &tf);
! 267: mtx_leave(&kvm86_mp_mutex);
! 268:
! 269: regs->eax = tf.tf_eax;
! 270: regs->ebx = tf.tf_ebx;
! 271: regs->ecx = tf.tf_ecx;
! 272: regs->edx = tf.tf_edx;
! 273: regs->esi = tf.tf_esi;
! 274: regs->edi = tf.tf_edi;
! 275: regs->es = tf.tf_vm86_es;
! 276: regs->eflags = tf.tf_eflags;
! 277:
! 278: return (res);
! 279: }
! 280:
! 281: void
! 282: kvm86_gpfault(struct trapframe *tf)
! 283: {
! 284: unsigned char *kva, insn, trapno;
! 285: uint16_t *sp;
! 286:
! 287: kva = (unsigned char *)((tf->tf_cs << 4) + tf->tf_eip);
! 288: insn = *kva;
! 289: #ifdef KVM86DEBUG
! 290: printf("kvm86_gpfault: cs=%x, eip=%x, insn=%x, eflags=%x\n",
! 291: tf->tf_cs, tf->tf_eip, insn, tf->tf_eflags);
! 292: #endif
! 293:
! 294: KASSERT(tf->tf_eflags & PSL_VM);
! 295:
! 296: switch (insn) {
! 297: case 0xf4: /* HLT - normal exit */
! 298: kvm86_ret(tf, 0);
! 299: break;
! 300: case 0xcd: /* INTxx */
! 301: /* fake a return stack frame and call real mode handler */
! 302: trapno = *(kva + 1);
! 303: sp = (uint16_t *)((tf->tf_ss << 4) + tf->tf_esp);
! 304: *(--sp) = tf->tf_eflags;
! 305: *(--sp) = tf->tf_cs;
! 306: *(--sp) = tf->tf_eip + 2;
! 307: tf->tf_esp -= 6;
! 308: tf->tf_cs = *(uint16_t *)(trapno * 4 + 2);
! 309: tf->tf_eip = *(uint16_t *)(trapno * 4);
! 310: break;
! 311: case 0xcf: /* IRET */
! 312: sp = (uint16_t *)((tf->tf_ss << 4) + tf->tf_esp);
! 313: tf->tf_eip = *(sp++);
! 314: tf->tf_cs = *(sp++);
! 315: tf->tf_eflags = *(sp++);
! 316: tf->tf_esp += 6;
! 317: tf->tf_eflags |= PSL_VM; /* outside of 16bit flag reg */
! 318: break;
! 319: #ifndef KVM86_IOPL3 /* XXX check VME? */
! 320: case 0xfa: /* CLI */
! 321: case 0xfb: /* STI */
! 322: /* XXX ignore for now */
! 323: tf->tf_eip++;
! 324: break;
! 325: case 0x9c: /* PUSHF */
! 326: sp = (uint16_t *)((tf->tf_ss << 4) + tf->tf_esp);
! 327: *(--sp) = tf->tf_eflags;
! 328: tf->tf_esp -= 2;
! 329: tf->tf_eip++;
! 330: break;
! 331: case 0x9d: /* POPF */
! 332: sp = (uint16_t *)((tf->tf_ss << 4) + tf->tf_esp);
! 333: tf->tf_eflags = *(sp++);
! 334: tf->tf_esp += 2;
! 335: tf->tf_eip++;
! 336: tf->tf_eflags |= PSL_VM; /* outside of 16bit flag reg */
! 337: break;
! 338: #endif
! 339: default:
! 340: #ifdef KVM86DEBUG
! 341: printf("kvm86_gpfault: unhandled\n");
! 342: #else
! 343: printf("kvm86_gpfault: cs=%x, eip=%x, insn=%x, eflags=%x\n",
! 344: tf->tf_cs, tf->tf_eip, insn, tf->tf_eflags);
! 345: #endif
! 346: /*
! 347: * signal error to caller
! 348: */
! 349: kvm86_ret(tf, -1);
! 350: break;
! 351: }
! 352: }
CVSweb