root/arch/i386/i386/kvm86.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. kvm86_init
  2. kvm86_prepare
  3. kvm86_map
  4. kvm86_mapbios
  5. kvm86_bios_addpage
  6. kvm86_bios_delpage
  7. kvm86_bios_read
  8. kvm86_bioscall
  9. kvm86_simplecall
  10. kvm86_gpfault

    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 }

/* [<][>][^][v][top][bottom][index][help] */