]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/plr/server/src/fault_handlers/swifi.h
update
[l4.git] / l4 / pkg / plr / server / src / fault_handlers / swifi.h
1 #pragma once
2
3 /*
4  * swifi.h --
5  *
6  *     Fault observer for fault injection experiments
7  *
8  * (c) 2011-2013 Björn Döbel <doebel@os.inf.tu-dresden.de>,
9  *     economic rights: Technische Universität Dresden (Germany)
10  * This file is part of TUD:OS and distributed under the terms of the
11  * GNU General Public License 2.
12  * Please see the COPYING-GPL-2 file for details.
13  */
14
15 #include "../asmjit/Assembler.h"
16 #include "../asmjit/MemoryManager.h"
17 #include "observers.h"
18 #include "debugging.h"
19 #include "../emulation"
20 #include "../app_loading"
21
22 /***************************************************************************
23  * ASMJit instruction wrappers. Generate an ASMJit instruction using the   *
24  * input operands from a given UDIS86 disassembled instruction.            *
25  ***************************************************************************/
26
27
28 namespace Romain
29 {
30 /*
31  * SEU simulation base class
32  *
33  * The flips are based on a common model:
34  *   - place an INT3 on the instruction to target
35  *   - upon the debug interrupt, revert the breakpoint and prepare the injection
36  *     -> flip()
37  *   - single-step or continue until next INT3
38  *   - upon next INT1/INT3 perform post-exec operations
39  *     -> revert()
40  */
41 class Flipper : public Emulator_base
42 {
43         protected:
44                 l4_addr_t       _flip_eip; // stores the original EIP that was flipped
45                 Romain::App_model *_am;
46                 unsigned        _when;          // XXX
47                 unsigned        _hitcount;      // XXX
48                 unsigned        _interval;      // XXX
49                 bool            _repeat;        // XXX
50
51         public:
52                 Flipper(L4vcpu::Vcpu *vcpu,
53                 Romain::App_model *am,
54                 Romain::App_instance *inst)
55                 : Emulator_base(vcpu, new Romain::AppModelAddressTranslator(am, inst)),
56                       _flip_eip(vcpu->r()->ip), _am(am),
57                       _when(0), _hitcount(0), _interval(1), _repeat(false)
58                 {
59                         _vcpu       = vcpu;
60                         _local_ip   = _translator->translate(ip());
61                         print_instruction();
62                 }
63
64                 virtual ~Flipper()
65                 {
66                         delete _translator;
67                 }
68
69                 l4_addr_t prev_eip() { return _flip_eip; }
70                 l4_addr_t next_eip() { return _flip_eip + ilen(); }
71
72                 /*
73                  * Prepare flipped instruction
74                  *
75                  * Returns: true if we want to single-step afterwards, false if not.
76                  */
77                 virtual bool flip()   = 0;
78                 virtual void revert() = 0;
79 };
80
81
82 class AsmJitUser
83 {
84         public:
85         static AsmJit::GPReg ud_to_jit_reg(ud_type t)
86         {
87 #define MAP(x, y) case UD_R_##x: return AsmJit::y;
88                 switch(t) {
89                         MAP(EAX, eax); MAP(EBX, ebx); MAP(ECX, ecx); MAP(EDX, edx);
90                         MAP(ESI, esi); MAP(EDI, edi); MAP(ESP, esp);
91                         MAP(AX, ax); MAP(BX, bx); MAP(CX, cx); MAP(DX, dx);
92                         MAP(SI, si); MAP(DI, di); MAP(SP, sp);
93                         MAP(AH, ah); MAP(BH, bh); MAP(CH, ch); MAP(DH, dh);
94                         MAP(AL, al); MAP(BL, bl); MAP(CL, cl); MAP(DL, dl);
95                         default:
96                                 ERROR() << "I don't know a mapping for " << (unsigned)t << " yet.";
97                                 enter_kdebug("mapping");
98                                 break;
99                 }
100                 return AsmJit::no_reg;
101 #undef MAP
102         }
103
104         void disassemble_mem(l4_addr_t start, l4_addr_t remote, unsigned size)
105         {
106                 unsigned count = 0;
107                 while (count < size)
108                         count += Romain::InstructionPrinter(start + count, remote + count).ilen();
109         }
110
111         void flip_bit_in_register(AsmJit::Assembler& as, AsmJit::GPReg& reg)
112         {
113                 unsigned i = random() % 32;
114                 as.xor_(reg, (1 << i));
115         }
116
117         void commit_asm(AsmJit::Assembler& as, Romain::App_model *_am,
118                         L4vcpu::Vcpu *_vcpu)
119         {
120                 as.int3(); // last instruction is an INT3 which will trigger the replica
121                            // to return to the master
122                 void *ptr    = as.make();
123                 unsigned len = as.getOffset();
124                 MSG() << "Created asm code @ " << ptr << ", size is " << len << " bytes";
125                 _check(!ptr, "code generation failed");
126                 Romain::dump_mem(ptr, len);
127
128                 memcpy((void*)_am->trampoline_local(), ptr, len);
129                 _vcpu->r()->ip = _am->trampoline_remote();
130                 disassemble_mem(_am->trampoline_local(), _am->trampoline_remote(), len);
131
132                 AsmJit::MemoryManager::getGlobal()->free(ptr);
133         }
134 };
135
136 #define FUNC1(name, op) \
137         struct name { \
138                 void operator() (AsmJit::Assembler& as, AsmJit::GPReg& r) \
139                 { as.op(r); } };
140
141 FUNC1(Decrement, dec);
142 FUNC1(Increment, inc);
143 FUNC1(Negate, neg);
144
145 #define FUNC2(name, op) \
146         struct name { \
147                 void operator() (AsmJit::Assembler& as, AsmJit::GPReg& op1, \
148                                  AsmJit::GPReg& op2) { \
149                         as.op(op1, op2); } \
150                 void operator()  (AsmJit::Assembler& as, AsmJit::GPReg& op1, \
151                                                   unsigned imm) { \
152                         as.op(op1, imm); } }
153
154 FUNC2(Addition, add);
155 FUNC2(Subtraction, sub);
156 FUNC2(And, and_);
157 FUNC2(Or, or_);
158 FUNC2(Xor, xor_);
159 FUNC2(ShiftLeft, shl);
160 FUNC2(ShiftRight, shr);
161
162 template <typename FN>
163 void UnaryOperation(ud_t ud, AsmJit::Assembler& as)
164 {
165         _check(ud.operand[0].scale != 0, "scale?");
166         AsmJit::GPReg op = AsmJitUser::ud_to_jit_reg(ud.operand[0].base);
167         FN()(as, op);
168 }
169
170
171 template <typename FN>
172 void BinaryOperation(ud_t ud, AsmJit::Assembler& as)
173 {
174         AsmJit::GPReg op1, op2;
175         int imm = 0;
176         MSG() << "BinaryOp " << (unsigned)ud.operand[0].type
177                 << " " << (unsigned)ud.operand[1].type
178                 << " " << (unsigned)UD_OP_CONST;
179
180         _check(ud.operand[0].type != UD_OP_REG, "1st op must be reg");
181         _check(ud.operand[0].scale != 0, "scaling in reg??");
182         _check((ud.operand[1].type != UD_OP_REG) &&
183                (ud.operand[1].type != UD_OP_CONST) &&
184                (ud.operand[1].type != UD_OP_IMM), "2nd must be reg or immediate");
185
186         op1 =  AsmJitUser::ud_to_jit_reg(ud.operand[0].base);
187
188         if (ud.operand[1].type == UD_OP_REG) {
189                 _check(ud.operand[1].scale != 0, "scaling in reg??");
190                 op2 = AsmJitUser::ud_to_jit_reg(ud.operand[1].base);
191                 FN()(as, op1, op2);
192         } else if ((ud.operand[1].type == UD_OP_IMM) ||
193                    (ud.operand[1].type == UD_OP_CONST)) {
194                 MSG() << "op size " << (int)ud.operand[1].size;
195                 switch(ud.operand[1].size) {
196                         case  8: imm = ud.operand[1].lval.sbyte; break;
197                         case 16: imm = ud.operand[1].lval.sword; break;
198                         case 32: imm = ud.operand[1].lval.sdword; break;
199                         case 64: enter_kdebug("64bit!"); break;
200                 }
201                 // XXX: sign extension bug -> some of the opcodes
202                 //      have immediates that are sign extended...
203                 MSG() << "Immediate: " << std::hex << imm;
204                 FN()(as, op1, imm);
205         }
206         MSG() << "code...";
207 }
208
209
210 /*
211  * Emulate bit flips within general-purpose registers
212  */
213 class GPRFlipEmulator : public Flipper
214 {
215         /*
216          * The registers
217          */
218         enum targetRegs {
219                 ax, bx, cx, dx, flags,
220                 si, di, bp, ip, sp,
221                 MAX_REG,
222         };
223
224         char const* reg_to_str(targetRegs r)
225         {
226 #define CASE(reg) case reg: return #reg;
227                 switch(r) {
228                         CASE(ax); CASE(bx); CASE(cx); CASE(dx); CASE(flags);
229                         CASE(si); CASE(di); CASE(bp); CASE(ip); CASE(sp)
230                         CASE(MAX_REG);
231                 }
232                 return "???";
233 #undef CASE
234         };
235
236         targetRegs str_to_reg(char const *r)
237         {
238 #define CASE(reg) if (strcmp(r, #reg) == 0) return reg;
239                 CASE(ax); CASE(bx); CASE(cx); CASE(dx); CASE(flags);
240                 CASE(si); CASE(di); CASE(bp); CASE(ip); CASE(sp);
241 #undef CASE
242
243                 return MAX_REG;
244         }
245  
246         unsigned _target_reg;
247         unsigned _target_bit;
248
249         public:
250                 GPRFlipEmulator(L4vcpu::Vcpu *vcpu,
251                         Romain::App_model *am,
252                         Romain::App_instance *inst)
253                         : Flipper(vcpu, am, inst)
254                 {
255                         char const *reg = ConfigStringValue("swifi:register", "none");
256                         _target_reg = str_to_reg(reg);
257                         _target_bit = ConfigIntValue("swifi:bit", -1);
258
259                         DEBUG() << "REG: " << reg << "(" << _target_reg
260                                         << ") BIT: " << _target_bit;
261                 }
262
263                 void flip_reg(unsigned reg, unsigned bit)
264                 {
265         #define FLIP(pos) \
266                         case pos: _vcpu->r()->pos ^= (1 << bit); break;
267
268                         switch(reg) {
269                                 FLIP(ax); FLIP(bx); FLIP(cx); FLIP(dx); FLIP(flags);
270                                 FLIP(si); FLIP(di); FLIP(bp); FLIP(ip); FLIP(sp);
271                         }
272         #undef FLIP
273                 }
274
275                 virtual bool flip()
276                 {
277                         unsigned reg = (_target_reg == MAX_REG) ?
278                                 random() % MAX_REG : _target_reg;
279                         unsigned bit = (_target_bit == -1) ?
280                                 random() % 32 : _target_bit;
281
282                         MSG() << "selected (register, bit): (" << reg_to_str((targetRegs)reg)
283                               << ", " << bit << ")";
284
285                         flip_reg(reg, bit);
286
287                         return false;
288                 }
289
290         virtual void revert() { }
291 };
292
293
294 /*
295 * Instruction emulator that is used to flip a bit in instruction code
296 * (thereby emulating an SEU in the instruction decoder) and later on
297 * to revert it.
298 */
299 class InstrFlipEmulator : public Flipper
300 {
301         l4_addr_t _flip_addr;
302         l4_addr_t _flip_bit;
303
304 public:
305         InstrFlipEmulator(L4vcpu::Vcpu *vcpu,
306                           Romain::App_model *am,
307                           Romain::App_instance *inst)
308                 : Flipper(vcpu, am, inst),
309                   _flip_addr(0), _flip_bit(0)
310         {
311         }
312
313         virtual bool flip()
314                 {
315                         unsigned len = ilen();
316                         len *= 8; // bits
317
318                         _flip_bit  = random() % len;
319                         _flip_addr = local();
320                         _flip_eip  = ip();
321
322                         flip_mem();
323
324                         InstructionPrinter(_flip_addr, _flip_eip);
325                         return true;
326                 }
327
328                 void virtual revert()
329                 {
330                         flip_mem();
331                         InstructionPrinter(_flip_addr, _flip_eip);
332                 }
333
334                 void flip_mem()
335                 {
336                         l4_addr_t start = _flip_addr;
337                         l4_addr_t bit   = _flip_bit;
338                         MSG() << std::hex << "-1- addr: " << start;
339                         MSG() << std::hex << "-2- bit:  " << bit;
340                         unsigned byte = bit >> 3;
341
342                         start += byte;
343                         bit &= 0x7;
344
345                         MSG() << std::hex << "-3- flip byte: " << start;
346                         MSG() << std::hex << "-4- flip bit: " << bit;
347                         *(unsigned char*)start ^= (1 << bit);
348                 }
349 };
350
351
352 /*
353  * Inject ALU bitflips
354  *
355  * This class randomly choses from three potential errors:
356  *   - instruction SEU -> the ALU performs an operation different
357  *                        from what it is supposed to do
358  *   - input SEU       -> one of the input operands encounters
359  *                        a bit flip while being processed
360  *   - output SEU      -> the output encounters a bit flip
361  *                        before being written back to the target
362  */
363 class ALUFlipEmulator : public Flipper,
364                         public Romain::AsmJitUser
365 {
366         enum ALUError {
367                 e_flip_instr,
368                 e_flip_input,
369                 e_flip_output,
370                 max_alu_error
371         };
372
373         ALUError      _mode;   // the selected ALU error mode
374         ud_operand_t  _target; // flip output: determined target
375
376         bool mnemonic_supported(unsigned mnemonic)
377         {
378                 switch(mnemonic) {
379                         case UD_Iinc: case UD_Idec: case UD_Iadd: case UD_Isub:
380                         case UD_Ishr: case UD_Ishl: case UD_Iand: case UD_Ior:
381                         case UD_Isar: case UD_Ixor: case UD_Ineg:
382                                 return true;
383                         default:
384                                 return false;
385                 }
386         }
387
388         public:
389         ALUFlipEmulator(L4vcpu::Vcpu *vcpu,
390                         Romain::App_model *am,
391                         Romain::App_instance *inst)
392                 : Flipper(vcpu, am, inst)
393         {
394                 _mode = e_flip_instr; //(ALUError)(random() % 3);
395
396                 if (!mnemonic_supported(_ud.mnemonic)) {
397                         ERROR() << "Mnemonic " << _ud.mnemonic << " not yet supported.";
398                         enter_kdebug("mnemonic");
399                 }
400         }
401
402
403         virtual bool flip()
404         {
405                 switch(_mode)
406                 {
407                         case e_flip_instr:  flip_instruction(); MSG() << "ALU::flip_instr()"; return false;
408                         case e_flip_input:  flip_input();       MSG() << "ALU::flip_in()"; return false;
409                         case e_flip_output: flip_output();      MSG() << "ALU::flip_out()"; return true;
410                         default: break;
411                 }
412                 enter_kdebug("ALU::flip");
413                 return true;
414         }
415
416
417         /*
418          * Reverting only happens in the flip_output case. Otherwise,
419          * we leave the trampoline as is and the caller is responsible
420          * for setting the vCPU's EIP to the next valid instruction.
421          */
422         virtual void revert()
423         {
424                 unsigned bit = random() % 32;
425
426                 if (_mode == e_flip_output) {
427                         MSG() << "flipping " << bit;
428                         _vcpu->print_state();
429                         switch(_target.base) {
430                                 case UD_R_AX: case UD_R_AL: case UD_R_AH: case UD_R_EAX:
431                                         _vcpu->r()->ax ^= (1 << bit); break;
432                                 case UD_R_BX: case UD_R_BL: case UD_R_BH: case UD_R_EBX:
433                                         _vcpu->r()->bx ^= (1 << bit); break;
434                                 case UD_R_CX: case UD_R_CL: case UD_R_CH: case UD_R_ECX:
435                                         _vcpu->r()->cx ^= (1 << bit); break;
436                                 case UD_R_DX: case UD_R_DL: case UD_R_DH: case UD_R_EDX:
437                                         _vcpu->r()->dx ^= (1 << bit); break;
438                                 case UD_R_ESP:
439                                         _vcpu->r()->sp ^= (1 << bit); break;
440                                 case UD_R_ESI:
441                                         _vcpu->r()->si ^= (1 << bit); break;
442                                 case UD_R_EDI:
443                                         _vcpu->r()->di ^= (1 << bit); break;
444                                 default:
445                                         ERROR() << "unhandled flip reg: " << _target.base;
446                                         enter_kdebug();
447                         }
448                 }
449         }
450
451
452         /*
453          * Flip an instruction.
454          *
455          * Look at the original instruction and randomly select an alternative
456          * one using the same input parameters. This maps unary operations to
457          * unary operations and binary ops to binary ops again.
458          */
459         
460         void flip_instruction()
461         {
462                 int r;
463                 AsmJit::Assembler as;
464
465                 if (_ud.operand[1].type == UD_NONE) { // single operand
466                         r = random() % 3;
467                         switch(r)
468                         {
469 #define CASE1(num, _class) case num: { UnaryOperation<_class>(_ud, as); } break;
470                                 CASE1(0, Decrement); CASE1(1, Increment); CASE1(2, Negate);
471 #undef CASE1
472                         }
473                 } else {
474                         r = random() % 7;
475                         switch(r) {
476 #define CASE2(num, _class) case num: { BinaryOperation<_class>(_ud, as); } break;
477                                 CASE2(0, Addition); CASE2(1, Subtraction);
478                                 CASE2(2, ShiftLeft); CASE2(3, ShiftRight);
479                                 CASE2(4, Or); CASE2(5, And); CASE2(6, Xor);
480                         }
481 #undef CASE2
482                 }
483                 commit_asm(as, _am, _vcpu);
484         }
485
486
487         /*
488          * Flip one input value.
489          *
490          * Selects one of the input values and generates code to flip a random bit
491          * within this value.
492          */
493         void flip_input()
494         {
495                 ud_operand_t o, p;
496                 AsmJit::Assembler as;
497                 unsigned bit = random() % 32;
498
499                 /*
500                  * Step 1: Determine operand.
501                  */
502                 if (_ud.operand[1].type == UD_NONE) { // single operand
503                         o     = _ud.operand[0];
504                 } else {
505                         int i = random() % 2;
506                         o     = _ud.operand[i];
507                         p     = _ud.operand[1-i]; // the other reg
508                 }
509
510                 /*
511                  * Step 2: generate XOR() operation to flip bit.
512                  */
513                 if (o.type == UD_OP_REG) { // easy: simply xor with constant
514                         _check(o.index != UD_NONE, "indexing...");
515                         as.xor_(AsmJitUser::ud_to_jit_reg(o.base), (1 << bit));
516                 } else {
517                         /* If the target is not a register, we need to move it to one
518                          * for XORing. For that purpose we use EAX unless it is the second
519                          * operand, in which case we use EBX.
520                          */
521                         AsmJit::GPReg scratch;
522                         switch (p.base) {
523                                 case UD_R_AL: case UD_R_AH: case UD_R_AX: case UD_R_EAX:
524                                         scratch = AsmJit::ebx;
525                                 default: scratch = AsmJit::eax; break;
526                         }
527
528                         unsigned value = o.lval.udword;
529                         as.push(scratch);       // push scratch to stack
530                         as.mov(scratch, value); // mov to scratch register
531                                                 // now calculate
532                         // XXX: shouldn't this be: XOR scratch register AND then move the
533                         //      result back to original memory address???
534                         as.xor_(AsmJitUser::ud_to_jit_reg(p.base), (1 << bit));
535                         as.pop(scratch);        // pop previously stored scratch register
536                 }
537
538                 commit_asm(as, _am, _vcpu);
539
540                 /*
541                  * Step 3: We only generated code to flip the bit. We still need to execute
542                  *         the original instruction. If we decrement the _flip_eip here by
543                  *         the original instruction length, then a future restart will continue
544                  *         at the original EIP:
545                  */
546                 _flip_eip -= ilen();
547         }
548         
549
550         /*
551          * Prepare output flip by determining the target register.
552          */
553         void flip_output()
554         {
555                 _check(_ud.operand[0].scale != UD_NONE, "scaling in target reg?");
556                 _target = _ud.operand[0];
557         }
558 };
559
560
561 /*
562  * Emulate SEU in the register allocation table which maps physical
563  * registers to GPRs.
564  *
565  * When hitting an instruction, we determine which operand (if more than 1) is
566  * going to be affected:
567  *
568  * 1) Input operand:
569  *    - store current value
570  *    - overwrite with randomized value
571  *    - single-step
572  *    - restore current value
573  *
574  * 2) Output operand:
575  *    - store current value
576  *    - overwrite with randomized value
577  *    - single-step
578  *    - write to randomized target
579  *    - restore current value
580  *
581  * Randomization works as follows: We simulate a physical register file that is
582  * 10x as large as the needed register file (this is the case on Intel's
583  * Sandybridge architecture, which has 160 integer registers for 16 GPRs).
584  * Thus, with a chance of 10% we pick a random other register from the available
585  * GPRs, and with a chance of 90% we use a random input and ignore the output
586  * value.
587  */
588 class RATFlipEmulator : public Flipper
589 {
590         ud_type  which;   // which operand is flipped
591         unsigned scratch; // temp storage
592         unsigned target;  // which target reg to use
593
594         l4_umword_t randomize()
595         {
596                 unsigned x = random() % 10;
597                 if (x == 1) { // 10% chose real register
598                         x = random() % 8 + 1;
599                         switch(x) {
600                                 case 1:  target = UD_R_EAX; break;
601                                 case 2:  target = UD_R_EBX; break;
602                                 case 3:  target = UD_R_ECX; break;
603                                 case 4:  target = UD_R_EDX; break;
604                                 case 5:  target = UD_R_ESP; break;
605                                 case 6:  target = UD_R_EBP; break;
606                                 case 7:  target = UD_R_ESI; break;
607                                 case 8:  target = UD_R_EDI; break;
608                         }
609                         return register_to_value((ud_type)target);
610                 } else {
611                         target = 0;
612                         return random();
613                 }
614         }
615
616         public:
617         RATFlipEmulator(L4vcpu::Vcpu *vcpu,
618                     Romain::App_model *am,
619                     Romain::App_instance *inst)
620                 : Flipper(vcpu, am, inst),
621               which(UD_NONE), scratch(0), target(0)
622         {
623                 unsigned opcount     = 0;
624                 unsigned operands[4] = { ~0U, ~0U, ~0U, ~0U };
625                 enum { 
626                         RAT_IDX_MASK   = 0x0FF,
627                         RAT_IDX_OFFSET = 0x100
628                 };
629
630                 for (unsigned i = 0; i < UD_MAX_OPERANDS; ++i) {
631                         /*
632                          * Case 1: operand is a register
633                          */
634                         if (_ud.operand[i].type == UD_OP_REG) {
635                                 operands[opcount++] = i;
636                         } else if (_ud.operand[i].type == UD_OP_MEM) {
637                                 /*
638                                  * Case 2: operand is memory op.
639                                  *
640                                  * In this case, we may have 2 registers involved for the
641                                  * index-scale address calculation.
642                                  */
643 #if 0
644                                 MSG() << "mem " << _ud.operand[i].base << " "
645                                       << _ud.operand[i].index;
646 #endif
647                                 if (_ud.operand[i].base != 0)  // 0 if hard-wired mem operand
648                                         operands[opcount++] = i;
649                                 if (_ud.operand[i].index != 0)
650                                         operands[opcount++] = i + RAT_IDX_OFFSET;
651                         }
652                 }
653
654                 unsigned rnd = opcount ? random() % opcount : 0;
655                 
656                 if (operands[rnd] > RAT_IDX_OFFSET) {
657                         which = _ud.operand[operands[rnd] - RAT_IDX_OFFSET].index;
658                 } else {
659                         which = _ud.operand[operands[rnd]].base;
660                 }
661                 MSG() << "operands " << opcount << " which " << which;
662         }
663
664
665         virtual bool flip()
666         {
667                 /*
668                  * In every case we need to get the original register value
669                  * and restore it later on, because we emulate the real 
670                  * register not being touched at all.
671                  */
672                 scratch = register_to_value(which);
673                 value_to_register(randomize(), which);
674                 MSG() << "RAT: target " << std::hex << which
675                       << " val " << scratch << " -> "
676                       << register_to_value(which);
677                 return true;
678         }
679
680
681         virtual void revert()
682         {
683                 MSG() << "RAT: revert " << which << " flip target " << target;
684                 if (which == _ud.operand[0].base) { // we work on an output reg
685                         switch(target) {
686                                 case 0:   // output goes to nirvana, ignore
687                                         break;
688                                 default:  // output goes to another reg
689                                           // -> read from orig operand and write to target
690                                 {
691                                         l4_umword_t val = register_to_value(which);
692                                         value_to_register(val, (ud_type)target);
693                                 }
694                         }
695                 }
696
697                 value_to_register(scratch, which);
698         }
699 };
700
701 class MemFlipEmulator : public Flipper,
702                         public AsmJitUser
703 {
704         public:
705         MemFlipEmulator(L4vcpu::Vcpu *vcpu,
706                         Romain::App_model *am,
707                         Romain::App_instance *inst)
708                 : Flipper(vcpu, am, inst)
709         { }
710
711         virtual bool flip()
712         {
713                 unsigned i = 0;
714                 for ( ; i < UD_MAX_OPERANDS; ++i) {
715                         if (_ud.operand[i].type == UD_OP_MEM)
716                                 break;
717                 }
718
719                 MSG() << "Mem operand is #" << i;
720                 MSG() << "     base " << std::setw(2) << _ud.operand[i].base;
721                 MSG() << "    index " << std::setw(2) << _ud.operand[i].index;
722                 MSG() << "    scale " << std::setw(2) << (int)_ud.operand[i].scale;
723                 MSG() << "     offs " << std::setw(2) << (int)_ud.operand[i].offset;
724                 MSG() << "     lval " << std::setw(8) << std::hex << (int)_ud.operand[i].lval.sdword;
725
726                 l4_umword_t addr = 0;
727                 if (_ud.operand[i].base != 0)
728                         addr += register_to_value(_ud.operand[i].base);
729                 if (_ud.operand[i].index != 0)
730                         addr += (register_to_value(_ud.operand[i].index) << (unsigned)_ud.operand[i].scale);
731                 switch(_ud.operand[i].offset) {
732                         case 0:  break;
733                         case 8:  addr += _ud.operand[i].lval.sbyte; break;
734                         case 16: addr += _ud.operand[i].lval.sword; break;
735                         case 32: addr += _ud.operand[i].lval.sdword; break;
736                         default: enter_kdebug("offset"); break;
737                 }
738
739                 MSG() << "target addr: " << std::hex << addr << " ("
740                       << *(unsigned*)_translator->translate(addr) << ")";
741
742                 AsmJit::Assembler as;
743                 ud_operand_t &udreg = _ud.operand[0];
744                 MSG() << "target op: " << udreg.base << "(" << register_to_value(udreg.base) << ")";
745                 AsmJit::GPReg tmp = udreg.base == UD_R_EAX ? AsmJit::ebx : AsmJit::eax;
746                 as.push(tmp);
747
748                 if (i == 0) { // output operand
749                         ud_operand_t &reg2 = _ud.operand[1];
750                         switch(reg2.type) {
751                                 case UD_OP_CONST:
752                                 case UD_OP_IMM:
753                                         MSG() << "const: " << std::hex << _ud.operand[1].lval.sdword;
754                                         as.push(AsmJit::ecx);
755                                         as.mov(AsmJit::ecx, AsmJit::imm(reg2.lval.sdword));
756                                         as.mov(tmp, AsmJit::imm(addr));
757                                         
758                                         flip_bit_in_register(as, tmp);
759                                         
760                                         as.mov(AsmJit::dword_ptr(tmp), AsmJit::ecx);
761                                         as.pop(AsmJit::ecx);
762                                         break;
763                                 default:
764                                         MSG() << _ud.operand[1].type;
765                                         enter_kdebug("op?");
766                                         break;
767                         }
768                 } else { // input operand
769                         _check(_ud.operand[0].index  != 0, "indexing...");
770                         _check(_ud.operand[0].scale  != 0, "scaling...");
771                         _check(_ud.operand[0].offset != 0, "offsetting...");
772
773                         as.mov(tmp, AsmJit::imm(addr));
774
775                         flip_bit_in_register(as, tmp);
776
777                         as.mov(AsmJitUser::ud_to_jit_reg(udreg.base), AsmJit::dword_ptr(tmp));
778                 }
779
780                 as.pop(tmp);
781                 commit_asm(as, _am, _vcpu);
782
783                 //enter_kdebug("mem::flip");
784                 return false;
785         }
786
787         virtual void revert()
788         { }
789 };
790
791 class SWIFIPriv : public Romain::SWIFIObserver
792 {
793         enum targetFlags {
794                 None,
795                 GPR,    // register bit flip
796                 INSTR,  // instruction decoding bit flip
797                 ALU,    // ALU fault injection
798                 RAT,    // RAT fault injection
799                 MEM,    // flip in mem address
800         };
801
802         Breakpoint * _breakpoint;
803         targetFlags  _flags;
804
805         Flipper    * _flipper;
806
807         unsigned     _alu_mode;   // 0 - flip instr, 1 - flip input, 2 - flip output
808
809         void flipper_trap1(Romain::App_thread* t);
810         void flipper_trap3(Romain::App_thread* t, bool want_stepping = true);
811
812         void remove_breakpoint(Romain::App_thread *t)
813         {
814                 MSG() << "bp: " << std::hex << _breakpoint;
815                 if (_breakpoint) {
816                         delete _breakpoint;
817                         _breakpoint = 0;
818                         t->vcpu()->r()->ip--;
819                 }
820         }
821
822         unsigned decode_insn(l4_addr_t local, l4_addr_t remote, ud_t *ud);
823
824         public:
825                 SWIFIPriv();
826                 DECLARE_OBSERVER("swifi");
827 };
828 };