[BACK]Return to kvm86.c CVS log [TXT][DIR] Up to [local] / sys / arch / i386 / i386

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