Re: RFC: cache_regs in kvm_emulate_pio

2008-06-26 Thread Avi Kivity

Marcelo Tosatti wrote:
  
  
Looks good, but we can aim higher.  The cache_regs() API was always  
confusing (I usually swap the two parts).  If we replace all -regs  
access with accessors, we can make it completely transparent.


It will be tricky in the emulator, but worthwhile, no?



OK, in the emulator an interface on top of guest_register_write() is
needed to save registers so that the original contents can be restored
on failure. Some brave soul can do it later, so I added a TODO in x86.c.

Smells better now?


--- dev/null2008-06-24 14:36:42.383774904 -0300
+++ b/arch/x86/kvm/kvm_cache_regs.h 2008-06-24 15:26:02.0 -0300
@@ -0,0 +1,21 @@
+#ifndef ASM_KVM_CACHE_REGS_H
+#define ASM_KVM_CACHE_REGS_H
+
+static inline unsigned long guest_register_read(struct kvm_vcpu *vcpu,
+   enum kvm_reg reg)
+{
+   if (!__test_and_set_bit(reg, vcpu-arch.regs_available))
+   kvm_x86_ops-cache_regs(vcpu, reg);
+
+   return vcpu-arch.regs[reg];
+}
+
+static inline void guest_register_write(struct kvm_vcpu *vcpu,
+   enum kvm_reg reg,
+   unsigned long val)
+{
+   vcpu-arch.regs[reg] = val;
+   __set_bit(reg, vcpu-arch.regs_dirty);
+}
+
+#endif
  


A new header file is excessive. Also, these are global names, so please 
prefix with kvm_.



@@ -241,7 +242,8 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
   svm-vmcb-save.rip,
   svm-next_rip);
 
-	vcpu-arch.rip = svm-vmcb-save.rip = svm-next_rip;

+   svm-vmcb-save.rip = svm-next_rip;
+   guest_register_write(vcpu, VCPU_REGS_RIP, svm-vmcb-save.rip);
svm-vmcb-control.int_state = ~SVM_INTERRUPT_SHADOW_MASK;
  


No need to write into save.rip, is there?

 
-static void svm_cache_regs(struct kvm_vcpu *vcpu)

+static void svm_cache_regs(struct kvm_vcpu *vcpu, enum kvm_reg reg)
 {
struct vcpu_svm *svm = to_svm(vcpu);
 
-	vcpu-arch.regs[VCPU_REGS_RAX] = svm-vmcb-save.rax;

-   vcpu-arch.regs[VCPU_REGS_RSP] = svm-vmcb-save.rsp;
-   vcpu-arch.rip = svm-vmcb-save.rip;
+   switch (reg) {
+   case VCPU_REGS_RAX:
+   vcpu-arch.regs[VCPU_REGS_RAX] = svm-vmcb-save.rax;
+   break;
+   case VCPU_REGS_RSP:
+   vcpu-arch.regs[VCPU_REGS_RSP] = svm-vmcb-save.rsp;
+   break;
+   case VCPU_REGS_RIP:
+   vcpu-arch.regs[VCPU_REGS_RIP] = svm-vmcb-save.rip;
+   break;
+   default:
+   break;
+   }
 }
  


For svm we ought to unconditionally copy all the registers and mark all 
registers as available, since it's so cheap. This will avoid some callbacks.


We can even to it on the vmexit path, so there will be no 
svm_cache_regs() at all.



@@ -707,9 +708,9 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
unsigned long rip;
u32 interruptibility;
 
-	rip = vmcs_readl(GUEST_RIP);

+   rip = guest_register_read(vcpu, VCPU_REGS_RIP);
  


Perhaps we ought to have a guest_rip_read() since rip is not truly a GPR.

 
 static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)

