summaryrefslogtreecommitdiff
path: root/target-i386
diff options
context:
space:
mode:
Diffstat (limited to 'target-i386')
-rw-r--r--target-i386/cpu.h10
-rw-r--r--target-i386/helper.c16
-rw-r--r--target-i386/kvm.c26
3 files changed, 50 insertions, 2 deletions
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 37dde79581..196b0c5c40 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 2586aff700..d12c9621bd 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 981192ddf8..9a732078f3 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",
@@ -1987,6 +2008,7 @@ int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)
bool kvm_arch_stop_on_emulation_error(CPUState *env)
{
+ kvm_cpu_synchronize_state(env);
return !(env->cr[0] & CR0_PE_MASK) ||
((env->segs[R_CS].selector & 3) != 3);
}