2 * This file is part of the Palacios Virtual Machine Monitor developed
3 * by the V3VEE Project with funding from the United States National
4 * Science Foundation and the Department of Energy.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
10 * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
11 * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
12 * All rights reserved.
14 * Author: Jack Lange <jarusl@cs.northwestern.edu>
15 * Patrick G. Bridges <bridges@cs.unm.edu>
17 * This is free software. You are permitted to use,
18 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
21 #include <palacios/vmm_time.h>
22 #include <palacios/vmm.h>
23 #include <palacios/vm_guest.h>
25 #ifndef CONFIG_DEBUG_TIME
27 #define PrintDebug(fmt, args...)
30 static int handle_cpufreq_hcall(struct guest_info * info, uint_t hcall_id, void * priv_data) {
31 struct vm_time * time_state = &(info->time_state);
33 info->vm_regs.rbx = time_state->cpu_freq;
35 PrintDebug("Guest request cpu frequency: return %ld\n", (long)info->vm_regs.rbx);
42 void v3_init_time(struct guest_info * info) {
43 struct vm_time * time_state = &(info->time_state);
45 time_state->cpu_freq = V3_CPU_KHZ();
47 time_state->pause_time = 0;
48 time_state->last_update = 0;
49 time_state->host_offset = 0;
50 time_state->offset_sum = 0;
52 INIT_LIST_HEAD(&(time_state->timers));
53 time_state->num_timers = 0;
55 v3_register_hypercall(info->vm_info, TIME_CPUFREQ_HCALL, handle_cpufreq_hcall, NULL);
58 int v3_start_time(struct guest_info * info) {
59 /* We start running with guest_time == host_time */
60 uint64_t t = v3_get_host_time(&info->time_state);
62 PrintDebug("Starting initial guest time as %llu\n", t);
63 info->time_state.last_update = t;
64 info->time_state.pause_time = t;
65 info->yield_start_cycle = t;
69 int v3_pause_time(struct guest_info * info) {
70 V3_ASSERT(info->time_state.pause_time == 0);
71 info->time_state.pause_time = v3_get_guest_time(&info->time_state);
72 PrintDebug("Time paused at guest time as %llu\n",
73 info->time_state.pause_time);
77 /* Use a control-theoretic approach, specifically a PI control approach,
78 * to adjust host_offset towards 0. Overall control documentation in
79 * palacios/docs/time_control.tex Control parameters are P and I,
80 * broken into rational numbers
83 /* These numbers need to be actually determined by pole placement work. They're
84 * just blind guesses for now, which is a really bad idea. :) */
90 void adjust_time_offset(struct guest_info * info) {
91 /* Set point for control: Desired offset = 0;
92 * Error = host_offset - 0 = host_offset */
96 /* Update the integral of the errror */
97 info->time_state.offset_sum += info->time_state.host_offset;
98 adjust = (P_NUM * info->time_state.host_offset) / P_DENOM +
99 (I_NUM * info->time_state.offset_sum) / I_DENOM;
101 /* We may want to constrain *adjust* because of
102 * resolution/accuracy constraints. Explore that later. */
103 info->time_state.host_offset -= adjust;
107 int v3_resume_time(struct guest_info * info) {
108 uint64_t t = v3_get_host_time(&info->time_state);
109 V3_ASSERT(info->time_state.pause_time != 0);
110 info->time_state.host_offset =
111 (sint64_t)info->time_state.pause_time - (sint64_t)t;
112 #ifdef CONFIG_TIME_TSC_OFFSET_ADJUST
113 adjust_time_offset(info);
115 info->time_state.pause_time = 0;
116 PrintDebug("Time resumed paused at guest time as %llu "
117 "offset %lld from host time.\n", t, info->time_state.host_offset);
122 int v3_add_timer(struct guest_info * info, struct vm_timer_ops * ops,
123 void * private_data) {
124 struct vm_timer * timer = NULL;
125 timer = (struct vm_timer *)V3_Malloc(sizeof(struct vm_timer));
126 V3_ASSERT(timer != NULL);
129 timer->private_data = private_data;
131 list_add(&(timer->timer_link), &(info->time_state.timers));
132 info->time_state.num_timers++;
138 int v3_remove_timer(struct guest_info * info, struct vm_timer * timer) {
139 list_del(&(timer->timer_link));
140 info->time_state.num_timers--;
146 void v3_update_timers(struct guest_info * info) {
147 struct vm_timer * tmp_timer;
148 uint64_t old_time = info->time_state.last_update;
151 info->time_state.last_update = v3_get_guest_time(&info->time_state);
152 cycles = info->time_state.last_update - old_time;
154 list_for_each_entry(tmp_timer, &(info->time_state.timers), timer_link) {
155 tmp_timer->ops->update_timer(info, cycles, info->time_state.cpu_freq, tmp_timer->private_data);