@@ -2370,22 +2379,18 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct 
kvm_run *kvm_run)
(u32)((u64)vcpu-arch.regs[reg]  32), handler);
switch (cr) {
case 0:
-   vcpu_load_rsp_rip(vcpu);
kvm_set_cr0(vcpu, vcpu-arch.regs[reg]);
  


What if reg points at rsp? You need to replace arch.regs[*] with the 
accessor.



@@ -61,6 +62,7 @@ static int kvm_dev_ioctl_get_supported_cpuid(struct 
kvm_cpuid2 *cpuid,
struct kvm_cpuid_entry2 __user *entries);
 
 struct kvm_x86_ops *kvm_x86_ops;

+EXPORT_SYMBOL(kvm_x86_ops);
  


_GPL


+static void flush_regs(struct kvm_vcpu *vcpu)
+{
+   if (__test_and_clear_bit(VCPU_REGS_RSP, vcpu-arch.regs_dirty))
+   kvm_x86_ops-decache_regs(vcpu, VCPU_REGS_RSP);
+   if (__test_and_clear_bit(VCPU_REGS_RIP, vcpu-arch.regs_dirty))
+   kvm_x86_ops-decache_regs(vcpu, VCPU_REGS_RIP);
+   if (__test_and_clear_bit(VCPU_REGS_RAX, vcpu-arch.regs_dirty))
+   kvm_x86_ops-decache_regs(vcpu, VCPU_REGS_RAX);
+}
  


This is better done in $subarch_vcpu_run, as it avoids callbacks and 
knows exactly which regs to look at. We can do it unconditionally for 
svm, too.


 
+void cache_all_regs(struct kvm_vcpu *vcpu)

+{
+   kvm_x86_ops-cache_regs(vcpu, VCPU_REGS_RAX);
+   kvm_x86_ops-cache_regs(vcpu, VCPU_REGS_RSP);
+   kvm_x86_ops-cache_regs(vcpu, VCPU_REGS_RIP);
+}
+
+void decache_all_regs(struct kvm_vcpu *vcpu)
+{
+   guest_register_write(vcpu, VCPU_REGS_RAX,
+vcpu-arch.regs[VCPU_REGS_RAX]);
+   guest_register_write(vcpu, VCPU_REGS_RSP,
+

Re: RFC: cache_regs in kvm_emulate_pio

2008-06-26 Thread Marcelo Tosatti
On Thu, Jun 26, 2008 at 12:18:07PM +0300, Avi Kivity wrote:
 A new header file is excessive. Also, these are global names, so please  
 prefix with kvm_.

The reason for a separate header is because these accessors need both
kvm_vcpu (linux/kvm_host.h) and kvm_vcpu_arch (asm/kvm_host.h).

I couldnt think of a better location to put them. Ideas?

 @@ -241,7 +242,8 @@ static void skip_emulated_instruction(struct kvm_vcpu 
 *vcpu)
 svm-vmcb-save.rip,
 svm-next_rip);
  -   vcpu-arch.rip = svm-vmcb-save.rip = svm-next_rip;
 +svm-vmcb-save.rip = svm-next_rip;
 +guest_register_write(vcpu, VCPU_REGS_RIP, svm-vmcb-save.rip);
  svm-vmcb-control.int_state = ~SVM_INTERRUPT_SHADOW_MASK;
   

 No need to write into save.rip, is there?

I'm not sure why it was there in the first place. Perhaps there's code
which reads svm-vmcb-save.rip directly as the current RIP after this
point?

Also kvm_guest_register_read is too long, so I dropped guest.

--- /dev/null   2008-06-26 10:56:31.025001212 -0300
+++ b/arch/x86/kvm/kvm_cache_regs.h 2008-06-26 18:38:48.0 -0300
@@ -0,0 +1,36 @@
+#ifndef ASM_KVM_CACHE_REGS_H
+#define ASM_KVM_CACHE_REGS_H
+
+static inline unsigned long kvm_register_read(struct kvm_vcpu *vcpu,
+ enum kvm_reg reg)
+{
+   if (!__test_and_set_bit(reg, vcpu-arch.regs_available))
+   kvm_x86_ops-cache_reg(vcpu, reg);
+
+   return vcpu-arch.regs[reg];
+}
+
+static inline void kvm_register_write(struct kvm_vcpu *vcpu,
+ enum kvm_reg reg,
+ unsigned long val)
+{
+   vcpu-arch.regs[reg] = val;
+   __set_bit(reg, vcpu-arch.regs_dirty);
+}
+
+static inline unsigned long kvm_rip_read(struct kvm_vcpu *vcpu)
+{
+   if (!__test_and_set_bit(VCPU_REGS_RIP, vcpu-arch.regs_available))
+   kvm_x86_ops-cache_reg(vcpu, VCPU_REGS_RIP);
+
+   return vcpu-arch.rip;
+}
+
+static inline void kvm_rip_write(struct kvm_vcpu *vcpu,
+unsigned long val)
+{
+   vcpu-arch.rip = val;
+   __set_bit(VCPU_REGS_RIP, vcpu-arch.regs_dirty);
+}
+
+#endif
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 73f43de..9fde0ac 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -32,6 +32,7 @@
 #include asm/current.h
 #include asm/apicdef.h
 #include asm/atomic.h
+#include kvm_cache_regs.h
 #include irq.h
 
 #define PRId64 d
@@ -558,8 +559,7 @@ static void __report_tpr_access(struct kvm_lapic *apic, 
bool write)
struct kvm_run *run = vcpu-run;
 
set_bit(KVM_REQ_REPORT_TPR_ACCESS, vcpu-requests);
-   kvm_x86_ops-cache_regs(vcpu);
-   run-tpr_access.rip = vcpu-arch.rip;
+   run-tpr_access.rip = kvm_rip_read(vcpu);
run-tpr_access.is_write = write;
 }
 
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 238e8f3..532a393 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -18,6 +18,7 @@
 #include kvm_svm.h
 #include irq.h
 #include mmu.h
+#include kvm_cache_regs.h
 
 #include linux/module.h
 #include linux/kernel.h
@@ -241,7 +242,8 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
   svm-vmcb-save.rip,
   svm-next_rip);
 
