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.


f37a2051731ee1de4109907f8ada7e878ec7ac5c
[palacios.git] / palacios / include / palacios / vmm_decoder.h
1 #ifndef __VMM_EMULATE_H
2 #define __VMM_EMULATE_H
3 #include <palacios/vm_guest.h>
4 #include <palacios/vmm.h>
5
6 /*
7  * This is where we do the hideous X86 instruction parsing among other things
8  * We can parse out the instruction prefixes, as well as decode the operands 
9  */
10
11 typedef enum {INVALID_OPERAND, REG_OPERAND, MEM_OPERAND} operand_type_t;
12
13
14
15
16 struct x86_operand {
17   addr_t operand;
18   uint_t size;
19   operand_type_t type;
20 };
21
22 struct x86_prefix_list {
23   uint_t lock   : 1;
24 };
25
26 /* This parses an instruction 
27  * All addresses in arguments are in the host address space
28  */
29 int v3_parse_instr(struct guest_info * info,             // input
30                    char * instr_ptr,                        // input 
31                    uint_t * instr_length,                // output
32                    addr_t * opcode,                      // output
33                    uint_t * opcode_length,               // output
34                    struct x86_prefix_list * prefixes,    // output
35                    struct x86_operand * src_operand,     // output
36                    struct x86_operand * dst_operand,     // output
37                    struct x86_operand * extra_operand);  // output
38                    
39
40
41 /* 
42  * JRL: Some of this was taken from the Xen sources... 
43  */
44
45 #define PACKED __attribute__((packed))
46
47 #define MODRM_MOD(x) ((x >> 6) & 0x3)
48 #define MODRM_REG(x) ((x >> 3) & 0x7)
49 #define MODRM_RM(x)  (x & 0x7)
50
51 struct modrm_byte {
52   uint_t rm   :   3 PACKED;
53   uint_t reg  :   3 PACKED;
54   uint_t mod  :   2 PACKED;
55 };
56
57
58 #define SIB_BASE(x) ((x >> 6) & 0x3)
59 #define SIB_INDEX(x) ((x >> 3) & 0x7)
60 #define SIB_SCALE(x) (x & 0x7)
61
62 struct sib_byte {
63   uint_t base     :   3 PACKED;
64   uint_t index    :   3 PACKED;
65   uint_t scale    :   2 PACKED;
66 };
67
68
69
70 #define MAKE_INSTR(nm, ...) static const uchar_t OPCODE_##nm[] = { __VA_ARGS__ }
71
72 /* 
73  * Here's how it works:
74  * First byte: Length. 
75  * Following bytes: Opcode bytes. 
76  * Special case: Last byte, if zero, doesn't need to match. 
77  */
78 MAKE_INSTR(INVD,   2, 0x0f, 0x08);
79 MAKE_INSTR(CPUID,  2, 0x0f, 0xa2);
80 MAKE_INSTR(RDMSR,  2, 0x0f, 0x32);
81 MAKE_INSTR(WRMSR,  2, 0x0f, 0x30);
82 MAKE_INSTR(RDTSC,  2, 0x0f, 0x31);
83 MAKE_INSTR(RDTSCP, 3, 0x0f, 0x01, 0xf9);
84 MAKE_INSTR(CLI,    1, 0xfa);
85 MAKE_INSTR(STI,    1, 0xfb);
86 MAKE_INSTR(RDPMC,  2, 0x0f, 0x33);
87 MAKE_INSTR(CLGI,   3, 0x0f, 0x01, 0xdd);
88 MAKE_INSTR(STGI,   3, 0x0f, 0x01, 0xdc);
89 MAKE_INSTR(VMRUN,  3, 0x0f, 0x01, 0xd8);
90 MAKE_INSTR(VMLOAD, 3, 0x0f, 0x01, 0xda);
91 MAKE_INSTR(VMSAVE, 3, 0x0f, 0x01, 0xdb);
92 MAKE_INSTR(VMCALL, 3, 0x0f, 0x01, 0xd9);
93 MAKE_INSTR(PAUSE,  2, 0xf3, 0x90);
94 MAKE_INSTR(SKINIT, 3, 0x0f, 0x01, 0xde);
95 MAKE_INSTR(MOV2CR, 3, 0x0f, 0x22, 0x00);
96 MAKE_INSTR(MOVCR2, 3, 0x0f, 0x20, 0x00);
97 MAKE_INSTR(MOV2DR, 3, 0x0f, 0x23, 0x00);
98 MAKE_INSTR(MOVDR2, 3, 0x0f, 0x21, 0x00);
99 MAKE_INSTR(PUSHF,  1, 0x9c);
100 MAKE_INSTR(POPF,   1, 0x9d);
101 MAKE_INSTR(RSM,    2, 0x0f, 0xaa);
102 MAKE_INSTR(INVLPG, 3, 0x0f, 0x01, 0x00);
103 MAKE_INSTR(INVLPGA,3, 0x0f, 0x01, 0xdf);
104 MAKE_INSTR(HLT,    1, 0xf4);
105 MAKE_INSTR(CLTS,   2, 0x0f, 0x06);
106 MAKE_INSTR(LMSW,   3, 0x0f, 0x01, 0x00);
107 MAKE_INSTR(SMSW,   3, 0x0f, 0x01, 0x00);
108
109
110 static const uchar_t PREFIX_LOCK = 0xF0;
111 static const uchar_t PREFIX_REPNE = 0xF2;
112 static const uchar_t PREFIX_REPNZ = 0xF2;
113 static const uchar_t PREFIX_REP = 0xF3;
114 static const uchar_t PREFIX_REPE = 0xF3;
115 static const uchar_t PREFIX_REPZ = 0xF3;
116 static const uchar_t PREFIX_CS_OVERRIDE = 0x2E;
117 static const uchar_t PREFIX_SS_OVERRIDE = 0x36;
118 static const uchar_t PREFIX_DS_OVERRIDE = 0x3E;
119 static const uchar_t PREFIX_ES_OVERRIDE = 0x26;
120 static const uchar_t PREFIX_FS_OVERRIDE = 0x64;
121 static const uchar_t PREFIX_GS_OVERRIDE = 0x65;
122 static const uchar_t PREFIX_BR_NOT_TAKEN = 0x2E;
123 static const uchar_t PREFIX_BR_TAKEN = 0x3E;
124 static const uchar_t PREFIX_OP_SIZE = 0x66;
125 static const uchar_t PREFIX_ADDR_SIZE = 0x67;
126
127 static inline int is_prefix_byte(char byte) {
128   switch (byte) {
129   case 0xF0:      // lock
130   case 0xF2:      // REPNE/REPNZ
131   case 0xF3:      // REP or REPE/REPZ
132   case 0x2E:      // CS override or Branch hint not taken (with Jcc instrs)
133   case 0x36:      // SS override
134   case 0x3E:      // DS override or Branch hint taken (with Jcc instrs)
135   case 0x26:      // ES override
136   case 0x64:      // FS override
137   case 0x65:      // GS override
138     //case 0x2E:      // branch not taken hint
139     //  case 0x3E:      // branch taken hint
140   case 0x66:      // operand size override
141   case 0x67:      // address size override
142     return 1;
143     break;
144   default:
145     return 0;
146     break;
147   }
148 }
149
150
151 static inline v3_reg_t get_gpr_mask(struct guest_info * info) {
152   switch (info->cpu_mode) {
153   case REAL: 
154     return 0xffff;
155     break;
156   case PROTECTED:
157     return 0xffffffff;
158   default:
159     V3_ASSERT(0);
160     return 0;
161   }
162 }
163
164
165 static inline addr_t get_addr_linear(struct guest_info * info, addr_t addr, struct v3_segment * seg) {
166   switch (info->cpu_mode) {
167   case REAL:
168     return addr + (seg->selector << 4);
169     break;
170   case PROTECTED:
171     return addr + seg->base;
172     break;
173   default:
174     V3_ASSERT(0);
175     return 0;
176   }
177 }
178
179
180 typedef enum {INVALID_ADDR_TYPE, REG, DISP0, DISP8, DISP16, DISP32} modrm_mode_t;
181 typedef enum {INVALID_REG_SIZE, REG64, REG32, REG16, REG8} reg_size_t;
182
183
184
185
186
187
188 struct v3_gprs;
189
190 static inline addr_t decode_register(struct v3_gprs * gprs, char reg_code, reg_size_t reg_size) {
191   addr_t reg_addr;
192
193   switch (reg_code) {
194   case 0:
195     reg_addr = (addr_t)&(gprs->rax);
196     break;
197   case 1:
198     reg_addr = (addr_t)&(gprs->rcx);
199     break;
200   case 2:
201     reg_addr = (addr_t)&(gprs->rdx);
202     break;
203   case 3:
204     reg_addr = (addr_t)&(gprs->rbx);
205     break;
206   case 4:
207     if (reg_size == REG8) {
208       reg_addr = (addr_t)&(gprs->rax) + 1;
209     } else {
210       reg_addr = (addr_t)&(gprs->rsp);
211     }
212     break;
213   case 5:
214     if (reg_size == REG8) {
215       reg_addr = (addr_t)&(gprs->rcx) + 1;
216     } else {
217       reg_addr = (addr_t)&(gprs->rbp);
218     }
219     break;
220   case 6:
221     if (reg_size == REG8) {
222       reg_addr = (addr_t)&(gprs->rdx) + 1;
223     } else {
224       reg_addr = (addr_t)&(gprs->rsi);
225     }
226     break;
227   case 7:
228     if (reg_size == REG8) {
229       reg_addr = (addr_t)&(gprs->rbx) + 1;
230     } else {
231       reg_addr = (addr_t)&(gprs->rdi);
232     }
233     break;
234   default:
235     reg_addr = 0;
236     break;
237   }
238
239   return reg_addr;
240 }
241
242
243
244 static inline operand_type_t decode_operands16(struct v3_gprs * gprs, // input/output
245                                                char * modrm_instr,       // input
246                                                int * offset,             // output
247                                                addr_t * first_operand,   // output
248                                                addr_t * second_operand,  // output
249                                                reg_size_t reg_size) {    // input
250   
251   struct modrm_byte * modrm = (struct modrm_byte *)modrm_instr;
252   addr_t base_addr = 0;
253   modrm_mode_t mod_mode = 0;
254   operand_type_t addr_type = INVALID_OPERAND;
255   char * instr_cursor = modrm_instr;
256
257   PrintDebug("ModRM mod=%d\n", modrm->mod);
258
259   instr_cursor += 1;
260
261   if (modrm->mod == 3) {
262     mod_mode = REG;
263     addr_type = REG_OPERAND;
264     PrintDebug("first operand = Register (RM=%d)\n",modrm->rm);
265
266     *first_operand = decode_register(gprs, modrm->rm, reg_size);
267
268   } else {
269
270     addr_type = MEM_OPERAND;
271
272     if (modrm->mod == 0) {
273       mod_mode = DISP0;
274     } else if (modrm->mod == 1) {
275       mod_mode = DISP8;
276     } else if (modrm->mod == 2) {
277       mod_mode = DISP16;
278     }
279
280     switch (modrm->rm) {
281     case 0:
282       base_addr = gprs->rbx + gprs->rsi;
283       break;
284     case 1:
285       base_addr = gprs->rbx + gprs->rdi;
286       break;
287     case 2:
288       base_addr = gprs->rbp + gprs->rsi;
289       break;
290     case 3:
291       base_addr = gprs->rbp + gprs->rdi;
292       break;
293     case 4:
294       base_addr = gprs->rsi;
295       break;
296     case 5:
297       base_addr = gprs->rdi;
298       break;
299     case 6:
300       if (modrm->mod == 0) {
301         base_addr = 0;
302         mod_mode = DISP16;
303       } else {
304         base_addr = gprs->rbp;
305       }
306       break;
307     case 7:
308       base_addr = gprs->rbx;
309       break;
310     }
311
312
313
314     if (mod_mode == DISP8) {
315       base_addr += (uchar_t)*(instr_cursor);
316       instr_cursor += 1;
317     } else if (mod_mode == DISP16) {
318       base_addr += (ushort_t)*(instr_cursor);
319       instr_cursor += 2;
320     }
321     
322     *first_operand = base_addr;
323   }
324
325   *offset +=  (instr_cursor - modrm_instr);
326   *second_operand = decode_register(gprs, modrm->reg, reg_size);
327
328   return addr_type;
329 }
330
331
332
333 static inline operand_type_t decode_operands32(struct v3_gprs * gprs, // input/output
334                                                char * modrm_instr,       // input
335                                                int * offset,             // output
336                                                addr_t * first_operand,   // output
337                                                addr_t * second_operand,  // output
338                                                reg_size_t reg_size) {    // input
339   
340   char * instr_cursor = modrm_instr;
341   struct modrm_byte * modrm = (struct modrm_byte *)modrm_instr;
342   addr_t base_addr = 0;
343   modrm_mode_t mod_mode = 0;
344   uint_t has_sib_byte = 0;
345   operand_type_t addr_type = INVALID_OPERAND;
346
347
348
349   instr_cursor += 1;
350
351   if (modrm->mod == 3) {
352     mod_mode = REG;
353     addr_type = REG_OPERAND;
354     
355     PrintDebug("first operand = Register (RM=%d)\n",modrm->rm);
356
357     *first_operand = decode_register(gprs, modrm->rm, reg_size);
358
359   } else {
360
361     addr_type = MEM_OPERAND;
362
363     if (modrm->mod == 0) {
364       mod_mode = DISP0;
365     } else if (modrm->mod == 1) {
366       mod_mode = DISP8;
367     } else if (modrm->mod == 2) {
368       mod_mode = DISP32;
369     }
370     
371     switch (modrm->rm) {
372     case 0:
373       base_addr = gprs->rax;
374       break;
375     case 1:
376       base_addr = gprs->rcx;
377       break;
378     case 2:
379       base_addr = gprs->rdx;
380       break;
381     case 3:
382       base_addr = gprs->rbx;
383       break;
384     case 4:
385       has_sib_byte = 1;
386       break;
387     case 5:
388       if (modrm->mod == 0) {
389         base_addr = 0;
390         mod_mode = DISP32;
391       } else {
392         base_addr = gprs->rbp;
393       }
394       break;
395     case 6:
396       base_addr = gprs->rsi;
397       break;
398     case 7:
399       base_addr = gprs->rdi;
400       break;
401     }
402
403     if (has_sib_byte) {
404       instr_cursor += 1;
405       struct sib_byte * sib = (struct sib_byte *)(instr_cursor);
406       int scale = 1;
407
408       instr_cursor += 1;
409
410
411       if (sib->scale == 1) {
412         scale = 2;
413       } else if (sib->scale == 2) {
414         scale = 4;
415       } else if (sib->scale == 3) {
416         scale = 8;
417       }
418
419
420       switch (sib->index) {
421       case 0:
422         base_addr = gprs->rax;
423         break;
424       case 1:
425         base_addr = gprs->rcx;
426         break;
427       case 2:
428         base_addr = gprs->rdx;
429         break;
430       case 3:
431         base_addr = gprs->rbx;
432         break;
433       case 4:
434         base_addr = 0;
435         break;
436       case 5:
437         base_addr = gprs->rbp;
438         break;
439       case 6:
440         base_addr = gprs->rsi;
441         break;
442       case 7:
443         base_addr = gprs->rdi;
444         break;
445       }
446
447       base_addr *= scale;
448
449
450       switch (sib->base) {
451       case 0:
452         base_addr += gprs->rax;
453         break;
454       case 1:
455         base_addr += gprs->rcx;
456         break;
457       case 2:
458         base_addr += gprs->rdx;
459         break;
460       case 3:
461         base_addr += gprs->rbx;
462         break;
463       case 4:
464         base_addr += gprs->rsp;
465         break;
466       case 5:
467         if (modrm->mod != 0) {
468           base_addr += gprs->rbp;
469         }
470         break;
471       case 6:
472         base_addr += gprs->rsi;
473         break;
474       case 7:
475         base_addr += gprs->rdi;
476         break;
477       }
478
479     } 
480
481
482     if (mod_mode == DISP8) {
483       base_addr += (uchar_t)*(instr_cursor);
484       instr_cursor += 1;
485     } else if (mod_mode == DISP32) {
486       base_addr += (uint_t)*(instr_cursor);
487       instr_cursor += 4;
488     }
489     
490
491     *first_operand = base_addr;
492   }
493
494   *offset += (instr_cursor - modrm_instr);
495
496   *second_operand = decode_register(gprs, modrm->reg, reg_size);
497
498   return addr_type;
499 }
500
501
502
503
504 #endif