fault-mon.c

来自「bochs : one pc simulator.」· C语言 代码 · 共 307 行

C
307
字号
/* *  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 inlineBit32u 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 */);  unsignedhandleInt(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);}  voidhandleGuestFault(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;    }}  voidhandleMonFault(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;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?