Commit 678dde1323f864a46730c303223b40c4571c23bb

Authored by ths
1 parent a80274c3

Generate double and triple faults, by Bernhard Kauer.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2563 c046a42c-6fe2-441c-8c8c-71466251a162
cpu-exec.c
... ... @@ -360,6 +360,8 @@ int cpu_exec(CPUState *env1)
360 360 env->exception_is_int,
361 361 env->error_code,
362 362 env->exception_next_eip, 0);
  363 + /* successfully delivered */
  364 + env->old_exception = -1;
363 365 #elif defined(TARGET_PPC)
364 366 do_interrupt(env);
365 367 #elif defined(TARGET_MIPS)
... ...
target-i386/cpu.h
... ... @@ -515,6 +515,7 @@ typedef struct CPUX86State {
515 515 uint32_t smbase;
516 516 int interrupt_request;
517 517 int user_mode_only; /* user mode only simulation */
  518 + int old_exception; /* exception in flight */
518 519  
519 520 CPU_COMMON
520 521  
... ...
target-i386/helper.c
... ... @@ -1193,6 +1193,40 @@ void do_interrupt(int intno, int is_int, int error_code,
1193 1193 }
1194 1194  
1195 1195 /*
  1196 + * Check nested exceptions and change to double or triple fault if
  1197 + * needed. It should only be called, if this is not an interrupt.
  1198 + * Returns the new exception number.
  1199 + */
  1200 +int check_exception(int intno, int *error_code)
  1201 +{
  1202 + char first_contributory = env->old_exception == 0 ||
  1203 + (env->old_exception >= 10 &&
  1204 + env->old_exception <= 13);
  1205 + char second_contributory = intno == 0 ||
  1206 + (intno >= 10 && intno <= 13);
  1207 +
  1208 + if (loglevel & CPU_LOG_INT)
  1209 + fprintf(logfile, "check_exception old: %x new %x\n",
  1210 + env->old_exception, intno);
  1211 +
  1212 + if (env->old_exception == EXCP08_DBLE)
  1213 + cpu_abort(env, "triple fault");
  1214 +
  1215 + if ((first_contributory && second_contributory)
  1216 + || (env->old_exception == EXCP0E_PAGE &&
  1217 + (second_contributory || (intno == EXCP0E_PAGE)))) {
  1218 + intno = EXCP08_DBLE;
  1219 + *error_code = 0;
  1220 + }
  1221 +
  1222 + if (second_contributory || (intno == EXCP0E_PAGE) ||
  1223 + (intno == EXCP08_DBLE))
  1224 + env->old_exception = intno;
  1225 +
  1226 + return intno;
  1227 +}
  1228 +
  1229 +/*
1196 1230 * Signal an interruption. It is executed in the main CPU loop.
1197 1231 * is_int is TRUE if coming from the int instruction. next_eip is the
1198 1232 * EIP value AFTER the interrupt instruction. It is only relevant if
... ... @@ -1201,6 +1235,9 @@ void do_interrupt(int intno, int is_int, int error_code,
1201 1235 void raise_interrupt(int intno, int is_int, int error_code,
1202 1236 int next_eip_addend)
1203 1237 {
  1238 + if (!is_int)
  1239 + intno = check_exception(intno, &error_code);
  1240 +
1204 1241 env->exception_index = intno;
1205 1242 env->error_code = error_code;
1206 1243 env->exception_is_int = is_int;
... ... @@ -1211,6 +1248,8 @@ void raise_interrupt(int intno, int is_int, int error_code,
1211 1248 /* same as raise_exception_err, but do not restore global registers */
1212 1249 static void raise_exception_err_norestore(int exception_index, int error_code)
1213 1250 {
  1251 + exception_index = check_exception(exception_index, &error_code);
  1252 +
1214 1253 env->exception_index = exception_index;
1215 1254 env->error_code = error_code;
1216 1255 env->exception_is_int = 0;
... ...