These files constitute the interface between bochs and the plex86

kernel driver.  I'll upload the minor mods for bochs to use
  this interface after we pull out of the 2.0 release mode.
This commit is contained in:
Kevin Lawton 2003-01-01 17:34:09 +00:00
parent 0768d01522
commit ac964e019a
2 changed files with 486 additions and 0 deletions

446
bochs/plex86-interface.cc Normal file
View File

@ -0,0 +1,446 @@
/////////////////////////////////////////////////////////////////////////
//// $Id: plex86-interface.cc,v 1.1 2003-01-01 17:34:09 kevinlawton Exp $
///////////////////////////////////////////////////////////////////////////
////
//// Copyright (C) 2002 Kevin P. Lawton
////
//// This library is free software; you can redistribute it and/or
//// modify it under the terms of the GNU Lesser General Public
//// License as published by the Free Software Foundation; either
//// version 2 of the License, or (at your option) any later version.
////
//// This library is distributed in the hope that it will be useful,
//// but WITHOUT ANY WARRANTY; without even the implied warranty of
//// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//// Lesser General Public License for more details.
////
//// You should have received a copy of the GNU Lesser General Public
//// License along with this library; if not, write to the Free Software
//// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "bochs.h"
#include <sys/ioctl.h>
#include <unistd.h>
#include <sys/mman.h>
#include "plex86-interface.h"
#define LOG_THIS genlog->
unsigned plex86State = 0;
int plex86FD = -1;
Bit8u *plex86MemPtr = 0;
size_t plex86MemSize = 0;
Bit8u *plex86PrintBuffer = 0;
guest_cpu_t *plex86GuestCPU = 0;
static void copyPlex86StateToBochs(BX_CPU_C *cpu);
static void copyBochsDescriptorToPlex86(descriptor_t *, bx_descriptor_t *);
static void copyPlex86DescriptorToBochs(BX_CPU_C *,
bx_descriptor_t *, descriptor_t *);
static unsigned faultCount[32];
int
plex86Open(void)
{
cpuid_info_t bochsCPUID;
if (plex86State) {
// This should be the first operation; no state should be set yet.
fprintf(stderr, "plex86Open: plex86State = 0x%x\n", plex86State);
return(-1); // Error.
}
// Open a new VM.
fprintf(stderr, "Opening VM.\n");
fprintf(stderr, "Trying /dev/misc/plex86...");
plex86FD = open("/dev/misc/plex86", O_RDWR);
if (plex86FD >= 0) {
fprintf(stderr, "OK.\n");
}
else {
fprintf(stderr, "failed.\n");
// Try the old name.
fprintf(stderr, "Trying /dev/plex86...");
plex86FD = open("/dev/plex86", O_RDWR);
if (plex86FD >= 0) {
fprintf(stderr, "OK.\n");
}
else {
fprintf(stderr, "failed.\n");
fprintf(stderr, "Did you load the kernel module?"
" Read the toplevel README file!\n");
perror ("open");
return(-1); // Error.
}
}
fprintf(stderr, "Zeroing guest CPUID info (complete this).\n");
memset(&bochsCPUID, 0, sizeof(bochsCPUID));
// xxx Fill in CPUID info here.
fprintf(stderr, "Passing guest CPUID to plex86.\n");
if ( ioctl(plex86FD, PLEX86_CPUID, &bochsCPUID) ) {
perror("ioctl CPUID: ");
return(-1); // Error.
}
return(plex86FD); // File descriptor is return val.
}
Bit8u *
plex86AllocateMemory(unsigned nMegs)
{
Bit8u *ptr;
plex86MemSize = nMegs * 1024 * 1024;
if (plex86FD < 0) {
fprintf(stderr, "plex86AllocateMemory: FD not open.\n");
return(0);
}
// Allocate memory from the host OS for the virtual physical memory.
fprintf(stderr, "Allocating %dMB of physical memory in VM.\n", nMegs);
if (ioctl(plex86FD, PLEX86_ALLOCVPHYS, nMegs) == -1) {
perror("ioctl ALLOCVPHYS: ");
plex86TearDown();
return(0);
}
plex86State |= Plex86StateMemAllocated;
// Map guest virtual physical memory into user address space and zero it.
fprintf(stderr, "Mapping virtualized physical memory into monitor.\n");
ptr = (Bit8u*) mmap(NULL, plex86MemSize, PROT_READ | PROT_WRITE,
MAP_SHARED, plex86FD, 0);
if (ptr == (void *) -1) {
perror("mmap of physical pages");
plex86TearDown();
return(0);
}
plex86State |= Plex86StateMMapPhyMem;
plex86MemPtr = ptr;
// No need to zero physical memory. It's zeroed by the plex86 module.
// Create a memory mapping of the monitor's print buffer into
// user memory. This is used for efficient printing of info that
// the monitor prints out.
fprintf(stderr, "Mapping monitor print buffer into user mem.\n");
plex86PrintBuffer = (Bit8u*) mmap(NULL, 4096, PROT_READ,
MAP_SHARED, plex86FD, plex86MemSize + 0*4096);
if (plex86PrintBuffer == (void *) -1) {
perror("mmap of monitor print buffer");
plex86TearDown();
return(0);
}
plex86State |= Plex86StateMMapPrintBuffer;
// Create a memory mapping of the monitor's guest_cpu structure into
// user memory. This is used for passing the guest_cpu state between
// user and kernel/monitor space.
fprintf(stderr, "Mapping guest_cpu structure into user mem.\n");
plex86GuestCPU = (guest_cpu_t *) mmap(NULL, 4096, PROT_READ | PROT_WRITE,
MAP_SHARED, plex86FD, plex86MemSize + 1*4096);
if (plex86GuestCPU == (void *) -1) {
perror("mmap of guest_cpu structure");
plex86TearDown();
return(0);
}
plex86State |= Plex86StateMMapGuestCPU;
// No need to zero guest_cpu structure. Kernel module does that.
return(ptr);
}
unsigned
plex86TearDown(void)
{
fprintf(stderr, "plex86TearDown called.\n");
fprintf(stderr, "Guest Fault Count (FYI):\n");
for (unsigned f=0; f<32; f++) {
if (faultCount[f])
fprintf(stderr, "FC[%u] = %u\n", f, faultCount[f]);
}
if ( plex86FD < 0 ) {
fprintf(stderr, "plex86TearDown: FD not open.\n");
return(0);
}
if ( plex86State & Plex86StateMMapPhyMem ) {
fprintf(stderr, "Unmapping guest physical memory.\n");
if (munmap(plex86MemPtr, plex86MemSize) != 0) {
perror ("munmap of guest physical memory");
return(0); // Failed.
}
}
plex86State &= ~Plex86StateMMapPhyMem;
if ( plex86State & Plex86StateMMapPrintBuffer ) {
fprintf(stderr, "Unmapping print buffer.\n");
if (munmap(plex86PrintBuffer, 4096) != 0) {
perror("munmap of print buffer.");
return(0); // Failed.
}
}
plex86State &= ~Plex86StateMMapPrintBuffer;
if ( plex86State & Plex86StateMMapGuestCPU ) {
fprintf(stderr, "Unmapping guest_cpu structure.\n");
if (munmap(plex86GuestCPU, 4096) != 0) {
perror("munmap of guest_cpu structure.");
return(0); // Failed.
}
}
plex86State &= ~Plex86StateMMapGuestCPU;
fprintf(stderr, "Tearing down VM.\n");
if (ioctl(plex86FD, PLEX86_TEARDOWN, 0) == -1) {
perror("ioctl TEARDOWN: ");
return(0); // Failed.
}
plex86State &= ~Plex86StateMemAllocated;
// Close the connection to the kernel module.
fprintf(stderr, "Closing VM device.\n");
if (close(plex86FD) == -1) {
perror("close of VM device\n");
return(0); // Failed.
}
plex86State = 0; // For good measure.
return(1); // OK.
}
unsigned
plex86ExecuteInVM(BX_CPU_C *cpu)
{
plex86IoctlExecute_t executeMsg;
int ret;
if ( plex86State != Plex86StateReady ) {
fprintf(stderr, "plex86ExecuteInVM: not in ready state (0x%x)\n",
plex86State);
BX_PANIC(("plex86ExecuteInVM: bailing"));
return(0);
}
executeMsg.executeMethod = Plex86ExecuteMethodNative;
plex86GuestCPU->edi = cpu->gen_reg[BX_32BIT_REG_EDI].dword.erx;
plex86GuestCPU->esi = cpu->gen_reg[BX_32BIT_REG_ESI].dword.erx;
plex86GuestCPU->ebp = cpu->gen_reg[BX_32BIT_REG_EBP].dword.erx;
plex86GuestCPU->esp = cpu->gen_reg[BX_32BIT_REG_ESP].dword.erx;
plex86GuestCPU->ebx = cpu->gen_reg[BX_32BIT_REG_EBX].dword.erx;
plex86GuestCPU->edx = cpu->gen_reg[BX_32BIT_REG_EDX].dword.erx;
plex86GuestCPU->ecx = cpu->gen_reg[BX_32BIT_REG_ECX].dword.erx;
plex86GuestCPU->eax = cpu->gen_reg[BX_32BIT_REG_EAX].dword.erx;
plex86GuestCPU->eflags = cpu->eflags.val32;
plex86GuestCPU->eip = cpu->dword.eip;
// ES/CS/SS/DS/FS/GS
for (unsigned s=0; s<6; s++) {
plex86GuestCPU->sreg[s].sel.raw = cpu->sregs[s].selector.value;
copyBochsDescriptorToPlex86(&plex86GuestCPU->sreg[s].des,
&cpu->sregs[s].cache);
plex86GuestCPU->sreg[s].valid = cpu->sregs[s].cache.valid;
}
// LDTR
plex86GuestCPU->ldtr.sel.raw = cpu->ldtr.selector.value;
copyBochsDescriptorToPlex86(&plex86GuestCPU->ldtr.des, &cpu->ldtr.cache);
plex86GuestCPU->ldtr.valid = cpu->ldtr.cache.valid;
// TR
plex86GuestCPU->tr.sel.raw = cpu->tr.selector.value;
copyBochsDescriptorToPlex86(&plex86GuestCPU->tr.des, &cpu->tr.cache);
plex86GuestCPU->tr.valid = cpu->tr.cache.valid;
// GDTR/IDTR
plex86GuestCPU->gdtr.base = cpu->gdtr.base;
plex86GuestCPU->gdtr.limit = cpu->gdtr.limit;
plex86GuestCPU->idtr.base = cpu->idtr.base;
plex86GuestCPU->idtr.limit = cpu->idtr.limit;
plex86GuestCPU->dr0 = cpu->dr0;
plex86GuestCPU->dr1 = cpu->dr1;
plex86GuestCPU->dr2 = cpu->dr2;
plex86GuestCPU->dr3 = cpu->dr3;
plex86GuestCPU->dr6 = cpu->dr6;
plex86GuestCPU->dr7 = cpu->dr7;
plex86GuestCPU->tr3 = 0; // Unimplemented in bochs.
plex86GuestCPU->tr4 = 0; // Unimplemented in bochs.
plex86GuestCPU->tr5 = 0; // Unimplemented in bochs.
plex86GuestCPU->tr6 = 0; // Unimplemented in bochs.
plex86GuestCPU->tr7 = 0; // Unimplemented in bochs.
plex86GuestCPU->cr0.raw = cpu->cr0.val32;
plex86GuestCPU->cr1 = cpu->cr1;
plex86GuestCPU->cr2 = cpu->cr2;
plex86GuestCPU->cr3 = cpu->cr3;
plex86GuestCPU->cr4.raw = cpu->cr4.registerValue;
plex86GuestCPU->a20Enable = BX_GET_ENABLE_A20();
ret = ioctl(plex86FD, PLEX86_EXECUTE, &executeMsg);
if (ret < 0) {
fprintf(stderr, "ioctl(PLEX86_EXECUTE) returns < 0\n");
}
else
switch ( executeMsg.monitorState.request ) {
case MonReqFlushPrintBuf:
fprintf(stderr, "MonReqFlushPrintBuf:\n");
fprintf(stderr, "::%s\n", plex86PrintBuffer);
break;
case MonReqPanic:
fprintf(stderr, "MonReqPanic:\n");
fprintf(stderr, "::%s\n", plex86PrintBuffer);
break;
//case MonReqNone:
// copyPlex86StateToBochs(cpu);
// return(0); /* All OK. */
case MonReqGuestFault:
faultCount[ executeMsg.monitorState.guestFaultNo ]++;
copyPlex86StateToBochs(cpu);
return(0); /* All OK. */
default:
fprintf(stderr, "executeMsg.request = %u\n",
executeMsg.monitorState.request);
break;
}
plex86TearDown();
BX_PANIC(("plex86ExecuteInVM: bailing"));
return(0);
}
void
copyPlex86StateToBochs(BX_CPU_C *cpu)
{
cpu->gen_reg[BX_32BIT_REG_EDI].dword.erx = plex86GuestCPU->edi;
cpu->gen_reg[BX_32BIT_REG_ESI].dword.erx = plex86GuestCPU->esi;
cpu->gen_reg[BX_32BIT_REG_EBP].dword.erx = plex86GuestCPU->ebp;
cpu->gen_reg[BX_32BIT_REG_ESP].dword.erx = plex86GuestCPU->esp;
cpu->gen_reg[BX_32BIT_REG_EBX].dword.erx = plex86GuestCPU->ebx;
cpu->gen_reg[BX_32BIT_REG_EDX].dword.erx = plex86GuestCPU->edx;
cpu->gen_reg[BX_32BIT_REG_ECX].dword.erx = plex86GuestCPU->ecx;
cpu->gen_reg[BX_32BIT_REG_EAX].dword.erx = plex86GuestCPU->eax;
cpu->eflags.val32 = plex86GuestCPU->eflags;
cpu->dword.eip = plex86GuestCPU->eip;
// Set fields used for exception processing.
cpu->prev_eip = plex86GuestCPU->eip;
cpu->prev_esp = plex86GuestCPU->esp;
// ES/CS/SS/DS/FS/GS
for (unsigned s=0; s<6; s++) {
cpu->sregs[s].selector.value = plex86GuestCPU->sreg[s].sel.raw;
cpu->sregs[s].cache.valid = plex86GuestCPU->sreg[s].valid;
if ( (cpu->sregs[s].selector.value & 0xfffc) == 0 ) {
/* Null selector. */
if ( cpu->sregs[s].cache.valid ) {
plex86TearDown();
BX_PANIC(("copyPlex86StateToBochs: null descriptor [%u] "
"with descriptor cache valid bit set.", s));
}
/* valid bit == 0, invalidates a bochs descriptor cache. */
}
else {
/* Non-null selector. */
if ( cpu->sregs[s].cache.valid==0 ) {
plex86TearDown();
BX_PANIC(("copyPlex86StateToBochs: non-null descriptor [%u] "
"with descriptor cache valid bit clear.", s));
}
copyPlex86DescriptorToBochs(cpu, &cpu->sregs[s].cache,
&plex86GuestCPU->sreg[s].des);
}
}
}
void
copyBochsDescriptorToPlex86(descriptor_t *plex86Desc, bx_descriptor_t *bochsDesc)
{
// For now this function is a hack to convert from bochs descriptor
// cache fields which are parsed out into separate fields, to
// a packed descriptor format as stored in a real segment descriptor.
// This is user only for code/data segments and the LDTR/TR.
// Ideally, bochs would store the 64-bit segment descriptor when
// it loads segment registers.
if (bochsDesc->valid == 0) {
memset(plex86Desc, 0, sizeof(*plex86Desc));
return;
}
plex86Desc->p = bochsDesc->p;
plex86Desc->dpl = bochsDesc->dpl;
plex86Desc->type = (bochsDesc->segment<<4) | bochsDesc->type;
if (bochsDesc->segment) {
// Code/Data segment type.
Bit32u limit = bochsDesc->u.segment.limit;
plex86Desc->limit_low = limit; // Only lower 16-bits.
plex86Desc->limit_high = limit >> 16;
Bit32u base = bochsDesc->u.segment.base;
plex86Desc->base_low = base;
plex86Desc->base_med = base >> 16;
plex86Desc->base_high = base >> 24;
plex86Desc->avl = bochsDesc->u.segment.avl;
plex86Desc->reserved = 0;
plex86Desc->d_b = bochsDesc->u.segment.d_b;
plex86Desc->g = bochsDesc->u.segment.g;
}
else if (bochsDesc->type == 2) {
// LDT descriptor.
plex86Desc->limit_low = bochsDesc->u.ldt.limit;
plex86Desc->limit_high = 0;
Bit32u base = bochsDesc->u.ldt.base;
plex86Desc->base_low = base;
plex86Desc->base_med = base >> 16;
plex86Desc->base_high = base >> 24;
plex86Desc->avl = 0;
plex86Desc->reserved = 0;
plex86Desc->d_b = 0;
plex86Desc->g = 0;
}
else if ( (bochsDesc->type == 9) || (bochsDesc->type==1) ) {
// TSS
Bit32u limit = bochsDesc->u.tss386.limit;
plex86Desc->limit_low = limit; // Only lower 16-bits.
plex86Desc->limit_high = limit >> 16;
Bit32u base = bochsDesc->u.tss386.base;
plex86Desc->base_low = base;
plex86Desc->base_med = base >> 16;
plex86Desc->base_high = base >> 24;
plex86Desc->avl = bochsDesc->u.tss386.avl;
plex86Desc->reserved = 0;
plex86Desc->d_b = 0;
plex86Desc->g = bochsDesc->u.tss386.g;
}
else {
BX_PANIC(("copyBochsDescriptorToPlex86: desc type = %u.",
bochsDesc->type));
}
}
void
copyPlex86DescriptorToBochs(BX_CPU_C *cpu,
bx_descriptor_t *bochsDesc, descriptor_t *plex86Desc)
{
Bit32u dword1, dword2, *dwordPtr;
dwordPtr = (Bit32u *) plex86Desc;
/* We can assume little endian, since we're running an x86 VM. */
dword1 = dwordPtr[0];
dword2 = dwordPtr[1];
cpu->parse_descriptor(dword1, dword2, bochsDesc);
}

