Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 133666
b: refs/heads/master
c: 42dbaa5
h: refs/heads/master
v: v3
  • Loading branch information
Jan Kiszka authored and Avi Kivity committed Mar 24, 2009
1 parent 1a63115 commit 588bbf8
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 97 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 55934c0bd3bb232a9cf902820dd63ad18ed65e49
refs/heads/master: 42dbaa5a057736bf8b5c22aa42dbe975bf1080e5
22 changes: 22 additions & 0 deletions trunk/arch/x86/include/asm/kvm_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,19 @@ enum {

#define KVM_NR_MEM_OBJS 40

#define KVM_NR_DB_REGS 4

#define DR6_BD (1 << 13)
#define DR6_BS (1 << 14)
#define DR6_FIXED_1 0xffff0ff0
#define DR6_VOLATILE 0x0000e00f

#define DR7_BP_EN_MASK 0x000000ff
#define DR7_GE (1 << 9)
#define DR7_GD (1 << 13)
#define DR7_FIXED_1 0x00000400
#define DR7_VOLATILE 0xffff23ff

/*
* We don't want allocation failures within the mmu code, so we preallocate
* enough memory for a single page fault in a cache.
Expand Down Expand Up @@ -334,6 +347,15 @@ struct kvm_vcpu_arch {

struct mtrr_state_type mtrr_state;
u32 pat;

int switch_db_regs;
unsigned long host_db[KVM_NR_DB_REGS];
unsigned long host_dr6;
unsigned long host_dr7;
unsigned long db[KVM_NR_DB_REGS];
unsigned long dr6;
unsigned long dr7;
unsigned long eff_db[KVM_NR_DB_REGS];
};

struct kvm_mem_alias {
Expand Down
2 changes: 1 addition & 1 deletion trunk/arch/x86/include/asm/vmx.h
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ enum vmcs_field {
#define DEBUG_REG_ACCESS_TYPE 0x10 /* 4, direction of access */
#define TYPE_MOV_TO_DR (0 << 4)
#define TYPE_MOV_FROM_DR (1 << 4)
#define DEBUG_REG_ACCESS_REG 0xf00 /* 11:8, general purpose reg. */
#define DEBUG_REG_ACCESS_REG(eq) (((eq) >> 8) & 0xf) /* 11:8, general purpose reg. */


/* segment AR */
Expand Down
6 changes: 0 additions & 6 deletions trunk/arch/x86/kvm/kvm_svm.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ static const u32 host_save_user_msrs[] = {
};

#define NR_HOST_SAVE_USER_MSRS ARRAY_SIZE(host_save_user_msrs)
#define NUM_DB_REGS 4

struct kvm_vcpu;

Expand All @@ -29,16 +28,11 @@ struct vcpu_svm {
struct svm_cpu_data *svm_data;
uint64_t asid_generation;

unsigned long db_regs[NUM_DB_REGS];

u64 next_rip;

u64 host_user_msrs[NR_HOST_SAVE_USER_MSRS];
u64 host_gs_base;
unsigned long host_cr2;
unsigned long host_db_regs[NUM_DB_REGS];
unsigned long host_dr6;
unsigned long host_dr7;

u32 *msrpm;
struct vmcb *hsave;
Expand Down
116 changes: 43 additions & 73 deletions trunk/arch/x86/kvm/svm.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ MODULE_LICENSE("GPL");
#define IOPM_ALLOC_ORDER 2
#define MSRPM_ALLOC_ORDER 1

#define DR7_GD_MASK (1 << 13)
#define DR6_BD_MASK (1 << 13)

#define SEG_TYPE_LDT 2
#define SEG_TYPE_BUSY_TSS16 3

Expand Down Expand Up @@ -181,32 +178,6 @@ static inline void kvm_write_cr2(unsigned long val)
asm volatile ("mov %0, %%cr2" :: "r" (val));
}

static inline unsigned long read_dr6(void)
{
unsigned long dr6;

asm volatile ("mov %%dr6, %0" : "=r" (dr6));
return dr6;
}

static inline void write_dr6(unsigned long val)
{
asm volatile ("mov %0, %%dr6" :: "r" (val));
}

static inline unsigned long read_dr7(void)
{
unsigned long dr7;

asm volatile ("mov %%dr7, %0" : "=r" (dr7));
return dr7;
}

static inline void write_dr7(unsigned long val)
{
asm volatile ("mov %0, %%dr7" :: "r" (val));
}

static inline void force_new_asid(struct kvm_vcpu *vcpu)
{
to_svm(vcpu)->asid_generation--;
Expand Down Expand Up @@ -695,7 +666,6 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
clear_page(svm->vmcb);
svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT;
svm->asid_generation = 0;
memset(svm->db_regs, 0, sizeof(svm->db_regs));
init_vmcb(svm);

fx_init(&svm->vcpu);
Expand Down Expand Up @@ -1035,7 +1005,29 @@ static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *svm_data)

static unsigned long svm_get_dr(struct kvm_vcpu *vcpu, int dr)
{
unsigned long val = to_svm(vcpu)->db_regs[dr];
struct vcpu_svm *svm = to_svm(vcpu);
unsigned long val;

switch (dr) {
case 0 ... 3:
val = vcpu->arch.db[dr];
break;
case 6:
if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)
val = vcpu->arch.dr6;
else
val = svm->vmcb->save.dr6;
break;
case 7:
if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)
val = vcpu->arch.dr7;
else
val = svm->vmcb->save.dr7;
break;
default:
val = 0;
}