-   vcpu-arch.rip = svm-vmcb-save.rip = svm-next_rip;
+   svm-vmcb-save.rip = svm-next_rip;
+   kvm_rip_write(vcpu, svm-vmcb-save.rip);
svm-vmcb-control.int_state = ~SVM_INTERRUPT_SHADOW_MASK;
 
vcpu-arch.interrupt_window_open = 1;
@@ -709,21 +711,42 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu)
rdtscll(vcpu-arch.host_tsc);
 }
 
-static void svm_cache_regs(struct kvm_vcpu *vcpu)
+static void svm_cache_reg(struct kvm_vcpu *vcpu, enum kvm_reg reg)
 {
struct vcpu_svm *svm = to_svm(vcpu);
 
-   vcpu-arch.regs[VCPU_REGS_RAX] = svm-vmcb-save.rax;
-   vcpu-arch.regs[VCPU_REGS_RSP] = svm-vmcb-save.rsp;
-   vcpu-arch.rip = svm-vmcb-save.rip;
+   switch (reg) {
+   case VCPU_REGS_RAX:
+   vcpu-arch.regs[VCPU_REGS_RAX] = svm-vmcb-save.rax;
+   break;
+   case VCPU_REGS_RSP:
+   vcpu-arch.regs[VCPU_REGS_RSP] = svm-vmcb-save.rsp;
+   break;
+   case VCPU_REGS_RIP:
+   vcpu-arch.rip = svm-vmcb-save.rip;
+   break;
+   default:
+   break;
+   }
 }
 
