inline static void target_freq(struct cpufreq_policy *policy, struct greenmax_info_s *this_greenmax, int new_freq, int old_freq, int prefered_relation) { int index, target; struct cpufreq_frequency_table *table = this_greenmax->freq_table; unsigned int cpu = this_greenmax->cpu; dprintk(GREENMAX_DEBUG_ALG, "%d: %s\n", old_freq, __func__); // apply policy limits - just to be sure new_freq = validate_freq(policy, new_freq); if (!cpufreq_frequency_table_target(policy, table, new_freq, prefered_relation, &index)) { target = table[index].frequency; if (target == old_freq) { // if for example we are ramping up to *at most* current + ramp_up_step // but there is no such frequency higher than the current, try also // to ramp up to *at least* current + ramp_up_step. if (new_freq > old_freq && prefered_relation == CPUFREQ_RELATION_H && !cpufreq_frequency_table_target(policy, table, new_freq, CPUFREQ_RELATION_L, &index)) target = table[index].frequency; // simlarly for ramping down: else if (new_freq < old_freq && prefered_relation == CPUFREQ_RELATION_L && !cpufreq_frequency_table_target(policy, table, new_freq, CPUFREQ_RELATION_H, &index)) target = table[index].frequency; } // no change if (target == old_freq) return; } else { dprintk(GREENMAX_DEBUG_ALG, "frequency change failed\n"); return; } dprintk(GREENMAX_DEBUG_JUMPS, "%d: jumping to %d (%d) cpu %d\n", old_freq, new_freq, target, cpu); __cpufreq_driver_target(policy, target, prefered_relation); // remember last time we changed frequency this_greenmax->freq_change_time = ktime_to_us(ktime_get()); }
static int set_parameters(struct quadd_parameters *p, uid_t *debug_app_uid) { int i, err, uid = 0; int pmu_events_id[QUADD_MAX_COUNTERS]; int pl310_events_id; int nr_pmu = 0, nr_pl310 = 0; struct task_struct *task; unsigned int extra; u64 *low_addr_p; if (!validate_freq(p->freq)) { pr_err("%s: incorrect frequency: %u\n", __func__, p->freq); return -EINVAL; } ctx.param.freq = p->freq; ctx.param.ma_freq = p->ma_freq; ctx.param.backtrace = p->backtrace; ctx.param.use_freq = p->use_freq; ctx.param.system_wide = p->system_wide; ctx.param.power_rate_freq = p->power_rate_freq; ctx.param.debug_samples = p->debug_samples; for (i = 0; i < ARRAY_SIZE(p->reserved); i++) ctx.param.reserved[i] = p->reserved[i]; /* Currently only one process */ if (p->nr_pids != 1) return -EINVAL; p->package_name[sizeof(p->package_name) - 1] = '\0'; rcu_read_lock(); task = pid_task(find_vpid(p->pids[0]), PIDTYPE_PID); rcu_read_unlock(); if (!task) { pr_err("Process not found: %u\n", p->pids[0]); return -ESRCH; } pr_info("owner/task uids: %u/%u\n", current_fsuid(), task_uid(task)); if (!capable(CAP_SYS_ADMIN)) { if (current_fsuid() != task_uid(task)) { uid = quadd_auth_is_debuggable((char *)p->package_name); if (uid < 0) { pr_err("Error: QuadD security service\n"); return uid; } else if (uid == 0) { pr_err("Error: app is not debuggable\n"); return -EACCES; } *debug_app_uid = uid; pr_info("debug_app_uid: %u\n", uid); } ctx.collect_kernel_ips = 0; } else { ctx.collect_kernel_ips = 1; } for (i = 0; i < p->nr_pids; i++) ctx.param.pids[i] = p->pids[i]; ctx.param.nr_pids = p->nr_pids; for (i = 0; i < p->nr_events; i++) { int event = p->events[i]; if (ctx.pmu && ctx.pmu_info.nr_supported_events > 0 && is_event_supported(&ctx.pmu_info, event)) { pmu_events_id[nr_pmu++] = p->events[i]; pr_info("PMU active event: %s\n", quadd_get_event_str(event)); } else if (ctx.pl310 && ctx.pl310_info.nr_supported_events > 0 && is_event_supported(&ctx.pl310_info, event)) { pl310_events_id = p->events[i]; pr_info("PL310 active event: %s\n", quadd_get_event_str(event)); if (nr_pl310++ > 1) { pr_err("error: multiply pl310 events\n"); return -EINVAL; } } else { pr_err("Bad event: %s\n", quadd_get_event_str(event)); return -EINVAL; } } if (ctx.pmu) { if (nr_pmu > 0) { err = ctx.pmu->set_events(pmu_events_id, nr_pmu); if (err) { pr_err("PMU set parameters: error\n"); return err; } ctx.pmu_info.active = 1; } else { ctx.pmu_info.active = 0; ctx.pmu->set_events(NULL, 0); } } if (ctx.pl310) { if (nr_pl310 == 1) { err = ctx.pl310->set_events(&pl310_events_id, 1); if (err) { pr_info("pl310 set_parameters: error\n"); return err; } ctx.pl310_info.active = 1; } else { ctx.pl310_info.active = 0; ctx.pl310->set_events(NULL, 0); } } extra = p->reserved[QUADD_PARAM_IDX_EXTRA]; if (extra & QUADD_PARAM_EXTRA_BT_UNWIND_TABLES) pr_info("unwinding: exception-handling tables\n"); if (extra & QUADD_PARAM_EXTRA_BT_FP) pr_info("unwinding: frame pointers\n"); if (extra & QUADD_PARAM_EXTRA_BT_MIXED) pr_info("unwinding: mixed mode\n"); low_addr_p = (u64 *)&p->reserved[QUADD_PARAM_IDX_BT_LOWER_BOUND]; ctx.hrt->low_addr = (unsigned long)*low_addr_p; pr_info("bt lower bound: %#lx\n", ctx.hrt->low_addr); err = quadd_unwind_start(task); if (err) return err; pr_info("New parameters have been applied\n"); return 0; }