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.


Implemented (but not yet tested) time interface changes for consistency
Patrick G. Bridges [Mon, 20 Sep 2010 19:58:46 +0000 (13:58 -0600)]
and, more importantly, and to control vmx offseting of TSC appropriately.

palacios/include/palacios/vmm_time.h
palacios/src/devices/8254.c
palacios/src/devices/apic.c
palacios/src/palacios/svm.c
palacios/src/palacios/vm_guest.c
palacios/src/palacios/vmm_halt.c
palacios/src/palacios/vmm_time.c
palacios/src/palacios/vmx.c

index 120838d..3f1ad95 100644 (file)
@@ -30,14 +30,14 @@ struct guest_info;
 struct vm_time {
     uint32_t cpu_freq; // in kHZ
 
-    // Total number of guest run time cycles
-    uint64_t guest_tsc;
-
+    // Last time (in guest time) the timers were updated
+    uint64_t last_update;
+    
     // Cache value to help calculate the guest_tsc
-    uint64_t cached_host_tsc;
+    uint64_t pause_time;
 
-    // The number of cycles pending for notification to the timers
-    //ullong_t pending_cycles;
+    // Offset of guest time from host time.
+    sint64_t host_offset;
 
     // Installed Timers 
     uint_t num_timers;
@@ -48,7 +48,7 @@ struct vm_time {
 
 
 struct vm_timer_ops {
-    void (*update_time)(struct guest_info * info, ullong_t cpu_cycles, ullong_t cpu_freq, void * priv_data);
+    void (*update_timer)(struct guest_info * info, ullong_t cpu_cycles, ullong_t cpu_freq, void * priv_data);
     void (*advance_timer)(struct guest_info * info, void * private_data);
 };
 
@@ -64,14 +64,15 @@ struct vm_timer {
 
 int v3_add_timer(struct guest_info * info, struct vm_timer_ops * ops, void * private_data);
 int v3_remove_timer(struct guest_info * info, struct vm_timer * timer);
-
-void v3_advance_time(struct guest_info * info);
-
-void v3_update_time(struct guest_info * info, ullong_t cycles);
+void v3_update_timers(struct guest_info * info);
 
 
 void v3_init_time(struct guest_info * info);
-
+int v3_start_time(struct guest_info * info);
+int v3_pause_time(struct guest_info * info);
+int v3_resume_time(struct guest_info * info);
+uint64_t v3_get_host_time(struct guest_info * info);
+uint64_t v3_get_guest_time(struct guest_info * info);
 #endif // !__V3VEE__
 
 #endif
index 51c3f04..ecb2fa0 100644 (file)
@@ -236,7 +236,7 @@ static int handle_crystal_tics(struct vm_device * dev, struct channel * ch, uint
 
 #include <palacios/vm_guest.h>
 
-static void pit_update_time(struct guest_info * info, ullong_t cpu_cycles, ullong_t cpu_freq, void * private_data) {
+static void pit_update_timer(struct guest_info * info, ullong_t cpu_cycles, ullong_t cpu_freq, void * private_data) {
     struct vm_device * dev = (struct vm_device *)private_data;
     struct pit * state = (struct pit *)dev->private_data;
     //  ullong_t tmp_ctr = state->pit_counter;
@@ -313,14 +313,6 @@ static void pit_update_time(struct guest_info * info, ullong_t cpu_cycles, ullon
     return;
 }
 
-
-static void pit_advance_time(struct guest_info * core, void * private_data) {
-
-    v3_raise_irq(core->vm_info, 0);
-}
-
-
-
 /* This should call out to handle_SQR_WAVE_write, etc...
  */
 static int handle_channel_write(struct channel * ch, char val) {
@@ -624,8 +616,7 @@ static int pit_write_command(struct guest_info * core, ushort_t port, void * src
 
 
 static struct vm_timer_ops timer_ops = {
-    .update_time = pit_update_time,
-    .advance_timer = pit_advance_time,
+    .update_timer = pit_update_timer,
 };
 
 
index c437c63..1880569 100644 (file)
@@ -978,7 +978,7 @@ static int apic_begin_irq(struct guest_info * info, void * private_data, int irq
 
 
 /* Timer Functions */
-static void apic_update_time(struct guest_info * info, ullong_t cpu_cycles, ullong_t cpu_freq, void * priv_data) {
+static void apic_update_timer(struct guest_info * info, ullong_t cpu_cycles, ullong_t cpu_freq, void * priv_data) {
     struct apic_state * apic = (struct apic_state *)(priv_data);
     // The 32 bit GCC runtime is a pile of shit
 #ifdef __V3_64BIT__
@@ -1071,7 +1071,7 @@ static struct intr_ctrl_ops intr_ops = {
 
 
 static struct vm_timer_ops timer_ops = {
-    .update_time = apic_update_time,
+    .update_timer = apic_update_timer,
 };
 
 
index 34fed45..3131cf2 100644 (file)
@@ -471,7 +471,7 @@ int v3_svm_enter(struct guest_info * info) {
 
 
     rdtscll(tmp_tsc);
-    v3_update_time(info, (tmp_tsc - info->time_state.cached_host_tsc));
+    v3_update_timers(info, (tmp_tsc - info->time_state.cached_host_tsc));
     rdtscll(info->time_state.cached_host_tsc);
     //    guest_ctrl->TSC_OFFSET = info->time_state.guest_tsc - info->time_state.cached_host_tsc;
 
index 4dddf6e..7dbbf2d 100644 (file)
@@ -376,7 +376,7 @@ static int info_hcall(struct guest_info * core, uint_t hcall_id, void * priv_dat
     }
 #endif
 #ifdef CONFIG_VMX
-    else if ((cpu_type == V3_VMX_CPU) || (cpu_type == V3_VMX_EPT_CPU)) {
+    if ((cpu_type == V3_VMX_CPU) || (cpu_type == V3_VMX_EPT_CPU)) {
        v3_print_vmcs();
     }
 #endif
@@ -452,7 +452,7 @@ int v3_init_vm(struct v3_vm_info * vm) {
     }
 #endif
 #ifdef CONFIG_VMX
-    else if ((cpu_type == V3_VMX_CPU) || (cpu_type == V3_VMX_EPT_CPU)) {
+    if ((cpu_type == V3_VMX_CPU) || (cpu_type == V3_VMX_EPT_CPU)) {
        v3_init_vmx_io_map(vm);
        v3_init_vmx_msr_map(vm);
     }
@@ -508,7 +508,7 @@ int v3_init_core(struct guest_info * core) {
     }
 #endif
 #ifdef CONFIG_VMX
-    else if ((cpu_type == V3_VMX_CPU) || (cpu_type == V3_VMX_EPT_CPU)) {
+    if ((cpu_type == V3_VMX_CPU) || (cpu_type == V3_VMX_EPT_CPU)) {
        if (v3_init_vmx_vmcs(core, vm->vm_class) == -1) {
            PrintError("Error in VMX initialization\n");
            return -1;
index 5015046..7970a40 100644 (file)
@@ -38,17 +38,12 @@ int v3_handle_halt(struct guest_info * info) {
     if (info->cpl != 0) { 
        v3_raise_exception(info, GPF_EXCEPTION);
     } else {
-       uint64_t yield_start = 0;
-       
        PrintDebug("CPU Yield\n");
 
        while (!v3_intr_pending(info)) {
-           rdtscll(yield_start);
+           /* Since we're in an exit, time is already paused here, so no need to pause again. */
            v3_yield(info);
-           
-           v3_update_time(info, yield_start - info->time_state.cached_host_tsc);
-           
-           rdtscll(info->time_state.cached_host_tsc);
+           v3_update_timers(info);
            
            /* At this point, we either have some combination of 
               interrupts, including perhaps a timer interrupt, or 
index b169669..4bd30ef 100644 (file)
@@ -38,18 +38,54 @@ void v3_init_time(struct guest_info * info) {
 
     time_state->cpu_freq = V3_CPU_KHZ();
  
-    time_state->guest_tsc = 0;
-    time_state->cached_host_tsc = 0;
-    // time_state->pending_cycles = 0;
-  
+    time_state->pause_time = 0;
+    time_state->last_update = 0;
+    time_state->host_offset = 0;
+    
     INIT_LIST_HEAD(&(time_state->timers));
     time_state->num_timers = 0;
 
     v3_register_hypercall(info->vm_info, TIME_CPUFREQ_HCALL, handle_cpufreq_hcall, NULL);
 }
 
+uint64_t v3_get_host_time(struct guest_info * info) {
+    uint64_t tmp;
+    rdtscll(tmp);
+    return tmp;
+}
+
+uint64_t v3_get_guest_time(struct guest_info * info) {
+    return v3_get_host_time(info) + info->time_state.host_offset;
+}
+
+
+int v3_start_time(struct guest_info * info) {
+    /* We start running with guest_time == host_time */
+    uint64_t t = v3_get_host_time(info); 
+    info->time_state.last_update = t;
+    info->time_state.pause_time = t;
+    return 0;
+}
+
+int v3_pause_time(struct guest_info * info) {
+    V3_ASSERT(info->time_state.pause_time == 0);
+    info->time_state.pause_time = v3_get_guest_time(info);
+    return 0;
+}
+
+int v3_resume_time(struct guest_info * info) {
+    uint64_t t = v3_get_host_time(info);
+    V3_ASSERT(info->time_state.pause_time != 0);
+#ifdef OPTION_TIME_ADJUST_TSC_OFFSET
+#endif
+    info->time_state.host_offset = 
+       (sint64_t)info->time_state.pause_time - (sint64_t)t;
+    info->time_state.pause_time = 0;
+    return 0;
+}
 
-int v3_add_timer(struct guest_info * info, struct vm_timer_ops * ops, void * private_data) {
+int v3_add_timer(struct guest_info * info, struct vm_timer_ops * ops, 
+            void * private_data) {
     struct vm_timer * timer = NULL;
     timer = (struct vm_timer *)V3_Malloc(sizeof(struct vm_timer));
     V3_ASSERT(timer != NULL);
@@ -72,34 +108,15 @@ int v3_remove_timer(struct guest_info * info, struct vm_timer * timer) {
     return 0;
 }
 
-
-
-void v3_update_time(struct guest_info * info, uint64_t cycles) {
+void v3_update_timers(struct guest_info * info) {
     struct vm_timer * tmp_timer;
-    
-    //   cycles *= 8;
-
-//    cycles /= 150;
+    uint64_t old_time = info->time_state.last_update;
+    uint64_t cycles;
 
-    info->time_state.guest_tsc += cycles;
+    info->time_state.last_update = v3_get_guest_time(info);
+    cycles = info->time_state.last_update - old_time;
 
     list_for_each_entry(tmp_timer, &(info->time_state.timers), timer_link) {
-       tmp_timer->ops->update_time(info, cycles, info->time_state.cpu_freq, tmp_timer->private_data);
-    }
-  
-
-
-    //info->time_state.pending_cycles = 0;
-}
-
-void v3_advance_time(struct guest_info * core) {
-    struct vm_timer * tmp_timer;
-
-
-    list_for_each_entry(tmp_timer, &(core->time_state.timers), timer_link) {
-       tmp_timer->ops->advance_timer(core, tmp_timer->private_data);
+       tmp_timer->ops->update_timer(info, cycles, info->time_state.cpu_freq, tmp_timer->private_data);
     }
-  
-
-
 }
index 18d183b..a297be2 100644 (file)
@@ -636,13 +636,12 @@ static void print_exit_log(struct guest_info * info) {
  */
 int v3_vmx_enter(struct guest_info * info) {
     int ret = 0;
-    uint64_t tmp_tsc = 0;
+    uint32_t tsc_offset_low, tsc_offset_high;
     struct vmx_exit_info exit_info;
 
     // Conditionally yield the CPU if the timeslice has expired
     v3_yield_cond(info);
 
-
     // v3_print_guest_state(info);
 
     // disable global interrupts for vm state transition
@@ -665,11 +664,15 @@ int v3_vmx_enter(struct guest_info * info) {
        vmcs_write(VMCS_GUEST_CR3, guest_cr3);
     }
 
-    // We do timer injection here to track real host time.
-    rdtscll(tmp_tsc);
-    v3_update_time(info, tmp_tsc - info->time_state.cached_host_tsc);
-    rdtscll(info->time_state.cached_host_tsc);
+    v3_update_timers(info);
+    v3_resume_time(info);
 
+    tsc_offset_high = 
+       (uint32_t)((info->time_state.host_offset >> 32) & 0xffffffff);
+    tsc_offset_low = (uint32_t)(info->time_state.host_offset & 0xffffffff);
+    check_vmcs_write(VMCS_TSC_OFFSET_HIGH, tsc_offset_high);
+    check_vmcs_write(VMCS_TSC_OFFSET, tsc_offset_low);
+                    
     if (info->vm_info->run_state == VM_STOPPED) {
        info->vm_info->run_state = VM_RUNNING;
        ret = v3_vmx_launch(&(info->vm_regs), info, &(info->ctrl_regs));
@@ -688,12 +691,13 @@ int v3_vmx_enter(struct guest_info * info) {
        return -1;
     }
 
-    //   rdtscll(tmp_tsc);
-    //    v3_update_time(info, tmp_tsc - info->time_state.cached_host_tsc);
+    v3_pause_time(info);
+#ifdef OPTION_TIME_MASK_OVERHEAD
+    v3_offset_time(info, -VMX_ENTRY_OVERHEAD);
+#endif
 
     info->num_exits++;
 
-
     /* Update guest state */
     v3_vmx_save_vmcs(info);
 
@@ -744,8 +748,7 @@ int v3_start_vmx_guest(struct guest_info* info) {
 
     PrintDebug("Launching VMX guest\n");
 
-    rdtscll(info->time_state.cached_host_tsc);
-
+    v3_start_time(info);
 
     while (1) {
        if (v3_vmx_enter(info) == -1) {