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.


Merge branch 'devel' of palacios@newskysaw.cs.northwestern.edu:/home/palacios/palacio...
Peter Dinda [Wed, 23 May 2012 18:13:25 +0000 (13:13 -0500)]
Kconfig
palacios/include/palacios/vmm_hypercall.h
palacios/include/palacios/vmm_time.h
palacios/src/extensions/Kconfig
palacios/src/palacios/svm.c
palacios/src/palacios/vmm.c
palacios/src/palacios/vmm_halt.c
palacios/src/palacios/vmm_time.c
palacios/src/palacios/vmx.c

diff --git a/Kconfig b/Kconfig
index a799842..e6e9dbf 100644 (file)
--- a/Kconfig
+++ b/Kconfig
@@ -219,41 +219,6 @@ config SHADOW_PAGING_CACHE1
 
 endmenu
 
-
-
-menu "Time Management"
-config TIME_DILATION
-       bool "Control Guest/Host Time Offseting"
-       default n
-       depends on EXPERIMENTAL
-       help
-           Controls the relative speeds of the guest and host processor
-           to allow the VM to provide the illusion of the guest seeing time
-           pass at a different rate than the host system does.
-
-config TIME_HIDE_VM_COST
-        bool "Hide VMM Run Cost"
-       default n
-       depends on EXPERIMENTAL 
-       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 
-           a good bit slower than the host in VM-intensive parts of the code.
-
-config TIME_VIRTUALIZE_TSC
-       bool "Fully virtualize guest TSC"
-       default n
-       depends on EXPERIMENTAL
-       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"
 
 config SYMBIOTIC
index 4304790..575a9bb 100644 (file)
@@ -51,7 +51,8 @@ typedef enum {
     BALLOON_START_HCALL =  0xba00,         // RAX: size
     BALLOON_QUERY_HCALL =  0xba01,         // RCX: req_pgs(out), RDX: alloc_pgs(out)
     OS_DEBUG_HCALL =       0xc0c0,          // RBX: msg_gpa, RCX: msg_len, RDX: buf_is_va (flag)
-    TIME_CPUFREQ_HCALL   =  0xd000       //RCX: cpu freq (out)
+    TIME_CPUFREQ_HCALL  =  0xd000,       //RBX: cpu freq (out)
+    TIME_RDHTSC_HCALL   =  0xd001,       //RBX: cpu freq (out)
 } hcall_id_t;
 
 
index 4b3cb2e..9293329 100644 (file)
 
 struct guest_info;
 
+
 /* Per-VM time information */
 struct v3_time {
-    uint32_t td_num, td_denom; /* Currently unused! */
-    char follow_host_time;
+    int flags;
+    uint32_t td_num, td_denom; 
 };
