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 | 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
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; | ... | ... |