120 lines
3.1 KiB
C
120 lines
3.1 KiB
C
|
/* drivers/gud/sec-os-ctrl/sec_os_ctrl.c
|
||
|
*
|
||
|
* Secure OS control driver for Samsung Exynos
|
||
|
*
|
||
|
* Copyright (c) 2014 Samsung Electronics
|
||
|
* http://www.samsungsemi.com/
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License version 2 as
|
||
|
* published by the Free Software Foundation.
|
||
|
*/
|
||
|
|
||
|
#include <linux/module.h>
|
||
|
#include <linux/sysfs.h>
|
||
|
#include <linux/device.h>
|
||
|
#include <linux/mutex.h>
|
||
|
|
||
|
#define DEFAULT_LITTLE_CORE 1
|
||
|
#define DEFAULT_BIG_CORE 6
|
||
|
#define ASCII_TO_DIGIT_NUM(ascii) (ascii - '0')
|
||
|
|
||
|
static unsigned int current_core, new_core;
|
||
|
static DEFINE_MUTEX(sec_os_ctrl_lock);
|
||
|
|
||
|
int nq_switch_core(uint32_t cpu);
|
||
|
uint32_t mc_active_core(void);
|
||
|
|
||
|
static struct bus_type sec_os_ctrl_subsys = {
|
||
|
.name = "sec_os_ctrl",
|
||
|
.dev_name = "sec_os_ctrl",
|
||
|
};
|
||
|
|
||
|
/* Migrate Secure OS */
|
||
|
static ssize_t migrate_os_store(struct kobject *kobj,
|
||
|
struct kobj_attribute *attr, const char *buf, size_t count)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
unsigned int core_num = 0;
|
||
|
|
||
|
/* Select only big or LITTLE */
|
||
|
if ((buf[0] != 'L') && (buf[0] != 'b')) {
|
||
|
pr_err("Invalid core number\n");
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
/* Derive core number */
|
||
|
core_num = ASCII_TO_DIGIT_NUM(buf[1]);
|
||
|
if (buf[0] == 'L') {
|
||
|
if ((buf[1] == 0xA) || (buf[1] == 0x0)) { /* if LF(Line Feed, 0xA) or NULL(0x0) */
|
||
|
new_core = DEFAULT_LITTLE_CORE;
|
||
|
} else if (core_num < 4) { /* From core 0 to core 3 */
|
||
|
new_core = core_num;
|
||
|
} else {
|
||
|
pr_err("[LITTLE] Enter correct core number(0~3)\n");
|
||
|
return count;
|
||
|
}
|
||
|
} else if (buf[0] == 'b') {
|
||
|
if ((buf[1] == 0xA) || (buf[1] == 0x0)) { /* if LF(Line Feed, 0xA) or NULL(0x0) */
|
||
|
new_core = DEFAULT_BIG_CORE;
|
||
|
} else if (core_num < 4) { /* From core 0 to core 3 */
|
||
|
new_core = core_num + 4;
|
||
|
} else {
|
||
|
pr_err("[big] Enter correct core number(0~3)\n");
|
||
|
return count;
|
||
|
}
|
||
|
}
|
||
|
pr_info("Secure OS will be migrated into core [%d]\n", new_core);
|
||
|
|
||
|
if (mutex_lock_interruptible(&sec_os_ctrl_lock)) {
|
||
|
pr_err("Fail to get lock\n");
|
||
|
return count;
|
||
|
}
|
||
|
ret = nq_switch_core(new_core);
|
||
|
mutex_unlock(&sec_os_ctrl_lock);
|
||
|
if (ret != 0) {
|
||
|
pr_err("Secure OS migration is failed!\n");
|
||
|
pr_err("Return value = %d\n", ret);
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
/* The current core where Secure OS is on */
|
||
|
static ssize_t current_core_show(struct kobject *kobj,
|
||
|
struct kobj_attribute *attr, char *buf)
|
||
|
{
|
||
|
current_core = mc_active_core();
|
||
|
|
||
|
return sprintf(buf, "Secure OS is on core [%c%d]\n",
|
||
|
(current_core < 4) ? 'L' : 'b', (current_core & 3));
|
||
|
}
|
||
|
|
||
|
static struct kobj_attribute migrate_os_attr =
|
||
|
__ATTR(migrate_os, 0600, NULL, migrate_os_store);
|
||
|
|
||
|
static struct kobj_attribute current_core_attr =
|
||
|
__ATTR(current_core, 0600, current_core_show, NULL);
|
||
|
|
||
|
static struct attribute *sec_os_ctrl_sysfs_attrs[] = {
|
||
|
&migrate_os_attr.attr,
|
||
|
¤t_core_attr.attr,
|
||
|
NULL,
|
||
|
};
|
||
|
|
||
|
static struct attribute_group sec_os_ctrl_sysfs_group = {
|
||
|
.attrs = sec_os_ctrl_sysfs_attrs,
|
||
|
};
|
||
|
|
||
|
static const struct attribute_group *sec_os_ctrl_sysfs_groups[] = {
|
||
|
&sec_os_ctrl_sysfs_group,
|
||
|
NULL,
|
||
|
};
|
||
|
|
||
|
static int __init sec_os_ctrl_init(void)
|
||
|
{
|
||
|
return subsys_system_register(&sec_os_ctrl_subsys, sec_os_ctrl_sysfs_groups);
|
||
|
}
|
||
|
late_initcall(sec_os_ctrl_init);
|