tests/linux: use Akaros's CFLAGS
[akaros.git] / user / vmm / decode.c
1 /*
2  * Copyright 2015 Google Inc.
3  *
4  * This file is part of Akaros.
5  *
6  * Akaros is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, version 2 of the License.
9  *
10  * Akaros is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * Lesser GNU General Public License for more details.
14  *
15  * See COPYING.LESSER for details on the GNU Lesser General Public License.
16  * See COPYING for details on the GNU General Public License.
17  *
18  *
19  * A few notes:
20  * - We only emulate memory operations, so we don't need to worry about decoding
21  *   the target addresses or whatnot.  We could, just for sanity reasons, though
22  *   the registers (via modrm/sib) are in the guest virtual address space.  We
23  *   operate in the guest physical space.  Having the GPA from the fault makes
24  *   this all easier.
25  * - Just like with fetch_insn(), since we use the GPA, we assume that the
26  *   target of our memory access is also contiguous physically.  The guest could
27  *   have two virtual pages, one mapped to something that triggers an EPT fault
28  *   and the other doesn't.  The upper part of that access will go to the
29  *   adjacent physical page (e.g. a virtio region), and not to the actual
30  *   destination that the guest had mapped.  Buyer beware.  I'm less concerned
31  *   about this than I am with instructions.
32  * - To emulate instructions that set rflags, like add and cmp, I just execute
33  *   the instruction with inline asm and pop rflags.  Let the hardware do it.
34  * - The inline asm often uses %2,%1 and not %1,%2 for the args to e.g. cmp.
35  *   The good book is in Intel syntax.  Code AT&T.  It's easier to read the args
36  *   as if they are in the book, and just switch the ASM args like that.
37  * - add and cmp (80 /0) have a rex, and the Good Book says to add a
38  *   sign-extended imm8 to r/m8.  Extended to what?  I skipped that, and treated
39  *   it like a regular imm8.  The rex should apply for register selection still.
40  */
41
42 #include <parlib/stdio.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <fcntl.h>
46 #include <parlib/arch/arch.h>
47 #include <parlib/ros_debug.h>
48 #include <unistd.h>
49 #include <errno.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <sys/uio.h>
53 #include <stdint.h>
54 #include <err.h>
55 #include <sys/mman.h>
56 #include <vmm/vmm.h>
57 #include <vmm/virtio.h>
58 #include <vmm/virtio_mmio.h>
59 #include <vmm/virtio_ids.h>
60 #include <vmm/virtio_config.h>
61 #include <ros/arch/mmu.h>
62 #include <ros/arch/trapframe.h>
63
64 int debug_decode = 0;
65 #define DPRINTF(fmt, ...) \
66         do { \
67                 if (debug_decode) { \
68                         fprintf(stderr, "decode: " fmt, ## __VA_ARGS__); \
69                 } \
70         } \
71         while (0)
72
73 enum x86_register {
74         X86_RAX = 0,
75         X86_RCX = 1,
76         X86_RDX = 2,
77         X86_RBX = 3,
78         X86_RSP = 4,
79         X86_RBP = 5,
80         X86_RSI = 6,
81         X86_RDI = 7,
82         X86_R8  = 8,
83         X86_R9  = 9,
84         X86_R10 = 10,
85         X86_R11 = 11,
86         X86_R12 = 12,
87         X86_R13 = 13,
88         X86_R14 = 14,
89         X86_R15 = 15,
90 };
91
92 static const char * const reg_names[] = {
93         "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
94         "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15"
95 };
96
97 static const char *regname(uint8_t reg)
98 {
99         return reg_names[reg];
100 }
101
102 /* Helper: points to the reg in the VMTF */
103 static uint64_t *reg_to_vmtf_reg(struct vm_trapframe *vm_tf, int reg)
104 {
105         switch (reg) {
106         case 0:
107                 return &vm_tf->tf_rax;
108         case 1:
109                 return &vm_tf->tf_rcx;
110         case 2:
111                 return &vm_tf->tf_rdx;
112         case 3:
113                 return &vm_tf->tf_rbx;
114         case 4:
115                 return &vm_tf->tf_rsp;
116         case 5:
117                 return &vm_tf->tf_rbp;
118         case 6:
119                 return &vm_tf->tf_rsi;
120         case 7:
121                 return &vm_tf->tf_rdi;
122         case 8:
123                 return &vm_tf->tf_r8;
124         case 9:
125                 return &vm_tf->tf_r9;
126         case 10:
127                 return &vm_tf->tf_r10;
128         case 11:
129                 return &vm_tf->tf_r11;
130         case 12:
131                 return &vm_tf->tf_r12;
132         case 13:
133                 return &vm_tf->tf_r13;
134         case 14:
135                 return &vm_tf->tf_r14;
136         case 15:
137                 return &vm_tf->tf_r15;
138         }
139         panic("Unknown reg %d\n", reg);
140 }
141
142 struct x86_decode {
143         uint8_t prefix_sz;
144         uint8_t opcode_sz;
145         uint8_t modrm_sib_sz;
146         uint8_t imm_sz;
147         uint8_t operand_bytes;
148         uint8_t address_bytes;
149         bool has_modrm;
150         bool is_store;
151         bool rex_r;
152         bool rex_x;
153         bool rex_b;
154 };
155
156 /* We decode instructions in response to memory faults, so most every
157  * instruction will have modrm. */
158 #define X86_DECODE_64_DEFAULT { \
159         .prefix_sz = 0, \
160         .opcode_sz = 1, \
161         .modrm_sib_sz = 0, \
162         .imm_sz = 0, \
163         .operand_bytes = 4, \
164         .address_bytes = 8, \
165         .has_modrm = true, \
166         .is_store = false, \
167         .rex_r = false, \
168         .rex_x = false, \
169         .rex_b = false, \
170 }
171
172 static void print_decoded_insn(uint8_t *insn, struct x86_decode *d);
173 static void run_decode_hokey_tests(void);
174
175 static int decode_prefix(uint8_t *insn, struct x86_decode *d)
176 {
177         uint8_t *p = insn;
178
179         for (;; p++) {
180                 /* Operand-size override prefix */
181                 if (p[0] == 0x66) {
182                         /* Ignore 0x66 if REX.W changed us to 8 bytes (64).
183                          * Though we should only see 0x66 before REX.W.
184                          *
185                          * If this was handling 32 bit code but with cs.d clear
186                          * (default 16), 66 should set us to 4 bytes. */
187                         if (d->operand_bytes == 4)
188                                 d->operand_bytes = 2;
189                         continue;
190                 }
191                 /* Address-size override prefix */
192                 if (p[0] == 0x67) {
193                         d->address_bytes = 4;
194                         continue;
195                 }
196                 /* REX.* */
197                 if ((p[0] & 0xf0) == 0x40) {
198                         if (p[0] & 0x08)
199                                 d->operand_bytes = 8;
200                         if (p[0] & 0x04)
201                                 d->rex_r = true;
202                         if (p[0] & 0x02)
203                                 d->rex_x = true;
204                         if (p[0] & 0x01)
205                                 d->rex_b = true;
206                         continue;
207                 }
208                 break;
209         }
210         d->prefix_sz = p - insn;
211         return 0;
212 }
213
214 static uint8_t *get_modrm(uint8_t *insn, struct x86_decode *d)
215 {
216         if (!d->has_modrm)
217                 return NULL;
218         return insn + d->prefix_sz + d->opcode_sz;
219 }
220
221 static uint8_t modrm_sib_bytes_16(int mod, int rm, struct x86_decode *d)
222 {
223         uint8_t ret = 1;        /* counting the mod/rm byte itself */
224
225         switch (mod) {
226         case 0:
227                 if (rm == 6)
228                         ret += 2; /* disp16 */
229                 break;
230         case 1:
231                 ret += 1; /* disp8 */
232                 if (rm == 4)
233                         ret += 1; /* SIB */
234                 break;
235         case 2:
236                 ret += 2; /* disp16 */
237                 break;
238         case 3:
239                 break;
240         }
241         return ret;
242 }
243
244 static uint8_t modrm_sib_bytes_32(int mod, int rm, struct x86_decode *d)
245 {
246         uint8_t ret = 1;        /* counting the mod/rm byte itself */
247
248         switch (mod) {
249         case 0:
250                 if (rm == 4)
251                         ret += 1; /* SIB */
252                 else if (rm == 5)
253                         ret += 4; /* disp32 */
254                 break;
255         case 1:
256                 ret += 1; /* disp8 */
257                 if (rm == 4)
258                         ret += 1; /* SIB */
259                 break;
260         case 2:
261                 ret += 4; /* disp32 */
262                 if (rm == 4) /* SIB */
263                         ret += 1;
264                 break;
265         case 3:
266                 break;
267         }
268         return ret;
269 }
270
271 /* Returns the number of bytes in the instruction due to things encoded by
272  * mod/rm, such as displacements (disp32) or the SIB byte, including the mod/rm
273  * byte itself. */
274 static uint8_t modrm_sib_bytes(uint8_t *insn, struct x86_decode *d)
275 {
276         uint8_t *modrm = get_modrm(insn, d);
277         int mod, rm;
278
279         if (!modrm)
280                 return 0;
281         mod = *modrm >> 6;
282         rm = *modrm & 0x7;
283
284         switch (d->address_bytes) {
285         case 2:
286                 /* We should never see this, but was easy enough to code */
287                 fprintf(stderr, "decode: %s had %u address bytes!\n", __func__,
288                         d->address_bytes);
289                 return modrm_sib_bytes_16(mod, rm, d);
290         case 4:
291         case 8:
292                 return modrm_sib_bytes_32(mod, rm, d);
293         default:
294                 panic("decode: %s had %u address bytes!\n", __func__,
295                         d->address_bytes);
296                 return 0;
297         }
298 }
299
300 static uint8_t modrm_get_reg_16(uint8_t reg, struct x86_decode *d)
301 {
302         return reg;
303 }
304
305 static uint8_t modrm_get_reg_32(uint8_t reg, struct x86_decode *d)
306 {
307         return reg + (d->rex_r ? 8 : 0);
308 }
309
310 static uint64_t get_imm(uint8_t *insn, struct x86_decode *d)
311 {
312         uint8_t *imm = insn + d->prefix_sz + d->opcode_sz + d->modrm_sib_sz;
313         uint64_t ret = 0;
314
315         switch (d->imm_sz) {
316         case 8:
317                 ret |= (uint64_t)imm[7] << (8 * 7);
318                 ret |= (uint64_t)imm[6] << (8 * 6);
319                 ret |= (uint64_t)imm[5] << (8 * 5);
320                 ret |= (uint64_t)imm[4] << (8 * 4);
321                 /* fall-through */
322         case 4:
323                 ret |= (uint64_t)imm[3] << (8 * 3);
324                 ret |= (uint64_t)imm[2] << (8 * 2);
325                 /* fall-through */
326         case 2:
327                 ret |= (uint64_t)imm[1] << (8 * 1);
328                 /* fall-through */
329         case 1:
330                 ret |= (uint64_t)imm[0] << (8 * 0);
331                 break;
332         default:
333                 panic("Bad IMM size %u", d->imm_sz);
334         }
335         return ret;
336 }
337
338 /* This is the three-bit (or more with REX) register used by opcodes that have
339  * /r.  The first argument for opcodes is in the modrm part, e.g. [eax]+disp8.
340  * We don't need to parse that, since we know the faulting GPA. */
341 static uint8_t modrm_get_reg(uint8_t *insn, struct x86_decode *d)
342 {
343         uint8_t *modrm = get_modrm(insn, d);
344         uint8_t reg;
345
346         if (!modrm) {
347                 fprintf(stderr, "%s called with no modrm!\n, insn: %p\n",
348                         __func__, insn);
349                 hexdump(stderr, insn, 15);
350                 panic("Continuing could corrupt registers");
351         }
352         reg = (*modrm >> 3) & 7;
353
354         switch (d->address_bytes) {
355         case 2:
356                 fprintf(stderr, "decode: %s had %u address bytes!\n", __func__,
357                         d->address_bytes);
358                 return modrm_get_reg_16(reg, d);
359         case 4:
360         case 8:
361                 return modrm_get_reg_32(reg, d);
362         default:
363                 panic("decode: %s had %u address bytes!\n", __func__,
364                         d->address_bytes);
365         }
366 }
367
368 /* Decodes the actual opcode, storing things we care about in d.
369  * -1 on error (for opcodes we haven't coded up), 0 success.
370  *
371  * Sets operand_bytes, various sizes, is_store, etc. */
372 static int decode_opcode(uint8_t *insn, struct x86_decode *d)
373 {
374         uint8_t *opcode = insn + d->prefix_sz;
375
376         /* If we don't set anything, we're using the defaults:  1 byte opcode,
377          * has_modrm, operand_bytes determined by the prefix/64-bit mode, etc */
378         switch (opcode[0]) {
379         case 0x80:
380                 switch (modrm_get_reg(insn, d)) {
381                 case 0: // add
382                 case 7: // cmp
383                         break;
384                 default:
385                         goto unknown;
386                 }
387                 d->imm_sz = 1;
388                 d->operand_bytes = 1;
389                 break;
390         case 0x81:
391                 switch (modrm_get_reg(insn, d)) {
392                 case 0: // add
393                 case 7: // cmp
394                         break;
395                 default:
396                         goto unknown;
397                 }
398                 d->imm_sz = d->address_bytes == 2 ? 2 : 4;
399                 break;
400         case 0x3a:      // cmp /r
401                 d->operand_bytes = 1;
402                 break;
403         case 0x88:      // mov
404         case 0x8a:      // mov
405                 d->operand_bytes = 1;
406                 /* Instructions that could be loads or stores differ in bit 2.
407                  * e.g.  88 (store, bit 2 unset) vs 8a (load, bit 2 set). */
408                 d->is_store = !(opcode[0] & 2);
409                 break;
410         case 0x89:      // mov
411         case 0x8b:      // mov
412                 d->is_store = !(opcode[0] & 2);
413                 break;
414         case 0x0f:
415                 d->opcode_sz = 2;
416                 switch (opcode[1]) {
417                 case 0xb7:      // movzw
418                         d->operand_bytes = 2;
419                         break;
420                 case 0xb6:      // movzb
421                         d->operand_bytes = 1;
422                         break;
423                 default:
424                         goto unknown;
425                 }
426                 break;
427         default:
428         unknown:
429                 fprintf(stderr, "unknown decode %02x %02x %02x@ %p\n",
430                         opcode[0], opcode[1], opcode[2], opcode);
431                 return -1;
432         }
433
434         d->modrm_sib_sz = modrm_sib_bytes(insn, d);
435         return 0;
436 }
437
438 static void set_rflags_status_bits(uint64_t *rfl, uint64_t new)
439 {
440         *rfl &= ~FL_STATUS;
441         new &= FL_STATUS;
442         *rfl |= new;
443 }
444
445 static int add_8081(struct guest_thread *gth, uint8_t *insn,
446                     struct x86_decode *d, emu_mem_access access,
447                     uint64_t gpa)
448 {
449         struct vm_trapframe *vm_tf = gth_to_vmtf(gth);
450         int ret;
451         uint64_t scratch = 0;
452         int8_t imm8, scr8;
453         int16_t imm16, scr16;
454         int32_t imm32, scr32;
455         int64_t imm64, scr64;
456         unsigned long rflags;
457
458         ret = access(gth, gpa, &scratch, d->operand_bytes, false);
459         if (ret < 0)
460                 return ret;
461         switch (d->operand_bytes) {
462         case 1:
463                 imm8 = get_imm(insn, d);
464                 /* scratch is input and output, but you can't cast it in an
465                  * output operand */
466                 scr8 = scratch;
467                 asm volatile ("addb %2,%1; pushfq; popq %0"
468                               : "=r"(rflags),
469                                 "+r"(scr8)
470                               : "r"(imm8)
471                               : "cc");
472                 scratch = scr8;
473                 break;
474         case 2:
475                 imm16 = get_imm(insn, d);
476                 scr16 = scratch;
477                 asm volatile ("addw %2,%1; pushfq; popq %0"
478                               : "=r"(rflags),
479                                 "+r"(scr16)
480                               : "r"(imm16)
481                               : "cc");
482                 scratch = scr16;
483                 break;
484         case 4:
485                 imm32 = get_imm(insn, d);
486                 scr32 = scratch;
487                 asm volatile ("addl %2,%1; pushfq; popq %0"
488                               : "=r"(rflags),
489                                 "+r"(scr32)
490                               : "r"(imm32)
491                               : "cc");
492                 scratch = scr32;
493                 break;
494         case 8:
495                 imm32 = get_imm(insn, d);
496                 scr64 = scratch;
497                 asm volatile ("addq %2,%1; pushfq; popq %0"
498                               : "=r"(rflags),
499                                 "+r"(scr64)
500                               : "r"((int64_t)imm32)
501                               : "cc");
502                 scratch = scr64;
503                 break;
504         }
505         set_rflags_status_bits(&vm_tf->tf_rflags, rflags);
506         return access(gth, gpa, &scratch, d->operand_bytes, true);
507 }
508
509 static int cmp_8081(struct guest_thread *gth, uint8_t *insn,
510                     struct x86_decode *d, emu_mem_access access,
511                     uint64_t gpa)
512 {
513         struct vm_trapframe *vm_tf = gth_to_vmtf(gth);
514         int ret;
515         uint64_t scratch = 0;
516         int8_t imm8;
517         int16_t imm16;
518         int32_t imm32;
519         int64_t imm64;
520         unsigned long rflags;
521
522         ret = access(gth, gpa, &scratch, d->operand_bytes, false);
523         if (ret < 0)
524                 return ret;
525         switch (d->operand_bytes) {
526         case 1:
527                 imm8 = get_imm(insn, d);
528                 asm volatile ("cmpb %2,%1; pushfq; popq %0"
529                               : "=r"(rflags)
530                               : "r"((int8_t)scratch),
531                                 "r"(imm8)
532                               : "cc");
533                 break;
534         case 2:
535                 imm16 = get_imm(insn, d);
536                 asm volatile ("cmpw %2,%1; pushfq; popq %0"
537                               : "=r"(rflags)
538                               : "r"((int16_t)scratch),
539                                 "r"(imm16)
540                               : "cc");
541                 break;
542         case 4:
543                 imm32 = get_imm(insn, d);
544                 asm volatile ("cmpl %2,%1; pushfq; popq %0"
545                               : "=r"(rflags)
546                               : "r"((int32_t)scratch),
547                                 "r"(imm32)
548                               : "cc");
549                 break;
550         case 8:
551                 imm32 = get_imm(insn, d);
552                 asm volatile ("cmpq %2,%1; pushfq; popq %0"
553                               : "=r"(rflags)
554                               : "r"((int64_t)scratch),
555                                 "r"((int64_t)imm32)
556                               : "cc");
557                 break;
558         }
559         set_rflags_status_bits(&vm_tf->tf_rflags, rflags);
560         return 0;
561 }
562
563 static int cmp_3a(struct guest_thread *gth, uint8_t *insn,
564                   struct x86_decode *d, emu_mem_access access,
565                   uint64_t gpa)
566 {
567         struct vm_trapframe *vm_tf = gth_to_vmtf(gth);
568         int ret;
569         uint64_t scratch = 0;
570         int8_t reg8;
571         unsigned long rflags;
572         int mod_reg = modrm_get_reg(insn, d);
573
574         assert(d->operand_bytes == 1);
575         ret = access(gth, gpa, &scratch, 1, false);
576         if (ret < 0)
577                 return ret;
578         reg8 = (int8_t)*reg_to_vmtf_reg(vm_tf, mod_reg);
579         asm volatile ("cmpb %2,%1; pushfq; popq %0"
580                       : "=r"(rflags)
581                       : "r"(reg8),
582                         "r"((int8_t)scratch)
583                       : "cc");
584         set_rflags_status_bits(&vm_tf->tf_rflags, rflags);
585         return 0;
586 }
587
588 static int execute_op(struct guest_thread *gth, uint8_t *insn,
589                       struct x86_decode *d, emu_mem_access access,
590                       uint64_t gpa)
591 {
592         struct vm_trapframe *vm_tf = gth_to_vmtf(gth);
593         uint8_t *opcode = insn + d->prefix_sz;
594         int ret, mod_reg;
595
596         switch (opcode[0]) {
597         case 0x80:
598         case 0x81:
599                 switch (modrm_get_reg(insn, d)) {
600                 case 0: // add
601                         return add_8081(gth, insn, d, access, gpa);
602                 case 7: // cmp
603                         return cmp_8081(gth, insn, d, access, gpa);
604                 }
605                 goto unknown;
606         case 0x3a:      // cmp
607                 return cmp_3a(gth, insn, d, access, gpa);
608         case 0x89:      // mov
609         case 0x8b:      // mov
610         case 0x8a:      // mov
611         case 0x88:      // mov
612                 mod_reg = modrm_get_reg(insn, d);
613                 ret = access(gth, gpa, reg_to_vmtf_reg(vm_tf, mod_reg),
614                              d->operand_bytes, d->is_store);
615                 /* We set a register's value.  For 32-bit operands, we need to
616                  * zero the upper 32 bits. */
617                 if (!ret && !d->is_store && d->operand_bytes == 4)
618                         *reg_to_vmtf_reg(vm_tf, mod_reg) &= 0xffffffff;
619                 return ret;
620         case 0x0f:
621                 switch (opcode[1]) {
622                 case 0xb7:      // movzw
623                 case 0xb6:      // movzb
624                         mod_reg = modrm_get_reg(insn, d);
625                         *reg_to_vmtf_reg(vm_tf, mod_reg) = 0;
626                         return access(gth, gpa, reg_to_vmtf_reg(vm_tf, mod_reg),
627                                       d->operand_bytes, d->is_store);
628                 }
629                 goto unknown;
630         default:
631         unknown:
632                 fprintf(stderr, "unknown execute %02x %02x %02x@ %p\n",
633                         opcode[0], opcode[1], opcode[2], opcode);
634                 return -1;
635         }
636 }
637
638 static int decode_inst_size(uint8_t *insn, struct x86_decode *d)
639 {
640         return d->prefix_sz + d->opcode_sz + d->modrm_sib_sz +
641                + d->imm_sz;
642 }
643
644 /* Emulates a memory operation that faulted/vmexited.  Despite the file name,
645  * this is x86-specific, so we only have at most one address involved.  We have
646  * at least one address involved, since it is a memory operation.
647  *
648  * The main thing our caller provides is a function pointer for accessing
649  * memory.  The address is gpa, the register (which doesn't have to be a real
650  * register in a VMTF) involved for the source/destination (based on 'store').
651  */
652 int emulate_mem_insn(struct guest_thread *gth, uint8_t *insn,
653                      emu_mem_access access, int *advance)
654 {
655         struct x86_decode d[1] = {X86_DECODE_64_DEFAULT};
656         uintptr_t gpa;
657
658         // Duh, which way did he go George? Which way did he go?
659         // First hit on Google gets you there!
660         // This is the guest physical address of the access.
661         // This is nice, because if we ever go with more complete
662         // instruction decode, knowing this gpa reduces our work:
663         // we don't have to find the source address in registers,
664         // only the register holding or receiving the value.
665         gpa = gth_to_vmtf(gth)->tf_guest_pa;
666         if (decode_prefix(insn, d) < 0)
667                 return -1;
668         if (decode_opcode(insn, d) < 0)
669                 return -1;
670         if (execute_op(gth, insn, d, access, gpa) < 0)
671                 return -1;
672         *advance = decode_inst_size(insn, d);
673
674         if (debug_decode) {
675                 /* This is racy - multiple decoded threads on different cores
676                  * will clutter the output. */
677                 fprintf(stderr, "gpa %p", gpa);
678                 print_decoded_insn(insn, d);
679         }
680         return 0;
681 }
682
683 /* Debugging */
684
685 static void print_decoded_insn(uint8_t *insn, struct x86_decode *d)
686 {
687         uint8_t inst_sz = decode_inst_size(insn, d);
688
689         fprintf(stderr,
690                 "oprnd_bs %d, addr_bs %d, reg %2d, imm 0x%08llx, inst_size %2d:",
691                 d->operand_bytes, d->address_bytes,
692                 get_modrm(insn, d) ? modrm_get_reg(insn, d) : -1,
693                 d->imm_sz ? get_imm(insn, d) : 0xdeadbeef, inst_sz);
694         for (int i = 0; i < inst_sz; i++)
695                 fprintf(stderr, " %02x", insn[i]);
696         fprintf(stderr, "\n");
697 }
698
699 static int tst_mem_access(struct guest_thread *gth, uintptr_t gpa,
700                           unsigned long *regp, size_t size, bool store)
701 {
702         if (store) {
703                 switch (size) {
704                 case 1:
705                         *(uint8_t*)gpa = *(uint8_t*)regp;
706                         break;
707                 case 2:
708                         *(uint16_t*)gpa = *(uint16_t*)regp;
709                         break;
710                 case 4:
711                         *(uint32_t*)gpa = *(uint32_t*)regp;
712                         break;
713                 case 8:
714                         *(uint64_t*)gpa = *(uint64_t*)regp;
715                         break;
716                 }
717         } else {
718                 switch (size) {
719                 case 1:
720                         *(uint8_t*)regp = *(uint8_t*)gpa;
721                         break;
722                 case 2:
723                         *(uint16_t*)regp = *(uint16_t*)gpa;
724                         break;
725                 case 4:
726                         *(uint32_t*)regp = *(uint32_t*)gpa;
727                         break;
728                 case 8:
729                         *(uint64_t*)regp = *(uint64_t*)gpa;
730                         break;
731                 }
732         }
733         return 0;
734 }
735
736 /* Far from exhaustive, and you need to call it manually.  It actually caught a
737  * bug though. */
738 static void run_decode_hokey_tests(void)
739 {
740         struct guest_thread gth[1] = {0};
741         struct vm_trapframe *vm_tf = gth_to_vmtf(gth);
742         uint8_t insn[VMM_MAX_INSN_SZ];
743         uint8_t ram[16];
744         int inst_size, ret;
745
746         vm_tf->tf_guest_pa = (uint64_t)ram;
747
748         // movw [rax],ecx (rax ignored, we use the GPA)
749         memcpy(insn, "\x89\x08", 2);
750         memset(ram, 0, sizeof(ram));
751         vm_tf->tf_rcx = 0x1234;
752         ret = emulate_mem_insn(gth, insn, tst_mem_access, &inst_size);
753         assert(!ret);
754         assert(inst_size = 2);
755         assert(*(uint16_t*)ram == 0x1234);
756
757         // add8 /0 [rbx], -1
758         memcpy(insn, "\x80\x03\xff", 3);
759         memset(ram, 0, sizeof(ram));
760         ram[0] = 1;
761         ret = emulate_mem_insn(gth, insn, tst_mem_access, &inst_size);
762         assert(!ret);
763         assert(inst_size == 3);
764         assert(ram[0] == 0);
765         assert(vm_tf->tf_rflags & FL_ZF);
766         assert(!(vm_tf->tf_rflags & FL_SF));
767
768         // REX.W add /0, r/m64/imm32: 84: SIB+disp32 /0. (-1 sign extend)
769         memcpy(insn, "\x48\x81\x84\x00\x00\x00\x00\x00\xff\xff\xff\xff", 12);
770         memset(ram, 0, sizeof(ram));
771         ram[0] = 2;
772         ret = emulate_mem_insn(gth, insn, tst_mem_access, &inst_size);
773         assert(!ret);
774         assert(inst_size == 12);
775         assert(*(uint64_t*)ram == 1);
776         assert(!(vm_tf->tf_rflags & FL_ZF));
777         assert(!(vm_tf->tf_rflags & FL_SF));
778
779         // REX.R movzw, 14: SIB, reg rdx -> r10
780         memcpy(insn, "\x44\x0f\xb7\x14\x00", 5);
781         memset(ram, 0, sizeof(ram));
782         ram[0] = 0x12;
783         vm_tf->tf_r10 = 0xffffffffffffffff;
784         ret = emulate_mem_insn(gth, insn, tst_mem_access, &inst_size);
785         assert(!ret);
786         assert(inst_size == 5);
787         assert(vm_tf->tf_r10 == 0x12);
788
789         fprintf(stderr, "Hokey decode tests passed\n");
790         return;
791
792         /* Helpful debuggers for the debugger */
793         fprintf(stderr, "ram %x %x %x %x %x %x %x %x\n",
794                 ram[0], ram[1], ram[2], ram[3], ram[4], ram[5], ram[6], ram[7]);
795 }