Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Fixes to time code to allow virtualization to hide costs of running in the
Patrick G. Bridges [Thu, 17 Feb 2011 18:51:32 +0000 (12:51 -0600)]
VM and attempt to hide hte costs of entering the VM.

Kconfig
palacios/include/palacios/vmm_time.h
palacios/src/devices/8254.c
palacios/src/devices/Kconfig
palacios/src/palacios/svm.c
palacios/src/palacios/vmm_time.c
test/geekos_test_vm/build/depend.mak [deleted file]

diff --git a/Kconfig b/Kconfig
index dcee752..0eb9692 100644 (file)
--- a/Kconfig
+++ b/Kconfig
@@ -226,14 +226,40 @@ endmenu
 
 menu "Time Management"
 
+config TIME_HIDE_VM_COST
+        bool "Hide VMM Run Cost"
+       default n
+       help
+           Offset guest time from host time sufficiently to hide the cost of
+           running in the virtual machine. This can aid the consistency of
+           time between multiple timers, but can cause the guest to run 
+           slightly slower than the host.
+
+config TIME_HIDE_EXIT_COST
+        bool "Hide VMM Exit Cost"
+       default n
+       depends on TIME_HIDE_VM_COST
+       help
+           Add additional TSC offset to hide VMM exit costs from the guest.
+
+config TIME_EXIT_COST_ADJUST
+       int "Exit cost adjustment for hiding VM exits"
+       default 2000
+       depends on TIME_HIDE_EXIT_COST
+       help
+           Amount to adjust the time to hide the exit cost of fully virtualizing
+          the timestamp counter. Used to hide the cost of fully virtualizing 
+          the TSC for OSes that assume that reading the TSC is inexpensive 
+          (e.g. Linux TSC-based timer calibration).
+
 config TIME_VIRTUALIZE_TSC
-       bool "Virtualize guest TSC"
+       bool "Fully virtualize guest TSC"
        default n
        help
            Virtualize the processor time stamp counter in the guest, 
            generally increasing consistency between various time sources 
            but also potentially making guest time run slower than real time.
-
+        
 endmenu
 
 menu "Symbiotic Functions"
index 9f1c432..6513e30 100644 (file)
@@ -7,11 +7,13 @@
  * and the University of New Mexico.  You can find out more at 
  * http://www.v3vee.org
  *