-static void svm_decache_regs(struct kvm_vcpu *vcpu)
+static void svm_decache_reg(struct kvm_vcpu *vcpu, enum kvm_reg reg)
 {
struct vcpu_svm *svm = to_svm(vcpu);
-   svm-vmcb-save.rax = vcpu-arch.regs[VCPU_REGS_RAX];
-   svm-vmcb-save.rsp = vcpu-arch.regs[VCPU_REGS_RSP];
-   svm-vmcb-save.rip = vcpu-arch.rip;
+
+   switch (reg) {
+   case VCPU_REGS_RAX:
+   svm-vmcb-save.rax = vcpu-arch.regs[VCPU_REGS_RAX];
+   break;
+   case VCPU_REGS_RSP:
+   svm-vmcb-save.rsp = 

Re: RFC: cache_regs in kvm_emulate_pio

2008-06-26 Thread Marcelo Tosatti
On Thu, Jun 26, 2008 at 07:15:45PM -0300, Marcelo Tosatti wrote:
 On Thu, Jun 26, 2008 at 12:18:07PM +0300, Avi Kivity wrote:
  A new header file is excessive. Also, these are global names, so please  
  prefix with kvm_.
 
 The reason for a separate header is because these accessors need both
 kvm_vcpu (linux/kvm_host.h) and kvm_vcpu_arch (asm/kvm_host.h).
 
 I couldnt think of a better location to put them. Ideas?
 
  @@ -241,7 +242,8 @@ static void skip_emulated_instruction(struct kvm_vcpu 
  *vcpu)
svm-vmcb-save.rip,
svm-next_rip);
   - vcpu-arch.rip = svm-vmcb-save.rip = svm-next_rip;
  +  svm-vmcb-save.rip = svm-next_rip;
  +  guest_register_write(vcpu, VCPU_REGS_RIP, svm-vmcb-save.rip);
 svm-vmcb-control.int_state = ~SVM_INTERRUPT_SHADOW_MASK;

 
  No need to write into save.rip, is there?
 
 I'm not sure why it was there in the first place. Perhaps there's code
 which reads svm-vmcb-save.rip directly as the current RIP after this
 point?
 
 Also kvm_guest_register_read is too long, so I dropped guest.

There was a missing convertion in vmx_vcpu_reset(). And haven't tested
AMD.

--- /dev/null   2008-06-26 10:56:31.025001212 -0300
+++ b/arch/x86/kvm/kvm_cache_regs.h 2008-06-26 23:21:28.0 -0300
@@ -0,0 +1,36 @@
+#ifndef ASM_KVM_CACHE_REGS_H
+#define ASM_KVM_CACHE_REGS_H
+
+static inline unsigned long kvm_register_read(struct kvm_vcpu *vcpu,
+ enum kvm_reg reg)
+{
+   if (!__test_and_set_bit(reg, vcpu-arch.regs_available))
+   kvm_x86_ops-cache_reg(vcpu, reg);
+
+   return vcpu-arch.regs[reg];
+}
+
+static inline void kvm_register_write(struct kvm_vcpu *vcpu,
+ enum kvm_reg reg,
+ unsigned long val)
+{
+   vcpu-arch.regs[reg] = val;
+   __set_bit(reg, vcpu-arch.regs_dirty);
+}
+
+static inline unsigned long kvm_rip_read(struct kvm_vcpu *vcpu)
+{
+   if (!__test_and_set_bit(VCPU_REGS_RIP, vcpu-arch.regs_available))
+   kvm_x86_ops-cache_reg(vcpu, VCPU_REGS_RIP);
+
+   return vcpu-arch.rip;
+}
+
+static inline void kvm_rip_write(struct kvm_vcpu *vcpu,
+unsigned long val)
+{
+   vcpu-arch.rip = val;
+   __set_bit(VCPU_REGS_RIP, vcpu-arch.regs_dirty);
+}
+
+#endif
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 73f43de..9fde0ac 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -32,6 +32,7 @@
 #include asm/current.h
 #include asm/apicdef.h
 #include asm/atomic.h
+#include kvm_cache_regs.h
 #include irq.h
 
 #define PRId64 d
@@ -558,8 +559,7 @@ static void __report_tpr_access(struct kvm_lapic *apic, 
bool write)
struct kvm_run *run = vcpu-run;
 
set_bit(KVM_REQ_REPORT_TPR_ACCESS, vcpu-requests);
-   kvm_x86_ops-cache_regs(vcpu);
-   run-tpr_access.rip = vcpu-arch.rip;
+   run-tpr_access.rip = kvm_rip_read(vcpu);
run-tpr_access.is_write = write;
 }
 
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 238e8f3..532a393 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -18,6 +18,7 @@
 #include kvm_svm.h
 #include irq.h
 #include mmu.h
+#include kvm_cache_regs.h
 
 #include linux/module.h
 #include linux/kernel.h
@@ -241,7 +242,8 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
   svm-vmcb-save.rip,
   svm-next_rip);
 
-   vcpu-arch.rip = svm-vmcb-save.rip = svm-next_rip;
+   svm-vmcb-save.rip = svm-next_rip;
+   kvm_rip_write(vcpu, svm-vmcb-save.rip);
svm-vmcb-control.int_state = ~SVM_INTERRUPT_SHADOW_MASK;
 
vcpu-arch.interrupt_window_open = 1;
@@ -709,21 +711,42 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu)
rdtscll(vcpu-arch.host_tsc);
 }
 
-static void svm_cache_regs(struct kvm_vcpu *vcpu)
+static void svm_cache_reg(struct kvm_vcpu *vcpu, enum kvm_reg reg)
 {
struct vcpu_svm *svm = to_svm(vcpu);
 
-   vcpu-arch.regs[VCPU_REGS_RAX] = svm-vmcb-save.rax;
-   vcpu-arch.regs[VCPU_REGS_RSP] = svm-vmcb-save.rsp;
-   vcpu-arch.rip = svm-vmcb-save.rip;
+   switch (reg) {
+   case VCPU_REGS_RAX:
+   vcpu-arch.regs[VCPU_REGS_RAX] = svm-vmcb-save.rax;
+   break;
+   case VCPU_REGS_RSP:
+   vcpu-arch.regs[VCPU_REGS_RSP] = svm-vmcb-save.rsp;
+   break;
+   case VCPU_REGS_RIP:
+   vcpu-arch.rip = svm-vmcb-save.rip;
+   break;
+   default:
+   break;
+   }
 }
 
