#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 \
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);
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;
#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
#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 {
#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];
XMMReg ymmh_regs[CPU_NB_REGS];
uint64_t xcr0;
+
+ TPRAccess tpr_access_type;
} CPUX86State;
CPUX86State *cpu_x86_init(const char *cpu_model);
uint32_t cpu_cc_compute_all(CPUState *env1, int op);
+void cpu_report_tpr_access(CPUState *env, TPRAccess access);
+
#endif /* CPU_I386_H */
}
}
}
+
+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)
}
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;
}
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;
}
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;
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",