File: fault-mon.c

package info (click to toggle)
bochs 2.3-2etch1
  • links: PTS
  • area: main
  • in suites: etch
  • size: 14,116 kB
  • ctags: 16,927
  • sloc: cpp: 130,524; ansic: 18,822; sh: 7,922; makefile: 3,836; yacc: 1,056; asm: 463; perl: 381; lex: 280; csh: 3
file content (306 lines) | stat: -rw-r--r-- 9,494 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
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;
}