-static void svm_decache_regs(struct kvm_vcpu *vcpu)
+static void svm_decache_reg(struct kvm_vcpu *vcpu, enum kvm_reg reg)
 {
struct vcpu_svm *svm = to_svm(vcpu);
-   svm-vmcb-save.rax = vcpu-arch.regs[VCPU_REGS_RAX];
-   svm-vmcb-save.rsp = vcpu-arch.regs[VCPU_REGS_RSP];
-   svm-vmcb-save.rip = vcpu-arch.rip;
+
+   switch (reg) {
+   case VCPU_REGS_RAX:
+   

Re: RFC: cache_regs in kvm_emulate_pio

2008-06-24 Thread Marcelo Tosatti
On Sun, Jun 22, 2008 at 08:16:19AM +0300, Avi Kivity wrote:
 Marcelo Tosatti wrote:
 On Sat, Jun 21, 2008 at 10:04:18AM +0300, Avi Kivity wrote:
   
 /*
  * Sync the rsp and rip registers into the vcpu structure.  This allows
  * registers to be accessed by indexing vcpu-arch.regs.
  */

 But I think it just refers to the interface in general, so that nobody
 would try to access RSP or RIP (and RAX in AMD's case) before calling
 -cache_regs().
 
 It refers to the fact that sometimes you don't know which registers 
 you  refer to, e.g. in the emulator.
 

 How's this? 

   

 Looks good, but we can aim higher.  The cache_regs() API was always  
 confusing (I usually swap the two parts).  If we replace all -regs  
 access with accessors, we can make it completely transparent.

 It will be tricky in the emulator, but worthwhile, no?

OK, in the emulator an interface on top of guest_register_write() is
needed to save registers so that the original contents can be restored
on failure. Some brave soul can do it later, so I added a TODO in x86.c.

Smells better now?


--- dev/null2008-06-24 14:36:42.383774904 -0300
+++ b/arch/x86/kvm/kvm_cache_regs.h 2008-06-24 15:26:02.0 -0300
@@ -0,0 +1,21 @@
+#ifndef ASM_KVM_CACHE_REGS_H
+#define ASM_KVM_CACHE_REGS_H
+
+static inline unsigned long guest_register_read(struct kvm_vcpu *vcpu,
+   enum kvm_reg reg)
+{
+   if (!__test_and_set_bit(reg, vcpu-arch.regs_available))
+   kvm_x86_ops-cache_regs(vcpu, reg);
+
+   return vcpu-arch.regs[reg];
+}
+
+static inline void guest_register_write(struct kvm_vcpu *vcpu,
+   enum kvm_reg reg,
+   unsigned long val)
+{
+   vcpu-arch.regs[reg] = val;
+   __set_bit(reg, vcpu-arch.regs_dirty);
+}
+
+#endif
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 73f43de..97919b6 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -32,6 +32,7 @@
 #include asm/current.h
 #include asm/apicdef.h
 #include asm/atomic.h
+#include kvm_cache_regs.h
 #include irq.h
 
 #define PRId64 d
@@ -558,8 +559,7 @@ static void __report_tpr_access(struct kvm_lapic *apic, 
bool write)
struct kvm_run *run = vcpu-run;
 
set_bit(KVM_REQ_REPORT_TPR_ACCESS, vcpu-requests);
-   kvm_x86_ops-cache_regs(vcpu);
-   run-tpr_access.rip = vcpu-arch.rip;
+   run-tpr_access.rip = guest_register_read(vcpu, VCPU_REGS_RIP);
run-tpr_access.is_write = write;
 }
 
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 238e8f3..acd96f6 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -18,6 +18,7 @@
 #include kvm_svm.h
 #include irq.h
 #include mmu.h
+#include kvm_cache_regs.h
 
 #include linux/module.h
 #include linux/kernel.h
@@ -241,7 +242,8 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
   svm-vmcb-save.rip,
   svm-next_rip);
 
-   vcpu-arch.rip = svm-vmcb-save.rip = svm-next_rip;
+   svm-vmcb-save.rip = svm-next_rip;
+   guest_register_write(vcpu, VCPU_REGS_RIP, svm-vmcb-save.rip);
svm-vmcb-control.int_state = ~SVM_INTERRUPT_SHADOW_MASK;
 
vcpu-arch.interrupt_window_open = 1;
@@ -709,21 +711,42 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu)
rdtscll(vcpu-arch.host_tsc);
 }
 