+ * Copyright (c) 2010, Patrick Bridges <bridges@cs.unm.edu>
  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
  * All rights reserved.
  *
  * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *         Patrick Bridges <bridges@cs.unm.edu>
  *
  * This is free software.  You are permitted to use,
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
@@ -32,15 +34,15 @@ struct guest_info;
 struct vm_time {
     uint32_t host_cpu_freq;    // in kHZ 
     uint32_t guest_cpu_freq;   // can be lower than host CPU freq!
-         
+
     sint64_t guest_host_offset;// Offset of monotonic guest time from host time
     sint64_t tsc_guest_offset; // Offset of guest TSC from monotonic guest time
-    
+
     uint64_t last_update;      // Last time (in monotonic guest time) the 
                                // timers were updated
 
     uint64_t initial_time;     // Time when VMM started. 
-    
+    uint64_t pause_time;       // Host time when VM entered and paused.
     struct v3_msr tsc_aux;     // Auxilliary MSR for RDTSCP
 
     // Installed Timers slaved off of the guest monotonic TSC
@@ -67,9 +69,12 @@ int v3_init_time_vm(struct v3_vm_info * vm);
 void v3_deinit_time_core(struct guest_info * core);
 void v3_deinit_time_vm(struct v3_vm_info * vm);
 
-
 int v3_start_time(struct guest_info * core);
+
 int v3_adjust_time(struct guest_info * core);
+int v3_pause_time(struct guest_info * core);
+int v3_offset_time(struct guest_info * core, sint64_t offset);
+int v3_restart_time(struct guest_info * core);
 
 // Basic functions for attaching timers to the passage of time
 struct v3_timer * v3_add_timer(struct guest_info * info, struct v3_timer_ops * ops, void * private_data);
@@ -85,7 +90,11 @@ static inline uint64_t v3_get_host_time(struct vm_time *t) {
 
 // Returns *monotonic* guest time.
 static inline uint64_t v3_get_guest_time(struct vm_time *t) {
-    return v3_get_host_time(t) + t->guest_host_offset;
+    if (t->pause_time) {
+        return t->pause_time + t->guest_host_offset;
+    } else {
+        return v3_get_host_time(t) + t->guest_host_offset;
+    }
 }
 
 // Returns the TSC value seen by the guest
index 7bf6a8c..ffae665 100644 (file)
@@ -299,10 +299,13 @@ static void pit_update_timer(struct guest_info * info, ullong_t cpu_cycles, ullo
        // update counter with remainder (mod reload)
        state->pit_counter = state->pit_reload - cpu_cycles;    
 
-       //PrintDebug("8254 PIT: Handling %d crystal tics\n", oscillations);
+       if (oscillations) {
+           PrintDebug("8254 PIT: Handling %d crystal tics\n", oscillations);
+       }
+
        if (handle_crystal_tics(state, &(state->ch_0), oscillations) == 1) {
            // raise interrupt
-           PrintDebug("8254 PIT: Injecting Timer interrupt to guest\n");
+           // PrintDebug("8254 PIT: Injecting Timer interrupt to guest\n");
            v3_raise_irq(info->vm_info, 0);
        }
 
index 671625f..99b788b 100644 (file)
@@ -3,7 +3,6 @@ menu "Virtual Devices"
 config APIC
        bool "APIC" 
        default y
-       depends on EXPERIMENTAL
        help 
          Includes the Virtual APIC device
 
@@ -19,7 +18,6 @@ config DEBUG_APIC
 
 config IO_APIC
        bool "IOAPIC"
-       depends on EXPERIMENTAL
        default y
        help 
          Includes the Virtual IO APIC
index 20adea3..7b1b919 100644 (file)
@@ -451,11 +451,11 @@ int v3_svm_enter(struct guest_info * info) {
     vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data)); 
     addr_t exit_code = 0, exit_info1 = 0, exit_info2 = 0;
 
-    v3_adjust_time(info);
-
     // Conditionally yield the CPU if the timeslice has expired
     v3_yield_cond(info);
 
+    v3_adjust_time(info);
+
     // disable global interrupts for vm state transition
     v3_clgi();
 
@@ -504,6 +504,9 @@ int v3_svm_enter(struct guest_info * info) {
 #endif
 
     v3_update_timers(info);
+#ifdef CONFIG_TIME_HIDE_VM_COST
+    v3_restart_time(info);
+#endif
     guest_ctrl->TSC_OFFSET = v3_tsc_host_offset(&info->time_state);
 
     //V3_Print("Calling v3_svm_launch\n");
@@ -514,6 +517,13 @@ int v3_svm_enter(struct guest_info * info) {
 
     v3_last_exit = (uint32_t)(guest_ctrl->exit_code);
 
+#ifdef CONFIG_TIME_HIDE_VM_COST
+    v3_pause_time(info);
+#ifdef CONFIG_TIME_HIDE_EXIT_COST
+    v3_offset_time(info, -CONFIG_TIME_EXIT_COST_ADJUST);
+#endif
+#endif
+
     //PrintDebug("SVM Returned\n");
     
     info->num_exits++;
index 51fbba7..1cb6478 100644 (file)
@@ -86,6 +86,11 @@ int v3_start_time(struct guest_info * info) {
     uint64_t t = v3_get_host_time(&info->time_state); 
 
     PrintDebug("Starting initial guest time as %llu\n", t);
+#ifdef CONFIG_TIME_HIDE_VM_COST
+    info->time_state.pause_time = t; 
+#else
+    info->time_state.pause_time = 0; 
+#endif
     info->time_state.last_update = t;
     info->time_state.initial_time = t;
     info->yield_start_cycle = t;
@@ -97,9 +102,7 @@ int v3_start_time(struct guest_info * info) {
 int v3_adjust_time(struct guest_info * info) {
     struct vm_time * time_state = &(info->time_state);
 
-    if (time_state->host_cpu_freq == time_state->guest_cpu_freq) {
-       time_state->guest_host_offset = 0;
-    } else {
+    if (time_state->host_cpu_freq != time_state->guest_cpu_freq) {
        uint64_t guest_time, guest_elapsed, desired_elapsed;
        uint64_t host_time, target_host_time;
 
@@ -118,12 +121,52 @@ int v3_adjust_time(struct guest_info * info) {
            host_time = v3_get_host_time(time_state);
        }
 
+       // This overrides any pause/unpause times because the difference 
+       // is going to be too big for any pause/unpause the notice.
        time_state->guest_host_offset = (sint64_t)guest_time - (sint64_t)host_time;
     }
 
     return 0;
 }
 
+int 
+v3_pause_time( struct guest_info * info ) 
+{
+    struct vm_time * time_state = &(info->time_state);
+    if (time_state->pause_time == 0) {
+        time_state->pause_time = v3_get_host_time(time_state);
+//     PrintDebug("Pausing at host time %llu.\n", time_state->pause_time);
+    } else {
+        PrintError("Palacios timekeeping paused when already paused.\n");
+    }
+    return 0;
+}
+
+int 
+v3_restart_time( struct guest_info * info )
+{
+    struct vm_time * time_state = &(info->time_state);
+
+    if (time_state->pause_time) {
+        sint64_t pause_diff = (v3_get_host_time(time_state) - time_state->pause_time);
+        time_state->guest_host_offset -= pause_diff;
+        time_state->pause_time = 0;
+//     PrintDebug("Resuming time after %lld cycles with offset %lld.\n", pause_diff, time_state->guest_host_offset);
+    } else {
+        PrintError( "Palacios time keeping restarted when not paused.");
+    }
+
+    return 0;
+}
+       
+int v3_offset_time( struct guest_info * info, sint64_t offset )
+{
+    struct vm_time * time_state = &(info->time_state);
+//    PrintDebug("Adding additional offset of %lld to guest time.\n", offset);
+    time_state->guest_host_offset += offset;
+    return 0;
+}
+          
 struct v3_timer * v3_add_timer(struct guest_info * info, 
                               struct v3_timer_ops * ops, 
                               void * private_data) {
@@ -149,15 +192,19 @@ int v3_remove_timer(struct guest_info * info, struct v3_timer * timer) {
 }
 
 void v3_update_timers(struct guest_info * info) {
+    struct vm_time *time_state = &info->time_state;
     struct v3_timer * tmp_timer;
     uint64_t old_time = info->time_state.last_update;
-    uint64_t cycles;
+    sint64_t cycles;
+
+    time_state->last_update = v3_get_guest_time(time_state);
+    cycles = time_state->last_update - old_time;
 
-    info->time_state.last_update = v3_get_guest_time(&info->time_state);
-    cycles = info->time_state.last_update - old_time;
+    //    PrintDebug("Updating timer for %lld elapsed cycles (pt=%llu, offset=%lld).\n", 
+    //        cycles, time_state->pause_time, time_state->guest_host_offset);
 
-    list_for_each_entry(tmp_timer, &(info->time_state.timers), timer_link) {
-       tmp_timer->ops->update_timer(info, cycles, info->time_state.guest_cpu_freq, tmp_timer->private_data);
+    list_for_each_entry(tmp_timer, &(time_state->timers), timer_link) {
+       tmp_timer->ops->update_timer(info, cycles, time_state->guest_cpu_freq, tmp_timer->private_data);
     }
 }
 
@@ -172,12 +219,14 @@ void v3_update_timers(struct guest_info * info) {
 
 int v3_rdtsc(struct guest_info * info) {
     uint64_t tscval = v3_get_guest_tsc(&info->time_state);
+    PrintDebug("Returning %llu as TSC.\n", tscval);
     info->vm_regs.rdx = tscval >> 32;
     info->vm_regs.rax = tscval & 0xffffffffLL;
     return 0;
 }
 
 int v3_handle_rdtsc(struct guest_info * info) {
+  PrintDebug("Handling virtual RDTSC call.\n");
     v3_rdtsc(info);
     
     info->vm_regs.rax &= 0x00000000ffffffffLL;
@@ -213,9 +262,10 @@ int v3_rdtscp(struct guest_info * info) {
 
 
 int v3_handle_rdtscp(struct guest_info * info) {
+  PrintDebug("Handling virtual RDTSCP call.\n");
 
     v3_rdtscp(info);
-    
+
     info->vm_regs.rax &= 0x00000000ffffffffLL;
     info->vm_regs.rcx &= 0x00000000ffffffffLL;
     info->vm_regs.rdx &= 0x00000000ffffffffLL;
diff --git a/test/geekos_test_vm/build/depend.mak b/test/geekos_test_vm/build/depend.mak
deleted file mode 100644 (file)
index e69de29..0000000