xref: /qemu/target/i386/tcg/excp_helper.c (revision 84307cd6027c4602913177ff09aeefa4743b7234)
1599b9a5aSBlue Swirl /*
2599b9a5aSBlue Swirl  *  x86 exception helpers
3599b9a5aSBlue Swirl  *
4599b9a5aSBlue Swirl  *  Copyright (c) 2003 Fabrice Bellard
5599b9a5aSBlue Swirl  *
6599b9a5aSBlue Swirl  * This library is free software; you can redistribute it and/or
7599b9a5aSBlue Swirl  * modify it under the terms of the GNU Lesser General Public
8599b9a5aSBlue Swirl  * License as published by the Free Software Foundation; either
9d9ff33adSChetan Pant  * version 2.1 of the License, or (at your option) any later version.
10599b9a5aSBlue Swirl  *
11599b9a5aSBlue Swirl  * This library is distributed in the hope that it will be useful,
12599b9a5aSBlue Swirl  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13599b9a5aSBlue Swirl  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14599b9a5aSBlue Swirl  * Lesser General Public License for more details.
15599b9a5aSBlue Swirl  *
16599b9a5aSBlue Swirl  * You should have received a copy of the GNU Lesser General Public
17599b9a5aSBlue Swirl  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18599b9a5aSBlue Swirl  */
19599b9a5aSBlue Swirl 
20b6a0aa05SPeter Maydell #include "qemu/osdep.h"
21599b9a5aSBlue Swirl #include "cpu.h"
221de7afc9SPaolo Bonzini #include "qemu/log.h"
23*32cad1ffSPhilippe Mathieu-Daudé #include "system/runstate.h"
242ef6175aSRichard Henderson #include "exec/helper-proto.h"
25ed69e831SClaudio Fontana #include "helper-tcg.h"
26599b9a5aSBlue Swirl 
helper_raise_interrupt(CPUX86State * env,int intno,int next_eip_addend)278905770bSMarc-André Lureau G_NORETURN void helper_raise_interrupt(CPUX86State *env, int intno,
28b82055aeSRichard Henderson                                           int next_eip_addend)
29599b9a5aSBlue Swirl {
3083280f6aSPaolo Bonzini     raise_interrupt(env, intno, next_eip_addend);
31599b9a5aSBlue Swirl }
32599b9a5aSBlue Swirl 
helper_raise_exception(CPUX86State * env,int exception_index)338905770bSMarc-André Lureau G_NORETURN void helper_raise_exception(CPUX86State *env, int exception_index)
34599b9a5aSBlue Swirl {
35599b9a5aSBlue Swirl     raise_exception(env, exception_index);
36599b9a5aSBlue Swirl }
37599b9a5aSBlue Swirl 
38599b9a5aSBlue Swirl /*
39599b9a5aSBlue Swirl  * Check nested exceptions and change to double or triple fault if
40599b9a5aSBlue Swirl  * needed. It should only be called, if this is not an interrupt.
41599b9a5aSBlue Swirl  * Returns the new exception number.
42599b9a5aSBlue Swirl  */
check_exception(CPUX86State * env,int intno,int * error_code,uintptr_t retaddr)4365c9d60aSPaolo Bonzini static int check_exception(CPUX86State *env, int intno, int *error_code,
4465c9d60aSPaolo Bonzini                            uintptr_t retaddr)
45599b9a5aSBlue Swirl {
46599b9a5aSBlue Swirl     int first_contributory = env->old_exception == 0 ||
47599b9a5aSBlue Swirl                               (env->old_exception >= 10 &&
48599b9a5aSBlue Swirl                                env->old_exception <= 13);
49599b9a5aSBlue Swirl     int second_contributory = intno == 0 ||
50599b9a5aSBlue Swirl                                (intno >= 10 && intno <= 13);
51599b9a5aSBlue Swirl 
52599b9a5aSBlue Swirl     qemu_log_mask(CPU_LOG_INT, "check_exception old: 0x%x new 0x%x\n",
53599b9a5aSBlue Swirl                 env->old_exception, intno);
54599b9a5aSBlue Swirl 
55599b9a5aSBlue Swirl #if !defined(CONFIG_USER_ONLY)
56599b9a5aSBlue Swirl     if (env->old_exception == EXCP08_DBLE) {
57f8dc4c64SPaolo Bonzini         if (env->hflags & HF_GUEST_MASK) {
5865c9d60aSPaolo Bonzini             cpu_vmexit(env, SVM_EXIT_SHUTDOWN, 0, retaddr); /* does not return */
59599b9a5aSBlue Swirl         }
60599b9a5aSBlue Swirl 
61599b9a5aSBlue Swirl         qemu_log_mask(CPU_LOG_RESET, "Triple fault\n");
62599b9a5aSBlue Swirl 
63cf83f140SEric Blake         qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
64599b9a5aSBlue Swirl         return EXCP_HLT;
65599b9a5aSBlue Swirl     }
66599b9a5aSBlue Swirl #endif
67599b9a5aSBlue Swirl 
68599b9a5aSBlue Swirl     if ((first_contributory && second_contributory)
69599b9a5aSBlue Swirl         || (env->old_exception == EXCP0E_PAGE &&
70599b9a5aSBlue Swirl             (second_contributory || (intno == EXCP0E_PAGE)))) {
71599b9a5aSBlue Swirl         intno = EXCP08_DBLE;
72599b9a5aSBlue Swirl         *error_code = 0;
73599b9a5aSBlue Swirl     }
74599b9a5aSBlue Swirl 
75599b9a5aSBlue Swirl     if (second_contributory || (intno == EXCP0E_PAGE) ||
76599b9a5aSBlue Swirl         (intno == EXCP08_DBLE)) {
77599b9a5aSBlue Swirl         env->old_exception = intno;
78599b9a5aSBlue Swirl     }
79599b9a5aSBlue Swirl 
80599b9a5aSBlue Swirl     return intno;
81599b9a5aSBlue Swirl }
82599b9a5aSBlue Swirl 
83599b9a5aSBlue Swirl /*
84599b9a5aSBlue Swirl  * Signal an interruption. It is executed in the main CPU loop.
85599b9a5aSBlue Swirl  * is_int is TRUE if coming from the int instruction. next_eip is the
86a78d0eabSliguang  * env->eip value AFTER the interrupt instruction. It is only relevant if
87599b9a5aSBlue Swirl  * is_int is TRUE.
88599b9a5aSBlue Swirl  */
898905770bSMarc-André Lureau static G_NORETURN
raise_interrupt2(CPUX86State * env,int intno,int is_int,int error_code,int next_eip_addend,uintptr_t retaddr)908905770bSMarc-André Lureau void raise_interrupt2(CPUX86State *env, int intno,
91599b9a5aSBlue Swirl                       int is_int, int error_code,
9291980095SPavel Dovgalyuk                       int next_eip_addend,
9391980095SPavel Dovgalyuk                       uintptr_t retaddr)
94599b9a5aSBlue Swirl {
956aa9e42fSRichard Henderson     CPUState *cs = env_cpu(env);
9627103424SAndreas Färber 
97599b9a5aSBlue Swirl     if (!is_int) {
98599b9a5aSBlue Swirl         cpu_svm_check_intercept_param(env, SVM_EXIT_EXCP_BASE + intno,
9965c9d60aSPaolo Bonzini                                       error_code, retaddr);
10065c9d60aSPaolo Bonzini         intno = check_exception(env, intno, &error_code, retaddr);
101599b9a5aSBlue Swirl     } else {
10265c9d60aSPaolo Bonzini         cpu_svm_check_intercept_param(env, SVM_EXIT_SWINT, 0, retaddr);
103599b9a5aSBlue Swirl     }
104599b9a5aSBlue Swirl 
10527103424SAndreas Färber     cs->exception_index = intno;
106599b9a5aSBlue Swirl     env->error_code = error_code;
107599b9a5aSBlue Swirl     env->exception_is_int = is_int;
108599b9a5aSBlue Swirl     env->exception_next_eip = env->eip + next_eip_addend;
10991980095SPavel Dovgalyuk     cpu_loop_exit_restore(cs, retaddr);
110599b9a5aSBlue Swirl }
111599b9a5aSBlue Swirl 
112599b9a5aSBlue Swirl /* shortcuts to generate exceptions */
113599b9a5aSBlue Swirl 
raise_interrupt(CPUX86State * env,int intno,int next_eip_addend)11483280f6aSPaolo Bonzini G_NORETURN void raise_interrupt(CPUX86State *env, int intno, int next_eip_addend)
115599b9a5aSBlue Swirl {
11683280f6aSPaolo Bonzini     raise_interrupt2(env, intno, 1, 0, next_eip_addend, 0);
117599b9a5aSBlue Swirl }
118599b9a5aSBlue Swirl 
raise_exception_err(CPUX86State * env,int exception_index,int error_code)1198905770bSMarc-André Lureau G_NORETURN void raise_exception_err(CPUX86State *env, int exception_index,
120599b9a5aSBlue Swirl                                     int error_code)
121599b9a5aSBlue Swirl {
12291980095SPavel Dovgalyuk     raise_interrupt2(env, exception_index, 0, error_code, 0, 0);
12391980095SPavel Dovgalyuk }
12491980095SPavel Dovgalyuk 
raise_exception_err_ra(CPUX86State * env,int exception_index,int error_code,uintptr_t retaddr)1258905770bSMarc-André Lureau G_NORETURN void raise_exception_err_ra(CPUX86State *env, int exception_index,
12691980095SPavel Dovgalyuk                                        int error_code, uintptr_t retaddr)
12791980095SPavel Dovgalyuk {
12891980095SPavel Dovgalyuk     raise_interrupt2(env, exception_index, 0, error_code, 0, retaddr);
129599b9a5aSBlue Swirl }
130599b9a5aSBlue Swirl 
raise_exception(CPUX86State * env,int exception_index)1318905770bSMarc-André Lureau G_NORETURN void raise_exception(CPUX86State *env, int exception_index)
132599b9a5aSBlue Swirl {
13391980095SPavel Dovgalyuk     raise_interrupt2(env, exception_index, 0, 0, 0, 0);
13491980095SPavel Dovgalyuk }
13591980095SPavel Dovgalyuk 
raise_exception_ra(CPUX86State * env,int exception_index,uintptr_t retaddr)1368905770bSMarc-André Lureau G_NORETURN void raise_exception_ra(CPUX86State *env, int exception_index,
137b82055aeSRichard Henderson                                    uintptr_t retaddr)
13891980095SPavel Dovgalyuk {
13991980095SPavel Dovgalyuk     raise_interrupt2(env, exception_index, 0, 0, 0, retaddr);
140599b9a5aSBlue Swirl }
141958e1dd1SPaolo Bonzini 
helper_icebp(CPUX86State * env)14273fb7b3cSPaolo Bonzini G_NORETURN void helper_icebp(CPUX86State *env)
14373fb7b3cSPaolo Bonzini {
14473fb7b3cSPaolo Bonzini     CPUState *cs = env_cpu(env);
14573fb7b3cSPaolo Bonzini 
14673fb7b3cSPaolo Bonzini     do_end_instruction(env);
14773fb7b3cSPaolo Bonzini 
14873fb7b3cSPaolo Bonzini     /*
14973fb7b3cSPaolo Bonzini      * INT1 aka ICEBP generates a trap-like #DB, but it is pretty special.
15073fb7b3cSPaolo Bonzini      *
15173fb7b3cSPaolo Bonzini      * "Although the ICEBP instruction dispatches through IDT vector 1,
15273fb7b3cSPaolo Bonzini      * that event is not interceptable by means of the #DB exception
15373fb7b3cSPaolo Bonzini      * intercept".  Instead there is a separate fault-like ICEBP intercept.
15473fb7b3cSPaolo Bonzini      */
15573fb7b3cSPaolo Bonzini     cs->exception_index = EXCP01_DB;
15673fb7b3cSPaolo Bonzini     env->error_code = 0;
15773fb7b3cSPaolo Bonzini     env->exception_is_int = 0;
15873fb7b3cSPaolo Bonzini     env->exception_next_eip = env->eip;
15973fb7b3cSPaolo Bonzini     cpu_loop_exit(cs);
16073fb7b3cSPaolo Bonzini }
16173fb7b3cSPaolo Bonzini 
handle_unaligned_access(CPUX86State * env,vaddr vaddr,MMUAccessType access_type,uintptr_t retaddr)162958e1dd1SPaolo Bonzini G_NORETURN void handle_unaligned_access(CPUX86State *env, vaddr vaddr,
163958e1dd1SPaolo Bonzini                                         MMUAccessType access_type,
164958e1dd1SPaolo Bonzini                                         uintptr_t retaddr)
165958e1dd1SPaolo Bonzini {
166958e1dd1SPaolo Bonzini     /*
167958e1dd1SPaolo Bonzini      * Unaligned accesses are currently only triggered by SSE/AVX
168958e1dd1SPaolo Bonzini      * instructions that impose alignment requirements on memory
169958e1dd1SPaolo Bonzini      * operands. These instructions raise #GP(0) upon accessing an
170958e1dd1SPaolo Bonzini      * unaligned address.
171958e1dd1SPaolo Bonzini      */
172958e1dd1SPaolo Bonzini     raise_exception_ra(env, EXCP0D_GPF, retaddr);
173958e1dd1SPaolo Bonzini }
174