-static void svm_cache_regs(struct kvm_vcpu *vcpu)
+static void svm_cache_regs(struct kvm_vcpu *vcpu, enum kvm_reg reg)
 {
struct vcpu_svm *svm = to_svm(vcpu);
 
-   vcpu-arch.regs[VCPU_REGS_RAX] = svm-vmcb-save.rax;
-   vcpu-arch.regs[VCPU_REGS_RSP] = svm-vmcb-save.rsp;
-   vcpu-arch.rip = svm-vmcb-save.rip;
+   switch (reg) {
+   case VCPU_REGS_RAX:
+   vcpu-arch.regs[VCPU_REGS_RAX] = svm-vmcb-save.rax;
+   break;
+   case VCPU_REGS_RSP:
+   vcpu-arch.regs[VCPU_REGS_RSP] = svm-vmcb-save.rsp;
+   break;
+   case VCPU_REGS_RIP:
+   vcpu-arch.regs[VCPU_REGS_RIP] = svm-vmcb-save.rip;
+   break;
+   default:
+   break;
+   }
 }
 
-static void svm_decache_regs(struct kvm_vcpu *vcpu)
+static void svm_decache_regs(struct kvm_vcpu *vcpu, enum kvm_reg reg)
 {
struct vcpu_svm *svm = to_svm(vcpu);
-   svm-vmcb-save.rax = vcpu-arch.regs[VCPU_REGS_RAX];
-   svm-vmcb-save.rsp = vcpu-arch.regs[VCPU_REGS_RSP];
-   svm-vmcb-save.rip = vcpu-arch.rip;
+
+   switch (reg) {
+   case VCPU_REGS_RAX:
+   svm-vmcb-save.rax = vcpu-arch.regs[VCPU_REGS_RAX];
+   break;
+   case VCPU_REGS_RSP:
+   svm-vmcb-save.rsp = vcpu-arch.regs[VCPU_REGS_RSP];
+   break;
+   case VCPU_REGS_RIP:
+   svm-vmcb-save.rip = vcpu-arch.regs[VCPU_REGS_RIP];
+   break;
+   default:
+   break;
+   }
 }
 
 static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu)
diff --git 

Re: RFC: cache_regs in kvm_emulate_pio

2008-06-22 Thread Marcelo Tosatti
On Sun, Jun 22, 2008 at 08:16:19AM +0300, Avi Kivity wrote:
 Looks good, but we can aim higher.  The cache_regs() API was always  
 confusing (I usually swap the two parts).  If we replace all -regs  
 access with accessors, we can make it completely transparent.

 It will be tricky in the emulator, but worthwhile, no?

Yes, agree. Will go for accessors.

Thanks.


--
To unsubscribe from this list: send the line unsubscribe kvm in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: RFC: cache_regs in kvm_emulate_pio

2008-06-21 Thread Marcelo Tosatti
On Sat, Jun 21, 2008 at 10:04:18AM +0300, Avi Kivity wrote:
 /*
  * Sync the rsp and rip registers into the vcpu structure.  This allows
  * registers to be accessed by indexing vcpu-arch.regs.
  */

 But I think it just refers to the interface in general, so that nobody
 would try to access RSP or RIP (and RAX in AMD's case) before calling
 -cache_regs().
   

 It refers to the fact that sometimes you don't know which registers you  
 refer to, e.g. in the emulator.

How's this? 

Test performed with idle UP guest booted with nohz=off
clocksource=acpi_pm, so most of the exits are acpi timer reads. This
average is from available entries in the dmesg buffer, about 1500.

regs_available and regs_dirty could be 8 bits, and placed in a hole
instead of in the middle of longs.

avg cycles to exit to qemu:
before: 3376
after: 3181

195 cycles (~= 6.1% improvement)

avg cycles to exit to qemu, handle exit and return to __vcpu_run before 
irq_disable:

before: 7482 cycles.
after: 7227 cycles.

255 cycles (~= 3.5% improvement)


diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 73f43de..ecf26e3 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -32,6 +32,7 @@
 #include asm/current.h
 #include asm/apicdef.h
 #include asm/atomic.h
+#include kvm_cache_regs.h
 #include irq.h
 
 #define PRId64 d
@@ -558,7 +559,7 @@ static void __report_tpr_access(struct kvm_lapic *apic, 
bool write)
struct kvm_run *run = vcpu-run;
 
set_bit(KVM_REQ_REPORT_TPR_ACCESS, vcpu-requests);
-   kvm_x86_ops-cache_regs(vcpu);
+   cache_regs(vcpu, REGS_RIP);
run-tpr_access.rip = vcpu-arch.rip;
run-tpr_access.is_write = write;
 }
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 238e8f3..8554b37 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -709,21 +709,38 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu)
rdtscll(vcpu-arch.host_tsc);
 }
 
