diff --git a/arch/x86/mm/mmio-mod.c b/arch/x86/mm/mmio-mod.c index 3adff7d..7f71884b 100644 --- a/arch/x86/mm/mmio-mod.c +++ b/arch/x86/mm/mmio-mod.c @@ -219,6 +219,11 @@ static void post(struct kmmio_probe *p, unsigned long condition, BUG(); } + if (my_trace->phys == 0xfaafc000) { + pr_info("ZAJEC: got it\n"); + set_ins_reg_val(my_reason->ip, regs, 0x13816666); + } + switch (my_reason->type) { case REG_READ: my_trace->value = get_ins_reg_val(my_reason->ip, regs); diff --git a/arch/x86/mm/pf_in.c b/arch/x86/mm/pf_in.c index 9f0614d..86449ed 100644 --- a/arch/x86/mm/pf_in.c +++ b/arch/x86/mm/pf_in.c @@ -461,6 +461,99 @@ err: return 0; } +static void set_reg_w32(int no, struct pt_regs *regs, u32 val) +{ + switch (no) { + case arg_AX: + regs->ax = val; + break; + case arg_BX: + regs->bx = val; + break; + case arg_CX: + regs->cx = val; + break; + case arg_DX: + regs->dx = val; + break; + case arg_SP: + regs->sp = val; + break; + case arg_BP: + regs->bp = val; + break; + case arg_SI: + regs->si = val; + break; + case arg_DI: + regs->di = val; + break; +#ifdef __amd64__ + case arg_R8: + regs->r8 = val; + break; + case arg_R9: + regs->r9 = val; + break; + case arg_R10: + regs->r10 = val; + break; + case arg_R11: + regs->r11 = val; + break; + case arg_R12: + regs->r12 = val; + break; + case arg_R13: + regs->r13 = val; + break; + case arg_R14: + regs->r14 = val; + break; + case arg_R15: + regs->r15 = val; + break; +#endif + default: + printk(KERN_ERR "mmiotrace: Error reg no# %d\n", no); + } +} + +void set_ins_reg_val(unsigned long ins_addr, struct pt_regs *regs, u32 val) +{ + unsigned int opcode; + int reg; + unsigned char *p; + struct prefix_bits prf; + int i; + + p = (unsigned char *)ins_addr; + p += skip_prefix(p, &prf); + p += get_opcode(p, &opcode); + for (i = 0; i < ARRAY_SIZE(reg_rop); i++) + if (reg_rop[i] == opcode) + goto do_work; + + for (i = 0; i < ARRAY_SIZE(reg_wop); i++) + if (reg_wop[i] == opcode) + goto do_work; + + printk(KERN_ERR "mmiotrace: Not a register instruction, opcode " + "0x%02x\n", opcode); + return; + +do_work: + /* for STOS, source register is fixed */ + if (opcode == 0xAA || opcode == 0xAB) { + reg = arg_AX; + } else { + unsigned char mod_rm = *p; + reg = ((mod_rm >> 3) & 0x7) | (prf.rexr << 3); + } + + set_reg_w32(reg, regs, val); +} + unsigned long get_ins_imm_val(unsigned long ins_addr) { unsigned int opcode; diff --git a/arch/x86/mm/pf_in.h b/arch/x86/mm/pf_in.h index e05341a..90b43ff 100644 --- a/arch/x86/mm/pf_in.h +++ b/arch/x86/mm/pf_in.h @@ -34,6 +34,7 @@ enum reason_type { enum reason_type get_ins_type(unsigned long ins_addr); unsigned int get_ins_mem_width(unsigned long ins_addr); unsigned long get_ins_reg_val(unsigned long ins_addr, struct pt_regs *regs); +void set_ins_reg_val(unsigned long ins_addr, struct pt_regs *regs, u32 val); unsigned long get_ins_imm_val(unsigned long ins_addr); #endif /* __PF_H_ */