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.


198c09c2bba92e9301bdce277673ccf47d59366a
[palacios.git] / palacios / src / palacios / svm_ctrl_regs.c
1 #include <palacios/svm_ctrl_regs.h>
2 #include <palacios/vmm_mem.h>
3 #include <palacios/vmm.h>
4 #include <palacios/vmcb.h>
5 #include <palacios/vmm_emulate.h>
6 #include <palacios/vm_guest_mem.h>
7 #include <palacios/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.selector), 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   } else {
185     PrintDebug("Unknown Mode write to CR0\n");
186     while(1);
187   }
188   return 0;
189 }
190
191
192 int handle_cr0_read(struct guest_info * info) {
193   //vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
194   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
195   char instr[15];
196
197   if (info->cpu_mode == REAL) {
198     int index = 0;
199     int ret;
200
201     // The real rip address is actually a combination of the rip + CS base 
202     ret = read_guest_pa_memory(info, get_addr_linear(info, guest_state->rip, guest_state->cs.selector), 15, instr);
203     if (ret != 15) {
204       // I think we should inject a GPF into the guest
205       PrintDebug("Could not read Real Mode instruction (ret=%d)\n", ret);
206       return -1;
207     }
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       *(char *)first_operand &= 0xf0;
248       *(char *)first_operand |= cr0_val;
249
250       PrintDebug("index = %d, rip = %x\n", index, (ulong_t)(info->rip));
251       info->rip += index;
252       PrintDebug("new_rip = %x\n", (ulong_t)(info->rip));
253     } else {
254       addr_t host_addr;
255
256       PrintDebug("Unknown read instr to CR0\n");
257       guest_pa_to_host_pa(info, get_addr_linear(info, guest_state->rip, guest_state->cs.selector), &host_addr);
258       
259       PrintDebug("Instr (15 bytes) at %x:\n", host_addr);
260       PrintTraceMemDump((char*)host_addr, 15);
261
262       return -1;
263     }
264
265   } else if (info->cpu_mode == PROTECTED) {
266     int index = 0;
267     int ret;
268
269     // The real rip address is actually a combination of the rip + CS base 
270     ret = read_guest_pa_memory(info, get_addr_linear(info, guest_state->rip, guest_state->cs.base), 15, instr);
271     if (ret != 15) {
272       // I think we should inject a GPF into the guest
273       PrintDebug("Could not read Proteced mode instruction (ret=%d)\n", ret);
274       return -1;
275     }
276
277     while (is_prefix_byte(instr[index])) {
278       index++; 
279     }
280
281
282   }
283
284
285   return 0;
286 }