Fail* directories reorganized, Code-cleanup (-> coding-style), Typos+comments fixed.
git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1321 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
306
simulators/bochs/plex86/kernel/fault-mon.c
Normal file
306
simulators/bochs/plex86/kernel/fault-mon.c
Normal file
@ -0,0 +1,306 @@
|
||||
/*
|
||||
* plex86: run multiple x86 operating systems concurrently
|
||||
* Copyright (C) 1999-2003 Kevin P. Lawton
|
||||
*
|
||||
* fault-mon.c: fault/int handlers for VM monitor - monitor space.
|
||||
*
|
||||
* 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.h"
|
||||
#define IN_MONITOR_SPACE
|
||||
#include "monitor.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* The monitor stack frame. When an exception or interrupt occurrs
|
||||
* during the execution of either guest or monitor code, the following
|
||||
* values are pushed.
|
||||
*
|
||||
* ss
|
||||
* esp
|
||||
* eflags Values pushed by the CPU and interrupt stub. To simplify
|
||||
* cs things, the stub pushes an error of zero for those
|
||||
* eip events which don't naturally cause an error push, and
|
||||
* error also pushes the vector of the exception/interrupt.
|
||||
* vector
|
||||
*
|
||||
* eax
|
||||
* ecx
|
||||
* edx General registers, pushed with a PUSHA instruction,
|
||||
* ebx by code below.
|
||||
* <esp>
|
||||
* ebp
|
||||
* esi
|
||||
* edi
|
||||
*
|
||||
* es
|
||||
* ds Segment selectors, pushed by code below.
|
||||
* fs
|
||||
* gs
|
||||
*/
|
||||
|
||||
void handleMonFault(guest_context_t *monContext);
|
||||
|
||||
static inline
|
||||
Bit32u readCR2(void)
|
||||
{
|
||||
Bit32u cr2;
|
||||
asm volatile ("movl %%cr2, %0" : "=r" (cr2));
|
||||
return( cr2 );
|
||||
}
|
||||
|
||||
|
||||
asm (
|
||||
".text \n\t"
|
||||
|
||||
/* __handle_fault: This is called by all of the monitor's fault handler
|
||||
* stubs. A fault could have originated from execution of the guest
|
||||
* (due to virtualization conditions or natural fault generation) or
|
||||
* from the monitor (currently only due to bugs in the monitor).
|
||||
*/
|
||||
".globl __handle_fault \n\t"
|
||||
"__handle_fault: \n\t"
|
||||
" pushal \n\t" /* Save general registers */
|
||||
" pushl %es \n\t" /* Save segment registers */
|
||||
" pushl %ds \n\t"
|
||||
" pushl %fs \n\t"
|
||||
" pushl %gs \n\t"
|
||||
" movl 60(%esp), %eax \n\t" /* CS pushed by CPU from fault */
|
||||
" andl $3, %eax \n\t" /* Check CS.RPL bits */
|
||||
" jz __fault_from_mon \n\t" /* RPL0 means from monitor */
|
||||
|
||||
/* We have determined that the fault was from guest code. Prepare
|
||||
* to call the monitor C code to do most of the fault handling.
|
||||
*/
|
||||
"__fault_from_guest: \n\t"
|
||||
" movl %ss, %eax \n\t" /* Copy SS into DS/ES */
|
||||
" movl %eax, %ds \n\t"
|
||||
" movl %eax, %es \n\t"
|
||||
" cld \n\t" /* gcc-compiled code needs this */
|
||||
" pushl %esp \n\t" /* Push pointer to saved guest context for C call.*/
|
||||
" call handleGuestFault\n\t" /* Call the C monitor fault handler. */
|
||||
" addl $4, %esp \n\t" /* Remove arg from stack. */
|
||||
".globl __ret_to_guest \n\t" /* Fault handled, work back to guest. */
|
||||
"__ret_to_guest: \n\t"
|
||||
/* Return to the guest. Restore registers from the monitor stack. */
|
||||
" popl %gs \n\t" /* Restore guest segments */
|
||||
" popl %fs \n\t"
|
||||
" popl %ds \n\t"
|
||||
" popl %es \n\t"
|
||||
" popal \n\t" /* Restore guest general registers */
|
||||
" addl $8, %esp \n\t" /* Ignore vector and error dwords */
|
||||
" iret \n\t" /* Resume execution of guest */
|
||||
|
||||
|
||||
"__fault_from_mon: \n\t"
|
||||
" cld \n\t" /* gcc-compiled code needs this */
|
||||
" pushl %esp \n\t" /* Push pointer to context. */
|
||||
" call handleMonFault \n\t" /* Call C code for real work */
|
||||
" addl $4, %esp \n\t"
|
||||
/* Return to monitor. Restore state from the monitor stack. */
|
||||
"__ret_to_monitor: \n\t"
|
||||
" popl %gs \n\t" /* Restore monitor segments */
|
||||
" popl %fs \n\t"
|
||||
" popl %ds \n\t"
|
||||
" popl %es \n\t"
|
||||
" popal \n\t" /* Restore monitor general registers */
|
||||
" addl $8, %esp \n\t" /* ignore vector and error dwords */
|
||||
" iret \n\t" /* Resume execution of monitor */
|
||||
|
||||
|
||||
/*
|
||||
* Hardware interrupt handler stub
|
||||
*/
|
||||
".globl __handle_int \n\t" /* Return to monitor code */
|
||||
"__handle_int: \n\t"
|
||||
" pushal \n\t" /* Save guest general registers */
|
||||
" pushl %es \n\t" /* Save guest segment registers */
|
||||
" pushl %ds \n\t"
|
||||
" pushl %fs \n\t"
|
||||
" pushl %gs \n\t"
|
||||
|
||||
" movl %ss, %eax \n\t" /* Copy SS into DS/ES */
|
||||
" movl %eax, %ds \n\t"
|
||||
" movl %eax, %es \n\t"
|
||||
" cld \n\t" /* gcc-compiled code needs this */
|
||||
" pushl %esp \n\t"
|
||||
" call handleInt \n\t" /* monitor interrupt handler */
|
||||
" addl $4, %esp \n\t"
|
||||
" cmpl $0x1, %eax \n\t" /* Was interrupt generated from monitor code? */
|
||||
" je __ret_to_monitor\n\t" /* Yes, so return to monitor code */
|
||||
" jmp __ret_to_guest \n\t" /* No, so return to guest code */
|
||||
);
|
||||
|
||||
|
||||
|
||||
unsigned
|
||||
handleInt(guest_context_t *context)
|
||||
/*
|
||||
* handleInt(): Redirect a hardware interrupt back to the host
|
||||
*/
|
||||
{
|
||||
nexus_t *nexus = (nexus_t *) (((Bit32u) context) & 0xfffff000);
|
||||
vm_t *vm = (vm_t *) nexus->vm;
|
||||
unsigned from_monitor;
|
||||
Bit64u t1;
|
||||
|
||||
t1 = vm_rdtsc();
|
||||
|
||||
if ( (context->cs & 0x0003) == 0x0003 ) {
|
||||
/* End of elapsed guest execution duration. Add elapsed */
|
||||
/* cycles to time framework. */
|
||||
vm->system.cyclesElapsed += (t1 - vm->system.t0);
|
||||
|
||||
from_monitor = 0; /* Event from guest code */
|
||||
}
|
||||
else {
|
||||
from_monitor = 1; /* Event from monitor code */
|
||||
}
|
||||
|
||||
/* Interrupts are off naturally here. */
|
||||
vm->mon_request = MonReqRedirect;
|
||||
vm->redirect_vector = context->vector;
|
||||
vm->guest.__mon2host();
|
||||
return(from_monitor);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
handleGuestFault(guest_context_t *context)
|
||||
/* Handle a fault from the guest. Called from the assembly stub
|
||||
* __handle_fault.
|
||||
*/
|
||||
{
|
||||
nexus_t *nexus = (nexus_t *) (((Bit32u) context) & 0xfffff000);
|
||||
vm_t *vm = (vm_t *) nexus->vm;
|
||||
Bit32u cr2 = readCR2();
|
||||
Bit64u t1;
|
||||
|
||||
/* End of elapsed guest execution duration */
|
||||
t1 = vm_rdtsc();
|
||||
vm->system.cyclesElapsed += (t1 - vm->system.t0);
|
||||
|
||||
#warning "Delete these checks"
|
||||
#if ANAL_CHECKS
|
||||
if ( !context->eflags.fields.if_ )
|
||||
monpanic(vm, "handleGuestFault: guest IF=0.\n");
|
||||
if ( context->eflags.fields.vm )
|
||||
monpanic(vm, "handleGuestFault: eflags.VM=1.\n");
|
||||
#endif
|
||||
|
||||
STI();
|
||||
|
||||
switch ( context->vector ) {
|
||||
case ExceptionDB: /* 1 */
|
||||
monpanic(vm, "handleGuestFault: #DB, method=%u not coded\n",
|
||||
vm->executeMethod);
|
||||
#if 0
|
||||
if (vm->executeMethod == RunGuestNMethodBreakpoint) {
|
||||
/* Breakpoint generated because we requested it via TF=1 */
|
||||
}
|
||||
else {
|
||||
monpanic(vm, "handleGuestFault: #DB, method=%u not coded\n",
|
||||
vm->executeMethod);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case ExceptionBR: /* 5 */
|
||||
monpanic(vm, "handleGuestFault: BR unfinished.\n");
|
||||
/* BOUND instruction fault; array index not in bounds */
|
||||
monpanic(vm, "handleGuestFault: emulate_exception was here.\n");
|
||||
/*emulate_exception(vm, context->vector, 0);*/
|
||||
break;
|
||||
|
||||
case ExceptionDE: /* 0 */
|
||||
case ExceptionBP: /* 3 */
|
||||
case ExceptionOF: /* 4 */
|
||||
case ExceptionNM: /* 7 */
|
||||
case ExceptionMF: /* 16 */
|
||||
toHostGuestFault(vm, context->vector);
|
||||
/*monpanic(vm, "handleGuestFault: DE/BP/OF/NM/MF unfinished.\n");*/
|
||||
/*monpanic(vm, "handleGuestFault: %u\n", context->vector);*/
|
||||
/* emulate_interrupt(vm, context->vector); */
|
||||
break;
|
||||
|
||||
case ExceptionNP: /* 11 */
|
||||
case ExceptionSS: /* 12 */
|
||||
case ExceptionAC: /* 17 */
|
||||
monpanic(vm, "handleGuestFault: NP/SS/AC unfinished.\n");
|
||||
/* use emulate_xyz() */
|
||||
/*interrupt(vm, context->vector, 0, 1, context->error); */
|
||||
monpanic(vm, "handleGuestFault: %u\n", context->vector);
|
||||
break;
|
||||
|
||||
case ExceptionUD: /* 6 */
|
||||
case ExceptionGP: /* 13 */
|
||||
toHostGuestFault(vm, context->vector);
|
||||
break;
|
||||
|
||||
case ExceptionPF: /* 14 */
|
||||
guestPageFault(vm, context, cr2);
|
||||
break;
|
||||
|
||||
default:
|
||||
monpanic(vm, "handleGuestFault: Unhandled Fault: %u\n", context->vector);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
handleMonFault(guest_context_t *monContext)
|
||||
{
|
||||
nexus_t *nexus = (nexus_t *) (((Bit32u) monContext) & 0xfffff000);
|
||||
vm_t *vm = (vm_t *) nexus->vm;
|
||||
|
||||
if (vm->inMonFault)
|
||||
monpanic(vm, "handleMonFault called recursively.\n");
|
||||
vm->inMonFault = 1;
|
||||
monpanic(vm, "handleMonFault: vector=%u\n", monContext->vector);
|
||||
|
||||
/* Fault occurred inside monitor code. */
|
||||
|
||||
switch ( monContext->vector ) {
|
||||
case ExceptionPF:
|
||||
case ExceptionGP:
|
||||
{
|
||||
Bit32u cr2;
|
||||
/*unsigned us, rw;*/
|
||||
|
||||
cr2 = readCR2();
|
||||
STI();
|
||||
|
||||
if (monContext->error & 0x8) /* If RSVD bits used in PDir */
|
||||
monpanic(vm, "handleMF: RSVD\n");
|
||||
/*us = G_GetCPL(vm)==3;*/
|
||||
/*rw = (monContext->error >> 1) & 1;*/
|
||||
monpanic(vm, "handleMF: \n");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
monpanic(vm, "hMF: vector=%u\n", monContext->vector);
|
||||
break;
|
||||
}
|
||||
|
||||
/*vm->abort_code = 1;*/
|
||||
/*monpanic_nomess(vm);*/
|
||||
CLI();
|
||||
vm->inMonFault = 0;
|
||||
}
|
||||
Reference in New Issue
Block a user