Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

MMC-fix source

Change-Id: I421b67038c269c486d67378e98051f115cae773e
  • Loading branch information...
commit 92421e7c09563d5d4abc88148d7708951dcf965e 1 parent 83125a3
@nadlabak nadlabak authored
View
6 mmcfix/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for MMC-fix module
+#
+
+obj-m += mmcfix.o
+mmcfix-objs := mmc-fix.o hook.o
View
108 mmcfix/hook.c
@@ -0,0 +1,108 @@
+/*
+ * hook - Hook utilities.
+ * use of Skrilax's symsearch added by Nadlabak
+ *
+ * Copyright (C) 2010 Nothize
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "hook.h"
+#include "symsearch.h"
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+#include <linux/smp_lock.h>
+
+//#define DEBUG_HOOK
+#ifdef DEBUG_HOOK
+#define P(format, ...) printk(KERN_INFO "hook: " format, ## __VA_ARGS__)
+#else
+#define P(format, ...)
+#endif
+
+#define INFO(format, ...) (printk(KERN_INFO "hook:%s:%d " format, __FUNCTION__, __LINE__, ## __VA_ARGS__))
+
+SYMSEARCH_DECLARE_FUNCTION_STATIC(unsigned long, pkallsyms_lookup_name, const char *);
+SYMSEARCH_DECLARE_FUNCTION_STATIC(const char *, pkallsyms_lookup, unsigned long, unsigned long *, unsigned long *, char **, char *);
+
+/* Only ARM is supported and the target will crash if there involves
+ PC related addressing in the first instruction. Because that
+ instruction will be moved to hook_info for execution.
+*/
+int hook(struct hook_info *hi) {
+ char targetName[KSYM_NAME_LEN];
+ char *ptargetName;
+ if ( !hi->target ) {
+ if ( hi->targetName ) {
+ hi->target = (unsigned int*)pkallsyms_lookup_name(hi->targetName);
+ }
+ if ( !hi->target ) {
+ P("Target address is not defined and targetName(%s) cannot be found.\n", hi->targetName ?
+ hi->targetName : "");
+ return -1;
+ }
+ ptargetName = hi->targetName;
+ } else {
+ pkallsyms_lookup((unsigned int)hi->target, NULL, NULL, NULL, targetName);
+ ptargetName = targetName;
+ }
+
+ // Save the first 2 instructions from target.
+ P("target = %p(%s), newf = %x\n", hi->target, ptargetName, hi->newfunc);
+ P("*target = %x\n", hi->target[0]);
+ hi->asm0 = hi->target[0];
+
+ // Use 1 instruction static replacement.
+ hi->target[0] = 0xea000000 + (0xffffff & (hi->newfunc - ((unsigned int)hi->target + 8)) / 4);
+ P("*target = %x\n", hi->target[0]);
+
+ // Setup jmp table to first non-overwritten offset.
+ hi->jmp = 0xe51ff004;
+ hi->target_cont = hi->target+1;
+ P("&invoke = %p, target_cont = %p\n", &hi->asm0, hi->target_cont);
+
+ INFO("hooked %s\n", ptargetName);
+ return 0;
+}
+
+int unhook(struct hook_info *hi) {
+ if ( hi->target ) {
+ // Restore the first 2 instructions to target.
+ hi->target[0] = hi->asm0;
+ INFO("unhooked %p\n", hi->target);
+ }
+ return 0;
+}
+
+void hook_init(void) {
+ int i;
+ SYMSEARCH_BIND_FUNCTION_TO(dsifix, kallsyms_lookup_name, pkallsyms_lookup_name);
+ SYMSEARCH_BIND_FUNCTION_TO(dsifix, kallsyms_lookup, pkallsyms_lookup);
+ lock_kernel();
+ for (i = 0; g_hi[i].newfunc; ++i) {
+ hook(&g_hi[i]);
+ }
+ unlock_kernel();
+}
+
+void hook_exit(void) {
+ int i;
+ lock_kernel();
+ for (i = 0; g_hi[i].newfunc; ++i) {
+ unhook(&g_hi[i]);
+ }
+ unlock_kernel();
+}
View
49 mmcfix/hook.h
@@ -0,0 +1,49 @@
+/*
+ * n
+ *
+ * Copyright (C) 2010 Nothize
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _HOOK_H_
+#define _HOOK_H_
+
+struct hook_info {
+ unsigned int asm0;
+ unsigned int jmp;
+ unsigned int *target_cont;
+ unsigned int *target;
+ char *targetName;
+ unsigned int newfunc;
+};
+
+int hook(struct hook_info *);
+
+int unhook(struct hook_info *);
+
+void hook_init(void);
+void hook_exit(void);
+
+extern struct hook_info g_hi[];
+
+#define HOOK_INVOKE(_f, ...) ((typeof(&_f))&g_hi[__COUNTER__].asm0)(__VA_ARGS__)
+
+#define HOOK_INIT(f) { .targetName = #f, .newfunc = (unsigned int)f }
+
+#define HOOK_INIT_END { .newfunc = 0 }
+
+#endif
View
124 mmcfix/mmc-fix.c
@@ -0,0 +1,124 @@
+/*
+ * MMC-fix: fix SD card read/write errors (mmcblk0: error -110 - common and known
+ * linux-omap issue) by replacement of set_data_timeout function in omap_hsmmc.c
+ * to use the default DTO value of 0xE instead of dynamic calculation.
+ *
+ * hooking taken from "n - for testing kernel function hooking" by Nothize.
+ *
+ * Copyright (C) 2011 Nadlabak
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include "hook.h"
+
+#define DTO 0xe
+#define DTO_MASK 0x000F0000
+#define DTO_SHIFT 16
+#define OMAP_HSMMC_SYSCTL 0x012C
+
+/*
+ * MMC Host controller read/write API's
+ */
+#define OMAP_HSMMC_READ(base, reg) \
+ __raw_readl((base) + OMAP_HSMMC_##reg)
+
+#define OMAP_HSMMC_WRITE(base, reg, val) \
+ __raw_writel((val), (base) + OMAP_HSMMC_##reg)
+
+struct omap_hsmmc_host {
+ struct device *dev;
+ struct mmc_host *mmc;
+ struct mmc_request *mrq;
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+ struct clk *fclk;
+ struct clk *iclk;
+ struct clk *dbclk;
+ struct semaphore sem;
+ struct work_struct mmc_carddetect_work;
+ void __iomem *base;
+ resource_size_t mapbase;
+ spinlock_t irq_lock; /* Prevent races with irq handler */
+ unsigned long flags;
+ unsigned int id;
+ unsigned int dma_len;
+ unsigned int dma_sg_idx;
+ unsigned char bus_mode;
+ unsigned char power_mode;
+ u32 *buffer;
+ u32 bytesleft;
+ int suspended;
+ int irq;
+ int use_dma, dma_ch;
+ int dma_line_tx, dma_line_rx;
+ int slot_id;
+ int got_dbclk;
+ int response_busy;
+ int context_loss;
+ int dpm_state;
+ int vdd;
+ int protect_card;
+ int reqs_blocked;
+
+ struct omap_mmc_platform_data *pdata;
+};
+
+// hooked function
+static void set_data_timeout(struct omap_hsmmc_host *host,
+ unsigned int timeout_ns,
+ unsigned int timeout_clks)
+{
+ uint32_t reg;
+
+// printk(KERN_INFO "MMC-fix: set_data_timeout called\n");
+ reg = OMAP_HSMMC_READ(host->base, SYSCTL);
+
+ reg &= ~DTO_MASK;
+ reg |= DTO << DTO_SHIFT;
+ OMAP_HSMMC_WRITE(host->base, SYSCTL, reg);
+ if (0) HOOK_INVOKE(set_data_timeout, host, timeout_ns, timeout_clks);
+}
+
+
+struct hook_info g_hi[] = {
+ HOOK_INIT(set_data_timeout),
+ HOOK_INIT_END
+};
+
+static int __init mmcfix_init(void)
+{
+ printk(KERN_INFO "MMC-fix init\n");
+ hook_init();
+ return 0;
+}
+
+static void __exit mmcfix_exit(void)
+{
+ hook_exit();
+}
+
+module_init(mmcfix_init);
+module_exit(mmcfix_exit);
+
+MODULE_ALIAS("MMC-fix");
+MODULE_DESCRIPTION("fix omap hsmmc driver via kernel function hook");
+MODULE_AUTHOR("Nadlabak");
+MODULE_LICENSE("GPL");
View
111 mmcfix/symsearch.h
@@ -0,0 +1,111 @@
+/*
+ * symsearch: - looks up also for unexproted symbols in the kernel
+ * exports function:
+ *
+ * Copyright (C) 2010 Skrilax_CZ
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _SYMSEARCH_H_
+#define _SYMSEARCH_H_
+
+//macros to call functions declared in C but addressed manually
+
+//ret -> return type
+//name -> function name
+//... parameter list
+//expname -> name under which the function is exported
+
+//addresses
+
+#define SYMSEARCH_DECLARE_ADDRESS(name) \
+ extern unsigned long name##_address
+
+#define SYMSEARCH_DECLARE_ADDRESS_STATIC(name) \
+ static unsigned long name##_address = 0
+
+#define SYMSEARCH_INIT_ADDRESS(name) \
+ unsigned long name##_address = 0
+
+#define SYMSEARCH_GET_ADDRESS(name) \
+ name##_address
+
+//functions
+
+#define SYMSEARCH_DECLARE_FUNCTION(ret,name,...) \
+ typedef ret (*name##_fp) ( __VA_ARGS__ ); \
+ extern name##_fp name
+
+#define SYMSEARCH_DECLARE_FUNCTION_STATIC(ret,name,...) \
+ typedef ret (*name##_fp) ( __VA_ARGS__ ); \
+ static name##_fp name = 0
+
+#define SYMSEARCH_INIT_FUNCTION(name) \
+ name##_fp name = (name##_fp)0
+
+//binding (call this in module_init and module is the module name)
+
+#define SYMSEARCH_BIND_ADDRESS(module,name) \
+ name##_address = lookup_symbol_address(#name); \
+ if(!name##_address) \
+ { \
+ printk(KERN_INFO #module ": Could not find symbol: " #name ".\n"); \
+ return -EBUSY; \
+ }
+
+#define SYMSEARCH_BIND_ADDRESS_TO(module,name,sym) \
+ sym##_address = lookup_symbol_address(#name); \
+ if(!sym##_address) \
+ { \
+ printk(KERN_INFO #module ": Could not find symbol: " #name ".\n"); \
+ return -EBUSY; \
+ }
+
+#define SYMSEARCH_BIND_FUNCTION(module,name) \
+ name = (name##_fp)lookup_symbol_address(#name); \
+ if(!name) \
+ { \
+ printk(KERN_INFO #module ": Could not find symbol: " #name ".\n"); \
+ return -EBUSY; \
+ }
+
+#define SYMSEARCH_BIND_FUNCTION_TO(module,name,sym) \
+ sym = (sym##_fp)lookup_symbol_address(#name); \
+ if(!sym) \
+ { \
+ printk(KERN_INFO #module ": Could not find symbol: " #name ".\n"); \
+ return -EBUSY; \
+ }
+
+//hijcaking a function
+//injects a Branch instruction to the function beginning
+
+//ARM MODE only !!!
+
+struct hijack_info
+{
+ unsigned long hijack_address;
+ unsigned long redirection_address;
+ unsigned long instruction_backup;
+};
+
+SYMSEARCH_DECLARE_FUNCTION(unsigned long, lookup_symbol_address, const char *name);
+
+struct hijack_info hijack_function(unsigned long hijack_address, unsigned long redirection_address);
+void restore_function(struct hijack_info hijack);
+
+#endif
Please sign in to comment.
Something went wrong with that request. Please try again.