-
-#define V3_TIME_TRAP_RDTSC 0x1
+#define V3_TIME_SLAVE_HOST (1 << 0)
+#define V3_TIME_TSC_PASSTHROUGH (1 << 1)
 
 /* Per-core time information */
 struct vm_core_time {
     uint32_t host_cpu_freq;    // in kHZ 
     uint32_t guest_cpu_freq;   // can be lower than host CPU freq!
 
-    uint32_t clock_ratio_num;  // Multipliers for converting from host
-    uint32_t clock_ratio_denom;// cycles to guest cycles.
+    // Multipliers for TSC speed and performance speed
+    uint32_t clock_ratio_num, clock_ratio_denom;
+    uint32_t ipc_ratio_num, ipc_ratio_denom;
 
     uint64_t guest_cycles;
     sint64_t tsc_guest_offset; // Offset of guest TSC from guest cycles
@@ -54,11 +56,9 @@ struct vm_core_time {
                                // timers were updated
 
     uint64_t initial_host_time;// Host time when VMM started. 
-    uint64_t vm_enter_host_time;  // Host time the guest was last entered
-    uint64_t vm_pause_host_time;   // Host time when we went into the VMM
     struct v3_msr tsc_aux;     // Auxilliary MSR for RDTSCP
 
-    int time_flags;
+    int flags;
        
     // Installed Timers slaved off of the guest monotonic TSC
     uint_t num_timers;
@@ -66,6 +66,10 @@ struct vm_core_time {
 
 };
 
+#define VM_TIME_SLAVE_HOST (1 << 0)
+#define VM_TIME_TSC_PASSTHROUGH (1 << 1)
+#define VM_TIME_TRAP_RDTSC (1 << 2)
+
 struct v3_timer_ops {
     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);
@@ -91,12 +95,7 @@ void v3_deinit_time_vm(struct v3_vm_info * vm);
 
 int v3_start_time(struct guest_info * core);
 
-int v3_time_enter_vm(struct guest_info * core);
-int v3_time_exit_vm(struct guest_info * core, uint64_t * guest_cycles);
-
-int v3_offset_time(struct guest_info * core, sint64_t offset);
-int v3_skip_time(struct guest_info * core);
-int v3_advance_time(struct guest_info * core);
+int v3_advance_time(struct guest_info * core, uint64_t * guest_cycles);
 
 // Basic functions for attaching timers to the passage of time - these timers 
 // should eventually specify their accuracy and resolution.
@@ -123,7 +122,7 @@ static inline uint64_t v3_get_guest_tsc(struct vm_core_time *t) {
 // Returns offset of guest TSC from host TSC
 static inline sint64_t v3_tsc_host_offset(struct vm_core_time *time_state) {
     uint64_t host_time = v3_get_host_time(time_state);
-    return ((sint64_t)host_time - (sint64_t)time_state->guest_cycles) + time_state->tsc_guest_offset;
+    return (sint64_t)v3_get_guest_tsc(time_state) - (sint64_t)host_time;
 }
 
 // Functions for handling exits on the TSC when fully virtualizing 
index 158ed42..98f35d8 100644 (file)
@@ -1,24 +1,5 @@
 menu "Extensions"
 
-config EXT_VTIME
-       bool "Enable Time virtualization"
-       default n
-       help
-          Enables the timer virtualization extensions. These hide the cost of 
-          running inside the VMM context.  This can aid the consistency of
-           time between multiple timers, but can cause the guest to run 
-           a good bit slower than the host in VM-intensive parts of the code.
-
-config EXT_VTSC
-       bool "Fully virtualize guest TSC"
-       default n
-       depends on EXT_VTIME
-       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.
-        
 config EXT_MTRRS
        bool "Support virtualized MTTRs"
        default n
index b4f692c..4d148e9 100644 (file)
@@ -523,13 +523,17 @@ int
 v3_svm_config_tsc_virtualization(struct guest_info * info) {
     vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
 
-    if (info->time_state.time_flags & V3_TIME_TRAP_RDTSC) {
+    if (info->time_state.flags & VM_TIME_TRAP_RDTSC) {
        ctrl_area->instrs.RDTSC = 1;
        ctrl_area->svm_instrs.RDTSCP = 1;
     } else {
        ctrl_area->instrs.RDTSC = 0;
        ctrl_area->svm_instrs.RDTSCP = 0;
-        ctrl_area->TSC_OFFSET = v3_tsc_host_offset(&info->time_state);
+       if (info->time_state.flags & VM_TIME_TSC_PASSTHROUGH) {
+               ctrl_area->TSC_OFFSET = 0;
+       } else {
+               ctrl_area->TSC_OFFSET = v3_tsc_host_offset(&info->time_state);
+       }
     }
     return 0;
 }
@@ -551,15 +555,15 @@ int v3_svm_enter(struct guest_info * info) {
     // Conditionally yield the CPU if the timeslice has expired
     v3_yield_cond(info);
 
+    // Update timer devices after being in the VM before doing 
+    // IRQ updates, so that any interrupts they raise get seen 
+    // immediately.
+    v3_advance_time(info, NULL);
+    v3_update_timers(info);
+
     // disable global interrupts for vm state transition
     v3_clgi();
 
-    // Update timer devices after being in the VM, with interupts
-    // disabled, but before doing IRQ updates, so that any interrupts they 
-    //raise get seen immediately.
-    v3_advance_time(info);
-    v3_update_timers(info);
-
     // Synchronize the guest state to the VMCB
     guest_state->cr0 = info->ctrl_regs.cr0;
     guest_state->cr2 = info->ctrl_regs.cr2;
@@ -610,7 +614,6 @@ int v3_svm_enter(struct guest_info * info) {
     }
 #endif
 
-    v3_time_enter_vm(info);
     v3_svm_config_tsc_virtualization(info);
 
     //V3_Print("Calling v3_svm_launch\n");
@@ -632,8 +635,7 @@ int v3_svm_enter(struct guest_info * info) {
 
     v3_last_exit = (uint32_t)(guest_ctrl->exit_code);
 
-    // Immediate exit from VM time bookkeeping
-    v3_time_exit_vm(info, &guest_cycles);
+    v3_advance_time(info, &guest_cycles);
 
     info->num_exits++;
 
@@ -684,6 +686,11 @@ int v3_svm_enter(struct guest_info * info) {
     // Conditionally yield the CPU if the timeslice has expired
     v3_yield_cond(info);
 
+    // This update timers is for time-dependent handlers
+    // if we're slaved to host time
+    v3_advance_time(info, NULL);
+    v3_update_timers(info);
+
     {
        int ret = v3_handle_svm_exit(info, exit_code, exit_info1, exit_info2);
        
index cef9ff5..ff5a55c 100644 (file)
@@ -698,8 +698,8 @@ void v3_yield_cond(struct guest_info * info) {
        //           (void *)cur_cycle, (void *)info->yield_start_cycle, 
        //         (void *)info->yield_cycle_period);
        
-       info->yield_start_cycle += info->vm_info->yield_cycle_period;
        V3_Yield();
+        info->yield_start_cycle +=  info->vm_info->yield_cycle_period;
     }
 }
 
@@ -713,7 +713,7 @@ void v3_yield(struct guest_info * info) {
     V3_Yield();
 
     if (info) {
-       info->yield_start_cycle = v3_get_host_time(&info->time_state);
+        info->yield_start_cycle +=  info->vm_info->yield_cycle_period;
     }
 }
 
index a183547..eca50cf 100644 (file)
@@ -41,13 +41,14 @@ int v3_handle_halt(struct guest_info * info) {
        PrintDebug("CPU Yield\n");
 
        while (!v3_intr_pending(info) && (info->vm_info->run_state == VM_RUNNING)) {
+            uint64_t t, cycles;
            /* Yield, allowing time to pass while yielded */
+           t = v3_get_host_time(&info->time_state);
            v3_yield(info);
-           v3_advance_time(info);
+           cycles = v3_get_host_time(&info->time_state) - t;
+           v3_advance_time(info, &cycles);
 
-           v3_disable_ints();
            v3_update_timers(info);
-           v3_enable_ints();
            
            /* At this point, we either have some combination of 
               interrupts, including perhaps a timer interrupt, or 
index 51ac5a7..7cf7853 100644 (file)
@@ -84,14 +84,22 @@ static int handle_cpufreq_hcall(struct guest_info * info, uint_t hcall_id, void
     return 0;
 }
 
+static int handle_rdhtsc_hcall(struct guest_info * info, uint_t hcall_id, void * priv_data) {
+    struct vm_core_time * time_state = &(info->time_state);
+
+    info->vm_regs.rbx = v3_get_host_time(time_state);
+
+    // PrintDebug("Guest request host TSC: return %ld\n", (long)info->vm_regs.rbx);
+    
+    return 0;
+}
+
 
 
 int v3_start_time(struct guest_info * info) {
     /* We start running with guest_time == host_time */
     uint64_t t = v3_get_host_time(&info->time_state); 
 
-    info->time_state.vm_enter_host_time = 0;
-    info->time_state.vm_pause_host_time = t; 
     info->time_state.initial_host_time = t;
     info->yield_start_cycle = t;
 
@@ -103,81 +111,52 @@ int v3_start_time(struct guest_info * info) {
     return 0;
 }
 
-int v3_offset_time( struct guest_info * info, sint64_t offset )
-{
-    struct vm_core_time * time_state = &(info->time_state);
-    if (info->vm_info->time_state.follow_host_time) {
-       PrintError("Cannot offset guest time passage while slaved to host clock.\n");
-       return 1;
-    } else {
-        time_state->guest_cycles += offset;
-    }
-    return 0;
-}
+static sint64_t 
+host_to_guest_cycles(struct guest_info * info, sint64_t host_cycles) {
+    struct vm_core_time * core_time_state = &(info->time_state);
+    uint32_t cl_num, cl_denom;
 
-int v3_skip_time(struct guest_info * info) {
-    if (info->vm_info->time_state.follow_host_time) {
-       PrintError("Cannot skip guest time passage while slaved to host clock.\n");
-       return 1;
-    } else {
-        info->time_state.vm_pause_host_time = v3_get_host_time(&info->time_state);
-    }
-    return 0;
-}
+    cl_num = core_time_state->clock_ratio_num;
+    cl_denom = core_time_state->clock_ratio_denom;
 
-static sint64_t host_to_guest_cycles(struct guest_info * info, sint64_t host_cycles) {
-    return (host_cycles * info->time_state.clock_ratio_num) / info->time_state.clock_ratio_denom;
+    return (host_cycles * cl_num) / cl_denom;
 }
 
-int v3_time_advance_cycles(struct guest_info * info, uint64_t *host_cycles)
-{
-    uint64_t t = v3_get_host_time(&info->time_state);
-
-    info->time_state.vm_pause_host_time = t;
+/*
+static sint64_t 
+guest_to_host_cycles(struct guest_info * info, sint64_t guest_cycles) {
+    struct vm_core_time * core_time_state = &(info->time_state);
+    uint32_t cl_num, cl_denom;
 
-    if (info->vm_info->time_state.follow_host_time) {
-       /* How many guest cycles should have elapsed? */
-       sint64_t host_elapsed = t - info->time_state.initial_host_time;
-       sint64_t guest_elapsed = host_to_guest_cycles(info, host_elapsed);
+    cl_num = core_time_state->clock_ratio_num;
+    cl_denom = core_time_state->clock_ratio_denom;
 
-       info->time_state.guest_cycles = guest_elapsed;
-    } else {
-        uint64_t guest_cycles;
-       if (*host_cycles) {
-           guest_cycles = host_to_guest_cycles(info, *host_cycles);
-       } else {
-           guest_cycles = host_to_guest_cycles(info, (sint64_t)(t - info->time_state.vm_pause_host_time));
-       }
-        info->time_state.guest_cycles += guest_cycles;
-    } 
-
-    return 0;
-}
-
-int v3_advance_time(struct guest_info * info) {
-    return v3_time_advance_cycles(info, NULL);
+    return (guest_cycles * cl_denom) / cl_num;
 }
+*/
 
-/* Called immediately upon entry in the the VMM */
-int 
-v3_time_exit_vm( struct guest_info * info, uint64_t * host_cycles ) 
+int v3_advance_time(struct guest_info * info, uint64_t *host_cycles)
 {
-    return v3_time_advance_cycles(info, host_cycles);
-}
-
-/* Called immediately prior to entry to the VM */
-int 
-v3_time_enter_vm( struct guest_info * info )
-{
-    struct vm_core_time * time_state = &(info->time_state);
-    uint64_t host_time = v3_get_host_time(&info->time_state);
+    uint64_t guest_cycles;
+
+    if (info->time_state.flags & VM_TIME_SLAVE_HOST) {
+       struct v3_time *vm_ts = &(info->vm_info->time_state);
+        uint64_t ht = v3_get_host_time(&info->time_state);
+        uint64_t host_elapsed = ht - info->time_state.initial_host_time;
+       uint64_t dilated_elapsed = (host_elapsed * vm_ts->td_num) / vm_ts->td_denom;
+       uint64_t guest_elapsed = host_to_guest_cycles(info, dilated_elapsed);
+       guest_cycles = guest_elapsed - v3_get_guest_time(&info->time_state);
+    } else if (host_cycles) {
+       guest_cycles = host_to_guest_cycles(info, *host_cycles);
+    } else {
+       guest_cycles = 0;
+    }
+    
+    info->time_state.guest_cycles += guest_cycles;
 
-    time_state->vm_enter_host_time = host_time;
     return 0;
-}
-       
+} 
 
-          
 struct v3_timer * v3_add_timer(struct guest_info * info, 
                               struct v3_timer_ops * ops, 
                               void * private_data) {
@@ -216,7 +195,7 @@ void v3_update_timers(struct guest_info * info) {
        return;
     }
 
-    PrintDebug("Updating timers with %lld elapsed cycles.\n", cycles);
+    //PrintDebug("Updating timers with %lld elapsed cycles.\n", cycles);
     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);
     }
@@ -242,6 +221,7 @@ int v3_rdtsc(struct guest_info * info) {
 }
 
 int v3_handle_rdtsc(struct guest_info * info) {
+    PrintDebug("Handling virtual RDTSC call.\n");
     v3_rdtsc(info);
     
     info->vm_regs.rax &= 0x00000000ffffffffLL;
@@ -277,7 +257,7 @@ int v3_rdtscp(struct guest_info * info) {
 
 
 int v3_handle_rdtscp(struct guest_info * info) {
-  PrintDebug("Handling virtual RDTSCP call.\n");
+    PrintDebug("Handling virtual RDTSCP call.\n");
 
     v3_rdtscp(info);
 
@@ -318,6 +298,7 @@ static int tsc_msr_read_hook(struct guest_info *info, uint_t msr_num,
                             struct v3_msr *msr_val, void *priv) {
     uint64_t time = v3_get_guest_tsc(&info->time_state);
 
+    PrintDebug("Handling virtual TSC MSR read call.\n");
     V3_ASSERT(msr_num == TSC_MSR);
 
     msr_val->hi = time >> 32;
@@ -331,6 +312,7 @@ static int tsc_msr_write_hook(struct guest_info *info, uint_t msr_num,
     struct vm_core_time * time_state = &(info->time_state);
     uint64_t guest_time, new_tsc;
 
+    PrintDebug("Handling virtual TSC MSR write call.\n");
     V3_ASSERT(msr_num == TSC_MSR);
 
     new_tsc = (((uint64_t)msr_val.hi) << 32) | (uint64_t)msr_val.lo;
@@ -340,10 +322,68 @@ static int tsc_msr_write_hook(struct guest_info *info, uint_t msr_num,
     return 0;
 }
 
+static int
+handle_time_configuration(struct v3_vm_info * vm, v3_cfg_tree_t *cfg) {
+    char *source, *dilation, *tsc;
+
+    vm->time_state.flags = V3_TIME_SLAVE_HOST;
+    vm->time_state.td_num = vm->time_state.td_denom = 1;
+
+    if (!cfg) return 0;
+
+    source = v3_cfg_val(cfg, "source");
+    if (source) {
+       if (strcasecmp(source, "none") == 0) {
+           vm->time_state.flags &= ~V3_TIME_SLAVE_HOST;
+       } else if (strcasecmp(source, "host") != 0) {
+           PrintError("Unknown time source for VM core time management.\n");
+       } else {
+           PrintDebug("VM time slaved to host TSC.\n");
+       }
+    }
+
+    // Should we make a separate TSC device that handles this sort of thing?
+    tsc = v3_cfg_val(cfg, "tsc");
+    if (tsc) {
+       if (strcasecmp(tsc, "host") == 0) {
+           if (!(vm->time_state.flags & V3_TIME_SLAVE_HOST)) {
+               PrintError("WARNING: Guest TSC set to passthrough host TSC, but guest time not slaved to host time.");
+           }
+           vm->time_state.flags |= V3_TIME_TSC_PASSTHROUGH;
+       } else if (strcasecmp(source, "guest") != 0) {
+           PrintError("ERROR: Unknown TSC configuration in time configuration.\n");
+       }
+    }
+
+    dilation = v3_cfg_val(cfg, "dilation");
+    if (dilation) {
+        if (!(vm->time_state.flags & VM_TIME_SLAVE_HOST)) {
+           PrintError("Time dilation only valid when slaved to host time.\n");
+       } else {
+           uint32_t num = 1, denom = 1;
+           denom = atoi(dilation);
+           if ((num > 0) && (denom > 0)) {
+               vm->time_state.td_num = num;
+               vm->time_state.td_denom = denom;
+           }
+       }
+       if ((vm->time_state.td_num != 1) 
+           || (vm->time_state.td_denom != 1)) {
+           V3_Print("Time dilated from host time by a factor of %d/%d"
+                    " in guest.\n", vm->time_state.td_denom, 
+                    vm->time_state.td_num);
+       } else {
+           PrintError("Time dilation specifier in configuration did not"
+                      " result in actual time dilation in VM.\n");
+       }
+    }
+    return 0;
+}
 
 int v3_init_time_vm(struct v3_vm_info * vm) {
+    v3_cfg_tree_t * cfg_tree = vm->cfg_data->cfg;
     int ret;
-
+    
     PrintDebug("Installing TSC MSR hook.\n");
     ret = v3_hook_msr(vm, TSC_MSR, 
                      tsc_msr_read_hook, tsc_msr_write_hook, NULL);
@@ -363,14 +403,12 @@ int v3_init_time_vm(struct v3_vm_info * vm) {
     PrintDebug("Registering TIME_CPUFREQ hypercall.\n");
     ret = v3_register_hypercall(vm, TIME_CPUFREQ_HCALL, 
                                handle_cpufreq_hcall, NULL);
+    PrintDebug("Registering TIME_RDHTSC hypercall.\n");
+    ret = v3_register_hypercall(vm, TIME_RDHTSC_HCALL, 
+                               handle_rdhtsc_hcall, NULL);
 
-    vm->time_state.td_num = 1;
-    vm->time_state.td_denom = 1;
-    PrintDebug("Setting base time dilation factor to %d/%d.\n", 
-              vm->time_state.td_num, vm->time_state.td_denom);
+    handle_time_configuration(vm, v3_cfg_subtree(cfg_tree, "time"));
 
-    vm->time_state.follow_host_time = 1;
-    PrintDebug("Locking guest time to host time.\n");
     return ret;
 }
 
@@ -381,6 +419,37 @@ void v3_deinit_time_vm(struct v3_vm_info * vm) {
     v3_remove_hypercall(vm, TIME_CPUFREQ_HCALL);
 }
 
+static uint32_t
+gcd ( uint32_t a, uint32_t b )
+{
+    uint32_t c;
+    while ( a != 0 ) {
+        c = a; a = b%a;  b = c;
+    }
+    return b;
+}
+
+static int compute_core_ratios(struct guest_info * info, 
+                              uint32_t hostKhz, uint32_t guestKhz)
+{
+    struct vm_core_time * time_state = &(info->time_state);
+    uint32_t khzGCD;
+
+    /* Compute these using the GCD() of the guest and host CPU freq.
+     * If the GCD is too small, make it "big enough" */
+    khzGCD = gcd(hostKhz, guestKhz);
+    if (khzGCD < 1024)
+       khzGCD = 1024;
+
+    time_state->clock_ratio_num = guestKhz / khzGCD;
+    time_state->clock_ratio_denom = hostKhz / khzGCD;
+
+    time_state->ipc_ratio_num = 1;
+    time_state->ipc_ratio_denom = 1;
+
+    return 0;
+}
+
 void v3_init_time_core(struct guest_info * info) {
     struct vm_core_time * time_state = &(info->time_state);
     v3_cfg_tree_t * cfg_tree = info->core_cfg_data;
@@ -396,35 +465,55 @@ void v3_init_time_core(struct guest_info * info) {
     } 
     
     if ( (khz == NULL) || 
-        (time_state->guest_cpu_freq <= 0)  || 
-        (time_state->guest_cpu_freq > time_state->host_cpu_freq) ) {
-
+        (time_state->guest_cpu_freq <= 0)) {
+/*  || (time_state->guest_cpu_freq > time_state->host_cpu_freq) ) { */
        time_state->guest_cpu_freq = time_state->host_cpu_freq;
     }
+    compute_core_ratios(info, time_state->host_cpu_freq, 
+                       time_state->guest_cpu_freq);
+    
+    time_state->flags = 0;
+    if (info->vm_info->time_state.flags & V3_TIME_SLAVE_HOST) {
+       time_state->flags |= VM_TIME_SLAVE_HOST;
+    }
+    if (info->vm_info->time_state.flags & V3_TIME_TSC_PASSTHROUGH) {
+       time_state->flags |= VM_TIME_TSC_PASSTHROUGH;
+    }
 
-    /* Compute these using the GCD() of the guest and host CPU freq.
-     * If the GCD is too small, make it "big enough" */
-    time_state->clock_ratio_num = 1;
-    time_state->clock_ratio_denom = 1;
+    if ((time_state->clock_ratio_denom != 1) ||
+       (time_state->clock_ratio_num != 1) ||
+       (info->vm_info->time_state.td_num != 1) || 
+       (info->vm_info->time_state.td_denom != 1)) { 
+       if (time_state->flags | VM_TIME_TSC_PASSTHROUGH) {
+           PrintError("WARNING: Cannot use reqested passthrough TSC with clock or time modification also requested.\n");
+           time_state->flags &= ~VM_TIME_TSC_PASSTHROUGH;
+       }
+       time_state->flags |= VM_TIME_TRAP_RDTSC;
+    }
 
     PrintDebug("Logical Core %d (vcpu=%d) CPU frequency set to %d KHz (host CPU frequency = %d KHz).\n", 
               info->pcpu_id, info->vcpu_id,
               time_state->guest_cpu_freq, 
               time_state->host_cpu_freq);
+    PrintDebug("    td_mult = %d/%d, cl_mult = %u/%u, ipc_mult = %u/%u.\n",
+              info->vm_info->time_state.td_num, 
+              info->vm_info->time_state.td_denom, 
+              time_state->clock_ratio_num, time_state->clock_ratio_denom,
+              time_state->ipc_ratio_num, time_state->ipc_ratio_denom);
+    PrintDebug("    time source = %s, tsc handling =  %s\n", 
+              (time_state->flags & VM_TIME_SLAVE_HOST) ? "host" : "none",
+              (time_state->flags & VM_TIME_TSC_PASSTHROUGH) ? "passthrough" 
+                  : (time_state->flags & VM_TIME_TRAP_RDTSC) ? "trapping" 
+                      : "offsettting");
 
     time_state->guest_cycles = 0;
     time_state->tsc_guest_offset = 0;
     time_state->last_update = 0;
-
     time_state->initial_host_time = 0;
-    time_state->vm_enter_host_time = 0;
-    time_state->vm_pause_host_time = 0;
-
-    time_state->time_flags = 0; // XXX need to set trap TSC flag or not wisely
 
     INIT_LIST_HEAD(&(time_state->timers));
     time_state->num_timers = 0;
-    
+           
     time_state->tsc_aux.lo = 0;
     time_state->tsc_aux.hi = 0;
 }
@@ -438,5 +527,4 @@ void v3_deinit_time_core(struct guest_info * core) {
     list_for_each_entry_safe(tmr, tmp, &(time_state->timers), timer_link) {
        v3_remove_timer(core, tmr);
     }
-
 }
index a024fb7..8d13c11 100644 (file)
@@ -880,7 +880,7 @@ int
 v3_vmx_config_tsc_virtualization(struct guest_info * info) {
     struct vmx_data * vmx_info = (struct vmx_data *)(info->vmm_data);
 
-    if (info->time_state.time_flags & V3_TIME_TRAP_RDTSC) {
+    if (info->time_state.flags & VM_TIME_TRAP_RDTSC) {
        if  (!vmx_info->pri_proc_ctrls.rdtsc_exit) {
            vmx_info->pri_proc_ctrls.rdtsc_exit = 1;
            check_vmcs_write(VMCS_PROC_CTRLS, vmx_info->pri_proc_ctrls.value);
@@ -894,7 +894,11 @@ v3_vmx_config_tsc_virtualization(struct guest_info * info) {
            check_vmcs_write(VMCS_PROC_CTRLS, vmx_info->pri_proc_ctrls.value);
        }
 
-        tsc_offset = v3_tsc_host_offset(&info->time_state);
+       if (info->time_state.flags & VM_TIME_TSC_PASSTHROUGH) {
+           tsc_offset = 0;
+       } else {
+            tsc_offset = v3_tsc_host_offset(&info->time_state);
+       }
         tsc_offset_high = (uint32_t)(( tsc_offset >> 32) & 0xffffffff);
         tsc_offset_low = (uint32_t)(tsc_offset & 0xffffffff);
 
@@ -921,16 +925,16 @@ int v3_vmx_enter(struct guest_info * info) {
     // Conditionally yield the CPU if the timeslice has expired
     v3_yield_cond(info);
 
-    // disable global interrupts for vm state transition
-    v3_disable_ints();
-
     // Update timer devices late after being in the VM so that as much 
     // of the time in the VM is accounted for as possible. Also do it before
     // updating IRQ entry state so that any interrupts the timers raise get 
-    // handled on the next VM entry. Must be done with interrupts disabled.
-    v3_advance_time(info);
+    // handled on the next VM entry.
+    v3_advance_time(info, NULL);
     v3_update_timers(info);
 
+    // disable global interrupts for vm state transition
+    v3_disable_ints();
+
     if (vmcs_store() != vmx_info->vmcs_ptr_phys) {
        vmcs_clear(vmx_info->vmcs_ptr_phys);
        vmcs_load(vmx_info->vmcs_ptr_phys);
@@ -955,12 +959,9 @@ int v3_vmx_enter(struct guest_info * info) {
     }
 
 
-    // Perform last-minute time bookkeeping prior to entering the VM
-    v3_time_enter_vm(info);
+    // Perform last-minute time setup prior to entering the VM
     v3_vmx_config_tsc_virtualization(info);
 
-    
-
     if (v3_update_vmcs_host_state(info)) {
        v3_enable_ints();
         PrintError("Could not write host state\n");
@@ -1027,8 +1028,7 @@ int v3_vmx_enter(struct guest_info * info) {
     }
 
     // Immediate exit from VM time bookkeeping
-    v3_time_exit_vm(info, &guest_cycles);
-
+    v3_advance_time(info, &guest_cycles);
 
     /* Update guest state */
     v3_vmx_save_vmcs(info);
@@ -1081,6 +1081,8 @@ int v3_vmx_enter(struct guest_info * info) {
 
     // Conditionally yield the CPU if the timeslice has expired
     v3_yield_cond(info);
+    v3_advance_time(info, NULL);
+    v3_update_timers(info);
 
     if (v3_handle_vmx_exit(info, &exit_info) == -1) {
        PrintError("Error in VMX exit handler (Exit reason=%x)\n", exit_info.exit_reason);