sync_init(&buffer_busy_sync);
/* Memory allocation for queue_busy */
- queue_busy = memory_allocation(sizeof(**queue_busy) * queue_subbuffer_count);
+ queue_busy = memory_allocation(sizeof(*queue_busy) * queue_subbuffer_count);
if (!queue_busy) {
result = -E_SB_NO_MEM_QUEUE_BUSY;
int i;
for (i = 0; i < size; i++)
- if ((area1 + i == area2) || (area1 + i == area2))
+ if ((area1 + i == area2) || (area2 + i == area1))
return 1;
return 0;
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/wait.h>
+#include <linux/workqueue.h>
#include <asm/uaccess.h>
#include <ksyms/ksyms.h>
/* Reading tasks queue */
static DECLARE_WAIT_QUEUE_HEAD(swap_device_wait);
+
+static atomic_t flag_wake_up = ATOMIC_INIT(0);
+
+static void __bottom_wake_up(void)
+{
+ if (waitqueue_active(&swap_device_wait))
+ wake_up_interruptible(&swap_device_wait);
+}
+
+static void bottom_wake_up(struct work_struct *work)
+{
+ if (atomic_read(&flag_wake_up)) {
+ atomic_set(&flag_wake_up, 0);
+ __bottom_wake_up();
+ }
+}
+
+static DECLARE_WORK(w_wake_up, bottom_wake_up);
+
+static void exit_w_wake_up(void)
+{
+ flush_scheduled_work();
+ __bottom_wake_up();
+}
+
+
/* We need this realization of splice_shrink_spd() because of the its desing
* frequent changes that I have encountered in custom kernels */
void swap_device_splice_shrink_spd(struct pipe_inode_info *pipe,
/* Unregister device TODO Check wether driver is registered */
void swap_device_exit(void)
{
+ exit_w_wake_up();
+
splice_to_pipe_p = NULL;
splice_grow_spd_p = NULL;
void swap_device_wake_up_process(void)
{
- wake_up_interruptible(&swap_device_wait);
+ if (atomic_read(&flag_wake_up) == 0) {
+ atomic_set(&flag_wake_up, 1);
+ schedule_work(&w_wake_up);
+ }
}
void set_msg_handler(msg_handler_t mh)
endif
+# PANEL_S6E8AA0:
+ifeq ($(CONFIG_DISPLAY_PANEL_S6E8AA0), y)
+ swap_energy-y += lcd/s6e8aa0_panel.o
+ LCD_FUNC_LIST += s6e8aa0_panel
+endif
+
+
# MARU:
ifeq ($(CONFIG_MARU_BACKLIGHT), y)
swap_energy-y += lcd/maru.o
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/fs.h>
+#include <linux/fb.h>
#include <energy/tm_stat.h>
#include "lcd_base.h"
#include "lcd_debugfs.h"
brt_cnt = 10
};
+enum power_t {
+ PW_ON,
+ PW_OFF
+};
+
struct lcd_priv_data {
int min_brt;
int max_brt;
struct tm_stat *tms_brt;
spinlock_t lock_tms;
int brt_old;
+ enum power_t power;
u64 min_denom;
u64 min_num;
spin_lock_init(&lcd->lock_tms);
lcd->brt_old = brt_no_init;
+ lcd->power = PW_OFF;
lcd->min_denom = 1;
lcd->min_num = 1;
spin_unlock(&lcd->lock_tms);
}
-static void set_brightness(struct lcd_ops *ops, int brt)
+static int get_brt_num_of_array(struct lcd_priv_data *lcd, int brt)
{
- struct lcd_priv_data *lcd = get_lcd_priv(ops);
- int n;
-
if (brt > lcd->max_brt || brt < lcd->min_brt) {
printk("LCD energy error: set brightness=%d, "
"when brightness[%d..%d]\n",
brt = brt > lcd->max_brt ? lcd->max_brt : lcd->min_brt;
}
- n = lcd->tms_brt_cnt * (brt - lcd->min_brt) /
- (lcd->max_brt - lcd->min_brt + 1);
+ return lcd->tms_brt_cnt * (brt - lcd->min_brt) /
+ (lcd->max_brt - lcd->min_brt + 1);
+}
+
+static void set_brightness(struct lcd_ops *ops, int brt)
+{
+ struct lcd_priv_data *lcd = get_lcd_priv(ops);
+ int n = get_brt_num_of_array(lcd, brt);
spin_lock(&lcd->lock_tms);
- if (lcd->brt_old != n) {
+
+ if (lcd->power == PW_ON && lcd->brt_old != n) {
u64 time = get_ntime();
if (lcd->brt_old != brt_no_init)
tm_stat_update(&lcd->tms_brt[lcd->brt_old], time);
tm_stat_set_timestamp(&lcd->tms_brt[n], time);
- lcd->brt_old = n;
}
+ lcd->brt_old = n;
+
+ spin_unlock(&lcd->lock_tms);
+}
+
+static void set_power_on_set_brt(struct lcd_priv_data *lcd)
+{
+ if (lcd->brt_old != brt_no_init) {
+ u64 time = get_ntime();
+ tm_stat_set_timestamp(&lcd->tms_brt[lcd->brt_old], time);
+ }
+}
+
+static void set_power_on(struct lcd_priv_data *lcd)
+{
+ if (lcd->power == PW_OFF)
+ set_power_on_set_brt(lcd);
+
+ lcd->power = PW_ON;
+}
+
+static void set_power_off_update_brt(struct lcd_priv_data *lcd)
+{
+ if (lcd->brt_old != brt_no_init) {
+ u64 time = get_ntime();
+ tm_stat_update(&lcd->tms_brt[lcd->brt_old], time);
+ lcd->brt_old = brt_no_init;
+ }
+}
+
+static void set_power_off(struct lcd_priv_data *lcd)
+{
+ if (lcd->power == PW_ON)
+ set_power_off_update_brt(lcd);
+
+ lcd->power = PW_OFF;
+}
+
+static void set_power(struct lcd_ops *ops, int val)
+{
+ struct lcd_priv_data *lcd = get_lcd_priv(ops);
+
+ spin_lock(&lcd->lock_tms);
+
+ switch (val) {
+ case FB_BLANK_UNBLANK:
+ set_power_on(lcd);
+ break;
+ case FB_BLANK_POWERDOWN:
+ set_power_off(lcd);
+ break;
+ default:
+ printk("LCD energy error: set power=%d\n", val);
+ break;
+ }
+
spin_unlock(&lcd->lock_tms);
}
case LAT_BRIGHTNESS:
set_brightness(ops, (int)data);
break;
+ case LAT_POWER:
+ set_power(ops, (int)data);
+ break;
default:
+ printk("LCD energy error: action=%d\n", action);
return -EINVAL;
}
int i;
spin_lock(&lcd->lock_tms);
- for (i = 0; i < lcd->tms_brt_cnt; ++i) {
+ for (i = 0; i < lcd->tms_brt_cnt; ++i)
array_time[i] = tm_stat_running(&lcd->tms_brt[i]);
- if (i == lcd->brt_old)
- array_time[i] += get_ntime() -
- tm_stat_timestamp(&lcd->tms_brt[i]);
+
+ if (lcd->power == PW_ON && lcd->brt_old != brt_no_init) {
+ int old = lcd->brt_old;
+ struct tm_stat *tm = &lcd->tms_brt[old];
+
+ array_time[old] += get_ntime() - tm_stat_timestamp(tm);
}
spin_unlock(&lcd->lock_tms);
}
}
set_brightness(ops, ops->get(ops, LPD_BRIGHTNESS));
+ set_power(ops, ops->get(ops, LPD_POWER));
stat_lcd_ops[i] |= SLO_SET;
++count;
enum lcd_action_type {
- LAT_BRIGHTNESS
+ LAT_BRIGHTNESS,
+ LAT_POWER
};
enum lcd_parameter_type {
LPD_MIN_BRIGHTNESS,
LPD_MAX_BRIGHTNESS,
- LPD_BRIGHTNESS
+ LPD_BRIGHTNESS,
+
+ LPD_POWER
};
struct lcd_ops;
static const char path_backlight[] = "/sys/class/backlight/emulator/brightness";
static const char path_backlight_min[] = "/sys/class/backlight/emulator/min_brightness";
static const char path_backlight_max[] = "/sys/class/backlight/emulator/max_brightness";
+static const char path_power[] = "/sys/class/lcd/emulator/lcd_power";
static const char *all_path[] = {
path_backlight,
path_backlight_min,
- path_backlight_max
+ path_backlight_max,
+ path_power
};
enum {
return read_val(path_backlight_max);
case LPD_BRIGHTNESS:
return read_val(path_backlight);
+ case LPD_POWER:
+ return read_val(path_power);
+ default:
+ return -EINVAL;
}
-
- return -EINVAL;
}
static const char path_backlight[] = "/sys/class/backlight/s6e8aa0-bl/brightness";
static const char path_backlight_min[] = "/sys/class/backlight/s6e8aa0-bl/min_brightness";
static const char path_backlight_max[] = "/sys/class/backlight/s6e8aa0-bl/max_brightness";
+static const char path_power[] = "/sys/class/lcd/s6e8aa0/lcd_power";
static const char *all_path[] = {
path_backlight,
path_backlight_min,
- path_backlight_max
+ path_backlight_max,
+ path_power
};
enum {
return read_val(path_backlight_max);
case LPD_BRIGHTNESS:
return read_val(path_backlight);
+ case LPD_POWER:
+ return read_val(path_power);
+ default:
+ return -EINVAL;
}
-
- return -EINVAL;
}
-
-
-#if 0 /* is not supported */
-/* ============================================================================
- * === POWER ===
- * ============================================================================
- */
-static int get_power(void)
-{
- const char *power_path = "/sys/class/lcd/s6e8aa0/lcd_power";
-
- return read_val(power_path);
-}
-
static int entry_handler_set_power(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- int *power = (int *)ri->data;
-
- *power = (int)regs->ARM_r1;
-
- return 0;
-}
-
+ struct pt_regs *regs);
static int ret_handler_set_power(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- int ret = regs_return_value(regs);
- int *power = (int *)ri->data;
-
- if (!ret && ops_s && ops_s->set_power)
- ops_s->set_power(*power);
-
- return 0;
-}
+ struct pt_regs *regs);
static struct kretprobe set_power_krp = {
.kp.symbol_name = "s6e8aa0_set_power",
.handler = ret_handler_set_power,
.data_size = sizeof(int)
};
-#endif
-
static int entry_handler_set_backlight(struct kretprobe_instance *ri,
int s6e8aa0_set(struct lcd_ops *ops)
{
- return dbi_register_kretprobe(&set_backlight_krp);
+ int ret;
+
+ ret = dbi_register_kretprobe(&set_power_krp);
+ if (ret)
+ return ret;
+
+ ret = dbi_register_kretprobe(&set_backlight_krp);
+ if (ret)
+ dbi_unregister_kretprobe(&set_power_krp);
+
+ return ret;
}
int s6e8aa0_unset(struct lcd_ops *ops)
{
dbi_unregister_kretprobe(&set_backlight_krp);
+ dbi_unregister_kretprobe(&set_power_krp);
+
return 0;
}
/* ============================================================================
+ * === POWER ===
+ * ============================================================================
+ */
+static int entry_handler_set_power(struct kretprobe_instance *ri,
+ struct pt_regs *regs)
+{
+ int *power = (int *)ri->data;
+
+ *power = (int)swap_get_karg(regs, 1);
+
+ return 0;
+}
+
+static int ret_handler_set_power(struct kretprobe_instance *ri,
+ struct pt_regs *regs)
+{
+ int ret = regs_return_value(regs);
+ int *power = (int *)ri->data;
+
+ if (!ret && s6e8aa0_ops.notifier)
+ s6e8aa0_ops.notifier(&s6e8aa0_ops, LAT_POWER, (void *)*power);
+
+ return 0;
+}
+
+
+
+
+
+/* ============================================================================
* === BACKLIGHT ===
* ============================================================================
*/
--- /dev/null
+#include <kprobe/dbi_kprobes.h>
+#include <linux/backlight.h>
+#include "lcd_base.h"
+
+
+static const char path_backlight[] = "/sys/class/backlight/s6e8aa0-bl/brightness";
+static const char path_backlight_max[] = "/sys/class/backlight/s6e8aa0-bl/max_brightness";
+static const char path_power[] = "/sys/class/lcd/s6e8aa0/lcd_power";
+
+static const char *all_path[] = {
+ path_backlight,
+ path_backlight_max,
+ path_power
+};
+
+enum {
+ all_path_cnt = sizeof(all_path) / sizeof(char *)
+};
+
+
+
+static int s6e8aa0_check(struct lcd_ops *ops)
+{
+ int i;
+
+ for (i = 0; i < all_path_cnt; ++i) {
+ int ret = read_val(all_path[i]);
+
+ if (IS_ERR_VALUE(ret))
+ return 0;
+ }
+
+ return 1;
+}
+
+static unsigned long s6e8aa0_get_parameter(struct lcd_ops *ops,
+ enum lcd_parameter_type type)
+{
+ switch (type) {
+ case LPD_MIN_BRIGHTNESS:
+ return 0;
+ case LPD_MAX_BRIGHTNESS:
+ return read_val(path_backlight_max);
+ case LPD_BRIGHTNESS:
+ return read_val(path_backlight);
+ case LPD_POWER:
+ return read_val(path_power);
+ }
+
+ return -EINVAL;
+}
+
+
+
+static int entry_handler_set_power(struct kretprobe_instance *ri,
+ struct pt_regs *regs);
+static int ret_handler_set_power(struct kretprobe_instance *ri,
+ struct pt_regs *regs);
+
+static struct kretprobe set_power_krp = {
+ .kp.symbol_name = "s6e8aa0_set_power",
+ .entry_handler = entry_handler_set_power,
+ .handler = ret_handler_set_power,
+ .data_size = sizeof(int)
+};
+
+
+static int entry_handler_set_backlight(struct kretprobe_instance *ri,
+ struct pt_regs *regs);
+static int ret_handler_set_backlight(struct kretprobe_instance *ri,
+ struct pt_regs *regs);
+
+static struct kretprobe set_backlight_krp = {
+ .kp.symbol_name = "s6e8aa0_update_status",
+ .entry_handler = entry_handler_set_backlight,
+ .handler = ret_handler_set_backlight,
+ .data_size = sizeof(int)
+};
+
+int s6e8aa0_set(struct lcd_ops *ops)
+{
+ int ret;
+
+ ret = dbi_register_kretprobe(&set_power_krp);
+ if (ret)
+ return ret;
+
+ ret = dbi_register_kretprobe(&set_backlight_krp);
+ if (ret)
+ dbi_unregister_kretprobe(&set_power_krp);
+
+ return ret;
+}
+
+int s6e8aa0_unset(struct lcd_ops *ops)
+{
+ dbi_unregister_kretprobe(&set_backlight_krp);
+ dbi_unregister_kretprobe(&set_power_krp);
+
+ return 0;
+}
+
+static struct lcd_ops s6e8aa0_ops = {
+ .name = "s6e8aa0_panel",
+ .check = s6e8aa0_check,
+ .set = s6e8aa0_set,
+ .unset = s6e8aa0_unset,
+ .get = s6e8aa0_get_parameter
+};
+
+struct lcd_ops *LCD_MAKE_FNAME(s6e8aa0_panel)(void)
+{
+ return &s6e8aa0_ops;
+}
+
+
+
+
+
+/* ============================================================================
+ * === POWER ===
+ * ============================================================================
+ */
+static int entry_handler_set_power(struct kretprobe_instance *ri,
+ struct pt_regs *regs)
+{
+ int *power = (int *)ri->data;
+
+ *power = (int)swap_get_karg(regs, 1);
+
+ return 0;
+}
+
+static int ret_handler_set_power(struct kretprobe_instance *ri,
+ struct pt_regs *regs)
+{
+ int ret = regs_return_value(regs);
+ int *power = (int *)ri->data;
+
+ if (!ret && s6e8aa0_ops.notifier)
+ s6e8aa0_ops.notifier(&s6e8aa0_ops, LAT_POWER,
+ (void *)*power);
+
+ return 0;
+}
+
+
+
+
+
+/* ============================================================================
+ * === BACKLIGHT ===
+ * ============================================================================
+ */
+static int entry_handler_set_backlight(struct kretprobe_instance *ri,
+ struct pt_regs *regs)
+{
+ int *brightness = (int *)ri->data;
+ struct backlight_device *bd;
+
+ bd = (struct backlight_device *)swap_get_karg(regs, 0);
+ *brightness = bd->props.brightness;
+
+ return 0;
+}
+
+static int ret_handler_set_backlight(struct kretprobe_instance *ri,
+ struct pt_regs *regs)
+{
+ int ret = regs_return_value(regs);
+ int *brightness = (int *)ri->data;
+
+ if (!ret && s6e8aa0_ops.notifier)
+ s6e8aa0_ops.notifier(&s6e8aa0_ops, LAT_BRIGHTNESS,
+ (void *)*brightness);
+
+ return 0;
+}
return -ENOMEM;
memcpy(insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
- ainsn.insn_arm = ainsn.insn = insn;
+ ainsn.insn = insn;
ret = arch_check_insn_arm(insn[0]);
if (!ret) {
p->opcode = *p->addr;
struct arch_specific_insn {
/* copy of the original instruction */
kprobe_opcode_t *insn;
- kprobe_opcode_t *insn_arm;
- kprobe_opcode_t *insn_thumb;
};
typedef kprobe_opcode_t (*entry_point_t) (unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
DBPRINTF ("val = %ld, data = 0x%X", val, (unsigned int) data);
- if (args->regs && user_mode_vm(args->regs))
+ if (args->regs == NULL || user_mode_vm(args->regs))
return ret;
DBPRINTF ("switch (val) %lu %d %d", val, DIE_INT3, DIE_TRAP);
DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
static DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
-DEFINE_SPINLOCK(kretprobe_lock); /* Protects kretprobe_inst_table */
-EXPORT_SYMBOL_GPL(kretprobe_lock);
+static DEFINE_SPINLOCK(kretprobe_lock); /* Protects kretprobe_inst_table */
static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL;
struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
* and add it to the address. That way the addr
* field can either be global or relative to a symbol.
*/
- if (p->symbol_name)
+ if (p->symbol_name) {
+ if (p->addr)
+ return -EINVAL;
p->addr = (kprobe_opcode_t *)swap_ksyms(p->symbol_name);
+ }
if (!p->addr)
return -EINVAL;
return ret;
}
-void dbi_unregister_kprobe(struct kprobe *p)
+static void dbi_unregister_valid_kprobe(struct kprobe *p, struct kprobe *old_p)
{
- struct kprobe *old_p, *list_p;
- int cleanup_p;
-
- old_p = get_kprobe(p->addr);
- DBPRINTF ("dbi_unregister_kprobe p=%p old_p=%p", p, old_p);
- if (unlikely (!old_p))
- return;
+ struct kprobe *list_p;
- if (p != old_p) {
- list_for_each_entry_rcu(list_p, &old_p->list, list)
- if (list_p == p)
- /* kprobe p is a valid probe */
- goto valid_p;
- return;
- }
-
-valid_p:
- DBPRINTF ("dbi_unregister_kprobe valid_p");
if ((old_p == p) || ((old_p->pre_handler == aggr_pre_handler) &&
(p->list.next == &old_p->list) && (p->list.prev == &old_p->list))) {
/* Only probe on the hash list */
arch_disarm_kprobe(p);
hlist_del_rcu(&old_p->hlist);
- cleanup_p = 1;
- } else {
- list_del_rcu(&p->list);
- cleanup_p = 0;
- }
- DBPRINTF ("dbi_unregister_kprobe cleanup_p=%d", cleanup_p);
- if (cleanup_p) {
- if (p != old_p) {
- list_del_rcu(&p->list);
+ if (p != old_p)
kfree(old_p);
- }
-
- if (!in_atomic()) {
- synchronize_sched();
- }
-
- remove_kprobe(p);
+ /* Synchronize and remove probe in bottom */
} else {
+ list_del_rcu(&p->list);
+
if (p->break_handler)
old_p->break_handler = NULL;
if (p->post_handler) {
- list_for_each_entry_rcu(list_p, &old_p->list, list) {
- if (list_p->post_handler) {
- cleanup_p = 2;
- break;
- }
- }
-
- if (cleanup_p == 0)
- old_p->post_handler = NULL;
+ list_for_each_entry_rcu(list_p, &old_p->list, list)
+ if (list_p->post_handler)
+ return;
+
+ old_p->post_handler = NULL;
}
}
+ /* Set NULL addr for reusability if symbol_name is used */
+ if (p->symbol_name)
+ p->addr = NULL;
+}
+
+void dbi_unregister_kprobe(struct kprobe *kp)
+{
+ struct kprobe *old_p, *list_p;
+
+ old_p = get_kprobe(kp->addr);
+ if (unlikely (!old_p))
+ return;
+
+ if (kp != old_p) {
+ list_for_each_entry_rcu(list_p, &old_p->list, list)
+ if (list_p == kp)
+ /* kprobe p is a valid probe */
+ dbi_unregister_valid_kprobe(kp, old_p);
+ return;
+ }
+
+ dbi_unregister_valid_kprobe(kp, old_p);
}
int dbi_register_jprobe(struct jprobe *jp)
static void dbi_unregister_kretprobe_top(struct kretprobe *rp)
{
- unsigned long flags;
struct kretprobe_instance *ri;
DECLARE_NODE_PTR_FOR_HLIST(node);
dbi_unregister_kprobe(&rp->kp);
- /* No race here */
- spin_lock_irqsave(&kretprobe_lock, flags);
-
swap_hlist_for_each_entry(ri, node, &rp->used_instances, uflist) {
if (!dbi_disarm_krp_inst(ri)) {
printk("%s (%d/%d): cannot disarm krp instance (%08lx)\n",
(unsigned long)rp->kp.addr);
}
}
- spin_unlock_irqrestore(&kretprobe_lock, flags);
}
static void dbi_unregister_kretprobe_bottom(struct kretprobe *rp)
unsigned long flags;
struct kretprobe_instance *ri;
+ if (list_empty(&rp->kp.list))
+ remove_kprobe(&rp->kp);
+
spin_lock_irqsave(&kretprobe_lock, flags);
+
while ((ri = get_used_rp_inst(rp)) != NULL) {
recycle_rp_inst(ri);
}
- spin_unlock_irqrestore(&kretprobe_lock, flags);
free_rp_inst(rp);
+
+ spin_unlock_irqrestore(&kretprobe_lock, flags);
+}
+
+void dbi_unregister_kretprobes(struct kretprobe **rpp, size_t size)
+{
+ size_t i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&kretprobe_lock, flags);
+
+ for (i = 0; i < size; i++)
+ dbi_unregister_kretprobe_top(rpp[i]);
+
+ spin_unlock_irqrestore(&kretprobe_lock, flags);
+
+ if (!in_atomic())
+ synchronize_sched();
+
+ for (i = 0; i < size; i++)
+ dbi_unregister_kretprobe_bottom(rpp[i]);
}
void dbi_unregister_kretprobe(struct kretprobe *rp)
{
- dbi_unregister_kretprobe_top(rp);
- dbi_unregister_kretprobe_bottom(rp);
+ dbi_unregister_kretprobes(&rp, 1);
}
struct kretprobe *clone_kretprobe(struct kretprobe *rp)
EXPORT_SYMBOL_GPL(dbi_unregister_jprobe);
EXPORT_SYMBOL_GPL(dbi_jprobe_return);
EXPORT_SYMBOL_GPL(dbi_register_kretprobe);
+EXPORT_SYMBOL_GPL(dbi_unregister_kretprobes);
EXPORT_SYMBOL_GPL(dbi_unregister_kretprobe);
MODULE_LICENSE("Dual BSD/GPL");
int alloc_nodes_kretprobe(struct kretprobe *rp);
int dbi_register_kretprobe (struct kretprobe *rp);
void dbi_unregister_kretprobe (struct kretprobe *rp);
+void dbi_unregister_kretprobes(struct kretprobe **rpp, size_t size);
void kretprobe_assert (struct kretprobe_instance *ri,
unsigned long orig_ret_address, unsigned long trampoline_address);
#endif
extern DEFINE_PER_CPU (struct kprobe *, current_kprobe);
-extern spinlock_t kretprobe_lock;
extern struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
//extern struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE];
extern atomic_t kprobe_count;
#include <linux/module.h>
+#include <linux/slab.h>
+
#include <asm/errno.h>
#include <ksyms/ksyms.h>
#include <kprobe/dbi_kprobes.h>
return ret;
}
+
static int unregister_syscall(size_t id)
{
printk("unregister_syscall: %s\n", get_sys_name(id));
return 0;
}
+static int unregister_multiple_syscalls(size_t *id_p, size_t cnt)
+{
+ struct kretprobe **rpp;
+ const size_t end = ((size_t) 0) - 1;
+ size_t i = 0, id;
+ int ret = 0;
+
+ if (cnt == 1)
+ return unregister_syscall(id_p[0]);
+
+ --cnt;
+
+ rpp = kmalloc(GFP_KERNEL, sizeof(&(((struct ks_probe *) 0)->rp)) * cnt);
+ if (rpp == NULL) {
+ for (; cnt != end; --cnt) {
+ ret = unregister_syscall(id_p[cnt]);
+ if (ret)
+ return ret;
+ }
+ return ret;
+ }
+
+ for (; cnt != end; --cnt) {
+ id = id_p[cnt];
+ if (ksp[id].rp.kp.addr != NULL) {
+ rpp[i] = &ksp[id].rp;
+ ++i;
+ }
+ }
+
+ dbi_unregister_kretprobes(rpp, i);
+ kfree(rpp);
+
+ return 0;
+}
+
static void set_pst(struct feature *f, size_t id)
{
ksp[id].sub_type |= f->sub_type;
static void do_uninstall_features(struct feature *f, size_t i)
{
int ret;
+ size_t *id_p;
size_t id;
+ size_t cnt = 0;
const size_t end = ((size_t) 0) - 1;
+ id_p = kmalloc(GFP_KERNEL, sizeof(id) * (i + 1));
+ /* NULL check is below in loop */
+
for (; i != end; --i) {
id = f->feature_list[i];
if (get_counter(id) == 0) {
printk("syscall %s not installed\n",
get_sys_name(id));
+ kfree(id_p);
BUG();
}
dec_counter(id);
if (get_counter(id) == 0) {
- ret = unregister_syscall(id);
- if (ret)
- printk("syscall %s uninstall error, ret=%d\n",
- get_sys_name(id), ret);
-
+ if (id_p != NULL) {
+ id_p[cnt] = id;
+ ++cnt;
+ } else {
+ ret = unregister_syscall(id);
+ if (ret)
+ printk("syscall %s uninstall error, ret=%d\n",
+ get_sys_name(id), ret);
+ }
}
unset_pst(f, id);
}
+
+ if (id_p != NULL) {
+ unregister_multiple_syscalls(id_p, cnt);
+ kfree(id_p);
+ }
}
static int do_install_features(struct feature *f)
ret = -EINVAL;
goto unlock;
}
-
do_uninstall_features(f, f->cnt - 1);
-
f->enable = 0;
unlock:
mutex_unlock(&mutex_features);
+
return ret;
}
int get_string(struct msg_buf *mb, char **str)
{
size_t len, len_max;
+ enum { min_len_str = 1 };
- len_max = mb->end - mb->ptr - 1;
- if(len_max < 0)
+ if (cmp_mb(mb, min_len_str) < 0)
return -EINVAL;
- len = strlen(mb->ptr) + 1;
+ len_max = remained_mb(mb) - 1;
+ len = strnlen(mb->ptr, len_max);
- *str = kmalloc(len, GFP_KERNEL);
+ *str = kmalloc(len + 1, GFP_KERNEL);
if (*str == NULL)
return -ENOMEM;
memcpy(*str, mb->ptr, len);
- mb->ptr += len;
+ (*str)[len] = '\0';
+
+ mb->ptr += len + 1;
print_parse_debug("str->'%s'\n", *str);
return 0;
switch (app_type) {
case AT_TIZEN_NATIVE_APP:
+ case AT_TIZEN_WEB_APP:
case AT_COMMON_EXEC:
ai->tgid = 0;
break;
case AT_PID: {
- u32 tgid;
- ret = str_to_u32(ta_id, &tgid);
- if (ret) {
- print_err("converting string to PID, str='%s'\n", ta_id);
- goto free_ai;
+ u32 tgid = 0;
+
+ if (*ta_id != '\0') {
+ ret = str_to_u32(ta_id, &tgid);
+ if (ret) {
+ print_err("converting string to PID, "
+ "str='%s'\n", ta_id);
+ goto free_ai;
+ }
}
ai->tgid = tgid;
print_parse_debug("func count:");
if (get_u32(mb, &cnt)) {
print_err("failed to read count of functions\n");
- return NULL;
+ goto free_path;
}
if (remained_mb(mb) / MIN_SIZE_FUNC_INST < cnt) {
print_err("to match count of functions(%u)\n", cnt);
- return NULL;
+ goto free_path;
}
li = kmalloc(sizeof(*li), GFP_KERNEL);
enum APP_TYPE {
AT_TIZEN_NATIVE_APP = 0x01,
AT_PID = 0x02,
- AT_COMMON_EXEC = 0x03
+ AT_COMMON_EXEC = 0x03,
+ AT_TIZEN_WEB_APP = 0x04
};
enum {
struct msg_buf mb;
void __user *payload;
struct basic_msg_fmt bmf;
+ enum { size_max = 128 * 1024 * 1024 };
ret = copy_from_user(&bmf, (void*)msg, sizeof(bmf));
if (ret)
return ret;
size = bmf.len;
+ if (size >= size_max) {
+ printk("%s: too large message, size=%u\n", __func__, size);
+ return -ENOMEM;
+ }
+
ret = init_mb(&mb, size);
if (ret)
return ret;
switch (app_info->app_type) {
case AT_PID:
+ if (app_info->tgid == 0)
+ goto pf_dentry;
+
*pfg = get_pf_group_by_tgid(app_info->tgid, dentry);
break;
case AT_TIZEN_NATIVE_APP:
+ case AT_TIZEN_WEB_APP:
case AT_COMMON_EXEC:
+ pf_dentry:
*pfg = get_pf_group_by_dentry(dentry, dentry);
break;
default:
struct die_args *args = (struct die_args *)data;
int ret = NOTIFY_DONE;
- if (args->regs && !user_mode_vm(args->regs))
+ if (args->regs == NULL || !user_mode_vm(args->regs))
return ret;
switch (val) {
unsigned long flag,
unsigned long offset)
{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
unsigned long populate;
return do_mmap_pgoff(filp, addr, len, prot, flag, offset, &populate);
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) */
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+ return do_mmap_pgoff(filp, addr, len, prot, flag, offset);
+#else
return do_mmap(filp, addr, len, prot, flag, offset);
#endif
}