From patchwork Fri Feb 17 17:31:17 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 141938 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 2C018B6FBA for ; Sat, 18 Feb 2012 04:32:00 +1100 (EST) Received: from localhost ([::1]:35937 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RyRf2-0000x1-8g for incoming@patchwork.ozlabs.org; Fri, 17 Feb 2012 12:31:56 -0500 Received: from eggs.gnu.org ([140.186.70.92]:32897) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RyRek-0000jp-Hz for qemu-devel@nongnu.org; Fri, 17 Feb 2012 12:31:40 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RyRea-0002IJ-Op for qemu-devel@nongnu.org; Fri, 17 Feb 2012 12:31:38 -0500 Received: from goliath.siemens.de ([192.35.17.28]:21092) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RyRea-0002Gx-4R for qemu-devel@nongnu.org; Fri, 17 Feb 2012 12:31:28 -0500 Received: from mail1.siemens.de (localhost [127.0.0.1]) by goliath.siemens.de (8.13.6/8.13.6) with ESMTP id q1HHVNgB022538; Fri, 17 Feb 2012 18:31:23 +0100 Received: from mchn199C.mchp.siemens.de ([139.25.109.49]) by mail1.siemens.de (8.13.6/8.13.6) with ESMTP id q1HHVMuN031868; Fri, 17 Feb 2012 18:31:23 +0100 From: Jan Kiszka To: Avi Kivity , Marcelo Tosatti Date: Fri, 17 Feb 2012 18:31:17 +0100 Message-Id: X-Mailer: git-send-email 1.7.3.4 In-Reply-To: References: In-Reply-To: References: X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6, seldom 2.4 (older, 4) X-Received-From: 192.35.17.28 Cc: Blue Swirl , Anthony Liguori , qemu-devel , kvm@vger.kernel.org, Gleb Natapov Subject: [Qemu-devel] [PATCH v4 05/10] target-i386: Add infrastructure for reporting TPR MMIO accesses X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This will allow the APIC core to file a TPR access report. Depending on the accelerator and kernel irqchip mode, it will either be delivered right away or queued for later reporting. In TCG mode, we can restart the triggering instruction and can therefore forward the event directly. KVM does not allows us to restart, so we postpone the delivery of events recording in the user space APIC until the current instruction is completed. Note that KVM without in-kernel irqchip will report the address after the instruction that triggered the access. Signed-off-by: Jan Kiszka --- cpu-all.h | 3 ++- hw/apic.h | 2 ++ hw/apic_common.c | 5 +++++ hw/mc146818rtc.c | 5 ++++- target-i386/cpu.h | 10 ++++++++++ target-i386/helper.c | 16 ++++++++++++++++ target-i386/kvm.c | 25 +++++++++++++++++++++++-- 7 files changed, 62 insertions(+), 4 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index e2c3c49..80e6d42 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -375,8 +375,9 @@ DECLARE_TLS(CPUState *,cpu_single_env); #define CPU_INTERRUPT_TGT_INT_0 0x0100 #define CPU_INTERRUPT_TGT_INT_1 0x0400 #define CPU_INTERRUPT_TGT_INT_2 0x0800 +#define CPU_INTERRUPT_TGT_INT_3 0x2000 -/* First unused bit: 0x2000. */ +/* First unused bit: 0x4000. */ /* The set of all bits that should be masked when single-stepping. */ #define CPU_INTERRUPT_SSTEP_MASK \ diff --git a/hw/apic.h b/hw/apic.h index a62d83b..d6d6d44 100644 --- a/hw/apic.h +++ b/hw/apic.h @@ -18,6 +18,8 @@ void cpu_set_apic_tpr(DeviceState *s, uint8_t val); uint8_t cpu_get_apic_tpr(DeviceState *s); void apic_init_reset(DeviceState *s); void apic_sipi(DeviceState *s); +void apic_handle_tpr_access_report(DeviceState *d, target_ulong ip, + TPRAccess access); /* pc.c */ int cpu_is_bsp(CPUState *env); diff --git a/hw/apic_common.c b/hw/apic_common.c index c91f7d5..340d793 100644 --- a/hw/apic_common.c +++ b/hw/apic_common.c @@ -68,6 +68,11 @@ uint8_t cpu_get_apic_tpr(DeviceState *d) return s ? s->tpr >> 4 : 0; } +void apic_handle_tpr_access_report(DeviceState *d, target_ulong ip, + TPRAccess access) +{ +} + void apic_report_irq_delivered(int delivered) { apic_irq_delivered += delivered; diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 6c1ad38..5671840 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -25,10 +25,13 @@ #include "qemu-timer.h" #include "sysemu.h" #include "pc.h" -#include "apic.h" #include "isa.h" #include "mc146818rtc.h" +#ifdef TARGET_I386 +#include "apic.h" +#endif + //#define DEBUG_CMOS //#define DEBUG_COALESCED diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 37dde79..196b0c5 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -482,6 +482,7 @@ #define CPU_INTERRUPT_VIRQ CPU_INTERRUPT_TGT_INT_0 #define CPU_INTERRUPT_INIT CPU_INTERRUPT_TGT_INT_1 #define CPU_INTERRUPT_SIPI CPU_INTERRUPT_TGT_INT_2 +#define CPU_INTERRUPT_TPR CPU_INTERRUPT_TGT_INT_3 enum { @@ -613,6 +614,11 @@ typedef struct { #define NB_MMU_MODES 2 +typedef enum TPRAccess { + TPR_ACCESS_READ, + TPR_ACCESS_WRITE, +} TPRAccess; + typedef struct CPUX86State { /* standard registers */ target_ulong regs[CPU_NB_REGS]; @@ -772,6 +778,8 @@ typedef struct CPUX86State { XMMReg ymmh_regs[CPU_NB_REGS]; uint64_t xcr0; + + TPRAccess tpr_access_type; } CPUX86State; CPUX86State *cpu_x86_init(const char *cpu_model); @@ -1064,4 +1072,6 @@ void svm_check_intercept(CPUState *env1, uint32_t type); uint32_t cpu_cc_compute_all(CPUState *env1, int op); +void cpu_report_tpr_access(CPUState *env, TPRAccess access); + #endif /* CPU_I386_H */ diff --git a/target-i386/helper.c b/target-i386/helper.c index 2586aff..d12c962 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1189,6 +1189,22 @@ void cpu_x86_inject_mce(Monitor *mon, CPUState *cenv, int bank, } } } + +void cpu_report_tpr_access(CPUState *env, TPRAccess access) +{ + TranslationBlock *tb; + + if (kvm_enabled()) { + env->tpr_access_type = access; + + cpu_interrupt(env, CPU_INTERRUPT_TPR); + } else { + tb = tb_find_pc(env->mem_io_pc); + cpu_restore_state(tb, env, env->mem_io_pc); + + apic_handle_tpr_access_report(env->apic_state, env->eip, access); + } +} #endif /* !CONFIG_USER_ONLY */ static void mce_init(CPUX86State *cenv) diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 0e0b63b..9a73207 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -1635,8 +1635,10 @@ void kvm_arch_pre_run(CPUState *env, struct kvm_run *run) } if (!kvm_irqchip_in_kernel()) { - /* Force the VCPU out of its inner loop to process the INIT request */ - if (env->interrupt_request & CPU_INTERRUPT_INIT) { + /* Force the VCPU out of its inner loop to process any INIT requests + * or pending TPR access reports. */ + if (env->interrupt_request & + (CPU_INTERRUPT_INIT | CPU_INTERRUPT_TPR)) { env->exit_request = 1; } @@ -1730,6 +1732,12 @@ int kvm_arch_process_async_events(CPUState *env) kvm_cpu_synchronize_state(env); do_cpu_sipi(env); } + if (env->interrupt_request & CPU_INTERRUPT_TPR) { + env->interrupt_request &= ~CPU_INTERRUPT_TPR; + kvm_cpu_synchronize_state(env); + apic_handle_tpr_access_report(env->apic_state, env->eip, + env->tpr_access_type); + } return env->halted; } @@ -1746,6 +1754,16 @@ static int kvm_handle_halt(CPUState *env) return 0; } +static int kvm_handle_tpr_access(CPUState *env) +{ + struct kvm_run *run = env->kvm_run; + + apic_handle_tpr_access_report(env->apic_state, run->tpr_access.rip, + run->tpr_access.is_write ? TPR_ACCESS_WRITE + : TPR_ACCESS_READ); + return 1; +} + int kvm_arch_insert_sw_breakpoint(CPUState *env, struct kvm_sw_breakpoint *bp) { static const uint8_t int3 = 0xcc; @@ -1950,6 +1968,9 @@ int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run) case KVM_EXIT_SET_TPR: ret = 0; break; + case KVM_EXIT_TPR_ACCESS: + ret = kvm_handle_tpr_access(env); + break; case KVM_EXIT_FAIL_ENTRY: code = run->fail_entry.hardware_entry_failure_reason; fprintf(stderr, "KVM: entry failed, hardware error 0x%" PRIx64 "\n",