KVMTRACE_2D(DR_READ, vcpu, (u32)dr, (u32)val, handler);
return val;
}
Expand All @@ -1045,33 +1037,40 @@ static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value,
{
struct vcpu_svm *svm = to_svm(vcpu);

*exception = 0;
KVMTRACE_2D(DR_WRITE, vcpu, (u32)dr, (u32)value, handler);

if (svm->vmcb->save.dr7 & DR7_GD_MASK) {
svm->vmcb->save.dr7 &= ~DR7_GD_MASK;
svm->vmcb->save.dr6 |= DR6_BD_MASK;
*exception = DB_VECTOR;
return;
}
*exception = 0;

switch (dr) {
case 0 ... 3:
svm->db_regs[dr] = value;
vcpu->arch.db[dr] = value;
if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
vcpu->arch.eff_db[dr] = value;
return;
case 4 ... 5:
if (vcpu->arch.cr4 & X86_CR4_DE) {
if (vcpu->arch.cr4 & X86_CR4_DE)
*exception = UD_VECTOR;
return;
case 6:
if (value & 0xffffffff00000000ULL) {
*exception = GP_VECTOR;
return;
}
case 7: {
if (value & ~((1ULL << 32) - 1)) {
vcpu->arch.dr6 = (value & DR6_VOLATILE) | DR6_FIXED_1;
return;
case 7:
if (value & 0xffffffff00000000ULL) {
*exception = GP_VECTOR;
return;
}
svm->vmcb->save.dr7 = value;
vcpu->arch.dr7 = (value & DR7_VOLATILE) | DR7_FIXED_1;
if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)) {
svm->vmcb->save.dr7 = vcpu->arch.dr7;
vcpu->arch.switch_db_regs = (value & DR7_BP_EN_MASK);
}
return;
}
default:
/* FIXME: Possible case? */
printk(KERN_DEBUG "%s: unexpected dr %u\n",
__func__, dr);
*exception = UD_VECTOR;
Expand Down Expand Up @@ -2365,22 +2364,6 @@ static int svm_set_tss_addr(struct kvm *kvm, unsigned int addr)
return 0;
}

static void save_db_regs(unsigned long *db_regs)
{
asm volatile ("mov %%dr0, %0" : "=r"(db_regs[0]));
asm volatile ("mov %%dr1, %0" : "=r"(db_regs[1]));
asm volatile ("mov %%dr2, %0" : "=r"(db_regs[2]));
asm volatile ("mov %%dr3, %0" : "=r"(db_regs[3]));
}

static void load_db_regs(unsigned long *db_regs)
{
asm volatile ("mov %0, %%dr0" : : "r"(db_regs[0]));
asm volatile ("mov %0, %%dr1" : : "r"(db_regs[1]));
asm volatile ("mov %0, %%dr2" : : "r"(db_regs[2]));
asm volatile ("mov %0, %%dr3" : : "r"(db_regs[3]));
}

static void svm_flush_tlb(struct kvm_vcpu *vcpu)
{
force_new_asid(vcpu);
Expand Down Expand Up @@ -2439,20 +2422,12 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
gs_selector = kvm_read_gs();
ldt_selector = kvm_read_ldt();
svm->host_cr2 = kvm_read_cr2();
svm->host_dr6 = read_dr6();
svm->host_dr7 = read_dr7();
if (!is_nested(svm))
svm->vmcb->save.cr2 = vcpu->arch.cr2;
/* required for live migration with NPT */
if (npt_enabled)
svm->vmcb->save.cr3 = vcpu->arch.cr3;

if (svm->vmcb->save.dr7 & 0xff) {
write_dr7(0);
save_db_regs(svm->host_db_regs);
load_db_regs(svm->db_regs);
}

clgi();

local_irq_enable();
Expand Down Expand Up @@ -2528,16 +2503,11 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
#endif
);

if ((svm->vmcb->save.dr7 & 0xff))
load_db_regs(svm->host_db_regs);

vcpu->arch.cr2 = svm->vmcb->save.cr2;
vcpu->arch.regs[VCPU_REGS_RAX] = svm->vmcb->save.rax;
vcpu->arch.regs[VCPU_REGS_RSP] = svm->vmcb->save.rsp;
vcpu->arch.regs[VCPU_REGS_RIP] = svm->vmcb->save.rip;

write_dr6(svm->host_dr6);
write_dr7(svm->host_dr7);
kvm_write_cr2(svm->host_cr2);

kvm_load_fs(fs_selector);
Expand Down
Loading

0 comments on commit 588bbf8

Please sign in to comment.