-static void svm_cache_regs(struct kvm_vcpu *vcpu)
+static void svm_cache_regs(struct kvm_vcpu *vcpu, enum kvm_reg_set regs)
 {
struct vcpu_svm *svm = to_svm(vcpu);
 
-   vcpu-arch.regs[VCPU_REGS_RAX] = svm-vmcb-save.rax;
-   vcpu-arch.regs[VCPU_REGS_RSP] = svm-vmcb-save.rsp;
-   vcpu-arch.rip = svm-vmcb-save.rip;
+   switch (regs) {
+   case REGS_GPR:
+   vcpu-arch.regs[VCPU_REGS_RAX] = svm-vmcb-save.rax;
+   break;
+   case REGS_RSP:
+   vcpu-arch.regs[VCPU_REGS_RSP] = svm-vmcb-save.rsp;
+   break;
+   case REGS_RIP:
+   vcpu-arch.rip = svm-vmcb-save.rip;
+   break;
+   }
 }
 
-static void svm_decache_regs(struct kvm_vcpu *vcpu)
+static void svm_decache_regs(struct kvm_vcpu *vcpu, enum kvm_reg_set regs)
 {
struct vcpu_svm *svm = to_svm(vcpu);
-   svm-vmcb-save.rax = vcpu-arch.regs[VCPU_REGS_RAX];
-   svm-vmcb-save.rsp = vcpu-arch.regs[VCPU_REGS_RSP];
-   svm-vmcb-save.rip = vcpu-arch.rip;
+
+   switch (regs) {
+   case REGS_GPR:
+   svm-vmcb-save.rax = vcpu-arch.regs[VCPU_REGS_RAX];
+   break;
+   case REGS_RSP:
+   svm-vmcb-save.rsp = vcpu-arch.regs[VCPU_REGS_RSP];
+   break;
+   case REGS_RIP:
+   svm-vmcb-save.rip = vcpu-arch.rip;
+   break;
+   }
 }
 
 static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu)
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 6e4278d..b7a988c 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -26,6 +26,7 @@
 #include linux/highmem.h
 #include linux/sched.h
 #include linux/moduleparam.h
+#include kvm_cache_regs.h
 
 #include asm/io.h
 #include asm/desc.h
@@ -707,9 +708,11 @@ static void skip_emulated_instruction(struct kvm_vcpu 
*vcpu)
unsigned long rip;
u32 interruptibility;
 
-   rip = vmcs_readl(GUEST_RIP);
+   cache_regs(vcpu, REGS_RIP);
+   rip = vcpu-arch.rip;
rip += vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
-   vmcs_writel(GUEST_RIP, rip);
+   vcpu-arch.rip = rip;
+   decache_regs(vcpu, REGS_RIP);
 
/*
 * We emulated an instruction, so temporary interrupt blocking
@@ -935,20 +938,48 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 
msr_index, u64 data)
  * Sync the rsp and rip registers into the vcpu structure.  This allows
  * registers to be accessed by indexing vcpu-arch.regs.
  */
-static void vcpu_load_rsp_rip(struct kvm_vcpu *vcpu)
+static void vmx_cache_regs(struct kvm_vcpu *vcpu, enum kvm_reg_set regs)
 {
-   vcpu-arch.regs[VCPU_REGS_RSP] = vmcs_readl(GUEST_RSP);
-   vcpu-arch.rip = vmcs_readl(GUEST_RIP);
+   switch (regs) {
+   case REGS_RSP:
+   vcpu-arch.regs[VCPU_REGS_RSP] = vmcs_readl(GUEST_RSP);
+   break;
+   case REGS_RIP:
+   vcpu-arch.rip = vmcs_readl(GUEST_RIP);
+   break;
+   case REGS_GPR:
+   break;
+   }
 }
 
 /*
  * Syncs rsp and rip back into the vmcs.  Should 

Re: RFC: cache_regs in kvm_emulate_pio

2008-06-21 Thread Avi Kivity

Marcelo Tosatti wrote:

On Sat, Jun 21, 2008 at 10:04:18AM +0300, Avi Kivity wrote:
  

/*
 * Sync the rsp and rip registers into the vcpu structure.  This allows
 * registers to be accessed by indexing vcpu-arch.regs.
 */

