xref: /openbmc/qemu/target/i386/tcg/excp_helper.c (revision 73fb7b3c)
11b248f14SClaudio Fontana /*
21b248f14SClaudio Fontana  *  x86 exception helpers
31b248f14SClaudio Fontana  *
41b248f14SClaudio Fontana  *  Copyright (c) 2003 Fabrice Bellard
51b248f14SClaudio Fontana  *
61b248f14SClaudio Fontana  * This library is free software; you can redistribute it and/or
71b248f14SClaudio Fontana  * modify it under the terms of the GNU Lesser General Public
81b248f14SClaudio Fontana  * License as published by the Free Software Foundation; either
91b248f14SClaudio Fontana  * version 2.1 of the License, or (at your option) any later version.
101b248f14SClaudio Fontana  *
111b248f14SClaudio Fontana  * This library is distributed in the hope that it will be useful,
121b248f14SClaudio Fontana  * but WITHOUT ANY WARRANTY; without even the implied warranty of
131b248f14SClaudio Fontana  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
141b248f14SClaudio Fontana  * Lesser General Public License for more details.
151b248f14SClaudio Fontana  *
161b248f14SClaudio Fontana  * You should have received a copy of the GNU Lesser General Public
171b248f14SClaudio Fontana  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
181b248f14SClaudio Fontana  */
191b248f14SClaudio Fontana 
201b248f14SClaudio Fontana #include "qemu/osdep.h"
211b248f14SClaudio Fontana #include "cpu.h"
221b248f14SClaudio Fontana #include "exec/exec-all.h"
231b248f14SClaudio Fontana #include "qemu/log.h"
241b248f14SClaudio Fontana #include "sysemu/runstate.h"
251b248f14SClaudio Fontana #include "exec/helper-proto.h"
26ed69e831SClaudio Fontana #include "helper-tcg.h"
271b248f14SClaudio Fontana 
helper_raise_interrupt(CPUX86State * env,int intno,int next_eip_addend)288905770bSMarc-André Lureau G_NORETURN void helper_raise_interrupt(CPUX86State *env, int intno,
29b82055aeSRichard Henderson                                           int next_eip_addend)
301b248f14SClaudio Fontana {
3183280f6aSPaolo Bonzini     raise_interrupt(env, intno, next_eip_addend);
321b248f14SClaudio Fontana }
331b248f14SClaudio Fontana 
helper_raise_exception(CPUX86State * env,int exception_index)348905770bSMarc-André Lureau G_NORETURN void helper_raise_exception(CPUX86State *env, int exception_index)
351b248f14SClaudio Fontana {
361b248f14SClaudio Fontana     raise_exception(env, exception_index);
371b248f14SClaudio Fontana }
381b248f14SClaudio Fontana 
391b248f14SClaudio Fontana /*
401b248f14SClaudio Fontana  * Check nested exceptions and change to double or triple fault if
411b248f14SClaudio Fontana  * needed. It should only be called, if this is not an interrupt.
421b248f14SClaudio Fontana  * Returns the new exception number.
431b248f14SClaudio Fontana  */
check_exception(CPUX86State * env,int intno,int * error_code,uintptr_t retaddr)441b248f14SClaudio Fontana static int check_exception(CPUX86State *env, int intno, int *error_code,
451b248f14SClaudio Fontana                            uintptr_t retaddr)
461b248f14SClaudio Fontana {
471b248f14SClaudio Fontana     int first_contributory = env->old_exception == 0 ||
481b248f14SClaudio Fontana                               (env->old_exception >= 10 &&
491b248f14SClaudio Fontana                                env->old_exception <= 13);
501b248f14SClaudio Fontana     int second_contributory = intno == 0 ||
511b248f14SClaudio Fontana                                (intno >= 10 && intno <= 13);
521b248f14SClaudio Fontana 
531b248f14SClaudio Fontana     qemu_log_mask(CPU_LOG_INT, "check_exception old: 0x%x new 0x%x\n",
541b248f14SClaudio Fontana                 env->old_exception, intno);
551b248f14SClaudio Fontana 
561b248f14SClaudio Fontana #if !defined(CONFIG_USER_ONLY)
571b248f14SClaudio Fontana     if (env->old_exception == EXCP08_DBLE) {
581b248f14SClaudio Fontana         if (env->hflags & HF_GUEST_MASK) {
591b248f14SClaudio Fontana             cpu_vmexit(env, SVM_EXIT_SHUTDOWN, 0, retaddr); /* does not return */
601b248f14SClaudio Fontana         }
611b248f14SClaudio Fontana 
621b248f14SClaudio Fontana         qemu_log_mask(CPU_LOG_RESET, "Triple fault\n");
631b248f14SClaudio Fontana 
641b248f14SClaudio Fontana         qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
651b248f14SClaudio Fontana         return EXCP_HLT;
661b248f14SClaudio Fontana     }
671b248f14SClaudio Fontana #endif
681b248f14SClaudio Fontana 
691b248f14SClaudio Fontana     if ((first_contributory && second_contributory)
701b248f14SClaudio Fontana         || (env->old_exception == EXCP0E_PAGE &&
711b248f14SClaudio Fontana             (second_contributory || (intno == EXCP0E_PAGE)))) {
721b248f14SClaudio Fontana         intno = EXCP08_DBLE;
731b248f14SClaudio Fontana         *error_code = 0;
741b248f14SClaudio Fontana     }
751b248f14SClaudio Fontana 
761b248f14SClaudio Fontana     if (second_contributory || (intno == EXCP0E_PAGE) ||
771b248f14SClaudio Fontana         (intno == EXCP08_DBLE)) {
781b248f14SClaudio Fontana         env->old_exception = intno;
791b248f14SClaudio Fontana     }
801b248f14SClaudio Fontana 
811b248f14SClaudio Fontana     return intno;
821b248f14SClaudio Fontana }
831b248f14SClaudio Fontana 
841b248f14SClaudio Fontana /*
851b248f14SClaudio Fontana  * Signal an interruption. It is executed in the main CPU loop.
861b248f14SClaudio Fontana  * is_int is TRUE if coming from the int instruction. next_eip is the
871b248f14SClaudio Fontana  * env->eip value AFTER the interrupt instruction. It is only relevant if
881b248f14SClaudio Fontana  * is_int is TRUE.
891b248f14SClaudio Fontana  */
908905770bSMarc-André Lureau static G_NORETURN
raise_interrupt2(CPUX86State * env,int intno,int is_int,int error_code,int next_eip_addend,uintptr_t retaddr)918905770bSMarc-André Lureau void raise_interrupt2(CPUX86State *env, int intno,
921b248f14SClaudio Fontana                       int is_int, int error_code,
931b248f14SClaudio Fontana                       int next_eip_addend,
941b248f14SClaudio Fontana                       uintptr_t retaddr)
951b248f14SClaudio Fontana {
961b248f14SClaudio Fontana     CPUState *cs = env_cpu(env);
971b248f14SClaudio Fontana 
981b248f14SClaudio Fontana     if (!is_int) {
991b248f14SClaudio Fontana         cpu_svm_check_intercept_param(env, SVM_EXIT_EXCP_BASE + intno,
1001b248f14SClaudio Fontana                                       error_code, retaddr);
1011b248f14SClaudio Fontana         intno = check_exception(env, intno, &error_code, retaddr);
1021b248f14SClaudio Fontana     } else {
1031b248f14SClaudio Fontana         cpu_svm_check_intercept_param(env, SVM_EXIT_SWINT, 0, retaddr);
1041b248f14SClaudio Fontana     }
1051b248f14SClaudio Fontana 
1061b248f14SClaudio Fontana     cs->exception_index = intno;
1071b248f14SClaudio Fontana     env->error_code = error_code;
1081b248f14SClaudio Fontana     env->exception_is_int = is_int;
1091b248f14SClaudio Fontana     env->exception_next_eip = env->eip + next_eip_addend;
1101b248f14SClaudio Fontana     cpu_loop_exit_restore(cs, retaddr);
1111b248f14SClaudio Fontana }
1121b248f14SClaudio Fontana 
1131b248f14SClaudio Fontana /* shortcuts to generate exceptions */
1141b248f14SClaudio Fontana 
raise_interrupt(CPUX86State * env,int intno,int next_eip_addend)11583280f6aSPaolo Bonzini G_NORETURN void raise_interrupt(CPUX86State *env, int intno, int next_eip_addend)
1161b248f14SClaudio Fontana {
11783280f6aSPaolo Bonzini     raise_interrupt2(env, intno, 1, 0, next_eip_addend, 0);
1181b248f14SClaudio Fontana }
1191b248f14SClaudio Fontana 
raise_exception_err(CPUX86State * env,int exception_index,int error_code)1208905770bSMarc-André Lureau G_NORETURN void raise_exception_err(CPUX86State *env, int exception_index,
1211b248f14SClaudio Fontana                                     int error_code)
1221b248f14SClaudio Fontana {
1231b248f14SClaudio Fontana     raise_interrupt2(env, exception_index, 0, error_code, 0, 0);
1241b248f14SClaudio Fontana }
1251b248f14SClaudio Fontana 
raise_exception_err_ra(CPUX86State * env,int exception_index,int error_code,uintptr_t retaddr)1268905770bSMarc-André Lureau G_NORETURN void raise_exception_err_ra(CPUX86State *env, int exception_index,
1271b248f14SClaudio Fontana                                        int error_code, uintptr_t retaddr)
1281b248f14SClaudio Fontana {
1291b248f14SClaudio Fontana     raise_interrupt2(env, exception_index, 0, error_code, 0, retaddr);
1301b248f14SClaudio Fontana }
1311b248f14SClaudio Fontana 
raise_exception(CPUX86State * env,int exception_index)1328905770bSMarc-André Lureau G_NORETURN void raise_exception(CPUX86State *env, int exception_index)
1331b248f14SClaudio Fontana {
1341b248f14SClaudio Fontana     raise_interrupt2(env, exception_index, 0, 0, 0, 0);
1351b248f14SClaudio Fontana }
1361b248f14SClaudio Fontana 
raise_exception_ra(CPUX86State * env,int exception_index,uintptr_t retaddr)1378905770bSMarc-André Lureau G_NORETURN void raise_exception_ra(CPUX86State *env, int exception_index,
138b82055aeSRichard Henderson                                    uintptr_t retaddr)
1391b248f14SClaudio Fontana {
1401b248f14SClaudio Fontana     raise_interrupt2(env, exception_index, 0, 0, 0, retaddr);
1411b248f14SClaudio Fontana }
142958e1dd1SPaolo Bonzini 
helper_icebp(CPUX86State * env)143*73fb7b3cSPaolo Bonzini G_NORETURN void helper_icebp(CPUX86State *env)
144*73fb7b3cSPaolo Bonzini {
145*73fb7b3cSPaolo Bonzini     CPUState *cs = env_cpu(env);
146*73fb7b3cSPaolo Bonzini 
147*73fb7b3cSPaolo Bonzini     do_end_instruction(env);
148*73fb7b3cSPaolo Bonzini 
149*73fb7b3cSPaolo Bonzini     /*
150*73fb7b3cSPaolo Bonzini      * INT1 aka ICEBP generates a trap-like #DB, but it is pretty special.
151*73fb7b3cSPaolo Bonzini      *
152*73fb7b3cSPaolo Bonzini      * "Although the ICEBP instruction dispatches through IDT vector 1,
153*73fb7b3cSPaolo Bonzini      * that event is not interceptable by means of the #DB exception
154*73fb7b3cSPaolo Bonzini      * intercept".  Instead there is a separate fault-like ICEBP intercept.
155*73fb7b3cSPaolo Bonzini      */
156*73fb7b3cSPaolo Bonzini     cs->exception_index = EXCP01_DB;
157*73fb7b3cSPaolo Bonzini     env->error_code = 0;
158*73fb7b3cSPaolo Bonzini     env->exception_is_int = 0;
159*73fb7b3cSPaolo Bonzini     env->exception_next_eip = env->eip;
160*73fb7b3cSPaolo Bonzini     cpu_loop_exit(cs);
161*73fb7b3cSPaolo Bonzini }
162*73fb7b3cSPaolo Bonzini 
handle_unaligned_access(CPUX86State * env,vaddr vaddr,MMUAccessType access_type,uintptr_t retaddr)163958e1dd1SPaolo Bonzini G_NORETURN void handle_unaligned_access(CPUX86State *env, vaddr vaddr,
164958e1dd1SPaolo Bonzini                                         MMUAccessType access_type,
165958e1dd1SPaolo Bonzini                                         uintptr_t retaddr)
166958e1dd1SPaolo Bonzini {
167958e1dd1SPaolo Bonzini     /*
168958e1dd1SPaolo Bonzini      * Unaligned accesses are currently only triggered by SSE/AVX
169958e1dd1SPaolo Bonzini      * instructions that impose alignment requirements on memory
170958e1dd1SPaolo Bonzini      * operands. These instructions raise #GP(0) upon accessing an
171958e1dd1SPaolo Bonzini      * unaligned address.
172958e1dd1SPaolo Bonzini      */
173958e1dd1SPaolo Bonzini     raise_exception_ra(env, EXCP0D_GPF, retaddr);
174958e1dd1SPaolo Bonzini }
175