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.


75e133f74cce18094e5b087e0e2d0bb3f7acd232
[palacios.git] / palacios / src / geekos / svm_ctrl_regs.c
1 #include <geekos/svm_ctrl_regs.h>
2 #include <geekos/vmm_mem.h>
3 #include <geekos/vmm.h>
4 #include <geekos/vmcb.h>
5 #include <geekos/vmm_emulate.h>
6 #include <geekos/vm_guest_mem.h>
7 #include <geekos/vmm_ctrl_regs.h>
8
9
10 /* Segmentation is a problem here...
11  *
12  * When we get a memory operand, presumably we use the default segment (which is?) 
13  * unless an alternate segment was specfied in the prefix...
14  */
15
16
17 int handle_cr0_write(struct guest_info * info) {
18   //vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
19   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
20   char instr[15];
21   
22   
23   if (info->cpu_mode == REAL) {
24     int index = 0;
25     int ret;
26
27     // The real rip address is actually a combination of the rip + CS base 
28     ret = read_guest_pa_memory(info, get_addr_linear(info, guest_state->rip, guest_state->cs.base), 15, instr);
29     if (ret != 15) {
30       // I think we should inject a GPF into the guest
31       PrintDebug("Could not read instruction (ret=%d)\n", ret);
32       return -1;
33     }
34
35     while (is_prefix_byte(instr[index])) {
36       index++; 
37     }
38
39     if ((instr[index] == cr_access_byte) && 
40         (instr[index + 1] == lmsw_byte) && 
41         (MODRM_REG(instr[index + 2]) == lmsw_reg_byte)) {
42  
43       addr_t first_operand;
44       addr_t second_operand;
45       struct cr0_real *old_cr0;
46       struct cr0_real *new_cr0;
47       operand_type_t addr_type;
48       char new_cr0_val = 0;
49       // LMSW
50       // decode mod/RM
51       index += 2;
52  
53       old_cr0 = (struct cr0_real*)&(guest_state->cr0);
54
55
56       addr_type = decode_operands16(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG16);
57
58
59       if (addr_type == REG_OPERAND) {
60         new_cr0 = (struct cr0_real *)first_operand;
61       } else if (addr_type == MEM_OPERAND) {
62         addr_t host_addr;
63
64         if (guest_pa_to_host_va(info, first_operand + (guest_state->ds.base << 4), &host_addr) == -1) {
65           // gpf the guest
66           return -1;
67         }
68
69         new_cr0 = (struct cr0_real *)host_addr;
70       } else {
71         // error... don't know what to do
72         return -1;
73       }
74                  
75       if ((new_cr0->pe == 1) && (old_cr0->pe == 0)) {
76         info->cpu_mode = PROTECTED;
77       } else if ((new_cr0->pe == 0) && (old_cr0->pe == 1)) {
78         info->cpu_mode = REAL;
79       }
80       
81       new_cr0_val = *(char*)(new_cr0) & 0x0f;
82
83
84       if (info->page_mode == SHADOW_PAGING) {
85         struct cr0_real * virt_cr0 = (struct cr0_real*)&(info->shdw_pg_state.guest_cr0);
86
87         /* struct cr0_real is only 4 bits wide, 
88          * so we can overwrite the old_cr0 without worrying about the shadow fields
89          */
90         *(char*)old_cr0 &= 0xf0;
91         *(char*)old_cr0 |= new_cr0_val;
92         
93         *(char*)virt_cr0 &= 0xf0;
94         *(char*)virt_cr0 |= new_cr0_val;
95       } else {
96         // for now we just pass through....
97         *(char*)old_cr0 &= 0xf0;
98         *(char*)old_cr0 |= new_cr0_val;
99       }
100
101       PrintDebug("index = %d, rip = %x\n", index, (ulong_t)(info->rip));
102       info->rip += index;
103       PrintDebug("new_rip = %x\n", (ulong_t)(info->rip));
104     } else if ((instr[index] == cr_access_byte) && 
105                (instr[index + 1] == clts_byte)) {
106       // CLTS
107     } else {
108       // unsupported instruction, UD the guest
109       return -1;
110     }
111
112
113   } else if (info->cpu_mode == PROTECTED) {
114     int index = 0;
115     int ret;
116
117     PrintDebug("Protected Mode write to CR0\n");
118
119     // The real rip address is actually a combination of the rip + CS base 
120     ret = read_guest_pa_memory(info, get_addr_linear(info, guest_state->rip, guest_state->cs.base), 15, instr);
121     if (ret != 0) {
122       // I think we should inject a GPF into the guest
123       PrintDebug("Could not read instruction (ret=%d)\n", ret);
124       return -1;
125     }
126
127     while (is_prefix_byte(instr[index])) {
128       index++; 
129     }
130
131
132     /* CHECK IF MOV_TO_CR CAN TAKE MEMORY OPERANDS... */
133     if ((instr[index] == cr_access_byte) && 
134         (instr[index + 1] == mov_to_cr_byte)) {
135     
136       addr_t first_operand;
137       addr_t second_operand;
138       struct cr0_32 *old_cr0;
139       struct cr0_32 *new_cr0;
140       operand_type_t addr_type;
141
142       index += 2;
143  
144       old_cr0 = (struct cr0_32*)&(guest_state->cr0);
145
146       addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
147
148
149       if (addr_type == REG_OPERAND) {
150         new_cr0 = (struct cr0_32 *)first_operand;
151       } else if (addr_type == MEM_OPERAND) {
152         addr_t host_addr;
153
154         if (guest_pa_to_host_va(info, first_operand + guest_state->ds.base, &host_addr) == -1) {
155           // gpf the guest
156           return -1;
157         }
158
159         new_cr0 = (struct cr0_32 *)host_addr;
160       } else {
161         // error... don't know what to do
162         return -1;
163       }
164
165
166       if (info->page_mode == SHADOW_PAGING) {
167         struct cr0_32 * virt_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
168
169         if ((new_cr0->pg == 1) && (virt_cr0->pg == 0)){
170           info->cpu_mode = PROTECTED_PG;
171
172           // Activate Shadow Paging
173         }
174
175         *virt_cr0 = *new_cr0;
176         *old_cr0 = *new_cr0;
177       } else {
178         // fill in
179       }
180
181       info->rip += index;
182
183     }
184     
185   } else {
186     PrintDebug("Unknown Mode write to CR0\n");
187     while(1);
188   }
189   return 0;
190 }
191
192
193 int handle_cr0_read(struct guest_info * info) {
194   //vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
195   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
196   char instr[15];
197
198   if (info->cpu_mode == REAL) {
199     int index = 0;
200     int ret;
201
202     // The real rip address is actually a combination of the rip + CS base 
203     ret = read_guest_pa_memory(info, get_addr_linear(info, guest_state->rip, guest_state->cs.base), 15, instr);
204     if (ret != 15) {
205       // I think we should inject a GPF into the guest
206       PrintDebug("Could not read instruction (ret=%d)\n", ret);
207       return -1;
208     }
209
210     while (is_prefix_byte(instr[index])) {
211       index++; 
212     }
213
214     if ((instr[index] == cr_access_byte) && 
215         (instr[index + 1] == smsw_byte) && 
216         (MODRM_REG(instr[index + 2]) == smsw_reg_byte)) {
217
218       addr_t first_operand;
219       addr_t second_operand;
220       struct cr0_real *cr0;
221       operand_type_t addr_type;
222       char cr0_val = 0;
223
224       index += 2;
225       
226       cr0 = (struct cr0_real*)&(guest_state->cr0);
227       
228       
229       addr_type = decode_operands16(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG16);
230       
231       if (addr_type == MEM_OPERAND) {
232         addr_t host_addr;
233         
234         if (guest_pa_to_host_va(info, first_operand + (guest_state->ds.base << 4), &host_addr) == -1) {
235           // gpf the guest
236           return -1;
237         }
238         
239         first_operand = host_addr;
240       } else {
241         // error... don't know what to do
242         return -1;
243       }
244
245       cr0_val = *(char*)cr0 & 0x0f;
246
247
248       *(char *)first_operand &= 0xf0;
249       *(char *)first_operand |= cr0_val;
250
251       info->rip += index;
252
253     }
254
255   } else if (info->cpu_mode == PROTECTED) {
256     int index = 0;
257     int ret;
258
259     // The real rip address is actually a combination of the rip + CS base 
260     ret = read_guest_pa_memory(info, get_addr_linear(info, guest_state->rip, guest_state->cs.base), 15, instr);
261     if (ret != 15) {
262       // I think we should inject a GPF into the guest
263       PrintDebug("Could not read instruction (ret=%d)\n", ret);
264       return -1;
265     }
266
267     while (is_prefix_byte(instr[index])) {
268       index++; 
269     }
270
271
272   }
273
274
275   return 0;
276 }