x86: split off exception handlers
Move exception handlers from op_helper.c to excp_helper.c. Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
This commit is contained in:
parent
77b2bc2c09
commit
599b9a5a51
@ -1,4 +1,5 @@
|
||||
obj-y += translate.o op_helper.o helper.o cpu.o
|
||||
obj-y += excp_helper.o
|
||||
obj-$(CONFIG_SOFTMMU) += machine.o arch_memory_mapping.o arch_dump.o
|
||||
obj-$(CONFIG_KVM) += kvm.o hyperv.o
|
||||
obj-$(CONFIG_LINUX_USER) += ioport-user.o
|
||||
|
@ -1071,12 +1071,16 @@ void cpu_x86_inject_mce(Monitor *mon, CPUX86State *cenv, int bank,
|
||||
uint64_t status, uint64_t mcg_status, uint64_t addr,
|
||||
uint64_t misc, int flags);
|
||||
|
||||
/* op_helper.c */
|
||||
void do_interrupt(CPUX86State *env);
|
||||
void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw);
|
||||
/* excp_helper.c */
|
||||
void QEMU_NORETURN raise_exception(CPUX86State *env, int exception_index);
|
||||
void QEMU_NORETURN raise_exception_err(CPUX86State *env, int exception_index,
|
||||
int error_code);
|
||||
void QEMU_NORETURN raise_interrupt(CPUX86State *nenv, int intno, int is_int,
|
||||
int error_code, int next_eip_addend);
|
||||
|
||||
/* op_helper.c */
|
||||
void do_interrupt(CPUX86State *env);
|
||||
void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw);
|
||||
|
||||
void do_smm_enter(CPUX86State *env1);
|
||||
|
||||
|
132
target-i386/excp_helper.c
Normal file
132
target-i386/excp_helper.c
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* x86 exception helpers
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "cpu.h"
|
||||
#include "qemu-log.h"
|
||||
#include "helper.h"
|
||||
|
||||
#if 0
|
||||
#define raise_exception_err(env, a, b) \
|
||||
do { \
|
||||
qemu_log("raise_exception line=%d\n", __LINE__); \
|
||||
(raise_exception_err)(env, a, b); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
void helper_raise_interrupt(CPUX86State *env, int intno, int next_eip_addend)
|
||||
{
|
||||
raise_interrupt(env, intno, 1, 0, next_eip_addend);
|
||||
}
|
||||
|
||||
void helper_raise_exception(CPUX86State *env, int exception_index)
|
||||
{
|
||||
raise_exception(env, exception_index);
|
||||
}
|
||||
|
||||
|
||||
/* This should come from sysemu.h - if we could include it here... */
|
||||
void qemu_system_reset_request(void);
|
||||
|
||||
/*
|
||||
* Check nested exceptions and change to double or triple fault if
|
||||
* needed. It should only be called, if this is not an interrupt.
|
||||
* Returns the new exception number.
|
||||
*/
|
||||
static int check_exception(CPUX86State *env, int intno, int *error_code)
|
||||
{
|
||||
int first_contributory = env->old_exception == 0 ||
|
||||
(env->old_exception >= 10 &&
|
||||
env->old_exception <= 13);
|
||||
int second_contributory = intno == 0 ||
|
||||
(intno >= 10 && intno <= 13);
|
||||
|
||||
qemu_log_mask(CPU_LOG_INT, "check_exception old: 0x%x new 0x%x\n",
|
||||
env->old_exception, intno);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (env->old_exception == EXCP08_DBLE) {
|
||||
if (env->hflags & HF_SVMI_MASK) {
|
||||
cpu_vmexit(env, SVM_EXIT_SHUTDOWN, 0); /* does not return */
|
||||
}
|
||||
|
||||
qemu_log_mask(CPU_LOG_RESET, "Triple fault\n");
|
||||
|
||||
qemu_system_reset_request();
|
||||
return EXCP_HLT;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((first_contributory && second_contributory)
|
||||
|| (env->old_exception == EXCP0E_PAGE &&
|
||||
(second_contributory || (intno == EXCP0E_PAGE)))) {
|
||||
intno = EXCP08_DBLE;
|
||||
*error_code = 0;
|
||||
}
|
||||
|
||||
if (second_contributory || (intno == EXCP0E_PAGE) ||
|
||||
(intno == EXCP08_DBLE)) {
|
||||
env->old_exception = intno;
|
||||
}
|
||||
|
||||
return intno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Signal an interruption. It is executed in the main CPU loop.
|
||||
* is_int is TRUE if coming from the int instruction. next_eip is the
|
||||
* EIP value AFTER the interrupt instruction. It is only relevant if
|
||||
* is_int is TRUE.
|
||||
*/
|
||||
static void QEMU_NORETURN raise_interrupt2(CPUX86State *env, int intno,
|
||||
int is_int, int error_code,
|
||||
int next_eip_addend)
|
||||
{
|
||||
if (!is_int) {
|
||||
cpu_svm_check_intercept_param(env, SVM_EXIT_EXCP_BASE + intno,
|
||||
error_code);
|
||||
intno = check_exception(env, intno, &error_code);
|
||||
} else {
|
||||
cpu_svm_check_intercept_param(env, SVM_EXIT_SWINT, 0);
|
||||
}
|
||||
|
||||
env->exception_index = intno;
|
||||
env->error_code = error_code;
|
||||
env->exception_is_int = is_int;
|
||||
env->exception_next_eip = env->eip + next_eip_addend;
|
||||
cpu_loop_exit(env);
|
||||
}
|
||||
|
||||
/* shortcuts to generate exceptions */
|
||||
|
||||
void QEMU_NORETURN raise_interrupt(CPUX86State *env, int intno, int is_int,
|
||||
int error_code, int next_eip_addend)
|
||||
{
|
||||
raise_interrupt2(env, intno, is_int, error_code, next_eip_addend);
|
||||
}
|
||||
|
||||
void raise_exception_err(CPUX86State *env, int exception_index,
|
||||
int error_code)
|
||||
{
|
||||
raise_interrupt2(env, exception_index, 0, error_code, 0);
|
||||
}
|
||||
|
||||
void raise_exception(CPUX86State *env, int exception_index)
|
||||
{
|
||||
raise_interrupt2(env, exception_index, 0, 0, 0);
|
||||
}
|
@ -138,14 +138,6 @@ static inline void cpu_load_efer(CPUX86State *env, uint64_t val)
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
#define raise_exception_err(env, a, b) \
|
||||
do { \
|
||||
qemu_log("raise_exception line=%d\n", __LINE__); \
|
||||
(raise_exception_err)(env, a, b); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
static const uint8_t parity_table[256] = {
|
||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
||||
@ -1529,101 +1521,6 @@ void do_interrupt_x86_hardirq(CPUX86State *env1, int intno, int is_hw)
|
||||
env = saved_env;
|
||||
}
|
||||
|
||||
/* This should come from sysemu.h - if we could include it here... */
|
||||
void qemu_system_reset_request(void);
|
||||
|
||||
/*
|
||||
* Check nested exceptions and change to double or triple fault if
|
||||
* needed. It should only be called, if this is not an interrupt.
|
||||
* Returns the new exception number.
|
||||
*/
|
||||
static int check_exception(CPUX86State *env, int intno, int *error_code)
|
||||
{
|
||||
int first_contributory = env->old_exception == 0 ||
|
||||
(env->old_exception >= 10 &&
|
||||
env->old_exception <= 13);
|
||||
int second_contributory = intno == 0 ||
|
||||
(intno >= 10 && intno <= 13);
|
||||
|
||||
qemu_log_mask(CPU_LOG_INT, "check_exception old: 0x%x new 0x%x\n",
|
||||
env->old_exception, intno);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (env->old_exception == EXCP08_DBLE) {
|
||||
if (env->hflags & HF_SVMI_MASK) {
|
||||
cpu_vmexit(env, SVM_EXIT_SHUTDOWN, 0); /* does not return */
|
||||
}
|
||||
|
||||
qemu_log_mask(CPU_LOG_RESET, "Triple fault\n");
|
||||
|
||||
qemu_system_reset_request();
|
||||
return EXCP_HLT;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((first_contributory && second_contributory)
|
||||
|| (env->old_exception == EXCP0E_PAGE &&
|
||||
(second_contributory || (intno == EXCP0E_PAGE)))) {
|
||||
intno = EXCP08_DBLE;
|
||||
*error_code = 0;
|
||||
}
|
||||
|
||||
if (second_contributory || (intno == EXCP0E_PAGE) ||
|
||||
(intno == EXCP08_DBLE)) {
|
||||
env->old_exception = intno;
|
||||
}
|
||||
|
||||
return intno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Signal an interruption. It is executed in the main CPU loop.
|
||||
* is_int is TRUE if coming from the int instruction. next_eip is the
|
||||
* EIP value AFTER the interrupt instruction. It is only relevant if
|
||||
* is_int is TRUE.
|
||||
*/
|
||||
static void QEMU_NORETURN raise_interrupt2(CPUX86State *env, int intno,
|
||||
int is_int, int error_code,
|
||||
int next_eip_addend)
|
||||
{
|
||||
if (!is_int) {
|
||||
cpu_svm_check_intercept_param(env, SVM_EXIT_EXCP_BASE + intno,
|
||||
error_code);
|
||||
intno = check_exception(env, intno, &error_code);
|
||||
} else {
|
||||
cpu_svm_check_intercept_param(env, SVM_EXIT_SWINT, 0);
|
||||
}
|
||||
|
||||
env->exception_index = intno;
|
||||
env->error_code = error_code;
|
||||
env->exception_is_int = is_int;
|
||||
env->exception_next_eip = env->eip + next_eip_addend;
|
||||
cpu_loop_exit(env);
|
||||
}
|
||||
|
||||
/* shortcuts to generate exceptions */
|
||||
|
||||
static void QEMU_NORETURN raise_interrupt(CPUX86State *nenv,
|
||||
int intno, int is_int,
|
||||
int error_code,
|
||||
int next_eip_addend)
|
||||
{
|
||||
env = nenv;
|
||||
raise_interrupt2(env, intno, is_int, error_code, next_eip_addend);
|
||||
}
|
||||
|
||||
void raise_exception_err(CPUX86State *nenv, int exception_index,
|
||||
int error_code)
|
||||
{
|
||||
env = nenv;
|
||||
raise_interrupt2(env, exception_index, 0, error_code, 0);
|
||||
}
|
||||
|
||||
void raise_exception(CPUX86State *nenv, int exception_index)
|
||||
{
|
||||
env = nenv;
|
||||
raise_interrupt2(env, exception_index, 0, 0, 0);
|
||||
}
|
||||
/* SMM support */
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
@ -5221,16 +5118,6 @@ void helper_reset_rf(void)
|
||||
env->eflags &= ~RF_MASK;
|
||||
}
|
||||
|
||||
void helper_raise_interrupt(CPUX86State *env, int intno, int next_eip_addend)
|
||||
{
|
||||
raise_interrupt(env, intno, 1, 0, next_eip_addend);
|
||||
}
|
||||
|
||||
void helper_raise_exception(CPUX86State *env, int exception_index)
|
||||
{
|
||||
raise_exception(env, exception_index);
|
||||
}
|
||||
|
||||
void helper_cli(void)
|
||||
{
|
||||
env->eflags &= ~IF_MASK;
|
||||
|
Loading…
Reference in New Issue
Block a user