This is a (still experimental) framework to run BIOS code in a virtual
8086 machine. Ifff it works, it is much easier and more elegant than going to real real mode: -simpler code -no need for "identity" memory mappings -easy passing of buffers for bulk data to functions -some more control There is no interrupt support ATM, and it lacks a function to access random virtual memory of the VM. MP issues to consider.
This commit is contained in:
parent
f6f0c7616b
commit
3b22d7973b
327
sys/arch/i386/i386/kvm86.c
Normal file
327
sys/arch/i386/i386/kvm86.c
Normal file
@ -0,0 +1,327 @@
|
||||
/* $NetBSD: kvm86.c,v 1.1 2002/07/07 12:56:34 drochner Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002
|
||||
* Matthias Drochner. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: kvm86.c,v 1.1 2002/07/07 12:56:34 drochner Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <uvm/uvm.h>
|
||||
#include <machine/pcb.h>
|
||||
#include <machine/pte.h>
|
||||
#include <machine/pmap.h>
|
||||
#include <machine/kvm86.h>
|
||||
|
||||
/* assembler functions in kvm86call.s */
|
||||
extern int kvm86_call(struct trapframe *);
|
||||
extern void kvm86_ret(struct trapframe *, int);
|
||||
|
||||
struct kvm86_data {
|
||||
#define PGTABLE_SIZE ((1024 + 64) * 1024 / NBPG)
|
||||
pt_entry_t pgtbl[PGTABLE_SIZE]; /* must be aliged */
|
||||
|
||||
struct segment_descriptor sd;
|
||||
|
||||
struct pcb pcb; /* contains TSS */
|
||||
u_long iomap[0x10000/32]; /* full size io permission map */
|
||||
};
|
||||
|
||||
static void kvm86_map(struct kvm86_data *, paddr_t, u_int32_t);
|
||||
static void kvm86_mapbios(struct kvm86_data *);
|
||||
|
||||
/*
|
||||
* global VM for BIOS calls
|
||||
*/
|
||||
struct kvm86_data *bioscallvmd;
|
||||
/* page for trampoline and stack */
|
||||
void *bioscallscratchpage;
|
||||
/* where this page is mapped in the vm86 */
|
||||
#define BIOSCALLSCRATCHPAGE_VMVA 0x1000
|
||||
|
||||
#define KVM86_IOPL3 /* not strictly necessary, saves a lot of traps */
|
||||
|
||||
void
|
||||
kvm86_init()
|
||||
{
|
||||
size_t vmdsize;
|
||||
char *buf;
|
||||
struct kvm86_data *vmd;
|
||||
struct pcb *pcb;
|
||||
int i;
|
||||
|
||||
vmdsize = round_page(sizeof(struct kvm86_data)) + NBPG;
|
||||
|
||||
buf = malloc(vmdsize, M_DEVBUF, M_NOWAIT);
|
||||
if ((u_long)buf & (NBPG - 1)) {
|
||||
printf("struct kvm86_data unaligned\n");
|
||||
return;
|
||||
}
|
||||
memset(buf, 0, vmdsize);
|
||||
/* first page is stack */
|
||||
vmd = (struct kvm86_data *)(buf + NBPG);
|
||||
pcb = &vmd->pcb;
|
||||
|
||||
/*
|
||||
* derive pcb and TSS from proc0
|
||||
* we want to access all IO ports, so we need a full-size
|
||||
* permission bitmap
|
||||
* XXX do we really need the pcb or just the TSS?
|
||||
*/
|
||||
memcpy(pcb, &proc0.p_addr->u_pcb, sizeof(struct pcb));
|
||||
pcb->pcb_tss.tss_esp0 = (int)vmd;
|
||||
pcb->pcb_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL);
|
||||
for (i = 0; i < sizeof(vmd->iomap) / 4; i++)
|
||||
vmd->iomap[i] = 0;
|
||||
pcb->pcb_tss.tss_ioopt =
|
||||
((caddr_t)vmd->iomap - (caddr_t)&pcb->pcb_tss) << 16;
|
||||
|
||||
/* setup TSS descriptor (including our iomap) */
|
||||
setsegment(&vmd->sd, &pcb->pcb_tss,
|
||||
sizeof(struct pcb) + sizeof(vmd->iomap) - 1,
|
||||
SDT_SYS386TSS, SEL_KPL, 0, 0);
|
||||
|
||||
/* prepare VM for BIOS calls */
|
||||
kvm86_mapbios(vmd);
|
||||
bioscallscratchpage = malloc(NBPG, M_DEVBUF, M_NOWAIT);
|
||||
kvm86_map(vmd, vtophys((vaddr_t)bioscallscratchpage),
|
||||
BIOSCALLSCRATCHPAGE_VMVA);
|
||||
bioscallvmd = vmd;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX pass some stuff to the assembler code
|
||||
* XXX this should be done cleanly (in call argument to kvm86_call())
|
||||
*/
|
||||
static void kvm86_prepare(struct kvm86_data *);
|
||||
static void
|
||||
kvm86_prepare(vmd)
|
||||
struct kvm86_data *vmd;
|
||||
{
|
||||
extern struct pcb *vm86pcb;
|
||||
extern int vm86tssd0, vm86tssd1;
|
||||
extern paddr_t vm86newptd;
|
||||
extern struct trapframe *vm86frame;
|
||||
extern pt_entry_t *vm86pgtableva;
|
||||
|
||||
vm86newptd = vtophys((vaddr_t)vmd) | PG_V | PG_RW | PG_U | PG_u;
|
||||
vm86pgtableva = vmd->pgtbl;
|
||||
vm86frame = (struct trapframe *)vmd - 1;
|
||||
vm86pcb = &vmd->pcb;
|
||||
vm86tssd0 = *(int*)&vmd->sd;
|
||||
vm86tssd1 = *((int*)&vmd->sd + 1);
|
||||
}
|
||||
|
||||
static void
|
||||
kvm86_map(vmd, pa, vmva)
|
||||
struct kvm86_data *vmd;
|
||||
paddr_t pa;
|
||||
u_int32_t vmva;
|
||||
{
|
||||
|
||||
vmd->pgtbl[vmva >> 12] = pa | PG_V | PG_RW | PG_U | PG_u;
|
||||
}
|
||||
|
||||
static void
|
||||
kvm86_mapbios(vmd)
|
||||
struct kvm86_data *vmd;
|
||||
{
|
||||
paddr_t pa;
|
||||
|
||||
/* map first physical page (vector table, BIOS data) */
|
||||
kvm86_map(vmd, 0, 0);
|
||||
|
||||
/* map ISA hole */
|
||||
for (pa = 0xa0000; pa < 0x100000; pa += NBPG)
|
||||
kvm86_map(vmd, pa, pa);
|
||||
}
|
||||
|
||||
void *
|
||||
kvm86_bios_addpage(vmva)
|
||||
u_int32_t vmva;
|
||||
{
|
||||
void *mem;
|
||||
|
||||
if (bioscallvmd->pgtbl[vmva >> 12]) /* allocated? */
|
||||
return (0);
|
||||
|
||||
mem = malloc(NBPG, M_DEVBUF, M_NOWAIT);
|
||||
if ((u_long)mem & (NBPG - 1)) {
|
||||
printf("kvm86_bios_addpage: unaligned");
|
||||
return (0);
|
||||
}
|
||||
kvm86_map(bioscallvmd, vtophys((vaddr_t)mem), vmva);
|
||||
|
||||
return (mem);
|
||||
}
|
||||
|
||||
void
|
||||
kvm86_bios_delpage(vmva, kva)
|
||||
u_int32_t vmva;
|
||||
void *kva;
|
||||
{
|
||||
|
||||
bioscallvmd->pgtbl[vmva >> 12] = 0;
|
||||
free(kva, M_DEVBUF);
|
||||
}
|
||||
|
||||
int
|
||||
kvm86_bioscall(intno, tf)
|
||||
int intno;
|
||||
struct trapframe *tf;
|
||||
{
|
||||
static const unsigned char call[] = {
|
||||
0xfa, /* CLI */
|
||||
0xcd, /* INTxx */
|
||||
0,
|
||||
0xfb, /* STI */
|
||||
0xf4 /* HLT */
|
||||
};
|
||||
|
||||
memcpy(bioscallscratchpage, call, sizeof(call));
|
||||
*((unsigned char *)bioscallscratchpage + 2) = intno;
|
||||
|
||||
tf->tf_eip = BIOSCALLSCRATCHPAGE_VMVA;
|
||||
tf->tf_cs = 0;
|
||||
tf->tf_esp = BIOSCALLSCRATCHPAGE_VMVA + NBPG - 2;
|
||||
tf->tf_ss = 0;
|
||||
tf->tf_eflags = PSL_USERSET | PSL_VM;
|
||||
#ifdef KVM86_IOPL3
|
||||
tf->tf_eflags |= PSL_IOPL;
|
||||
#endif
|
||||
|
||||
kvm86_prepare(bioscallvmd); /* XXX */
|
||||
return (kvm86_call(tf));
|
||||
}
|
||||
|
||||
int
|
||||
kvm86_bioscall_simple(intno, r)
|
||||
int intno;
|
||||
struct bioscallregs *r;
|
||||
{
|
||||
struct trapframe tf;
|
||||
int res;
|
||||
|
||||
memset(&tf, 0, sizeof(struct trapframe));
|
||||
tf.tf_eax = r->EAX;
|
||||
tf.tf_ebx = r->EBX;
|
||||
tf.tf_ecx = r->ECX;
|
||||
tf.tf_edx = r->EDX;
|
||||
tf.tf_esi = r->ESI;
|
||||
tf.tf_edi = r->EDI;
|
||||
tf.tf_es = r->ES;
|
||||
|
||||
res = kvm86_bioscall(intno, &tf);
|
||||
|
||||
r->EAX = tf.tf_eax;
|
||||
r->EBX = tf.tf_ebx;
|
||||
r->ECX = tf.tf_ecx;
|
||||
r->EDX = tf.tf_edx;
|
||||
r->ESI = tf.tf_esi;
|
||||
r->EDI = tf.tf_edi;
|
||||
r->ES = tf.tf_es;
|
||||
r->EFLAGS = tf.tf_eflags;
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
void
|
||||
kvm86_gpfault(tf)
|
||||
struct trapframe *tf;
|
||||
{
|
||||
unsigned char *kva, insn, trapno;
|
||||
u_int16_t *sp;
|
||||
|
||||
kva = (unsigned char *)((tf->tf_cs << 4) + tf->tf_eip);
|
||||
insn = *kva;
|
||||
#ifdef KVM86DEBUG
|
||||
printf("kvm86_gpfault: cs=%x, eip=%x, insn=%x, eflags=%x\n",
|
||||
tf->tf_cs, tf->tf_eip, insn, tf->tf_eflags);
|
||||
#endif
|
||||
|
||||
KASSERT(tf->tf_eflags & PSL_VM);
|
||||
|
||||
switch (insn) {
|
||||
case 0xf4: /* HLT - normal exit */
|
||||
kvm86_ret(tf, 0);
|
||||
break;
|
||||
case 0xcd: /* INTxx */
|
||||
/* fake a return stack frame and call real mode handler */
|
||||
trapno = *(kva + 1);
|
||||
sp = (u_int16_t *)((tf->tf_ss << 4) + tf->tf_esp);
|
||||
*(--sp) = tf->tf_eflags;
|
||||
*(--sp) = tf->tf_cs;
|
||||
*(--sp) = tf->tf_eip + 2;
|
||||
tf->tf_esp -= 6;
|
||||
tf->tf_cs = *(u_int16_t *)(trapno * 4 + 2);
|
||||
tf->tf_eip = *(u_int16_t *)(trapno * 4);
|
||||
break;
|
||||
case 0xcf: /* IRET */
|
||||
sp = (u_int16_t *)((tf->tf_ss << 4) + tf->tf_esp);
|
||||
tf->tf_eip = *(sp++);
|
||||
tf->tf_cs = *(sp++);
|
||||
tf->tf_eflags = *(sp++);
|
||||
tf->tf_esp += 6;
|
||||
tf->tf_eflags |= PSL_VM; /* outside of 16bit flag reg */
|
||||
break;
|
||||
#ifndef KVM86_IOPL3 /* XXX check VME? */
|
||||
case 0xfa: /* CLI */
|
||||
case 0xfb: /* STI */
|
||||
/* XXX ignore for now */
|
||||
tf->tf_eip++;
|
||||
break;
|
||||
case 0x9c: /* PUSHF */
|
||||
sp = (u_int16_t *)((tf->tf_ss << 4) + tf->tf_esp);
|
||||
*(--sp) = tf->tf_eflags;
|
||||
tf->tf_esp -= 2;
|
||||
tf->tf_eip++;
|
||||
break;
|
||||
case 0x9d: /* POPF */
|
||||
sp = (u_int16_t *)((tf->tf_ss << 4) + tf->tf_esp);
|
||||
tf->tf_eflags = *(sp++);
|
||||
tf->tf_esp += 2;
|
||||
tf->tf_eip++;
|
||||
tf->tf_eflags |= PSL_VM; /* outside of 16bit flag reg */
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
#ifdef KVM86DEBUG
|
||||
printf("kvm86_gpfault: unhandled\n");
|
||||
#else
|
||||
printf("kvm86_gpfault: cs=%x, eip=%x, insn=%x, eflags=%x\n",
|
||||
tf->tf_cs, tf->tf_eip, insn, tf->tf_eflags);
|
||||
#endif
|
||||
/*
|
||||
* signal error to caller
|
||||
*/
|
||||
kvm86_ret(tf, -1);
|
||||
break;
|
||||
}
|
||||
}
|
183
sys/arch/i386/i386/kvm86call.s
Normal file
183
sys/arch/i386/i386/kvm86call.s
Normal file
@ -0,0 +1,183 @@
|
||||
/* $NetBSD: kvm86call.s,v 1.1 2002/07/07 12:56:34 drochner Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1998 Jonathan Lemon
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2002
|
||||
* Matthias Drochner. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD: src/sys/i386/i386/vm86bios.s,v 1.28 2001/12/11 23:33:40 jhb Exp $
|
||||
*/
|
||||
|
||||
#include <machine/param.h>
|
||||
#include <machine/asm.h>
|
||||
|
||||
#include "assym.h"
|
||||
|
||||
__KERNEL_RCSID(0, "$NetBSD: kvm86call.s,v 1.1 2002/07/07 12:56:34 drochner Exp $");
|
||||
|
||||
.data
|
||||
.align 4
|
||||
|
||||
/* flag for trap() */
|
||||
.globl kvm86_incall
|
||||
kvm86_incall: .long 0
|
||||
|
||||
/* XXX arguments for kvm86call() */
|
||||
.globl vm86pcb, vm86newptd, vm86frame, vm86pgtableva
|
||||
.globl vm86tssd0, vm86tssd1
|
||||
vm86pcb: .long 0
|
||||
vm86newptd: .long 0
|
||||
vm86frame: .long 0
|
||||
vm86pgtableva: .long 0
|
||||
vm86tssd0: .long 0
|
||||
vm86tssd1: .long 0
|
||||
|
||||
/* locals */
|
||||
SCRARGFRAME: .long 0
|
||||
SCRSTACK: .long 0
|
||||
SCRTSS0: .long 0
|
||||
SCRTSS1: .long 0
|
||||
|
||||
.text
|
||||
|
||||
/* int kvm86_call(struct trapframe *) */
|
||||
ENTRY(kvm86_call)
|
||||
pushl %ebp
|
||||
movl %esp,%ebp /* set up frame ptr */
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
pushl %ebx
|
||||
pushl %fs
|
||||
pushl %gs
|
||||
|
||||
movl 8(%ebp),%eax
|
||||
movl %eax,SCRARGFRAME /* save argument pointer */
|
||||
|
||||
movl vm86frame,%edi /* target frame location */
|
||||
movl SCRARGFRAME,%esi /* source (set on entry) */
|
||||
movl $FRAMESIZE/4,%ecx /* sizeof(struct trapframe)/4 */
|
||||
cld
|
||||
rep
|
||||
movsl /* copy frame to new stack */
|
||||
|
||||
movl _C_LABEL(curproc),%ecx
|
||||
movl P_ADDR(%ecx),%eax
|
||||
pushl %eax /* save curpcb */
|
||||
movl vm86pcb,%eax
|
||||
movl %eax,P_ADDR(%ecx) /* set curpcb to vm86pcb */
|
||||
|
||||
movl _C_LABEL(gdt),%eax
|
||||
movl P_MD_TSS_SEL(%ecx),%edi
|
||||
|
||||
andl $~0x0200,4(%eax,%edi,1) /* reset "task busy" */
|
||||
|
||||
movl 0(%eax,%edi,1),%edx
|
||||
movl %edx,SCRTSS0 /* save first word */
|
||||
movl 4(%eax,%edi,1),%edx
|
||||
movl %edx,SCRTSS1 /* save second word */
|
||||
|
||||
movl vm86tssd0,%edx /* vm86 tssd entry */
|
||||
movl %edx,0(%eax,%edi,1)
|
||||
movl vm86tssd1,%edx /* vm86 tssd entry */
|
||||
movl %edx,4(%eax,%edi,1)
|
||||
ltr %di
|
||||
|
||||
movl %cr3,%eax
|
||||
pushl %eax /* save address space */
|
||||
movl PTDpaddr,%ecx
|
||||
movl %ecx,%ebx
|
||||
addl $KERNBASE,%ebx /* va of Idle PTD */
|
||||
movl 0(%ebx),%eax
|
||||
pushl %eax /* old pde */
|
||||
pushl %ebx /* keep address for reuse */
|
||||
|
||||
movl %esp,SCRSTACK /* save current stack location */
|
||||
|
||||
movl vm86newptd,%eax /* mapping for vm86 page table */
|
||||
movl %eax,0(%ebx) /* ... install as PTD entry 0 */
|
||||
|
||||
movl %ecx,%cr3 /* new page tables */
|
||||
movl vm86frame,%esp /* switch to new stack */
|
||||
|
||||
movl $1,kvm86_incall /* set flag for trap() */
|
||||
|
||||
/* INTRFASTEXIT */
|
||||
popl %gs
|
||||
popl %fs
|
||||
popl %es
|
||||
popl %ds
|
||||
popl %edi
|
||||
popl %esi
|
||||
popl %ebp
|
||||
popl %ebx
|
||||
popl %edx
|
||||
popl %ecx
|
||||
popl %eax
|
||||
addl $8,%esp
|
||||
iret
|
||||
|
||||
|
||||
/* void kvm86_ret(struct trapframe *, int) */
|
||||
ENTRY(kvm86_ret)
|
||||
pushl %ebp
|
||||
movl %esp,%ebp /* set up frame ptr */
|
||||
|
||||
movl 8(%ebp),%esi /* source */
|
||||
movl SCRARGFRAME,%edi /* destination */
|
||||
movl $FRAMESIZE/4,%ecx /* size */
|
||||
cld
|
||||
rep
|
||||
movsl /* copy frame to original frame */
|
||||
|
||||
movl SCRSTACK,%esp /* back to old stack */
|
||||
popl %ebx /* saved va of Idle PTD */
|
||||
popl %eax
|
||||
movl %eax,0(%ebx) /* restore old pde */
|
||||
popl %eax
|
||||
movl %eax,%cr3 /* install old page table */
|
||||
|
||||
movl $0,kvm86_incall /* reset trapflag */
|
||||
|
||||
movl _C_LABEL(gdt),%eax
|
||||
movl _C_LABEL(curproc),%ecx
|
||||
movl P_MD_TSS_SEL(%ecx),%edi
|
||||
movl SCRTSS0, %edx
|
||||
movl %edx, 0(%eax,%edi,1) /* restore first word */
|
||||
movl SCRTSS1, %edx
|
||||
movl %edx, 4(%eax,%edi,1) /* restore second word */
|
||||
ltr %di
|
||||
|
||||
popl %eax /* restore curpcb */
|
||||
movl %eax, P_ADDR(%ecx)
|
||||
|
||||
movl 12(%ebp), %eax /* will be kvm86_call()'s retval */
|
||||
|
||||
popl %gs
|
||||
popl %fs
|
||||
popl %ebx
|
||||
popl %edi
|
||||
popl %esi
|
||||
popl %ebp
|
||||
ret /* back to kvm86_call()'s caller */
|
13
sys/arch/i386/include/kvm86.h
Normal file
13
sys/arch/i386/include/kvm86.h
Normal file
@ -0,0 +1,13 @@
|
||||
/* $NetBSD: kvm86.h,v 1.1 2002/07/07 12:56:34 drochner Exp $ */
|
||||
|
||||
void kvm86_init(void);
|
||||
void kvm86_gpfault(struct trapframe *);
|
||||
extern int kvm86_incall;
|
||||
|
||||
void *kvm86_bios_addpage(u_int32_t);
|
||||
void kvm86_bios_delpage(u_int32_t, void *);
|
||||
int kvm86_bioscall(int, struct trapframe *);
|
||||
|
||||
/* for migration from bioscall() */
|
||||
#include <machine/bioscall.h>
|
||||
int kvm86_bioscall_simple(int, struct bioscallregs *);
|
Loading…
Reference in New Issue
Block a user