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());
}
Пример #2
0
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;
}