40
bochs/plex86-interface.h Normal file
View File

@ -0,0 +1,40 @@
/////////////////////////////////////////////////////////////////////////
//// $Id: plex86-interface.h,v 1.1 2003-01-01 17:34:09 kevinlawton Exp $
///////////////////////////////////////////////////////////////////////////
////
//// Copyright (C) 2002 Kevin P. Lawton
////
//// This library is free software; you can redistribute it and/or
//// modify it under the terms of the GNU Lesser General Public
//// License as published by the Free Software Foundation; either
//// version 2 of the License, or (at your option) any later version.
////
//// This library is distributed in the hope that it will be useful,
//// but WITHOUT ANY WARRANTY; without even the implied warranty of
//// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//// Lesser General Public License for more details.
////
//// You should have received a copy of the GNU Lesser General Public
//// License along with this library; if not, write to the Free Software
//// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "plex86/plex86.h"
#define Plex86StateMemAllocated 0x01
#define Plex86StateMMapPhyMem 0x02
#define Plex86StateMMapPrintBuffer 0x04
#define Plex86StateMMapGuestCPU 0x08
#define Plex86StateReady 0x0f /* All bits set. */
extern unsigned plex86State;
extern int plex86FD;
extern Bit8u *plex86MemPtr;
extern unsigned plex86MemSize;
extern Bit8u *plex86PrintBuffer;
extern guest_cpu_t *plex86GuestCPU;
extern int plex86Open(void);
extern unsigned char * plex86AllocateMemory(unsigned nMegs);
extern unsigned plex86TearDown(void);
extern unsigned plex86ExecuteInVM(BX_CPU_C *cpu);