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.


added support for in/out instructions
[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, (addr_t)guest_state->rip + (guest_state->cs.base << 4), 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, (addr_t)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     if ((instr[index] == cr_access_byte) && 
132         (instr[index + 1] == mov_to_cr_byte)) {
133     
134       addr_t first_operand;
135       addr_t second_operand;
136       struct cr0_32 *old_cr0;
137       struct cr0_32 *new_cr0;
138       operand_type_t addr_type;
139
140       index += 2;
141  
142       old_cr0 = (struct cr0_32*)&(guest_state->cr0);
143
144       addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
145
146
147       if (addr_type == REG_OPERAND) {
148         new_cr0 = (struct cr0_32 *)first_operand;
149       } else if (addr_type == MEM_OPERAND) {
150         addr_t host_addr;
151
152         if (guest_pa_to_host_va(info, first_operand + guest_state->ds.base, &host_addr) == -1) {
153           // gpf the guest
154           return -1;
155         }
156
157         new_cr0 = (struct cr0_32 *)host_addr;
158       } else {
159         // error... don't know what to do
160         return -1;
161       }
162
163
164       if (info->page_mode == SHADOW_PAGING) {
165         struct cr0_32 * virt_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
166
167         if ((new_cr0->pg == 1) && (virt_cr0->pg == 0)){
168           info->cpu_mode = PROTECTED_PG;
169
170           // Activate Shadow Paging
171         }
172
173         *virt_cr0 = *new_cr0;
174         *old_cr0 = *new_cr0;
175       } else {
176         // fill in
177       }
178
179       info->rip += index;
180
181     }
182     
183   } else {
184     PrintDebug("Unknown Mode write to CR0\n");
185     while(1);
186   }
187   return 0;
188 }
189
190
191 int handle_cr0_read(struct guest_info * info) {
192   //vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
193   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
194   char instr[15];
195
196   if (info->cpu_mode == REAL) {
197     int index = 0;
198     int ret;
199
200     // The real rip address is actually a combination of the rip + CS base 
201     ret = read_guest_pa_memory(info, (addr_t)guest_state->rip + (guest_state->cs.base << 4), 15, instr);
202     if (ret != 15) {
203       // I think we should inject a GPF into the guest
204       PrintDebug("Could not read instruction (ret=%d)\n", ret);
205       return -1;
206     }
207
208     while (is_prefix_byte(instr[index])) {
209       index++; 
210     }
211
212     if ((instr[index] == cr_access_byte) && 
213         (instr[index + 1] == smsw_byte) && 
214         (MODRM_REG(instr[index + 2]) == smsw_reg_byte)) {
215
216       addr_t first_operand;
217       addr_t second_operand;
218       struct cr0_real *cr0;
219       operand_type_t addr_type;
220       char cr0_val = 0;
221
222       index += 2;
223       
224       cr0 = (struct cr0_real*)&(guest_state->cr0);
225       
226       
227       addr_type = decode_operands16(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG16);
228       
229       if (addr_type == MEM_OPERAND) {
230         addr_t host_addr;
231         
232         if (guest_pa_to_host_va(info, first_operand + (guest_state->ds.base << 4), &host_addr) == -1) {
233           // gpf the guest
234           return -1;
235         }
236         
237         first_operand = host_addr;
238       } else {
239         // error... don't know what to do
240         return -1;
241       }
242
243       cr0_val = *(char*)cr0 & 0x0f;
244
245
246       *(char *)first_operand &= 0xf0;
247       *(char *)first_operand |= cr0_val;
248
249       info->rip += index;
250
251     }
252
253   } else if (info->cpu_mode == PROTECTED) {
254     int index = 0;
255     int ret;
256
257     // The real rip address is actually a combination of the rip + CS base 
258     ret = read_guest_pa_memory(info, (addr_t)guest_state->rip + guest_state->cs.base, 15, instr);
259     if (ret != 15) {
260       // I think we should inject a GPF into the guest
261       PrintDebug("Could not read instruction (ret=%d)\n", ret);
262       return -1;
263     }
264
265     while (is_prefix_byte(instr[index])) {
266       index++; 
267     }
268
269
270   }
271
272
273   return 0;
274 }