From patchwork Mon Mar 6 15:57:22 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Alex_Benn=C3=A9e?= X-Patchwork-Id: 94923 Delivered-To: patch@linaro.org Received: by 10.140.82.71 with SMTP id g65csp1452616qgd; Mon, 6 Mar 2017 07:58:06 -0800 (PST) X-Received: by 10.200.55.55 with SMTP id o52mr16596416qtb.279.1488815886839; Mon, 06 Mar 2017 07:58:06 -0800 (PST) Return-Path: Received: from lists.gnu.org (lists.gnu.org. [2001:4830:134:3::11]) by mx.google.com with ESMTPS id u2si15739140qki.218.2017.03.06.07.58.06 for (version=TLS1 cipher=AES128-SHA bits=128/128); Mon, 06 Mar 2017 07:58:06 -0800 (PST) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) client-ip=2001:4830:134:3::11; Authentication-Results: mx.google.com; dkim=fail header.i=@linaro.org; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) smtp.mailfrom=qemu-devel-bounces+patch=linaro.org@nongnu.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([::1]:44669 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ckv1Q-00014T-C1 for patch@linaro.org; Mon, 06 Mar 2017 10:58:04 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:45034) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ckv0s-00014C-JI for qemu-devel@nongnu.org; Mon, 06 Mar 2017 10:57:31 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ckv0p-0001hz-HL for qemu-devel@nongnu.org; Mon, 06 Mar 2017 10:57:30 -0500 Received: from mail-wr0-x235.google.com ([2a00:1450:400c:c0c::235]:34095) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1ckv0p-0001he-7J for qemu-devel@nongnu.org; Mon, 06 Mar 2017 10:57:27 -0500 Received: by mail-wr0-x235.google.com with SMTP id l37so119907346wrc.1 for ; Mon, 06 Mar 2017 07:57:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Mt+A/ts+CraeYotUjkB3WgW9r42chsblTOyUmSOSFYg=; b=V6+XBBT72ej+C2dhKjjgb76aXbu8SrYv+ZT2oBcdxGbHUwUPmbPo6agzEHurJhV6fV MUfMUAvCmBrvJTEAErbXFUFwmqbKJ5UujlWm5/RSQnhhuy9LXMF3V36DFdU1eLA6sKON 5HaaBX/inZDl+WEn85xrfqK2qVU00AO080tVk= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Mt+A/ts+CraeYotUjkB3WgW9r42chsblTOyUmSOSFYg=; b=IosjwPeTTU+zX6vAiN4uY6eInbo7/wi7JOuLWpAqxywgGYX4rV8HfrKMGcZNrn53ir h7tK2YEhXrjGZ7kK//NOeCnzQJBaXlztKhddQGR6CQWXu0MZHehFCzee16akpse55UYl /k8Svtveps2E573BUBitBguKeZ3Ts+DzEHry5JcpGOyvWl7qPqpS14jf8+GBjf+Mu5Jq VJYVr1TgyDEbawB+hOxwUVIhGngrti5p21mXxjJECkCh6KSCobS8qwGj1JQpe0oUP5zQ usWNvWvng3IZJlvo88NTg+C3xgxImenP5V38MW0jGyvW2ezeioVdSGs8i3ETfZXgx0dY hznA== X-Gm-Message-State: AMke39kAM0NhuYUOJK4fqyYBc98n7yu8X2Hsw05CS63LaeLK49zW6bwUjqCLmq5MCHCEIGUC X-Received: by 10.223.138.250 with SMTP id z55mr16426491wrz.130.1488815845853; Mon, 06 Mar 2017 07:57:25 -0800 (PST) Received: from zen.linaro.local ([81.128.185.34]) by smtp.gmail.com with ESMTPSA id l21sm10933664wrl.59.2017.03.06.07.57.24 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 06 Mar 2017 07:57:25 -0800 (PST) Received: from zen.linaroharston (localhost [127.0.0.1]) by zen.linaro.local (Postfix) with ESMTP id CC9ED3E0321; Mon, 6 Mar 2017 15:57:32 +0000 (GMT) From: =?utf-8?q?Alex_Benn=C3=A9e?= To: alexander.boettcher@genode-labs.com Date: Mon, 6 Mar 2017 15:57:22 +0000 Message-Id: <20170306155722.31315-1-alex.bennee@linaro.org> X-Mailer: git-send-email 2.11.0 In-Reply-To: References: MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:400c:c0c::235 Subject: [Qemu-devel] [PATCH] target/i386: move nested exception check to x86_cpu_exec_interrupt X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Paolo Bonzini , =?utf-8?q?Alex_Benn=C3=A9e?= , qemu-devel@nongnu.org, Eduardo Habkost , rth@twiddle.net Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: "Qemu-devel" (DUMB CODE MOTION COMMIT WITHOUT FULL UNDERSTANDING OF X86 NEEDS REVIEW) During code generation cpu_svm_check_intercept_param can through a sequence of events generated a tlb_fill which fails due to a double tb_lock(). Moving the checking to x86_cpu_exec_interrupt where it can take the lock at will. Reported-by: Alexander Boettcher Signed-off-by: Alex Bennée CC: Richard Henderson --- target/i386/cpu.h | 1 + target/i386/excp_helper.c | 54 +------------------------------------------ target/i386/seg_helper.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 53 deletions(-) -- 2.11.0 diff --git a/target/i386/cpu.h b/target/i386/cpu.h index fb09aee7f8..07c591672c 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1105,6 +1105,7 @@ typedef struct CPUX86State { /* exception/interrupt handling */ int error_code; int exception_is_int; + uintptr_t exception_retaddr; target_ulong exception_next_eip; target_ulong dr[8]; /* debug registers; note dr4 and dr5 are unused */ union { diff --git a/target/i386/excp_helper.c b/target/i386/excp_helper.c index ee596c6082..0a1a02cdd4 100644 --- a/target/i386/excp_helper.c +++ b/target/i386/excp_helper.c @@ -35,51 +35,6 @@ void helper_raise_exception(CPUX86State *env, int exception_index) } /* - * 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, - uintptr_t retaddr) -{ - 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, retaddr); /* 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 * env->eip value AFTER the interrupt instruction. It is only relevant if @@ -92,18 +47,11 @@ static void QEMU_NORETURN raise_interrupt2(CPUX86State *env, int intno, { CPUState *cs = CPU(x86_env_get_cpu(env)); - if (!is_int) { - cpu_svm_check_intercept_param(env, SVM_EXIT_EXCP_BASE + intno, - error_code, retaddr); - intno = check_exception(env, intno, &error_code, retaddr); - } else { - cpu_svm_check_intercept_param(env, SVM_EXIT_SWINT, 0, retaddr); - } - cs->exception_index = intno; env->error_code = error_code; env->exception_is_int = is_int; env->exception_next_eip = env->eip + next_eip_addend; + env->exception_retaddr = retaddr; cpu_loop_exit_restore(cs, retaddr); } diff --git a/target/i386/seg_helper.c b/target/i386/seg_helper.c index 5c845dc25c..055b6d4025 100644 --- a/target/i386/seg_helper.c +++ b/target/i386/seg_helper.c @@ -25,6 +25,7 @@ #include "exec/exec-all.h" #include "exec/cpu_ldst.h" #include "exec/log.h" +#include "sysemu/sysemu.h" //#define DEBUG_PCALL @@ -1314,12 +1315,70 @@ void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw) do_interrupt_all(x86_env_get_cpu(env), intno, 0, 0, 0, is_hw); } +/* + * 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, + uintptr_t retaddr) +{ + 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, retaddr); /* 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; +} + bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request) { X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; bool ret = false; + if (!env->exception_is_int) { + cpu_svm_check_intercept_param(env, + SVM_EXIT_EXCP_BASE + cs->exception_index, + env->error_code, + env->exception_retaddr); + cs->exception_index = check_exception(env, cs->exception_index, + &env->error_code, + env->exception_retaddr); + } else { + cpu_svm_check_intercept_param(env, SVM_EXIT_SWINT, 0, + env->exception_retaddr); + } + #if !defined(CONFIG_USER_ONLY) if (interrupt_request & CPU_INTERRUPT_POLL) { cs->interrupt_request &= ~CPU_INTERRUPT_POLL;