Skip to content

Commit b209749

Browse files
committed
KVM: local APIC TPR access reporting facility
Add a facility to report on accesses to the local apic tpr even if the local apic is emulated in the kernel. This is basically a hack that allows userspace to patch Windows which tends to bang on the tpr a lot. Signed-off-by: Avi Kivity <avi@qumranet.com>
1 parent 565f1fb commit b209749

File tree

5 files changed

+65
-1
lines changed

5 files changed

+65
-1
lines changed

arch/x86/kvm/lapic.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,23 @@ static u32 apic_get_tmcct(struct kvm_lapic *apic)
551551
return tmcct;
552552
}
553553

554+
static void __report_tpr_access(struct kvm_lapic *apic, bool write)
555+
{
556+
struct kvm_vcpu *vcpu = apic->vcpu;
557+
struct kvm_run *run = vcpu->run;
558+
559+
set_bit(KVM_REQ_REPORT_TPR_ACCESS, &vcpu->requests);
560+
kvm_x86_ops->cache_regs(vcpu);
561+
run->tpr_access.rip = vcpu->arch.rip;
562+
run->tpr_access.is_write = write;
563+
}
564+
565+
static inline void report_tpr_access(struct kvm_lapic *apic, bool write)
566+
{
567+
if (apic->vcpu->arch.tpr_access_reporting)
568+
__report_tpr_access(apic, write);
569+
}
570+
554571
static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset)
555572
{
556573
u32 val = 0;
@@ -568,6 +585,9 @@ static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset)
568585
val = apic_get_tmcct(apic);
569586
break;
570587

588+
case APIC_TASKPRI:
589+
report_tpr_access(apic, false);
590+
/* fall thru */
571591
default:
572592
apic_update_ppr(apic);
573593
val = apic_get_reg(apic, offset);
@@ -677,6 +697,7 @@ static void apic_mmio_write(struct kvm_io_device *this,
677697
break;
678698

679699
case APIC_TASKPRI:
700+
report_tpr_access(apic, true);
680701
apic_set_tpr(apic, val & 0xff);
681702
break;
682703

arch/x86/kvm/x86.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,7 @@ int kvm_dev_ioctl_check_extension(long ext)
684684
case KVM_CAP_USER_MEMORY:
685685
case KVM_CAP_SET_TSS_ADDR:
686686
case KVM_CAP_EXT_CPUID:
687+
case KVM_CAP_VAPIC:
687688
r = 1;
688689
break;
689690
default:
@@ -1055,6 +1056,15 @@ static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
10551056
return 0;
10561057
}
10571058

1059+
static int vcpu_ioctl_tpr_access_reporting(struct kvm_vcpu *vcpu,
1060+
struct kvm_tpr_access_ctl *tac)
1061+
{
1062+
if (tac->flags)
1063+
return -EINVAL;
1064+
vcpu->arch.tpr_access_reporting = !!tac->enabled;
1065+
return 0;
1066+
}
1067+
10581068
long kvm_arch_vcpu_ioctl(struct file *filp,
10591069
unsigned int ioctl, unsigned long arg)
10601070
{
@@ -1148,6 +1158,21 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
11481158
case KVM_SET_MSRS:
11491159
r = msr_io(vcpu, argp, do_set_msr, 0);
11501160
break;
1161+
case KVM_TPR_ACCESS_REPORTING: {
1162+
struct kvm_tpr_access_ctl tac;
1163+
1164+
r = -EFAULT;
1165+
if (copy_from_user(&tac, argp, sizeof tac))
1166+
goto out;
1167+
r = vcpu_ioctl_tpr_access_reporting(vcpu, &tac);
1168+
if (r)
1169+
goto out;
1170+
r = -EFAULT;
1171+
if (copy_to_user(argp, &tac, sizeof tac))
1172+
goto out;
1173+
r = 0;
1174+
break;
1175+
};
11511176
default:
11521177
r = -EINVAL;
11531178
}

include/asm-x86/kvm_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ struct kvm_vcpu_arch {
211211
int mp_state;
212212
int sipi_vector;
213213
u64 ia32_misc_enable_msr;
214+
bool tpr_access_reporting;
214215

215216
struct kvm_mmu mmu;
216217

include/linux/kvm.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ struct kvm_irqchip {
7272
#define KVM_EXIT_FAIL_ENTRY 9
7373
#define KVM_EXIT_INTR 10
7474
#define KVM_EXIT_SET_TPR 11
75+
#define KVM_EXIT_TPR_ACCESS 12
7576

7677
/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
7778
struct kvm_run {
@@ -130,6 +131,12 @@ struct kvm_run {
130131
__u32 longmode;
131132
__u32 pad;
132133
} hypercall;
134+
/* KVM_EXIT_TPR_ACCESS */
135+
struct {
136+
__u64 rip;
137+
__u32 is_write;
138+
__u32 pad;
139+
} tpr_access;
133140
/* Fix the size of the union. */
134141
char padding[256];
135142
};
@@ -202,6 +209,13 @@ struct kvm_signal_mask {
202209
__u8 sigset[0];
203210
};
204211

212+
/* for KVM_TPR_ACCESS_REPORTING */
213+
struct kvm_tpr_access_ctl {
214+
__u32 enabled;
215+
__u32 flags;
216+
__u32 reserved[8];
217+
};
218+
205219
#define KVMIO 0xAE
206220

207221
/*
@@ -229,6 +243,7 @@ struct kvm_signal_mask {
229243
#define KVM_CAP_USER_MEMORY 3
230244
#define KVM_CAP_SET_TSS_ADDR 4
231245
#define KVM_CAP_EXT_CPUID 5
246+
#define KVM_CAP_VAPIC 6
232247

233248
/*
234249
* ioctls for VM fds
@@ -274,5 +289,7 @@ struct kvm_signal_mask {
274289
#define KVM_SET_LAPIC _IOW(KVMIO, 0x8f, struct kvm_lapic_state)
275290
#define KVM_SET_CPUID2 _IOW(KVMIO, 0x90, struct kvm_cpuid2)
276291
#define KVM_GET_CPUID2 _IOWR(KVMIO, 0x91, struct kvm_cpuid2)
292+
/* Available with KVM_CAP_VAPIC */
293+
#define KVM_TPR_ACCESS_REPORTING _IOWR(KVMIO, 0x92, struct kvm_tpr_access_ctl)
277294

278295
#endif

include/linux/kvm_host.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
* vcpu->requests bit members
3636
*/
3737
#define KVM_REQ_TLB_FLUSH 0
38-
38+
#define KVM_REQ_REPORT_TPR_ACCESS 2
3939

4040
struct kvm_vcpu;
4141
extern struct kmem_cache *kvm_vcpu_cache;

0 commit comments

Comments
 (0)