root / target-i386 / excp_helper.c @ 5918fffb
History | View | Annotate | Download (4.1 kB)
1 | 599b9a5a | Blue Swirl | /*
|
---|---|---|---|
2 | 599b9a5a | Blue Swirl | * x86 exception helpers
|
3 | 599b9a5a | Blue Swirl | *
|
4 | 599b9a5a | Blue Swirl | * Copyright (c) 2003 Fabrice Bellard
|
5 | 599b9a5a | Blue Swirl | *
|
6 | 599b9a5a | Blue Swirl | * This library is free software; you can redistribute it and/or
|
7 | 599b9a5a | Blue Swirl | * modify it under the terms of the GNU Lesser General Public
|
8 | 599b9a5a | Blue Swirl | * License as published by the Free Software Foundation; either
|
9 | 599b9a5a | Blue Swirl | * version 2 of the License, or (at your option) any later version.
|
10 | 599b9a5a | Blue Swirl | *
|
11 | 599b9a5a | Blue Swirl | * This library is distributed in the hope that it will be useful,
|
12 | 599b9a5a | Blue Swirl | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 | 599b9a5a | Blue Swirl | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14 | 599b9a5a | Blue Swirl | * Lesser General Public License for more details.
|
15 | 599b9a5a | Blue Swirl | *
|
16 | 599b9a5a | Blue Swirl | * You should have received a copy of the GNU Lesser General Public
|
17 | 599b9a5a | Blue Swirl | * License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
18 | 599b9a5a | Blue Swirl | */
|
19 | 599b9a5a | Blue Swirl | |
20 | 599b9a5a | Blue Swirl | #include "cpu.h" |
21 | 599b9a5a | Blue Swirl | #include "qemu-log.h" |
22 | 9dd69d65 | Blue Swirl | #include "sysemu.h" |
23 | 599b9a5a | Blue Swirl | #include "helper.h" |
24 | 599b9a5a | Blue Swirl | |
25 | 599b9a5a | Blue Swirl | #if 0
|
26 | 599b9a5a | Blue Swirl | #define raise_exception_err(env, a, b) \
|
27 | 599b9a5a | Blue Swirl | do { \
|
28 | 599b9a5a | Blue Swirl | qemu_log("raise_exception line=%d\n", __LINE__); \
|
29 | 599b9a5a | Blue Swirl | (raise_exception_err)(env, a, b); \
|
30 | 599b9a5a | Blue Swirl | } while (0)
|
31 | 599b9a5a | Blue Swirl | #endif
|
32 | 599b9a5a | Blue Swirl | |
33 | 599b9a5a | Blue Swirl | void helper_raise_interrupt(CPUX86State *env, int intno, int next_eip_addend) |
34 | 599b9a5a | Blue Swirl | { |
35 | 599b9a5a | Blue Swirl | raise_interrupt(env, intno, 1, 0, next_eip_addend); |
36 | 599b9a5a | Blue Swirl | } |
37 | 599b9a5a | Blue Swirl | |
38 | 599b9a5a | Blue Swirl | void helper_raise_exception(CPUX86State *env, int exception_index) |
39 | 599b9a5a | Blue Swirl | { |
40 | 599b9a5a | Blue Swirl | raise_exception(env, exception_index); |
41 | 599b9a5a | Blue Swirl | } |
42 | 599b9a5a | Blue Swirl | |
43 | 599b9a5a | Blue Swirl | /*
|
44 | 599b9a5a | Blue Swirl | * Check nested exceptions and change to double or triple fault if
|
45 | 599b9a5a | Blue Swirl | * needed. It should only be called, if this is not an interrupt.
|
46 | 599b9a5a | Blue Swirl | * Returns the new exception number.
|
47 | 599b9a5a | Blue Swirl | */
|
48 | 599b9a5a | Blue Swirl | static int check_exception(CPUX86State *env, int intno, int *error_code) |
49 | 599b9a5a | Blue Swirl | { |
50 | 599b9a5a | Blue Swirl | int first_contributory = env->old_exception == 0 || |
51 | 599b9a5a | Blue Swirl | (env->old_exception >= 10 &&
|
52 | 599b9a5a | Blue Swirl | env->old_exception <= 13);
|
53 | 599b9a5a | Blue Swirl | int second_contributory = intno == 0 || |
54 | 599b9a5a | Blue Swirl | (intno >= 10 && intno <= 13); |
55 | 599b9a5a | Blue Swirl | |
56 | 599b9a5a | Blue Swirl | qemu_log_mask(CPU_LOG_INT, "check_exception old: 0x%x new 0x%x\n",
|
57 | 599b9a5a | Blue Swirl | env->old_exception, intno); |
58 | 599b9a5a | Blue Swirl | |
59 | 599b9a5a | Blue Swirl | #if !defined(CONFIG_USER_ONLY)
|
60 | 599b9a5a | Blue Swirl | if (env->old_exception == EXCP08_DBLE) {
|
61 | 599b9a5a | Blue Swirl | if (env->hflags & HF_SVMI_MASK) {
|
62 | 599b9a5a | Blue Swirl | cpu_vmexit(env, SVM_EXIT_SHUTDOWN, 0); /* does not return */ |
63 | 599b9a5a | Blue Swirl | } |
64 | 599b9a5a | Blue Swirl | |
65 | 599b9a5a | Blue Swirl | qemu_log_mask(CPU_LOG_RESET, "Triple fault\n");
|
66 | 599b9a5a | Blue Swirl | |
67 | 599b9a5a | Blue Swirl | qemu_system_reset_request(); |
68 | 599b9a5a | Blue Swirl | return EXCP_HLT;
|
69 | 599b9a5a | Blue Swirl | } |
70 | 599b9a5a | Blue Swirl | #endif
|
71 | 599b9a5a | Blue Swirl | |
72 | 599b9a5a | Blue Swirl | if ((first_contributory && second_contributory)
|
73 | 599b9a5a | Blue Swirl | || (env->old_exception == EXCP0E_PAGE && |
74 | 599b9a5a | Blue Swirl | (second_contributory || (intno == EXCP0E_PAGE)))) { |
75 | 599b9a5a | Blue Swirl | intno = EXCP08_DBLE; |
76 | 599b9a5a | Blue Swirl | *error_code = 0;
|
77 | 599b9a5a | Blue Swirl | } |
78 | 599b9a5a | Blue Swirl | |
79 | 599b9a5a | Blue Swirl | if (second_contributory || (intno == EXCP0E_PAGE) ||
|
80 | 599b9a5a | Blue Swirl | (intno == EXCP08_DBLE)) { |
81 | 599b9a5a | Blue Swirl | env->old_exception = intno; |
82 | 599b9a5a | Blue Swirl | } |
83 | 599b9a5a | Blue Swirl | |
84 | 599b9a5a | Blue Swirl | return intno;
|
85 | 599b9a5a | Blue Swirl | } |
86 | 599b9a5a | Blue Swirl | |
87 | 599b9a5a | Blue Swirl | /*
|
88 | 599b9a5a | Blue Swirl | * Signal an interruption. It is executed in the main CPU loop.
|
89 | 599b9a5a | Blue Swirl | * is_int is TRUE if coming from the int instruction. next_eip is the
|
90 | 599b9a5a | Blue Swirl | * EIP value AFTER the interrupt instruction. It is only relevant if
|
91 | 599b9a5a | Blue Swirl | * is_int is TRUE.
|
92 | 599b9a5a | Blue Swirl | */
|
93 | 599b9a5a | Blue Swirl | static void QEMU_NORETURN raise_interrupt2(CPUX86State *env, int intno, |
94 | 599b9a5a | Blue Swirl | int is_int, int error_code, |
95 | 599b9a5a | Blue Swirl | int next_eip_addend)
|
96 | 599b9a5a | Blue Swirl | { |
97 | 599b9a5a | Blue Swirl | if (!is_int) {
|
98 | 599b9a5a | Blue Swirl | cpu_svm_check_intercept_param(env, SVM_EXIT_EXCP_BASE + intno, |
99 | 599b9a5a | Blue Swirl | error_code); |
100 | 599b9a5a | Blue Swirl | intno = check_exception(env, intno, &error_code); |
101 | 599b9a5a | Blue Swirl | } else {
|
102 | 599b9a5a | Blue Swirl | cpu_svm_check_intercept_param(env, SVM_EXIT_SWINT, 0);
|
103 | 599b9a5a | Blue Swirl | } |
104 | 599b9a5a | Blue Swirl | |
105 | 599b9a5a | Blue Swirl | env->exception_index = intno; |
106 | 599b9a5a | Blue Swirl | env->error_code = error_code; |
107 | 599b9a5a | Blue Swirl | env->exception_is_int = is_int; |
108 | 599b9a5a | Blue Swirl | env->exception_next_eip = env->eip + next_eip_addend; |
109 | 599b9a5a | Blue Swirl | cpu_loop_exit(env); |
110 | 599b9a5a | Blue Swirl | } |
111 | 599b9a5a | Blue Swirl | |
112 | 599b9a5a | Blue Swirl | /* shortcuts to generate exceptions */
|
113 | 599b9a5a | Blue Swirl | |
114 | 599b9a5a | Blue Swirl | void QEMU_NORETURN raise_interrupt(CPUX86State *env, int intno, int is_int, |
115 | 599b9a5a | Blue Swirl | int error_code, int next_eip_addend) |
116 | 599b9a5a | Blue Swirl | { |
117 | 599b9a5a | Blue Swirl | raise_interrupt2(env, intno, is_int, error_code, next_eip_addend); |
118 | 599b9a5a | Blue Swirl | } |
119 | 599b9a5a | Blue Swirl | |
120 | 599b9a5a | Blue Swirl | void raise_exception_err(CPUX86State *env, int exception_index, |
121 | 599b9a5a | Blue Swirl | int error_code)
|
122 | 599b9a5a | Blue Swirl | { |
123 | 599b9a5a | Blue Swirl | raise_interrupt2(env, exception_index, 0, error_code, 0); |
124 | 599b9a5a | Blue Swirl | } |
125 | 599b9a5a | Blue Swirl | |
126 | 599b9a5a | Blue Swirl | void raise_exception(CPUX86State *env, int exception_index) |
127 | 599b9a5a | Blue Swirl | { |
128 | 599b9a5a | Blue Swirl | raise_interrupt2(env, exception_index, 0, 0, 0); |
129 | 599b9a5a | Blue Swirl | } |