Commit 678dde1323f864a46730c303223b40c4571c23bb
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
Showing
3 changed files
with
42 additions
and
0 deletions
cpu-exec.c
| @@ -360,6 +360,8 @@ int cpu_exec(CPUState *env1) | @@ -360,6 +360,8 @@ int cpu_exec(CPUState *env1) | ||
| 360 | env->exception_is_int, | 360 | env->exception_is_int, |
| 361 | env->error_code, | 361 | env->error_code, |
| 362 | env->exception_next_eip, 0); | 362 | env->exception_next_eip, 0); |
| 363 | + /* successfully delivered */ | ||
| 364 | + env->old_exception = -1; | ||
| 363 | #elif defined(TARGET_PPC) | 365 | #elif defined(TARGET_PPC) |
| 364 | do_interrupt(env); | 366 | do_interrupt(env); |
| 365 | #elif defined(TARGET_MIPS) | 367 | #elif defined(TARGET_MIPS) |
target-i386/cpu.h
| @@ -515,6 +515,7 @@ typedef struct CPUX86State { | @@ -515,6 +515,7 @@ typedef struct CPUX86State { | ||
| 515 | uint32_t smbase; | 515 | uint32_t smbase; |
| 516 | int interrupt_request; | 516 | int interrupt_request; |
| 517 | int user_mode_only; /* user mode only simulation */ | 517 | int user_mode_only; /* user mode only simulation */ |
| 518 | + int old_exception; /* exception in flight */ | ||
| 518 | 519 | ||
| 519 | CPU_COMMON | 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,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 | * Signal an interruption. It is executed in the main CPU loop. | 1230 | * Signal an interruption. It is executed in the main CPU loop. |
| 1197 | * is_int is TRUE if coming from the int instruction. next_eip is the | 1231 | * is_int is TRUE if coming from the int instruction. next_eip is the |
| 1198 | * EIP value AFTER the interrupt instruction. It is only relevant if | 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,6 +1235,9 @@ void do_interrupt(int intno, int is_int, int error_code, | ||
| 1201 | void raise_interrupt(int intno, int is_int, int error_code, | 1235 | void raise_interrupt(int intno, int is_int, int error_code, |
| 1202 | int next_eip_addend) | 1236 | int next_eip_addend) |
| 1203 | { | 1237 | { |
| 1238 | + if (!is_int) | ||
| 1239 | + intno = check_exception(intno, &error_code); | ||
| 1240 | + | ||
| 1204 | env->exception_index = intno; | 1241 | env->exception_index = intno; |
| 1205 | env->error_code = error_code; | 1242 | env->error_code = error_code; |
| 1206 | env->exception_is_int = is_int; | 1243 | env->exception_is_int = is_int; |
| @@ -1211,6 +1248,8 @@ void raise_interrupt(int intno, int is_int, int error_code, | @@ -1211,6 +1248,8 @@ void raise_interrupt(int intno, int is_int, int error_code, | ||
| 1211 | /* same as raise_exception_err, but do not restore global registers */ | 1248 | /* same as raise_exception_err, but do not restore global registers */ |
| 1212 | static void raise_exception_err_norestore(int exception_index, int error_code) | 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 | env->exception_index = exception_index; | 1253 | env->exception_index = exception_index; |
| 1215 | env->error_code = error_code; | 1254 | env->error_code = error_code; |
| 1216 | env->exception_is_int = 0; | 1255 | env->exception_is_int = 0; |