]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/plr/server/src/emulation.cc
update
[l4.git] / l4 / pkg / plr / server / src / emulation.cc
1 /*
2  * emulation.cc --
3  *
4  *     Implementation of the write instruction emulator.
5  *
6  * (c) 2011-2013 Björn Döbel <doebel@os.inf.tu-dresden.de>,
7  *     economic rights: Technische Universität Dresden (Germany)
8  * This file is part of TUD:OS and distributed under the terms of the
9  * GNU General Public License 2.
10  * Please see the COPYING-GPL-2 file for details.
11  */
12
13 #include "log"
14 #include "exceptions"
15 #include "memory"
16 #include "emulation"
17
18 #include <string.h>
19 #include <l4/sys/kdebug.h>
20
21 #define MSG() DEBUGf(Romain::Log::Emulator)
22
23 /*
24  * Debugging: get human-readable operand type
25  */
26 static char const *operand_type_string(ud_operand_t *op)
27 {
28         switch (op->type) {
29                 case UD_OP_REG: return "register";
30                 case UD_OP_MEM: return "memory";
31                 case UD_OP_PTR: return "pointer";
32                 case UD_OP_IMM: return "immediate";
33                 case UD_OP_JIMM: return "immediate jmp target";
34                 case UD_OP_CONST: return "constant";
35                 default: return "invalid";
36         }
37 }
38
39
40 void Romain::Emulator_base::init_ud()
41 {
42         ud_init(&_ud);
43         ud_set_mode(&_ud, 32);
44         ud_set_syntax(&_ud, UD_SYN_INTEL);
45
46         ud_set_pc(&_ud, ip());
47         ud_set_input_buffer(&_ud, (l4_uint8_t*)_local_ip, 32);
48
49         l4_mword_t num_bytes = ud_disassemble(&_ud);
50         (void)num_bytes;
51 #if 0
52         MSG() << "print_instruction "
53                                   << num_bytes << " byte"
54                                   << (num_bytes > 1 ? "s" : "") << ".";
55 #endif
56 }
57
58 /*
59  * Romain::Emulator constructor
60  *
61  * Nothing fancy -- use of udis86 should be hidden behind another
62  * property. XXX
63  */
64 Romain::Emulator_base::Emulator_base(L4vcpu::Vcpu *vcpu,
65                                      Romain::AddressTranslator const *trans)
66         : _vcpu(vcpu), _translator(trans)
67 {
68         _local_ip = _translator->translate(ip());
69         //init_ud();
70 }
71
72
73 /*
74  * Get register value from VCPU
75  *
76  * Returns an MWord even if the real operand is only 16 or 8 bit.
77  */
78 l4_umword_t Romain::Emulator_base::register_to_value(ud_type op)
79 {
80         l4_umword_t  val = ~0;
81
82 #define REG(udis_name, vcpu_name, target, ...) \
83         case UD_R_##udis_name: target = _vcpu->r()->vcpu_name __VA_ARGS__; break
84
85         switch(op) {
86                 REG(AL, ax, val, & 0xFF); REG(CL, cx, val, & 0xFF); REG(DL, dx, val, & 0xFF);
87                 REG(BL, bx, val, & 0xFF); REG(SPL, sp, val, & 0xFF); REG(BPL, bp, val, & 0xFF);
88                 REG(SIL, si, val, & 0xFF); REG(DIL, di, val, & 0xFF);
89                 
90 #if 0
91                 REG(AH, ax, val, & 0xFF00); REG(CH, cx, val, & 0xFF00); REG(DH, dx, val, & 0xFF00);
92                 REG(BH, bx, val, & 0xFF00);
93 #endif
94
95                 REG(AX, ax, val, & 0xFFFF); REG(CX, cx, val, & 0xFFFF); REG(DX, dx, val, & 0xFFFF);
96                 REG(BX, bx, val, & 0xFFFF); REG(SP, sp, val, & 0xFFFF); REG(BP, bp, val, & 0xFFFF);
97                 REG(SI, si, val, & 0xFFFF); REG(DI, di, val, & 0xFFFF);
98
99                 REG(EAX, ax, val); REG(ECX, cx, val); REG(EDX, dx, val);
100                 REG(EBX, bx, val); REG(ESP, sp, val); REG(EBP, bp, val);
101                 REG(ESI, si, val); REG(EDI, di, val);
102
103                 default: 
104                         MSG() << "target register: " << std::hex << op;
105                         enter_kdebug("unhandled register target");
106                         break;
107         }
108 #undef REG
109         return val;
110 }
111
112
113 void Romain::Emulator_base::value_to_register(l4_umword_t val, ud_type op)
114 {
115 #define REG(udis_name, vcpu_name, ...) \
116         case UD_R_##udis_name: _vcpu->r()->vcpu_name = val __VA_ARGS__; break;
117
118         switch(op) {
119                 REG(AL, ax, & 0xFF); REG(CL, cx, & 0xFF); REG(DL, dx, & 0xFF);
120                 REG(BL, bx, & 0xFF); REG(SPL, sp, & 0xFF); REG(BPL, bp, & 0xFF);
121                 REG(SIL, si, & 0xFF); REG(DIL, di, & 0xFF);
122
123                 REG(AX, ax, & 0xFFFF); REG(CX, cx, & 0xFFFF); REG(DX, dx, & 0xFFFF);
124                 REG(BX, bx, & 0xFFFF); REG(SP, sp, & 0xFFFF); REG(BP, bp, & 0xFFFF);
125                 REG(SI, si, & 0xFFFF); REG(DI, di, & 0xFFFF);
126
127                 REG(EAX, ax); REG(ECX, cx); REG(EDX, dx);
128                 REG(EBX, bx); REG(ESP, sp); REG(EBP, bp);
129                 REG(ESI, si); REG(EDI, di);
130                 
131                 default:
132                         MSG() << "target register: " << std::hex << op;
133                         enter_kdebug("unhandled register target");
134                         break;
135         }
136
137 #undef REG
138 }
139
140
141 /*
142  * Calculate the value for an operand
143  *
144  * Note, this always returns an MWord. Users need to check op->size
145  * to determine what to do with the value.
146  */
147 l4_umword_t Romain::Emulator_base::operand_to_value(ud_operand_t *op)
148 {
149         bool valid = false;
150         l4_umword_t val = ~0;
151
152         switch(op->type) {
153                 // Operand is a register. The specific register is contained in
154                 // base in the form of an enumerated constant, enum ud_type.
155                 case UD_OP_REG:
156                         {
157                                 char buf[80];
158                                 snprintf(buf, 80, "reg b %02x idx %02x scale %02x offs %02x",
159                                          op->base, op->index, op->scale, op->offset);
160                                 MSG() << buf;
161
162                                 // addr: = base + index * scale + offset
163
164                                 _check(op->scale != 0, "!! implement register scaling");
165                                 _check(op->offset != 0, "!! implement register offset");
166
167                                 l4_umword_t idx = op->index ? register_to_value(op->index) : 0;
168                                 l4_umword_t bas = op->base ? register_to_value(op->base) : 0;
169
170                                 val = bas + idx * op->scale;
171                                 if (op->offset)
172                                         val += op->lval.sdword;
173
174                                 MSG() << "val = " << std::hex << val;
175
176                                 valid = true;
177                         }
178                         break;
179
180                 // Immediate operand. Value available in lval.
181                 case UD_OP_IMM:
182                         {
183                                 MSG() << "op sz " << (int)op->size
184                                         << "op val " << std::hex << op->lval.uqword;
185                                 val = op->lval.udword;
186
187                                 switch (op->size) {
188                                         case 8: val &= 0xFF; break;
189                                         case 16: val &= 0xFFFF; break;
190                                         default: MSG() << "strange op size: " << op->size;
191                                         case 32: break;
192                                 }
193
194                                 valid = true;
195                         }
196                         break;
197
198                 // Memory operand. The intermediate form normalizes all memory
199                 // address equations to the scale-index-base form. The address
200                 // equation is availabe in base, index, and scale. If the offset
201                 // field has a non-zero value (one of 8, 16, 32, and 64), lval
202                 // will contain the memory offset. Note that base and index fields
203                 // contain the base and index register of the address equation,
204                 // in the form of an enumerated constant enum ud_type. scale
205                 // contains an integer value that the index register must be
206                 // scaled by.
207                 case UD_OP_MEM:
208                         {
209                                 char buf[80];
210                                 long long offset = 0;
211                                 snprintf(buf, 80, "mem b %02x idx %02x scale %02x offs %02x",
212                                          op->base, op->index, op->scale, op->offset);
213
214                                 MSG() << buf;
215
216                                 _check(op->scale != 0, "!! implement register scaling");
217
218                                 l4_umword_t addr = register_to_value(op->base);
219                                 MSG() << "    reg " << std::hex << addr;
220
221                                 switch(op->offset) {
222                                         case 0:  offset = 0; break;
223                                         case 8:  offset = op->lval.sbyte; break;
224                                         case 16: offset = op->lval.sword; break;
225                                         case 32: offset = op->lval.sdword; break;
226                                         case 64: offset = op->lval.sqword; enter_kdebug("64bit offset"); break;
227                                         default: enter_kdebug("unknown offset??");
228                                 }
229
230                                 MSG() << std::hex << addr << " + " << offset << " = " << addr + offset;
231                                 addr += offset;
232
233                                 // reading a full mword here is okay, because users of the
234                                 // results returned from this function need to check the real
235                                 // operand size anyway
236                                 val = *(l4_umword_t*)_translator->translate(addr);
237
238                                 MSG() << std::hex << addr << " := " << val;
239
240                                 valid = true;
241                         }
242
243                         break;
244                 default:
245                         MSG() << "Need to handle " << operand_type_string(op);
246                         enter_kdebug("unhandled src operand type");
247                         break;
248         }
249
250         MSG() << std::hex << "v " << val
251                 << (valid ? " (ok)" : " \033[31;1m(INV!)\033[0m")
252                 << " ilen " << ilen();
253
254         if (!valid)
255                 enter_kdebug("unhandled operand type");
256         return val;
257 }
258
259
260 /*
261  * Extract the offset encoded in an operand.
262  *
263  * This incorporates looking at the operand's size to figure out
264  * the right masking. Plus, the result is _SIGNED_!
265  */
266 l4_mword_t Romain::Emulator_base::offset_from_operand(ud_operand_t *op)
267 {
268         uint8_t offs    = op->offset;
269         long long value = 0;
270         bool neg        = false;
271         
272         if (!offs) return op->lval.sword;
273
274         /*
275          * Mask only the lower N bits
276          */
277         value = op->lval.sdword & ((1LL << offs) - 1);
278         neg   = value & (1LL << (offs-1));
279         if (neg) {
280                 value = -((1LL << offs) - value);
281         }
282
283         // XXX: so far, we don't support 64bit offsets...
284         return (int)value;
285 }
286
287
288 /*
289  * Given a value, write it to whatever target is described by the
290  * operand.
291  *
292  * So far, only memory targets are needed as we don't get to see writes to
293  * other stuff, such as registers.
294  */
295 void Romain::Emulator_base::value_to_operand(l4_umword_t val, ud_operand_t *op)
296 {
297         switch(op->type) {
298                 // Memory operand. The intermediate form normalizes all memory
299                 // address equations to the scale-index-base form. The address
300                 // equation is availabe in base, index, and scale. If the offset
301                 // field has a non-zero value (one of 8, 16, 32, and 64), lval
302                 // will contain the memory offset. Note that base and index fields
303                 // contain the base and index register of the address equation,
304                 // in the form of an enumerated constant enum ud_type. scale
305                 // contains an integer value that the index register must be
306                 // scaled by.
307                 //
308                 // addr: = base + index * scale + offset
309                 case UD_OP_MEM:
310                         {
311                                 char buf[80];
312                                 snprintf(buf, 80, "b %02x idx %02x scale %02x offs %02x",
313                                          op->base, op->index, op->scale, op->offset);
314                                 MSG() << buf;
315
316                                 // no base reg, 32 bit size -> this is an address
317                                 if (!op->base && op->offset) {
318                                         l4_addr_t target = _translator->translate(op->lval.sdword);
319                                         MSG() << std::hex
320                                                 << "writing to address: (r " << op->lval.sdword
321                                                 << " l " << target << ") := " << val;
322                                         *(l4_umword_t*)target = val;
323                                 }
324                                 else if (op->base) { // else there must be at least a base addr
325                                         l4_umword_t b_addr = register_to_value(op->base);
326                                         MSG() << "BASE: " << std::hex << b_addr;
327                                         l4_umword_t i_addr = op->index ? register_to_value(op->index) : 0;
328                                         l4_umword_t scale  = op->scale;
329
330                                         MSG() << std::hex << b_addr << " + (" << i_addr << " << " << scale << ") + "
331                                                 << op->lval.sword << " = " << b_addr + (i_addr << scale) + offset_from_operand(op);
332                                         b_addr = b_addr + (i_addr << scale) + offset_from_operand(op);
333
334                                         l4_addr_t target = _translator->translate(b_addr);
335                                         MSG() << "target: " << std::hex << target;
336                                         // XXX: error check
337                                         MSG() << std::hex
338                                                 << "writing to address: (r " << b_addr
339                                                 << " l " << target << ") := " << val;
340                                         write_target(target, val, op->size);
341                                 }
342                                 else {
343                                         MSG() << "strange mem encoding??";
344                                         enter_kdebug("!");
345                                 }
346                         }
347                         break;
348                 default:
349                         MSG() << "Need to handle " << operand_type_string(op);
350                         enter_kdebug("unhandled target operand");
351                         break;
352         }
353 }
354
355
356 /*
357  * Handle PUSH instruction
358  */
359 void Romain::WriteEmulator::handle_push()
360 {
361         l4_umword_t val = ~0;
362         ud_operand_t *op = &_ud.operand[0];
363
364         val = operand_to_value(op);
365
366         Romain::Stack(_translator->translate(_vcpu->r()->sp)).push(val);
367
368         _vcpu->r()->sp -= sizeof(l4_umword_t);
369         _vcpu->r()->ip += ilen();
370 }
371
372
373 /*
374  * Emulate a CALL instruction
375  */
376 void Romain::WriteEmulator::handle_call()
377 {
378         // push return address
379         _vcpu->r()->ip += ilen();
380         Romain::Stack(_translator->translate(_vcpu->r()->sp)).push(ip());
381
382         // adapt EIP
383         ud_operand_t *op = &_ud.operand[0];
384
385         // XXX: check later, if this can be moved into operand_to_value(), too
386         switch(op->type) {
387                 case UD_OP_JIMM:
388                         _check(op->size != 32, "!! immediate jmp offset not an mword");
389                         MSG() << std::hex << op->lval.sdword
390                               << " " << _vcpu->r()->ip + op->lval.sdword;
391                         _vcpu->r()->ip += op->lval.sdword;
392                         break;
393
394                 case UD_OP_MEM: // fallthrough
395                 case UD_OP_REG:
396                         {
397                                 l4_umword_t v = operand_to_value(op);
398                                 MSG() << std::hex << v;
399                                 _vcpu->r()->ip = v;
400                         }
401                         break;
402
403                 default:
404                         MSG() << "Unhandled: " << operand_type_string(op);
405                         enter_kdebug("unhandled target");
406                         break;
407         }
408
409         /* We must not touch the SP _before_ looking at the immediate value,
410          * because otherwise offset calculations might be wrong.
411          */
412         _vcpu->r()->sp -= sizeof(l4_umword_t);
413 }
414
415
416 /*
417  * Handle MOV instruction
418  */
419 void Romain::WriteEmulator::handle_mov()
420 {
421         ud_operand_t *op1 = &_ud.operand[0];
422         ud_operand_t *op2 = &_ud.operand[1];
423
424         l4_umword_t val = operand_to_value(op2);
425         value_to_operand(val, op1);
426
427         _vcpu->r()->ip += ilen();
428 }
429
430
431 /*
432  * Handle (REP:)STOS instruction
433  */
434 void Romain::WriteEmulator::handle_stos()
435 {
436         _check(_ud.mnemonic != UD_Istosd, "non-word string copy");
437
438         l4_umword_t count = _ud.pfx_rep != UD_NONE ? _vcpu->r()->cx : 1;
439
440         MSG() << std::hex << "rep = 0x" << (int)_ud.pfx_rep;
441         MSG() << "iterations: " << count;
442
443         l4_addr_t base = _vcpu->r()->di;
444         base = _translator->translate(base);
445
446         for (l4_umword_t idx = 0; idx < count; ++idx) {
447                 *(l4_umword_t*)base = _vcpu->r()->ax;
448
449                 // XXX: Handle
450                 // 1) other stos-sizes than 4
451                 // 2) direction flag
452                 base += 4;
453         }
454
455         if (_ud.pfx_rep != UD_NONE) // we're done rep'ing
456                 _vcpu->r()->cx = 0;
457
458         _vcpu->r()->di += count * sizeof(l4_umword_t);
459
460         _vcpu->r()->ip += ilen();
461 }
462
463
464 /*
465  * Handle MOVSD instruction
466  */
467 void Romain::WriteEmulator::handle_movsd()
468 {
469         _check(_ud.mnemonic != UD_Imovsd, "non-word memcopy");
470
471         l4_umword_t count = _ud.pfx_rep != UD_NONE ? _vcpu->r()->cx : 1;
472         MSG() << std::hex << "rep = 0x" << (int)_ud.pfx_rep;
473         MSG() << "iterations: " << count;
474
475         l4_addr_t src = _translator->translate(_vcpu->r()->si);
476         l4_addr_t dst = _translator->translate(_vcpu->r()->di);
477
478         for (l4_umword_t idx = 0; idx < count; ++idx) {
479                 *(l4_umword_t*)dst = *(l4_umword_t*)src;
480                 dst += 4;
481                 src += 4;
482         }
483
484         if (_ud.pfx_rep != UD_NONE) // we're done rep'ing
485                 _vcpu->r()->cx = 0;
486         _vcpu->r()->si += count * sizeof(l4_umword_t);
487         _vcpu->r()->di += count * sizeof(l4_umword_t);
488
489         _vcpu->r()->ip += ilen();
490 }
491
492
493 /*
494  * Handle MOVSB instruction
495  */
496 void Romain::WriteEmulator::handle_movsb()
497 {
498         _check(_ud.mnemonic != UD_Imovsb, "non-byte memcopy");
499
500         l4_umword_t count = _ud.pfx_rep != UD_NONE ? _vcpu->r()->cx : 1;
501         MSG() << std::hex << "rep = 0x" << (int)_ud.pfx_rep;
502         MSG() << "iterations: " << count;
503
504         l4_addr_t src = _translator->translate(_vcpu->r()->si);
505         l4_addr_t dst = _translator->translate(_vcpu->r()->di);
506
507         for (l4_umword_t idx = 0; idx < count; ++idx) {
508                 *(l4_uint8_t*)dst = *(l4_uint8_t*)src;
509                 dst++;
510                 src++;
511         }
512
513         if (_ud.pfx_rep != UD_NONE) // we're done rep'ing
514                 _vcpu->r()->cx = 0;
515         _vcpu->r()->si += count * sizeof(l4_uint8_t);
516         _vcpu->r()->di += count * sizeof(l4_uint8_t);
517
518         _vcpu->r()->ip += ilen();
519 }
520
521
522 /*
523  * Handle arithmetic instructions
524  *
525  * Arithmetics modify EFLAGS, too...
526  */
527 void Romain::WriteEmulator::handle_arithmetics(ArithmeticOperations op)
528 {
529         static char const *opstr[] = {"+", "-", "*", "/", "%", "--"};
530
531         ud_operand_t *op1  = &_ud.operand[0];
532         ud_operand_t *op2  = NULL; //  = &_ud.operand[1];
533         l4_umword_t orig   = operand_to_value(op1);
534         l4_umword_t arval  = 0; // operand_to_value(op2);
535         l4_umword_t flags  = 0;
536
537         switch(op) {
538                 case ADD:
539                 case SUB:
540                 case MULT:
541                 case DIV:
542                 case MOD:
543                         op2   = &_ud.operand[1];
544                         arval = operand_to_value(op2);
545                         break;
546                 case DEC:
547                         arval = 1;
548                         op = SUB;
549         }
550
551         MSG() << "value: " << std::hex << orig
552                                   << opstr[op] << arval << " = ";
553
554         switch (op) {
555                 case ADD:  orig += arval; break;
556                 case SUB:  orig -= arval; break;
557                 case MULT: orig *= arval; break;
558                 case DIV:  orig /= arval; break;
559                 case MOD:  orig %= arval; break;
560                 default: enter_kdebug("unknown arith op"); break;
561         }
562
563         /*
564          * Now obtain the flags and insert them into the
565          * already set flags.
566          */
567         asm volatile ("pushf\n\t"
568                       "pop %0"
569                       : "=r" (flags));
570         /* First, we plain copy the lowest 8 bits. */
571         _vcpu->r()->flags = (_vcpu->r()->flags & 0xFFFFFF00) | (flags & 0xFF);
572         /* The next three would be IF, TF, DF, which we don't want to touch.
573          * The remaining OF needs to be put in, though.
574          */
575         if (flags & OverflowFlag) {
576                 _vcpu->r()->flags |= OverflowFlag;
577         } else {
578                 _vcpu->r()->flags &= ~OverflowFlag;
579         }
580
581         MSG() << std::hex << "flags " << flags << " result " << orig;
582
583         value_to_operand(orig, op1);
584
585         _vcpu->r()->ip += ilen();
586         MSG() << std::hex << "vcpu.eflags = " << _vcpu->r()->flags;
587         //enter_kdebug("arith");
588 }
589
590 /*
591  * Emulation entry point
592  */
593 void Romain::WriteEmulator::emulate()
594 {
595         //print_instruction(); // debugging
596 #define HANDLE(val, fn) \
597         case val: fn(); break;
598 #define HANDLE_1(val, fn, arg) \
599         case val: fn(arg); break;
600
601         switch(_ud.mnemonic) {
602                 HANDLE(UD_Icall,  handle_call);
603                 HANDLE(UD_Imov,   handle_mov);
604                 HANDLE(UD_Ipush,  handle_push);
605                 HANDLE(UD_Istosd, handle_stos);
606                 HANDLE(UD_Imovsd, handle_movsd);
607                 HANDLE(UD_Imovsb, handle_movsb); // XXX merge with movsd
608                 HANDLE_1(UD_Isub, handle_arithmetics, SUB);
609                 HANDLE_1(UD_Idec, handle_arithmetics, DEC);
610                 default:
611                         MSG() << _ud.mnemonic;
612                         enter_kdebug("unhandled mnemonic");
613                         break;
614         }
615 #undef HANDLE
616 #undef HANDLE_1
617 }
618
619
620 void Romain::Emulator_base::print_instruction()
621 {
622         INFO() << "INSTR(" << std::setw(16) << ud_insn_hex(&_ud) << ") "
623                << std::setw(20) << ud_insn_asm(&_ud);
624 }
625
626 static unsigned long long rdtsc1()
627 {
628         unsigned long long ret = 0;
629         unsigned long hi, lo;
630         asm volatile ("cpuid\t\n"
631                                   "rdtsc\t\n"
632                                   "mov %%edx, %0\n\t"
633                                   "mov %%eax, %1\n\t"
634                                   : "=r"(hi), "=r"(lo)
635                                   :
636                                   : "eax", "ebx", "ecx", "edx");
637         ret = hi;
638         ret <<= 32;
639         ret |= lo;
640         return ret;
641 }
642
643
644 static unsigned long long rdtsc2()
645 {
646         unsigned long long ret = 0;
647         unsigned long hi, lo;
648         asm volatile ("rdtscp\n\t"
649                                   "mov %%edx, %0\n\t"
650                                   "mov %%eax, %1\n\t"
651                                   "cpuid\n\t"
652                                   : "=r"(hi), "=r"(lo)
653                                   :
654                                   : "eax", "ebx", "ecx", "edx");
655         ret = hi;
656         ret <<= 32;
657         ret |= lo;
658         //printf("%lx %lx %llx\n", hi, lo, ret);
659         return ret;
660 }
661
662
663 #if 1
664 static unsigned long long t = 0;
665 static unsigned count = 0;
666 #endif
667
668 #include "instruction_length.h"
669
670 void Romain::CopyAndExecute::emulate(Romain::AddressTranslator *at)
671 {
672         unsigned long long t1, t2;
673 #if 0
674         MSG() << "CopyAndExecute::emulate() called @ " << std::hex << _vcpu->r()->ip
675               << "\n   local IP @ " << _local_ip << "\n   ilen " << _ilen;
676 #endif
677
678         // XXX: need rewrite support for rep:movs, because this instruction would
679         //      potentially use a second address that is not a shared mem address
680         _local_ip = at->translate(_vcpu->r()->ip);
681         _ilen     = mlde32((void*)_local_ip);
682
683         //static char instbuf[32];
684         //memset(_instbuf, 0x90, 32); // NOP
685         t1 = rdtsc1();
686         for (unsigned inc = 0; inc <= _ilen; inc += 4) {
687                 *(unsigned*)(_instbuf + inc) = *(unsigned*)(_local_ip + inc);
688         }
689         t2 = rdtsc2();
690         //memcpy((void*)_instbuf, (void*)_local_ip, _ilen); // THE instruction
691         _instbuf[_ilen] = 0xC3; // RET
692
693         asm volatile(
694                                  "call *%5\n\t"
695                                  : "=a" (_vcpu->r()->ax),
696                                    "=c" (_vcpu->r()->cx),
697                                    "=d" (_vcpu->r()->dx),
698                                    "=S" (_vcpu->r()->si),
699                                    "=D" (_vcpu->r()->di)
700                                  : "r" (_instbuf), "a" (_vcpu->r()->ax),
701                                    "d" (_vcpu->r()->dx), "D" (_vcpu->r()->di),
702                                    "c" (_vcpu->r()->cx), "S" (_vcpu->r()->si)
703                                  : "cc", "memory"
704         );
705
706
707 #if 1
708         t += (t2-t1);
709
710         count++;
711
712         if (count >= 100000) {
713                 printf("DT: %lld %p %p\n", t / count, this, _instbuf);
714                 count = 0;
715                 t = 0;
716         }
717 #endif
718         _vcpu->r()->ip += _ilen;
719 }