But I think it just refers to the interface in general, so that nobody
would try to access RSP or RIP (and RAX in AMD's case) before calling
-cache_regs().
  
  
It refers to the fact that sometimes you don't know which registers you  
refer to, e.g. in the emulator.



How's this? 

  


Looks good, but we can aim higher.  The cache_regs() API was always 
confusing (I usually swap the two parts).  If we replace all -regs 
access with accessors, we can make it completely transparent.


It will be tricky in the emulator, but worthwhile, no?

--
Do not meddle in the internals of kernels, for they are subtle and quick to 
panic.

--
To unsubscribe from this list: send the line unsubscribe kvm in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RFC: cache_regs in kvm_emulate_pio

2008-06-19 Thread Marcelo Tosatti
Hi,

From my understanding the -cache_regs call on kvm_emulate_pio() is
necessary only on AMD, where vcpu-arch.regs[RAX] is not copied during
exit in svm_vcpu_load().

On both architectures, the remaining general purpose registers are saved
on exit.

The following patch saves 100 cycles out of both light and heavy exits
on Intel (if correct, kvm_emulate_hypercall and complete_pio could also
benefit, thus saving 200 cycles for in-kernel devices).

BTW, the decache_regs(vcpu) call at the end of complete_pio() could also
be a noop on Intel from what I can tell ?


diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 238e8f3..6f247cc 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -709,6 +709,13 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu)
rdtscll(vcpu-arch.host_tsc);
 }
 
+static void svm_cache_rax(struct kvm_vcpu *vcpu)
+{
+   struct vcpu_svm *svm = to_svm(vcpu);
+
+   vcpu-arch.regs[VCPU_REGS_RAX] = svm-vmcb-save.rax;
+}
+
 static void svm_cache_regs(struct kvm_vcpu *vcpu)
 {
struct vcpu_svm *svm = to_svm(vcpu);
@@ -1949,6 +1956,7 @@ static struct kvm_x86_ops svm_x86_ops = {
.set_gdt = svm_set_gdt,
.get_dr = svm_get_dr,
.set_dr = svm_set_dr,
+   .cache_rax = svm_cache_rax,
.cache_regs = svm_cache_regs,
.decache_regs = svm_decache_regs,
.get_rflags = svm_get_rflags,
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 6e4278d..0d9a148 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -932,6 +932,13 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 
msr_index, u64 data)
 }
 
 /*
+ * vcpu-arch.regs[RAX] already loaded by vmx_vcpu_run().
+ */
+static void vcpu_load_rax(struct kvm_vcpu *vcpu)
+{
+}
+
+/*
  * Sync the rsp and rip registers into the vcpu structure.  This allows
  * registers to be accessed by indexing vcpu-arch.regs.
  */
@@ -3213,6 +3220,7 @@ static struct kvm_x86_ops vmx_x86_ops = {
.set_idt = vmx_set_idt,
.get_gdt = vmx_get_gdt,
.set_gdt = vmx_set_gdt,
+   .cache_rax = vcpu_load_rax,
.cache_regs = vcpu_load_rsp_rip,
.decache_regs = vcpu_put_rsp_rip,
.get_rflags = vmx_get_rflags,
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 26b051b..6111946 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2302,7 +2302,7 @@ int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run 
*run, int in,
KVMTRACE_2D(IO_WRITE, vcpu, vcpu-run-io.port, (u32)size,
handler);
 
-   kvm_x86_ops-cache_regs(vcpu);
+   kvm_x86_ops-cache_rax(vcpu);
memcpy(vcpu-arch.pio_data, vcpu-arch.regs[VCPU_REGS_RAX], 4);
 
kvm_x86_ops-skip_emulated_instruction(vcpu);
diff --git a/include/asm-x86/kvm_host.h b/include/asm-x86/kvm_host.h
index 851184d..95a0736 100644
--- a/include/asm-x86/kvm_host.h
+++ b/include/asm-x86/kvm_host.h
@@ -410,6 +410,7 @@ struct kvm_x86_ops {
unsigned long (*get_dr)(struct kvm_vcpu *vcpu, int dr);
void (*set_dr)(struct kvm_vcpu *vcpu, int dr, unsigned long value,
   int *exception);
+   void (*cache_rax)(struct kvm_vcpu *vcpu);
void (*cache_regs)(struct kvm_vcpu *vcpu);
void (*decache_regs)(struct kvm_vcpu *vcpu);
unsigned long (*get_rflags)(struct kvm_vcpu *vcpu);
--
To unsubscribe from this list: send the line unsubscribe kvm in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html