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.


Minor bug fix
[palacios.git] / palacios / src / extensions / ext_vtsc.c
1 /* 
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.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
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.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *         Patrick G. Bridges <bridges@cs.unm.edu>
16  *
17  * This is free software.  You are permitted to use,
18  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
19  */
20
21 #include <palacios/vmm.h>
22 #include <palacios/vmm_time.h>
23 #include <palacios/vm_guest.h>
24
25
26 // Functions for handling exits on the TSC when fully virtualizing 
27 // the timestamp counter.
28 #define TSC_MSR     0x10
29 #define TSC_AUX_MSR 0xC0000103
30
31 int v3_handle_rdtscp(struct guest_info *info);
32 int v3_handle_rdtsc(struct guest_info *info);
33
34
35 struct vtsc_state {
36
37     struct v3_msr tsc_aux;     // Auxilliary MSR for RDTSCP
38
39 };
40
41
42
43 /* 
44  * Handle full virtualization of the time stamp counter.  As noted
45  * above, we don't store the actual value of the TSC, only the guest's
46  * offset from monotonic guest's time. If the guest writes to the TSC, we
47  * handle this by changing that offset.
48  *
49  * Possible TODO: Proper hooking of TSC read/writes?
50  */ 
51
52 static int rdtsc(struct guest_info * info) {
53     uint64_t tscval = v3_get_guest_tsc(&info->time_state);
54
55     info->vm_regs.rdx = tscval >> 32;
56     info->vm_regs.rax = tscval & 0xffffffffLL;
57
58     return 0;
59 }
60
61 int v3_handle_rdtsc(struct guest_info * info) {
62     rdtsc(info);
63     
64     info->vm_regs.rax &= 0x00000000ffffffffLL;
65     info->vm_regs.rdx &= 0x00000000ffffffffLL;
66
67     info->rip += 2;
68     
69     return 0;
70 }
71
72 int v3_rdtscp(struct guest_info * info) {
73     int ret;
74     /* First get the MSR value that we need. It's safe to futz with
75      * ra/c/dx here since they're modified by this instruction anyway. */
76     info->vm_regs.rcx = TSC_AUX_MSR; 
77     ret = v3_handle_msr_read(info);
78
79     if (ret != 0) {
80         return ret;
81     }
82
83     info->vm_regs.rcx = info->vm_regs.rax;
84
85     /* Now do the TSC half of the instruction */
86     ret = v3_rdtsc(info);
87
88     if (ret != 0) {
89         return ret;
90     }
91
92     return 0;
93 }
94
95
96 int v3_handle_rdtscp(struct guest_info * info) {
97   PrintDebug("Handling virtual RDTSCP call.\n");
98
99     v3_rdtscp(info);
100
101     info->vm_regs.rax &= 0x00000000ffffffffLL;
102     info->vm_regs.rcx &= 0x00000000ffffffffLL;
103     info->vm_regs.rdx &= 0x00000000ffffffffLL;
104
105     info->rip += 3;
106     
107     return 0;
108 }
109
110
111
112
113 static int tsc_aux_msr_read_hook(struct guest_info *info, uint_t msr_num, 
114                                  struct v3_msr *msr_val, void *priv) {
115     struct vm_time * time_state = &(info->time_state);
116
117     V3_ASSERT(msr_num == TSC_AUX_MSR);
118
119     msr_val->lo = time_state->tsc_aux.lo;
120     msr_val->hi = time_state->tsc_aux.hi;
121
122     return 0;
123 }
124
125
126 static int tsc_aux_msr_write_hook(struct guest_info *info, uint_t msr_num, 
127                               struct v3_msr msr_val, void *priv) {
128     struct vm_time * time_state = &(info->time_state);
129
130     V3_ASSERT(msr_num == TSC_AUX_MSR);
131
132     time_state->tsc_aux.lo = msr_val.lo;
133     time_state->tsc_aux.hi = msr_val.hi;
134
135     return 0;
136 }
137
138
139 static int tsc_msr_read_hook(struct guest_info *info, uint_t msr_num,
140                              struct v3_msr *msr_val, void *priv) {
141     uint64_t time = v3_get_guest_tsc(&info->time_state);
142
143     V3_ASSERT(msr_num == TSC_MSR);
144
145     msr_val->hi = time >> 32;
146     msr_val->lo = time & 0xffffffffLL;
147     
148     return 0;
149 }
150
151
152 static int tsc_msr_write_hook(struct guest_info *info, uint_t msr_num,
153                              struct v3_msr msr_val, void *priv) {
154     struct vm_time * time_state = &(info->time_state);
155     uint64_t guest_time, new_tsc;
156
157     V3_ASSERT(msr_num == TSC_MSR);
158
159     new_tsc = (((uint64_t)msr_val.hi) << 32) | (uint64_t)msr_val.lo;
160     guest_time = v3_get_guest_time(time_state);
161     time_state->tsc_guest_offset = (sint64_t)new_tsc - (sint64_t)guest_time; 
162
163     return 0;
164 }
165
166
167 static int deinit() {
168     v3_unhook_msr(vm, TSC_MSR);
169     v3_unhook_msr(vm, TSC_AUX_MSR);
170 }
171
172
173 static int init() {
174
175     time_state->tsc_aux.lo = 0;
176     time_state->tsc_aux.hi = 0;
177
178
179
180     PrintDebug("Installing TSC MSR hook.\n");
181     ret = v3_hook_msr(vm, TSC_MSR, 
182                       tsc_msr_read_hook, tsc_msr_write_hook, NULL);
183
184     if (ret != 0) {
185         return ret;
186     }
187
188     PrintDebug("Installing TSC_AUX MSR hook.\n");
189     ret = v3_hook_msr(vm, TSC_AUX_MSR, tsc_aux_msr_read_hook, 
190                       tsc_aux_msr_write_hook, NULL);
191
192     if (ret != 0) {
193         return ret;
194     }
195 }