diff --git a/arch/x86/mm/mmio-mod.c b/arch/x86/mm/mmio-mod.c index 3adff7d..f8513bb 100644 --- a/arch/x86/mm/mmio-mod.c +++ b/arch/x86/mm/mmio-mod.c @@ -206,6 +206,12 @@ static void pre(struct kmmio_probe *p, struct pt_regs *regs, put_cpu_var(pf_reason); } +#define MMIO_BASE 0xfaafc000 +#define B43_MMIO_PHY_CONTROL 0x3FC +#define B43_MMIO_PHY_DATA 0x3FE + +static u16 broadcom_phy_addr; + static void post(struct kmmio_probe *p, unsigned long condition, struct pt_regs *regs) { @@ -219,6 +225,18 @@ static void post(struct kmmio_probe *p, unsigned long condition, BUG(); } + if (my_reason->type == REG_READ && my_trace->phys == MMIO_BASE + B43_MMIO_PHY_DATA) { + pr_info("ZAJEC: read PHY 0x%X\n", broadcom_phy_addr); + switch (broadcom_phy_addr){ + case 0x20: + case 0x22: + case 0x27: + pr_info("ZAJEC: overwriting 0x%X with 0xFFFF\n", broadcom_phy_addr); + set_ins_reg_val(my_reason->ip, regs, 0xFFFF); + break; + } + } + switch (my_reason->type) { case REG_READ: my_trace->value = get_ins_reg_val(my_reason->ip, regs); @@ -227,6 +245,11 @@ static void post(struct kmmio_probe *p, unsigned long condition, break; } + if (my_reason->type == REG_WRITE && my_trace->phys == MMIO_BASE + B43_MMIO_PHY_CONTROL) { + broadcom_phy_addr = my_trace->value; + //pr_info("ZAJEC: setting PHY addr to 0x%X\n", broadcom_phy_addr); + } + mmio_trace_rw(my_trace); put_cpu_var(cpu_trace); put_cpu_var(pf_reason); 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_ */