diff --git a/LICENSE b/LICENSE
index 62471c6ba7452c23970246acb734d955e1d1e717..fc48fd28904f6680c1da24e70d27c7ffb7a31c16 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,5 +1,6 @@
(1) The directories below are licensed under GPL-2.0-or-later.
./newip/
./xpm/
+ ./qos_auth/
As for the specific use of the licenses, please refer to the relevant description in the documents.
diff --git a/OAT.xml b/OAT.xml
index 6056c1f730a3dae9ec3a5aa1bb50e1b7b5b2acb6..9de7aacb31ad265d296ee9139b08fe3783166732 100644
--- a/OAT.xml
+++ b/OAT.xml
@@ -59,8 +59,10 @@ Note:If the text contains special characters, please escape them according to th
+
+
@@ -78,6 +80,7 @@ Note:If the text contains special characters, please escape them according to th
+
diff --git a/qos_auth/README_zh.md b/qos_auth/README_zh.md
new file mode 100644
index 0000000000000000000000000000000000000000..6fb66b509fb4a5276da62e98821e10908710ba74
--- /dev/null
+++ b/qos_auth/README_zh.md
@@ -0,0 +1,71 @@
+## 背景
+
+为支持并发编程框架FFRT的底层调度能力而设计,允许app侧根据业务逻辑在线程间分配调度资源,保障关键任务时延达标,保障用户体验。
+
+涉及到权限下放和调度资源分配,需要内核实现:
+
+1. 高效的能感知状态的app权限管控机制(轻量化权限管控)
+2. 动态的调度资源分配机制(动态多级qos)
+
+## auth_ctrl(Authority Control)模块
+
+轻量化权限管控模块,uid粒度的权限管控,根据app前后台状态动态管控对内核feature接口的访问权限
+
+
+
+## qos_ctrl(Qos Control)模块
+
+动态多级qos模块,提供多种policy(前台/后台/system等),每个policy包含6个qos等级,可以从时间片、调度时延、供给3个维度去更改线程调度行为
+
+
+
+## 目录
+
+```
+├── README_zh.md
+├── apply_qos_auth.sh
+├── figures # ReadMe 内嵌图例
+├── auth_ctl
+│ ├── Kconfig
+│ ├── Makefile
+│ ├── auth_ctrl.c #权限管控主体代码
+│ ├── auth_ctrl.h
+│ ├── auth_qos_debug.c #debug节点主体
+│ ├── qos_ctrl.c #多级qos主体代码
+│ └── qos_ctrl.h
+└── include
+ ├── auth_ctrl.h
+ ├── qos_auth.h
+ ├── qos_ctrl.h
+ └── rtg_auth.h
+```
+
+## QOS_AUTH配置指导
+
+1. 权限管控使能`CONFIG_AUTHORITY_CTRL=y`
+2. 多级qos使能`CONFIG_QOS_CTRL=y`
+3. RTG鉴权使能`CONFIG_RTG_AUTHORITY=y`
+4. qos鉴权使能`CONFIG_QOS_AUTHORITY=y`
+5. Debug节点使能`CONFIG_AUTH_QOS_DEBUG=y`
+6. Qos策略数量限制`CONFIG_QOS_POLICY_MAX_NR=5`,范围[5, 20]
+
+qos成功设置的宏依赖:
+
+```
+# 时延控制
+CONFIG_SCHED_LATENCY_NICE=y
+
+# 供给
+CONFIG_UCLAMP_TASK=y
+CONFIG_UCLAMP_BUCKETS_COUNT=20
+CONFIG_UCLAMP_TASK_GROUP=y
+```
+
+## 相关仓
+
+
+[kernel_linux_5.10](https://gitee.com/openharmony/kernel_linux_5.10)
+
+[kernel_linux_config](https://gitee.com/openharmony/kernel_linux_config)
+
+[device_board_hihope](https://gitee.com/openharmony/device_board_hihope)https://gitee.com/openharmony/device_board_hihope)
\ No newline at end of file
diff --git a/qos_auth/apply_qos_auth.sh b/qos_auth/apply_qos_auth.sh
new file mode 100644
index 0000000000000000000000000000000000000000..77860cad417912504a61aae9600b25ed5405fd2b
--- /dev/null
+++ b/qos_auth/apply_qos_auth.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2023 Huawei Device Co., Ltd.
+#
+
+set -e
+
+OHOS_SOURCE_ROOT=$1
+KERNEL_BUILD_ROOT=$2
+PRODUCT_NAME=$3
+KERNEL_VERSION=$4
+QOS_AUTH_SOURCE_ROOT=$OHOS_SOURCE_ROOT/kernel/linux/common_modules/qos_auth
+
+function main()
+{
+ pushd .
+
+ cd $KERNEL_BUILD_ROOT/include/linux/sched
+ ln -sf $(realpath --relative-to=$KERNEL_BUILD_ROOT/include/linux/sched $QOS_AUTH_SOURCE_ROOT/include)/*.h ./
+
+ if [ ! -d "$KERNEL_BUILD_ROOT/drivers/auth_ctl" ]; then
+ mkdir $KERNEL_BUILD_ROOT/drivers/auth_ctl
+ fi
+
+ cd $KERNEL_BUILD_ROOT/drivers/auth_ctl
+ ln -sf $(realpath --relative-to=$KERNEL_BUILD_ROOT/drivers/auth_ctl $QOS_AUTH_SOURCE_ROOT/auth_ctl)/* ./
+
+ popd
+}
+
+main
diff --git a/qos_auth/auth_ctl/Kconfig b/qos_auth/auth_ctl/Kconfig
new file mode 100644
index 0000000000000000000000000000000000000000..84182a28e6a790648b1d6fe5f3e69ddc864680da
--- /dev/null
+++ b/qos_auth/auth_ctl/Kconfig
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: GPL-2.0
+config AUTHORITY_CTRL
+ tristate "Authority Control for RTG & QOS"
+ default n
+ help
+ Control thread's authority for specific kenrel feature such as RTG
+ or QOS. Use uid as the authentication granularity. Status switching
+ will change uid's authority, and would trigger additional actions
+ registered by specific kernel feature.
+
+config QOS_CTRL
+ bool "Multiple Level Qos Control for thread"
+ default n
+ depends on AUTHORITY_CTRL
+ help
+ If set, thread can apply qos for less execution latency and get more
+ cpu supply. Permission and absolute supply aggressiveness was controlled
+ by AUTHORITY_CTRL.
+
+config RTG_AUTHORITY
+ bool "Authority Control for SCHED_RTG_FRAME"
+ default n
+ depends on AUTHORITY_CTRL
+ depends on SCHED_RTG_FRAME
+ help
+ Authority control for SCHED_RTG_FRAME. If set, access to SCHED_RTG_FRAME's
+ ioctl cmd will be restricted.
+
+config QOS_AUTHORITY
+ bool "Authority Control for QOS_CTRL"
+ default n
+ depends on AUTHORITY_CTRL
+ depends on QOS_CTRL
+ help
+ Authority control for QOS_CTRL. If set, access to QOS_CTRL's ioctl cmd will
+ be restricted.
+
+config AUTH_QOS_DEBUG
+ bool "Debug fs for qos_ctrl and auth_ctrl"
+ default n
+ depends on AUTHORITY_CTRL
+ depends on RTG_AUTHORITY
+ depends on QOS_AUTHORITY
+ help
+ If set, debug node will show auth and qos info
+
+config QOS_POLICY_MAX_NR
+ int "Number of supported qos policy"
+ range 5 20
+ default 5
+ depends on QOS_CTRL
+ help
+ Qos policy number limit. Truly initialized qos policy could small then
+ this value.
+
diff --git a/qos_auth/auth_ctl/Makefile b/qos_auth/auth_ctl/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..548ec4535ec2f4d29255b04aa06cf4ec7be33509
--- /dev/null
+++ b/qos_auth/auth_ctl/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_AUTHORITY_CTRL) += auth_qos_ctrl.o
+auth_qos_ctrl-$(CONFIG_AUTHORITY_CTRL) += auth_ctrl.o
+auth_qos_ctrl-$(CONFIG_QOS_CTRL) += qos_ctrl.o
+auth_qos_ctrl-$(CONFIG_AUTH_QOS_DEBUG) += auth_qos_debug.o
diff --git a/qos_auth/auth_ctl/auth_ctrl.c b/qos_auth/auth_ctl/auth_ctrl.c
new file mode 100644
index 0000000000000000000000000000000000000000..944535cefd0dfabfdebeaa9114c4a656af982229
--- /dev/null
+++ b/qos_auth/auth_ctl/auth_ctrl.c
@@ -0,0 +1,588 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * drivers/auth_ctl/auth_ctrl.c
+ *
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "auth_ctrl.h"
+#ifdef CONFIG_QOS_CTRL
+#include "qos_ctrl.h"
+#endif
+
+typedef long (*auth_ctrl_func)(struct file *file, void __user *arg);
+
+static long ctrl_auth_basic_operation(struct file *file, void __user *uarg);
+
+static auth_ctrl_func g_func_array[AUTH_CTRL_MAX_NR] = {
+ NULL, /* reserved */
+ ctrl_auth_basic_operation,
+};
+
+/*
+ * uid-based authority idr table
+ */
+static struct idr *ua_idr;
+
+struct idr *get_auth_ctrl_idr(void)
+{
+ return ua_idr;
+}
+
+static DEFINE_MUTEX(ua_idr_mutex);
+
+struct mutex *get_auth_idr_mutex(void)
+{
+ return &ua_idr_mutex;
+}
+
+static struct auth_struct auth_super;
+
+/*
+ * change auth's status to SYSTEM and enable all feature access
+ */
+static void change_to_super(struct auth_struct *auth)
+{
+#ifdef CONFIG_RTG_AUTHORITY
+ auth->rtg_auth_flag = AF_RTG_ALL;
+#endif
+#ifdef CONFIG_QOS_AUTHORITY
+ auth->qos_auth_flag = AF_QOS_ALL;
+#endif
+ auth->status = AUTH_STATUS_SYSTEM_SERVER;
+}
+
+static void init_authority_record(struct auth_struct *auth)
+{
+#ifdef CONFIG_QOS_AUTHORITY
+ int i;
+#endif
+
+#ifdef CONFIG_RTG_AUTHORITY
+ auth->rtg_auth_flag = 0;
+#endif
+#ifdef CONFIG_QOS_AUTHORITY
+ auth->qos_auth_flag = 0;
+#endif
+ auth->status = AUTH_STATUS_DISABLED;
+ mutex_init(&auth->mutex);
+ refcount_set(&auth->usage, 1);
+#ifdef CONFIG_QOS_CTRL
+ for (i = QOS_POLICY_MIN_LEVEL; i < NR_QOS; ++i) {
+ INIT_LIST_HEAD(&auth->tasks[i]);
+ auth->num[i] = 0;
+ }
+#endif
+}
+
+void get_auth_struct(struct auth_struct *auth)
+{
+ refcount_inc(&auth->usage);
+}
+
+static void __put_auth_struct(struct auth_struct *auth)
+
+{
+ WARN_ON(auth->status != AUTH_STATUS_DEAD);
+ WARN_ON(refcount_read(&auth->usage));
+
+#ifdef CONFIG_QOS_CTRL
+ /* refcount is zero here, no contend, no lock. */
+ remove_qos_tasks(auth);
+#endif
+ kfree(auth);
+}
+
+void put_auth_struct(struct auth_struct *auth)
+{
+ if (refcount_dec_and_test(&auth->usage))
+ __put_auth_struct(auth);
+}
+
+static int init_authority_control(void)
+{
+ int ret;
+
+ ua_idr = kzalloc(sizeof(*ua_idr), GFP_ATOMIC);
+ if (ua_idr == NULL) {
+ pr_err("[AUTH_CTRL] auth idr init failed, no memory!\n");
+ return -ENOMEM;
+ }
+
+ idr_init(ua_idr);
+
+ init_authority_record(&auth_super);
+ change_to_super(&auth_super);
+
+ ret = idr_alloc(ua_idr, &auth_super, SUPER_UID, SUPER_UID + 1, GFP_ATOMIC);
+ if (ret != SUPER_UID) {
+ pr_err("[AUTH_CTRL] authority for super init failed! ret=%d\n", ret);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ idr_destroy(ua_idr);
+ kfree(ua_idr);
+
+ return ret;
+}
+
+int authority_remove_handler(int id, void *p, void *para)
+{
+ struct auth_struct *auth = (struct auth_struct *)p;
+
+ mutex_lock(&auth->mutex);
+#ifdef CONFIG_QOS_CTRL
+ qos_switch(auth, AUTH_STATUS_DISABLED);
+#endif
+ auth->status = AUTH_STATUS_DEAD;
+ mutex_unlock(&auth->mutex);
+ put_auth_struct(auth);
+
+ return 0;
+}
+
+void remove_authority_control(void)
+{
+ int ret;
+
+ mutex_lock(&ua_idr_mutex);
+ ret = idr_for_each(ua_idr, authority_remove_handler, NULL);
+ if (ret < 0)
+ pr_err("[AUTH_CTRL] authority item remove failed\n");
+
+ idr_destroy(ua_idr);
+ kfree(ua_idr);
+
+ mutex_unlock(&ua_idr_mutex);
+}
+
+/*
+ * constrain user assigned auth_flag to kernel accepted auth_flag
+ */
+static int generic_auth_trim(unsigned int orig_flag, unsigned int constrain)
+{
+ return orig_flag & constrain;
+}
+
+static inline void set_auth_flag(struct auth_ctrl_data *data, struct auth_struct *auth_to_enable)
+{
+#ifdef CONFIG_RTG_AUTHORITY
+ auth_to_enable->rtg_auth_flag = generic_auth_trim(data->rtg_ua_flag, AF_RTG_DELEGATED);
+#endif
+#ifdef CONFIG_QOS_AUTHORITY
+ auth_to_enable->qos_auth_flag = generic_auth_trim(data->qos_ua_flag, AF_QOS_ALL);
+#endif
+}
+
+static int auth_enable(struct auth_ctrl_data *data)
+{
+ struct auth_struct *auth_to_enable;
+ unsigned int uid = data->uid;
+ int status = data->status;
+ int ret;
+
+ mutex_lock(&ua_idr_mutex);
+ auth_to_enable = idr_find(ua_idr, uid);
+ /* auth exist, just resume the task's qos request */
+ if (auth_to_enable) {
+ get_auth_struct(auth_to_enable);
+ mutex_unlock(&ua_idr_mutex);
+
+ mutex_lock(&auth_to_enable->mutex);
+ if (auth_to_enable->status == AUTH_STATUS_DEAD) {
+ mutex_unlock(&auth_to_enable->mutex);
+ put_auth_struct(auth_to_enable);
+ return -INVALID_AUTH;
+ }
+
+ set_auth_flag(data, auth_to_enable);
+#ifdef CONFIG_QOS_CTRL
+ qos_switch(auth_to_enable, status);
+#endif
+ auth_to_enable->status = status;
+ mutex_unlock(&auth_to_enable->mutex);
+ ret = 0;
+ put_auth_struct(auth_to_enable);
+ goto out;
+ }
+
+ /* auth not exist, build a new auth, then insert to idr */
+ auth_to_enable = kzalloc(sizeof(*auth_to_enable), GFP_ATOMIC);
+ if (!auth_to_enable) {
+ mutex_unlock(&ua_idr_mutex);
+ pr_err("[AUTH_CTRL] alloc auth data failed, no memory!\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ init_authority_record(auth_to_enable);
+
+ /* no one could get the auth from idr now, no need to lock */
+ set_auth_flag(data, auth_to_enable);
+ auth_to_enable->status = status;
+
+ ret = idr_alloc(ua_idr, auth_to_enable, uid, uid + 1, GFP_ATOMIC);
+ if (ret < 0) {
+ pr_err("[AUTH_CTRL] add auth to idr failed, no memory!\n");
+ kfree(auth_to_enable);
+ }
+
+ mutex_unlock(&ua_idr_mutex);
+
+out:
+ return ret;
+}
+
+static int auth_delete(struct auth_ctrl_data *data)
+{
+ struct auth_struct *auth_to_delete;
+ unsigned int uid = data->uid;
+
+ mutex_lock(&ua_idr_mutex);
+ auth_to_delete = (struct auth_struct *)idr_remove(ua_idr, uid);
+ if (!auth_to_delete) {
+ mutex_unlock(&ua_idr_mutex);
+ pr_err("[AUTH_CTRL] no auth data for this uid=%d, delete failed\n", uid);
+ return -UID_NOT_FOUND;
+ }
+ mutex_unlock(&ua_idr_mutex);
+
+ mutex_lock(&auth_to_delete->mutex);
+#ifdef CONFIG_QOS_CTRL
+ qos_switch(auth_to_delete, AUTH_STATUS_DISABLED);
+#endif
+ auth_to_delete->status = AUTH_STATUS_DEAD;
+ mutex_unlock(&auth_to_delete->mutex);
+
+ put_auth_struct(auth_to_delete);
+
+ return 0;
+}
+
+static int auth_get(struct auth_ctrl_data *data)
+{
+ struct auth_struct *auth_to_get;
+ unsigned int uid = data->uid;
+
+ mutex_lock(&ua_idr_mutex);
+ auth_to_get = idr_find(ua_idr, uid);
+ if (!auth_to_get) {
+ mutex_unlock(&ua_idr_mutex);
+ pr_err("[AUTH_CTRL] no auth data for this uid=%d to get\n", uid);
+ return -UID_NOT_FOUND;
+ }
+ get_auth_struct(auth_to_get);
+ mutex_unlock(&ua_idr_mutex);
+
+ mutex_lock(&auth_to_get->mutex);
+ if (auth_to_get->status == AUTH_STATUS_DEAD) {
+ mutex_unlock(&auth_to_get->mutex);
+ put_auth_struct(auth_to_get);
+ return -INVALID_AUTH;
+ }
+#ifdef CONFIG_RTG_AUTHORITY
+ data->rtg_ua_flag = auth_to_get->rtg_auth_flag;
+#endif
+#ifdef CONFIG_QOS_AUTHORITY
+ data->qos_ua_flag = auth_to_get->qos_auth_flag;
+#endif
+ data->status = auth_to_get->status;
+ mutex_unlock(&auth_to_get->mutex);
+
+ put_auth_struct(auth_to_get);
+
+ return 0;
+}
+
+static int auth_switch(struct auth_ctrl_data *data)
+{
+ struct auth_struct *auth;
+ unsigned int uid = data->uid;
+ unsigned int status = data->status;
+
+ if (status == 0 || status >= AUTH_STATUS_MAX_NR) {
+ pr_err("[AUTH_CTRL] not valied status %d\n", status);
+ return -ARG_INVALID;
+ }
+
+ mutex_lock(&ua_idr_mutex);
+ auth = idr_find(ua_idr, uid);
+ if (!auth) {
+ mutex_unlock(&ua_idr_mutex);
+ pr_err("[AUTH_CTRL] no auth data for this uid to switch=%d\n", uid);
+ return -UID_NOT_FOUND;
+ }
+ get_auth_struct(auth);
+ mutex_unlock(&ua_idr_mutex);
+
+ mutex_lock(&auth->mutex);
+ if (auth->status == AUTH_STATUS_DEAD) {
+ mutex_unlock(&auth->mutex);
+ put_auth_struct(auth);
+ return -INVALID_AUTH;
+ }
+
+ set_auth_flag(data, auth);
+#ifdef CONFIG_QOS_CTRL
+ qos_switch(auth, status);
+#endif
+ auth->status = status;
+ mutex_unlock(&auth->mutex);
+
+ put_auth_struct(auth);
+
+ return 0;
+}
+
+typedef int (*auth_manipulate_func)(struct auth_ctrl_data *data);
+
+static auth_manipulate_func auth_func_array[AUTH_MAX_NR] = {
+ /*
+ * auth_enable: Start authority control for specific uid.
+ * auth_delte: End authroity control, remove statistic datas.
+ * auth_get: Get auth info, deprecated.
+ * auth_switch: Change authority flag and status for specific uid.
+ */
+ NULL,
+ auth_enable,
+ auth_delete,
+ auth_get,
+ auth_switch,
+};
+
+static long do_auth_manipulate(struct auth_ctrl_data *data)
+{
+ long ret = 0;
+ unsigned int type = data->type;
+
+ if (type >= AUTH_MAX_NR) {
+ pr_err("[AUTH_CTRL] BASIC_AUTH_CTRL_OPERATION type not valid\n");
+ return -ARG_INVALID;
+ }
+
+ if (auth_func_array[type])
+ ret = (long)(*auth_func_array[type])(data);
+
+ return ret;
+}
+
+static long ctrl_auth_basic_operation(struct file *file, void __user *uarg)
+{
+ struct auth_ctrl_data auth_data;
+ long ret;
+
+ if (copy_from_user(&auth_data, uarg, sizeof(struct auth_ctrl_data))) {
+ pr_err("[AUTH_CTRL] BASIC_AUTH_CTRL_OPERATION copy data failed\n");
+ return -ARG_INVALID;
+ }
+
+ ret = do_auth_manipulate(&auth_data);
+ if (ret < 0) {
+ pr_err("[AUTH_CTRL] BASIC_AUTH_CTRL_OPERATION failed\n");
+ return ret;
+ }
+
+ if (copy_to_user(uarg, &auth_data, sizeof(struct auth_ctrl_data))) {
+ pr_err("[AUTH_CTRL] BASIC_AUTH_CTRL_OPERATION send data failed\n");
+ return -ARG_INVALID;
+ }
+
+ return 0;
+}
+
+long auth_ctrl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ void __user *uarg = (void __user *)arg;
+ unsigned int func_cmd = _IOC_NR(cmd);
+
+ if (uarg == NULL) {
+ pr_err("%s: invalid user uarg\n", __func__);
+ return -EINVAL;
+ }
+
+ if (_IOC_TYPE(cmd) != AUTH_CTRL_IPC_MAGIG) {
+ pr_err("%s: authority ctrl magic fail, TYPE=%d\n",
+ __func__, _IOC_TYPE(cmd));
+ return -EINVAL;
+ }
+
+ if (func_cmd >= AUTH_CTRL_MAX_NR) {
+ pr_err("%s: authority ctrl cmd error, cmd:%d\n",
+ __func__, _IOC_TYPE(cmd));
+ return -EINVAL;
+ }
+
+ if (g_func_array[func_cmd])
+ return (*g_func_array[func_cmd])(file, uarg);
+
+ return -EINVAL;
+}
+
+#define get_authority_flag(func_id) (1 << (func_id - 1))
+
+static inline unsigned int get_true_uid(struct task_struct *p)
+{
+ if (!p)
+ return get_uid(current_user())->uid.val;
+
+ return task_uid(p).val;
+}
+
+/*
+ * Return 1000 for both SYSTEM and ROOT
+ * Return current's uid if p is NULL
+ */
+static inline unsigned int get_authority_uid(struct task_struct *p)
+{
+ unsigned int uid = get_true_uid(p);
+
+ if (super_uid(uid))
+ uid = SUPER_UID;
+
+ return uid;
+}
+
+static unsigned int auth_flag(struct auth_struct *auth, unsigned int type)
+{
+ switch (type) {
+#ifdef CONFIG_RTG_AUTHORITY
+ case RTG_AUTH_FLAG:
+ return auth->rtg_auth_flag;
+#endif
+#ifdef CONFIG_QOS_AUTHORITY
+ case QOS_AUTH_FLAG:
+ return auth->qos_auth_flag;
+#endif
+ default:
+ pr_err("[AUTH_CTRL] not valid auth type\n");
+ return INVALIED_AUTH_FLAG;
+ }
+}
+
+bool check_authorized(unsigned int func_id, unsigned int type)
+{
+ bool authorized = false;
+ struct auth_struct *auth;
+ unsigned int af = get_authority_flag(func_id);
+ unsigned int uid = get_authority_uid(NULL);
+
+ mutex_lock(&ua_idr_mutex);
+ if (!ua_idr) {
+ mutex_unlock(&ua_idr_mutex);
+ pr_err("[AUTH_CTRL] authority idr table missed, auth failed\n");
+ return authorized;
+ }
+
+ auth = (struct auth_struct *)idr_find(ua_idr, uid);
+ if (!auth) {
+ mutex_unlock(&ua_idr_mutex);
+ pr_err("[AUTH_CTRL] no auth data for this uid=%d\n", uid);
+ return authorized;
+ }
+ get_auth_struct(auth);
+ mutex_unlock(&ua_idr_mutex);
+
+ mutex_lock(&auth->mutex);
+ if (auth->status == AUTH_STATUS_DEAD) {
+ mutex_unlock(&auth->mutex);
+ pr_info("[AUTH_CTRL] not valied auth for uid %d\n", uid);
+ put_auth_struct(auth);
+ return authorized;
+ }
+ if (auth && (auth_flag(auth, type) & af))
+ authorized = true;
+
+ mutex_unlock(&auth->mutex);
+
+ put_auth_struct(auth);
+
+ return authorized;
+}
+
+/*
+ * Return authority info for given task
+ * return current's auth if p is NULL
+ * recount will inc if this call return the valid auth
+ * make sure to call put_auth_struct before the calling end
+ */
+struct auth_struct *get_authority(struct task_struct *p)
+{
+ unsigned int uid = get_authority_uid(p);
+ struct auth_struct *auth;
+
+ mutex_lock(&ua_idr_mutex);
+ auth = idr_find(ua_idr, uid);
+ if (auth)
+ get_auth_struct(auth);
+ mutex_unlock(&ua_idr_mutex);
+
+ return auth;
+}
+
+static const struct file_operations auth_ctrl_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = auth_ctrl_ioctl,
+ .compat_ioctl = auth_ctrl_ioctl,
+};
+
+static struct miscdevice auth_ctrl_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "auth_ctrl",
+ .fops = &auth_ctrl_fops,
+};
+
+static __init int auth_ctrl_init_module(void)
+{
+ int err;
+
+ err = misc_register(&auth_ctrl_device);
+ if (err < 0) {
+ pr_err("auth_ctrl register failed\n");
+ return err;
+ }
+
+ pr_info("auth_ctrl init success\n");
+
+ BUG_ON(init_authority_control());
+
+#ifdef CONFIG_QOS_CTRL
+ init_qos_ctrl();
+#endif
+
+ init_sched_auth_debug_procfs();
+
+ return 0;
+}
+
+static void auth_ctrl_exit_module(void)
+{
+ remove_authority_control();
+ misc_deregister(&auth_ctrl_device);
+}
+
+/* module entry points */
+module_init(auth_ctrl_init_module);
+module_exit(auth_ctrl_exit_module);
+
+MODULE_LICENSE("GPL v2");
+
diff --git a/qos_auth/auth_ctl/auth_ctrl.h b/qos_auth/auth_ctl/auth_ctrl.h
new file mode 100644
index 0000000000000000000000000000000000000000..e55c39abee38f547826dcadbc3a356b88b032415
--- /dev/null
+++ b/qos_auth/auth_ctl/auth_ctrl.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * drivers/auth_ctl/auth_ctrl.h
+ *
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ *
+ */
+
+#ifndef __AUTH_CTRL_H
+#define __AUTH_CTRL_H
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+struct auth_struct {
+ struct mutex mutex;
+ refcount_t usage;
+ unsigned int status;
+#ifdef CONFIG_RTG_AUTHORITY
+ unsigned int rtg_auth_flag;
+#endif
+#ifdef CONFIG_QOS_AUTHORITY
+ unsigned int qos_auth_flag;
+#endif
+#ifdef CONFIG_QOS_CTRL
+ unsigned int num[NR_QOS];
+ struct list_head tasks[NR_QOS];
+#endif
+};
+
+/*
+ * for debug fs
+ */
+struct idr *get_auth_ctrl_idr(void);
+struct mutex *get_auth_idr_mutex(void);
+
+#ifdef CONFIG_AUTH_QOS_DEBUG
+int __init init_sched_auth_debug_procfs(void);
+#else
+static inline int init_sched_auth_debug_procfs(void)
+{
+ return 0;
+}
+#endif
+
+#endif /* __AUTH_CTRL_H */
+
diff --git a/qos_auth/auth_ctl/auth_qos_debug.c b/qos_auth/auth_ctl/auth_qos_debug.c
new file mode 100644
index 0000000000000000000000000000000000000000..a627ce47298ffe4ca50118981d51035a363b2cc4
--- /dev/null
+++ b/qos_auth/auth_ctl/auth_qos_debug.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * drivers/auth_ctl/auth_qos_debug.c
+ *
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ *
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "auth_ctrl.h"
+#include "qos_ctrl.h"
+
+#define seq_printf_auth(m, x...) \
+do { \
+ if (m) \
+ seq_printf(m, x); \
+ else \
+ printk(x); \
+} while (0)
+
+static void print_auth_id(struct seq_file *file,
+ const int uid)
+{
+ seq_printf_auth(file, "AUTH_ID :%d\n", uid);
+}
+
+static void print_auth_info(struct seq_file *file,
+ const struct auth_struct *auth)
+{
+ seq_printf_auth(file, "AUTH_STATUS :%d\n", auth->status);
+#ifdef CONFIG_RTG_AUTHORITY
+ seq_printf_auth(file, "RTG_FLAG :%04x\n", auth->rtg_auth_flag);
+#endif
+#ifdef CONFIG_QOS_AUTHORITY
+ seq_printf_auth(file, "QOS_FLAG :%04x\n", auth->qos_auth_flag);
+#endif
+}
+
+static void print_qos_count(struct seq_file *file,
+ const struct auth_struct *auth)
+{
+ int i;
+
+ for (i = QOS_POLICY_MIN_LEVEL; i < NR_QOS; ++i)
+ seq_printf_auth(file, "QOS level %d thread nr :%d\n", i, auth->num[i]);
+}
+
+static void print_qos_thread(struct seq_file *file,
+ const struct auth_struct *auth)
+{
+ struct qos_task_struct *tmp, *next;
+ struct task_struct *p;
+ int i;
+
+ for (i = QOS_POLICY_MIN_LEVEL; i < NR_QOS; ++i) {
+ seq_printf_auth(file, "QOS level %d threads:", i);
+ list_for_each_entry_safe(tmp, next, &auth->tasks[i], qos_list) {
+ p = container_of(tmp, struct task_struct, qts);
+ seq_printf_auth(file, "%d ", p->pid);
+ }
+ seq_printf_auth(file, "\n");
+ }
+
+}
+
+static inline void print_auth_struct(struct seq_file *file, struct auth_struct *auth)
+{
+ print_auth_info(file, auth);
+ seq_printf_auth(file, "\n");
+ print_qos_count(file, auth);
+ seq_printf_auth(file, "\n");
+#ifdef CONFIG_QOS_CTRL
+ print_qos_thread(file, auth);
+#endif
+ seq_printf_auth(file, "---------------------------------------------------------\n");
+
+}
+
+int authority_printf_handler(int id, void *p, void *para)
+{
+ struct auth_struct *auth = (struct auth_struct *)p;
+ struct seq_file *file = (struct seq_file *)para;
+
+ /*
+ * data consistency is not that important here
+ */
+ seq_printf_auth(file, "\n\n");
+ print_auth_id(file, id);
+ seq_printf_auth(file, "\n");
+
+ /* no need to add refcount here, auth must alive in ua_idr_mutex */
+ print_auth_struct(file, auth);
+
+ return 0;
+}
+
+static int sched_auth_debug_show(struct seq_file *file, void *param)
+{
+ struct idr *ua_idr = get_auth_ctrl_idr();
+ struct mutex *ua_idr_mutex = get_auth_idr_mutex();
+ /*
+ * NOTICE:
+ * if mutex in authority_printf_handler, sleep may occur
+ * change ths spin_lock to mutex, or remove mutex in handler
+ */
+
+ mutex_lock(ua_idr_mutex);
+ /* will never return 0 here, auth in ua_idr must alive */
+ idr_for_each(ua_idr, authority_printf_handler, file);
+ mutex_unlock(ua_idr_mutex);
+
+ return 0;
+}
+
+static int sched_auth_debug_release(struct inode *inode, struct file *file)
+{
+ seq_release(inode, file);
+ return 0;
+}
+
+static int sched_auth_debug_open(struct inode *inode, struct file *filp)
+{
+ return single_open(filp, sched_auth_debug_show, NULL);
+}
+
+static const struct proc_ops sched_auth_debug_fops = {
+ .proc_open = sched_auth_debug_open,
+ .proc_read = seq_read,
+ .proc_lseek = seq_lseek,
+ .proc_release = sched_auth_debug_release,
+};
+
+int __init init_sched_auth_debug_procfs(void)
+{
+ struct proc_dir_entry *pe = NULL;
+
+ pe = proc_create("sched_auth_qos_debug",
+ 0400, NULL, &sched_auth_debug_fops);
+ if (unlikely(!pe))
+ return -ENOMEM;
+ return 0;
+}
+
diff --git a/qos_auth/auth_ctl/qos_ctrl.c b/qos_auth/auth_ctl/qos_ctrl.c
new file mode 100644
index 0000000000000000000000000000000000000000..a2816d3417c2c6053fafddd4368ea5ef8c1702cc
--- /dev/null
+++ b/qos_auth/auth_ctl/qos_ctrl.c
@@ -0,0 +1,662 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * drivers/auth_ctl/auth_ctrl.c
+ *
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ *
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "auth_ctrl.h"
+#include "qos_ctrl.h"
+
+typedef long (*qos_ctrl_func)(struct file *file, void __user *uarg);
+
+static long ctrl_qos_operation(struct file *file, void __user *uarg);
+static long ctrl_qos_policy(struct file *file, void __user *uarg);
+
+static qos_ctrl_func g_func_array[QOS_CTRL_MAX_NR] = {
+ NULL, /* reserved */
+ ctrl_qos_operation,
+ ctrl_qos_policy,
+};
+
+static struct qos_policy_map qos_policy_array[QOS_POLICY_MAX_NR];
+
+void remove_qos_tasks(struct auth_struct *auth)
+{
+ int i;
+ struct qos_task_struct *tmp, *next;
+ struct task_struct *p;
+
+ mutex_lock(&auth->mutex);
+ for (i = QOS_POLICY_MIN_LEVEL; i < NR_QOS; ++i) {
+ list_for_each_entry_safe(tmp, next, &auth->tasks[i], qos_list) {
+ p = container_of(tmp, struct task_struct, qts);
+ if (!list_empty(&tmp->qos_list)) {
+ list_del_init(&tmp->qos_list);
+ tmp->in_qos = NO_QOS;
+ put_task_struct(p);
+ }
+ }
+ }
+ mutex_unlock(&auth->mutex);
+}
+
+static void init_sched_attr(struct sched_attr *attr)
+{
+ memset(attr, 0, sizeof(struct sched_attr));
+}
+
+static inline bool is_system(unsigned int uid)
+{
+ return uid == SYSTEM_UID;
+}
+
+/* This function must be called when p is valid. That means the p's refcount must exist */
+static int sched_set_task_qos_attr(struct task_struct *p, int level, int status)
+{
+ struct qos_policy_item *item;
+ struct qos_policy_map *policy_map;
+ struct sched_attr attr;
+
+ read_lock(&qos_policy_array[status].lock);
+ if (!qos_policy_array[status].initialized) {
+ pr_err("[QOS_CTRL] dirty qos policy, pid=%d, uid=%d, status=%d\n",
+ p->pid, p->cred->uid.val, status);
+ read_unlock(&qos_policy_array[status].lock);
+ return -DIRTY_QOS_POLICY;
+ }
+
+ policy_map = &qos_policy_array[status];
+ item = &policy_map->levels[level];
+
+ init_sched_attr(&attr);
+ attr.size = sizeof(struct sched_attr);
+ attr.sched_policy = SCHED_NORMAL;
+
+ if (policy_map->policy_flag & QOS_FLAG_NICE)
+ attr.sched_nice = item->nice;
+
+ if (policy_map->policy_flag & QOS_FLAG_LATENCY_NICE) {
+ attr.sched_flags |= SCHED_FLAG_LATENCY_NICE;
+ attr.sched_latency_nice = item->latency_nice;
+ }
+
+ if ((policy_map->policy_flag & QOS_FLAG_RT) && item->rt_sched_priority) {
+ attr.sched_policy = SCHED_FIFO;
+ attr.sched_flags |= SCHED_FLAG_RESET_ON_FORK;
+ attr.sched_priority = item->rt_sched_priority;
+ }
+
+ read_unlock(&qos_policy_array[status].lock);
+
+ if (unlikely(p->flags & PF_EXITING)) {
+ pr_info("[QOS_CTRL] dying task, no need to set qos\n");
+ return -THREAD_EXITING;
+ }
+
+ return sched_setattr_nocheck(p, &attr);
+}
+
+/*
+ * Switch qos mode when status changed.
+ * Lock auth before calling this function
+ */
+void qos_switch(struct auth_struct *auth, int target_status)
+{
+ int i;
+ int ret;
+ struct task_struct *task;
+ struct qos_task_struct *qts;
+
+ if (!auth) {
+ pr_err("[QOS_CTRL] auth no exist, qos switch failed\n");
+ return;
+ }
+
+ lockdep_assert_held(&auth->mutex);
+
+ if (auth->status == target_status) {
+ pr_info("[QOS_CTRL] same status, no need to switch qos\n");
+ return;
+ }
+
+ for (i = QOS_POLICY_MIN_LEVEL; i < NR_QOS; ++i) {
+ list_for_each_entry(qts, &auth->tasks[i], qos_list) {
+ task = container_of(qts, struct task_struct, qts);
+ ret = sched_set_task_qos_attr(task, i, target_status);
+ if (ret)
+ pr_err("[QOS_CTRL] set qos attr failed, qos switch failed\n");
+ }
+ }
+}
+
+static int qos_insert_task(struct task_struct *p, struct list_head *head, unsigned int level)
+{
+ struct qos_task_struct *qts = &p->qts;
+
+ if (qts->in_qos > NO_QOS) {
+ pr_err("[QOS_CTRL] qos apply still active, no duplicate add\n");
+ return -PID_DUPLICATE;
+ }
+
+ if (likely(list_empty(&qts->qos_list))) {
+ get_task_struct(p);
+ list_add(&qts->qos_list, head);
+ qts->in_qos = level;
+ }
+
+ return 0;
+}
+
+static int qos_remove_task(struct task_struct *p)
+{
+ struct qos_task_struct *qts = (struct qos_task_struct *) &p->qts;
+
+ if (qts->in_qos == NO_QOS) {
+ pr_err("[QOS_CTRL] task not in qos, no need to remove\n");
+ return -PID_NOT_EXIST;
+ }
+
+ if (likely(!list_empty(&qts->qos_list))) {
+ list_del_init(&qts->qos_list);
+ qts->in_qos = NO_QOS;
+ put_task_struct(p);
+ }
+
+ return 0;
+}
+
+static inline bool same_uid(struct task_struct *dude, struct task_struct *bro)
+{
+ return uid_eq(task_uid(dude), task_uid(bro));
+}
+
+static inline bool super_user(struct task_struct *p)
+{
+ return super_uid(task_uid(p).val);
+}
+
+/*
+ * judge permission for changing other tasks' qos
+ */
+static bool can_change_qos(struct task_struct *p)
+{
+ if (p != current && !same_uid(current, p) && !super_user(current)) {
+ pr_err("[QOS_CTRL] %d apply for others not permit\n", p->pid);
+ return false;
+ }
+
+ return true;
+}
+
+int qos_apply(struct qos_ctrl_data *data)
+{
+ unsigned int level = data->level;
+ struct auth_struct *auth;
+ struct task_struct *p;
+ struct qos_task_struct *qts;
+ int pid = data->pid;
+ int ret;
+
+ if (level >= NR_QOS || level == NO_QOS) {
+ pr_err("[QOS_CTRL] no this qos level, qos apply failed\n");
+ ret = -ARG_INVALID;
+ goto out;
+ }
+
+ p = find_get_task_by_vpid((pid_t)pid);
+ if (unlikely(!p)) {
+ pr_err("[QOS_CTRL] no matching task for this pid, qos apply failed\n");
+ ret = -ESRCH;
+ goto out;
+ }
+
+ if (unlikely(p->flags & PF_EXITING)) {
+ pr_info("[QOS_CTRL] dying task, no need to set qos\n");
+ ret = -THREAD_EXITING;
+ goto out_put_task;
+ }
+
+ if (!can_change_qos(p)) {
+ pr_err("[QOS_CTRL] apply for others not permit\n");
+ ret = -ARG_INVALID;
+ goto out_put_task;
+ }
+
+ auth = get_authority(p);
+ if (!auth) {
+ pr_err("[QOS_CTRL] no auth data for pid=%d(%s) this uid=%d, qos apply failed\n",
+ p->pid, p->comm, p->cred->uid.val);
+ put_task_struct(p);
+ ret = -UID_NOT_FOUND;
+ goto out;
+ }
+
+ mutex_lock(&auth->mutex);
+ if (auth->status == AUTH_STATUS_DEAD) {
+ pr_err("[QOS_CTRL] this auth data has been deleted\n");
+ ret = -INVALID_AUTH;
+ goto out_unlock;
+ }
+
+ if (auth->num[level] >= QOS_NUM_MAX) {
+ pr_err("[QOS_CTRL] qos num exceeds limit, cached only\n");
+ ret = -QOS_THREAD_NUM_EXCEED_LIMIT;
+ goto out_unlock;
+ }
+
+ qts = (struct qos_task_struct *) &p->qts;
+
+ /* effective qos must in range [NO_QOS, NR_QOS) */
+ if (qts->in_qos != NO_QOS) {
+ if (qts->in_qos == level) {
+ ret = 0;
+ goto out_unlock;
+ }
+
+ --auth->num[qts->in_qos];
+ qos_remove_task(p);
+ }
+
+ ret = qos_insert_task(p, &auth->tasks[level], level);
+ if (ret < 0) {
+ pr_err("[QOS_CTRL] insert task to qos list %d failed\n", level);
+ goto out_unlock;
+ }
+
+ ++auth->num[level];
+
+ ret = sched_set_task_qos_attr(p, level, auth->status);
+ if (ret) {
+ pr_err("[QOS_CTRL] set qos_level %d for thread %d on status %d failed\n",
+ level, p->pid, auth->status);
+ --auth->num[level];
+ qos_remove_task(p);
+ }
+
+out_unlock:
+ mutex_unlock(&auth->mutex);
+ put_auth_struct(auth);
+out_put_task:
+ put_task_struct(p);
+out:
+ return ret;
+}
+
+int qos_leave(struct qos_ctrl_data *data)
+{
+ unsigned int level;
+ struct auth_struct *auth;
+ struct task_struct *p;
+ struct qos_task_struct *qts;
+ int pid = data->pid;
+ int ret;
+
+ p = find_get_task_by_vpid((pid_t)pid);
+ if (!p) {
+ pr_err("[QOS_CTRL] no matching task for this pid, qos apply failed\n");
+ ret = -ESRCH;
+ goto out;
+ }
+
+ if (unlikely(p->flags & PF_EXITING)) {
+ pr_info("[QOS_CTRL] dying task, no need to set qos\n");
+ ret = -THREAD_EXITING;
+ goto out_put_task;
+ }
+
+ if (!can_change_qos(p)) {
+ pr_err("[QOS_CTRL] apply for others not permit\n");
+ ret = -ARG_INVALID;
+ goto out_put_task;
+ }
+
+ auth = get_authority(p);
+ if (!auth) {
+ pr_err("[QOS_CTRL] no auth data for pid=%d(%s) this uid=%d, qos stop failed\n",
+ p->pid, p->comm, p->cred->uid.val);
+ put_task_struct(p);
+ ret = -UID_NOT_FOUND;
+ goto out;
+ }
+
+ mutex_lock(&auth->mutex);
+
+ qts = (struct qos_task_struct *) &p->qts;
+
+ level = qts->in_qos;
+
+ if (level == NO_QOS) {
+ pr_err("[QOS_CTRL] task not in qos list, qos stop failed\n");
+ ret = -ARG_INVALID;
+ goto out_unlock;
+ }
+
+ if (auth->status == AUTH_STATUS_DEAD) {
+ pr_err("[QOS_CTRL] this auth data has been deleted\n");
+ ret = -INVALID_AUTH;
+ goto out_unlock;
+ }
+
+ ret = qos_remove_task(p);
+ if (ret < 0) {
+ pr_err("[QOS_CTRL] remove task from qos list %d failed\n", level);
+ goto out_unlock;
+ }
+
+ --auth->num[level];
+
+ /*
+ * NO NEED to judge whether current status is AUTH_STATUS_DISABLE.
+ * In the auth destoring context, the removing of thread's sched attr was protected by
+ * auth->mutex, AUTH_STATUS_DISABLED will never appear here.
+ *
+ * The second param 3 means nothing, actually you can use any valid level here, cause the
+ * policy matching AUTH_STATUS_DISABLED has default parameters for all qos level, which can
+ * keep a powerful thread to behave like a ordinary thread.
+ */
+ ret = sched_set_task_qos_attr(p, 3, AUTH_STATUS_DISABLED);
+ if (ret)
+ pr_err("[QOS_CTRL] set qos_level %d for thread %d on status %d to default failed\n",
+ level, p->pid, auth->status);
+
+out_unlock:
+ mutex_unlock(&auth->mutex);
+ put_auth_struct(auth);
+out_put_task:
+ put_task_struct(p);
+out:
+ return ret;
+}
+
+void init_task_qos(struct task_struct *p)
+{
+ struct qos_task_struct *qts = (struct qos_task_struct *) &p->qts;
+
+ INIT_LIST_HEAD(&qts->qos_list);
+ qts->in_qos = NO_QOS;
+}
+
+/*
+ * Remove statistic info in auth when task exit
+ */
+void sched_exit_qos_list(struct task_struct *p)
+{
+ struct auth_struct *auth;
+ struct qos_task_struct *qts = (struct qos_task_struct *) &p->qts;
+
+ /*
+ * For common tasks(the vast majority):
+ * skip get authority, fast return here.
+ *
+ * For qos tasks:
+ * If contend with auth_delete() happens,
+ * 1. function return here, auth_delete() will do the clean up
+ * 2. function go on, either no auth return, either do clean up here
+ * Both cases guarantee data synchronization
+ */
+ if (likely(qts->in_qos == NO_QOS))
+ return;
+
+ auth = get_authority(p);
+ if (!auth)
+ goto out;
+
+ mutex_lock(&auth->mutex);
+ if (qts->in_qos == NO_QOS) {
+ mutex_unlock(&auth->mutex);
+ goto out_put_auth;
+ }
+ --auth->num[qts->in_qos];
+ list_del_init(&qts->qos_list);
+ qts->in_qos = NO_QOS;
+ mutex_unlock(&auth->mutex);
+
+out_put_auth:
+ put_auth_struct(auth);
+out:
+ return;
+}
+
+typedef int (*qos_manipulate_func)(struct qos_ctrl_data *data);
+
+static qos_manipulate_func qos_func_array[QOS_OPERATION_CMD_MAX_NR] = {
+ NULL,
+ qos_apply, //1
+ qos_leave,
+};
+
+static long do_qos_manipulate(struct qos_ctrl_data *data)
+{
+ long ret = 0;
+ unsigned int type = data->type;
+
+ if (type <= 0 || type >= QOS_OPERATION_CMD_MAX_NR) {
+ pr_err("[QOS_CTRL] CMD_ID_QOS_MANIPULATE type not valid\n");
+ return -ARG_INVALID;
+ }
+
+ if (qos_func_array[type])
+ ret = (long)(*qos_func_array[type])(data);
+
+ return ret;
+}
+
+static long ctrl_qos_operation(struct file *file, void __user *uarg)
+{
+ struct qos_ctrl_data qos_data;
+
+ if (copy_from_user(&qos_data, uarg, sizeof(struct qos_ctrl_data))) {
+ pr_err("[QOS_CTRL] CMD_ID_QOS_APPLY copy data failed\n");
+ return -ARG_INVALID;
+ }
+
+ /* transfer user space qos level to kernel space qos level */
+ qos_data.level -= QOS_LEVEL_INTERVAL;
+
+ return do_qos_manipulate(&qos_data);
+}
+
+#define MAX_LATENCY_NICE 19
+#define MIN_LATENCY_NICE -20
+
+static inline bool valid_nice(int nice)
+{
+ return nice >= MIN_NICE && nice <= MAX_NICE;
+}
+
+static inline bool valid_latency_nice(int latency_nice)
+{
+ return latency_nice >= MIN_LATENCY_NICE && latency_nice <= MAX_LATENCY_NICE;
+}
+
+static inline bool valid_uclamp(int uclamp_min, int uclamp_max)
+{
+ if (uclamp_min > uclamp_max)
+ return false;
+ if (uclamp_max > SCHED_CAPACITY_SCALE)
+ return false;
+
+ return true;
+}
+
+static inline bool valid_rt(int sched_priority)
+{
+ if (sched_priority > MAX_USER_RT_PRIO - 1 || sched_priority < 0)
+ return false;
+
+ return true;
+}
+
+static bool valid_qos_flag(unsigned int qos_flag)
+{
+ if (qos_flag & ~QOS_FLAG_ALL)
+ return false;
+
+ return true;
+}
+
+static inline bool valid_qos_item(struct qos_policy_datas *datas)
+{
+ int i;
+ int type = datas->policy_type;
+ struct qos_policy_data *data;
+
+ if (type <= 0 || type >= QOS_POLICY_MAX_NR) {
+ pr_err("[QOS_CTRL] not valid qos policy type, policy change failed\n");
+ goto out_failed;
+ }
+
+ if (!valid_qos_flag(datas->policy_flag)) {
+ pr_err("[QOS_CTRL] not valid qos flag, policy change failed\n");
+ goto out_failed;
+ }
+
+ /* check user space qos polcicy data, level 0 reserved */
+ for (i = 0; i <= NR_QOS; ++i) {
+ data = &datas->policys[i];
+
+ if (!valid_nice(data->nice)) {
+ pr_err("[QOS_CTRL] invalid nice, policy change failed\n");
+ goto out_failed;
+ }
+
+ if (!valid_latency_nice(data->latency_nice)) {
+ pr_err("[QOS_CTRL] invalid latency_nice, policy change failed\n");
+ goto out_failed;
+ }
+
+ if (!valid_uclamp(data->uclamp_min, data->uclamp_max)) {
+ pr_err("[QOS_CTRL] invalid uclamp, policy change failed\n");
+ goto out_failed;
+ }
+
+ if (!valid_rt(data->rt_sched_priority)) {
+ pr_err("[QOS_CTRL] invalid rt, policy change failed\n");
+ goto out_failed;
+ }
+ }
+
+ return true;
+
+out_failed:
+ pr_err("[QOS_CTRL] not valid qos policy params\n");
+ return false;
+}
+
+static long do_qos_policy_change(struct qos_policy_datas *datas)
+{
+ long ret = 0;
+ int i;
+ struct qos_policy_item *item;
+ struct qos_policy_data *data;
+ int type = datas->policy_type;
+
+ if (type >= QOS_POLICY_MAX_NR) {
+ pr_err("[QOS_CTRL] not valid policy type\n");
+ goto out_failed;
+ }
+
+ if (!valid_qos_item(datas))
+ goto out_failed;
+
+ write_lock(&qos_policy_array[type].lock);
+ for (i = QOS_POLICY_MIN_LEVEL; i < NR_QOS; ++i) {
+ item = &qos_policy_array[type].levels[i];
+
+ /* user space policy params */
+ data = &datas->policys[i + QOS_LEVEL_INTERVAL];
+
+ item->nice = data->nice;
+ item->latency_nice = data->latency_nice;
+ item->uclamp_min = data->uclamp_min;
+ item->uclamp_max = data->uclamp_max;
+ /* only specific qos level could use SCHED_FIFO */
+ item->rt_sched_priority = (i < MIN_RT_QOS_LEVEL) ? 0 :
+ data->rt_sched_priority;
+ }
+ qos_policy_array[type].policy_flag = datas->policy_flag;
+ qos_policy_array[type].initialized = true;
+ write_unlock(&qos_policy_array[type].lock);
+
+ return ret;
+
+out_failed:
+ return -ARG_INVALID;
+}
+
+static long ctrl_qos_policy(struct file *file, void __user *uarg)
+{
+ struct qos_policy_datas policy_datas;
+
+ if (copy_from_user(&policy_datas, uarg, sizeof(struct qos_policy_datas))) {
+ pr_err("[QOS_CTRL] CMD_ID_QOS_APPLY copy data failed\n");
+ return -ARG_INVALID;
+ }
+
+ return do_qos_policy_change(&policy_datas);
+}
+
+long do_qos_ctrl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ void __user *uarg = (void __user *)arg;
+ unsigned int func_cmd = _IOC_NR(cmd);
+
+ if (uarg == NULL) {
+ pr_err("%s: invalid user uarg\n", __func__);
+ return -EINVAL;
+ }
+
+ if (_IOC_TYPE(cmd) != QOS_CTRL_IPC_MAGIG) {
+ pr_err("%s: qos ctrl magic fail, TYPE=%d\n",
+ __func__, _IOC_TYPE(cmd));
+ return -EINVAL;
+ }
+
+ if (func_cmd >= QOS_CTRL_MAX_NR) {
+ pr_err("%s: qos ctrl cmd error, cmd:%d\n",
+ __func__, _IOC_TYPE(cmd));
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_QOS_AUTHORITY
+ if (!check_authorized(func_cmd, QOS_AUTH_FLAG)) {
+ pr_err("[QOS_CTRL] %s: uid not authorized\n", __func__);
+ return -UID_NOT_AUTHORIZED;
+ }
+#endif
+
+ if (g_func_array[func_cmd])
+ return (*g_func_array[func_cmd])(file, uarg);
+
+ return -EINVAL;
+}
+
+static void init_qos_policy_array(void)
+{
+ int i;
+
+ /* index 0 reserved */
+ for (i = 1; i < QOS_POLICY_MAX_NR; ++i)
+ rwlock_init(&qos_policy_array[i].lock);
+
+ pr_info("[QOS_CTRL] lock in qos policy initialized\n");
+}
+
+int __init init_qos_ctrl(void)
+{
+ init_qos_policy_array();
+
+ return 0;
+}
+
diff --git a/qos_auth/auth_ctl/qos_ctrl.h b/qos_auth/auth_ctl/qos_ctrl.h
new file mode 100644
index 0000000000000000000000000000000000000000..301f1413d737b209bb1713b55f8f184e08c57044
--- /dev/null
+++ b/qos_auth/auth_ctl/qos_ctrl.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * drivers/auth_ctl/qos_ctrl.h
+ *
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ *
+ */
+
+#ifndef __QOS_CTRL_H
+#define __QOS_CTRL_H
+
+#include "../../kernel/sched/sched.h"
+
+#include
+
+/* qos level interval between user space and kernel space */
+#define QOS_LEVEL_INTERVAL 1
+
+/* min qos level used in kernel space, begin index for LOOP */
+#define QOS_POLICY_MIN_LEVEL (NO_QOS + QOS_LEVEL_INTERVAL)
+
+struct qos_policy_item {
+ int nice;
+ int latency_nice;
+ int uclamp_min;
+ int uclamp_max;
+ int rt_sched_priority;
+};
+
+struct qos_policy_map {
+ rwlock_t lock;
+ bool initialized;
+ unsigned int policy_flag;
+ struct qos_policy_item levels[NR_QOS];
+};
+
+int __init init_qos_ctrl(void);
+
+#endif /* __OQS_CTRL_H */
+
diff --git "a/qos_auth/figures/\345\244\232\347\272\247qos\346\236\266\346\236\204\345\233\276.png" "b/qos_auth/figures/\345\244\232\347\272\247qos\346\236\266\346\236\204\345\233\276.png"
new file mode 100644
index 0000000000000000000000000000000000000000..1d92d90990b5065fafa7a1643b09f6e4ccc99671
Binary files /dev/null and "b/qos_auth/figures/\345\244\232\347\272\247qos\346\236\266\346\236\204\345\233\276.png" differ
diff --git "a/qos_auth/figures/\350\275\273\351\207\217\345\214\226\346\235\203\351\231\220\347\256\241\346\216\247\346\236\266\346\236\204.png" "b/qos_auth/figures/\350\275\273\351\207\217\345\214\226\346\235\203\351\231\220\347\256\241\346\216\247\346\236\266\346\236\204.png"
new file mode 100644
index 0000000000000000000000000000000000000000..6100d0ad2ff5574cb6c86fba2321b0a504a7391c
Binary files /dev/null and "b/qos_auth/figures/\350\275\273\351\207\217\345\214\226\346\235\203\351\231\220\347\256\241\346\216\247\346\236\266\346\236\204.png" differ
diff --git a/qos_auth/include/auth_ctrl.h b/qos_auth/include/auth_ctrl.h
new file mode 100644
index 0000000000000000000000000000000000000000..6cbc423276cd1da227f9f8a5410614c563491306
--- /dev/null
+++ b/qos_auth/include/auth_ctrl.h
@@ -0,0 +1,116 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * include/linux/sched/auth_ctrl.h
+ *
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ */
+
+#ifndef _AUTH_CTRL_H
+#define _AUTH_CTRL_H
+
+#include
+
+#define ROOT_UID 0
+#define SYSTEM_UID 1000
+
+#define SUPER_UID SYSTEM_UID
+#define super_uid(uid) (uid == ROOT_UID || uid == SYSTEM_UID)
+
+enum auth_ctrl_cmdid {
+ BASIC_AUTH_CTRL = 1,
+ AUTH_CTRL_MAX_NR
+};
+
+#define AUTH_CTRL_IPC_MAGIG 0xCD
+
+#define BASIC_AUTH_CTRL_OPERATION \
+ _IOWR(AUTH_CTRL_IPC_MAGIG, BASIC_AUTH_CTRL, struct auth_ctrl_data)
+
+enum auth_flag_type {
+#ifdef CONFIG_RTG_AUTHORITY
+ RTG_AUTH_FLAG,
+#endif
+#ifdef CONFIG_QOS_AUTHORITY
+ QOS_AUTH_FLAG,
+#endif
+};
+
+#define INVALIED_AUTH_FLAG 0x00000000
+
+struct auth_ctrl_data {
+ unsigned int uid;
+
+ /*
+ * type: operation type, see auth_manipulate_type, valid range [1, AUTH_MAX_NR)
+ *
+ * rtg_ua_flag: authority flag for RTG, see AF_RTG_ALL
+ *
+ * qos_ua_flag: authority flag for QOS, see AF_QOS_ALL
+ *
+ * status: current status for uid, use to match qos policy, see auth_status and
+ * qos_policy_type, valid range [1, AUTH_STATUS_MAX_NR - 1)
+ *
+ */
+ unsigned int type;
+ unsigned int rtg_ua_flag;
+ unsigned int qos_ua_flag;
+ unsigned int status;
+};
+
+enum auth_err_no {
+ ARG_INVALID = 1,
+ THREAD_EXITING,
+ DIRTY_QOS_POLICY,
+ UID_NOT_AUTHORIZED,
+ UID_NOT_FOUND,
+ PID_DUPLICATE,
+ PID_NOT_EXIST,
+ INVALID_AUTH,
+ QOS_THREAD_NUM_EXCEED_LIMIT,
+};
+
+enum auth_manipulate_type {
+ AUTH_ENABLE = 1,
+ AUTH_DELETE,
+ AUTH_GET,
+ AUTH_SWITCH,
+ AUTH_MAX_NR,
+};
+
+#ifndef CONFIG_QOS_POLICY_MAX_NR
+#define QOS_STATUS_COUNT 5
+#else
+#define QOS_STATUS_COUNT CONFIG_QOS_POLICY_MAX_NR
+#endif
+
+/* keep match with qos_policy_type */
+enum auth_status {
+ /* reserved fo QOS_POLICY_DEFAULT, no qos supply in this status */
+ AUTH_STATUS_DISABLED = 1,
+
+ /* reserved for ROOT and SYSTEM */
+ AUTH_STATUS_SYSTEM_SERVER = 2,
+
+ /*
+ * these space for user specific status
+ * range (AUTH_STATUS_SYSTEM_SERVER, AUTH_STATUS_DEAD)
+ *
+ * initial the policy in matching index of qos_policy_array first before use
+ * see ctrl_qos_policy
+ */
+
+ /* reserved for destorying auth_struct*/
+ AUTH_STATUS_DEAD = QOS_STATUS_COUNT,
+
+ AUTH_STATUS_MAX_NR = QOS_STATUS_COUNT + 1,
+};
+
+struct auth_struct;
+long auth_ctrl_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+void get_auth_struct(struct auth_struct *auth);
+void put_auth_struct(struct auth_struct *auth);
+struct auth_struct *get_authority(struct task_struct *p);
+bool check_authorized(unsigned int func_id, unsigned int type);
+
+#endif /* _AUTH_CTRL_H */
+
diff --git a/qos_auth/include/qos_auth.h b/qos_auth/include/qos_auth.h
new file mode 100644
index 0000000000000000000000000000000000000000..f89a91194ef809f2f7d5dab043f2797bea30a770
--- /dev/null
+++ b/qos_auth/include/qos_auth.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * include/linux/sched/qos_auth.h
+ *
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ */
+
+#ifndef _QOS_AUTH_H
+#define _QOS_AUTH_H
+
+#include
+#include
+
+/*
+ * QOS authority flags for SYSTEM or ROOT
+ *
+ * keep sync with qos_ctrl_cmdid
+ * when add a new cmd to qos_ctrl_cmdid
+ * keep new_flag = (old_flag << 1) + 1
+ * up to now, next flag value is 0x0007
+ */
+#define AF_QOS_ALL 0x0003
+
+/*
+ * delegated authority for normal uid
+ * trim access range for QOS
+ */
+#define AF_QOS_DELEGATED 0x0001
+
+bool check_authorized(unsigned int func_id, unsigned int type);
+
+#endif /* _QOS_AUTH_H */
+
diff --git a/qos_auth/include/qos_ctrl.h b/qos_auth/include/qos_ctrl.h
new file mode 100644
index 0000000000000000000000000000000000000000..a20d7420ee11229828ec811f96cf6dbc99f9ff67
--- /dev/null
+++ b/qos_auth/include/qos_ctrl.h
@@ -0,0 +1,119 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * include/linux/sched/qos_ctrl.h
+ *
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ */
+
+#ifndef _QOS_CTRL_H
+#define _QOS_CTRL_H
+
+#include
+#include
+
+enum qos_ctrl_cmdid {
+ QOS_CTRL = 1,
+ QOS_POLICY,
+ QOS_CTRL_MAX_NR
+};
+
+#define QOS_CTRL_IPC_MAGIG 0xCC
+
+#define QOS_CTRL_BASIC_OPERATION \
+ _IOWR(QOS_CTRL_IPC_MAGIG, QOS_CTRL, struct qos_ctrl_data)
+#define QOS_CTRL_POLICY_OPERATION \
+ _IOWR(QOS_CTRL_IPC_MAGIG, QOS_POLICY, struct qos_policy_datas)
+
+#define NO_QOS -1
+#define NR_QOS 6
+#define NR_RT_QOS 1
+#define MIN_RT_QOS_LEVEL (NR_QOS - NR_RT_QOS)
+
+#define QOS_NUM_MAX 2000
+
+enum qos_manipulate_type {
+ QOS_APPLY = 1,
+ QOS_LEAVE,
+ QOS_OPERATION_CMD_MAX_NR,
+};
+
+#ifndef CONFIG_QOS_POLICY_MAX_NR
+#define QOS_POLICYS_COUNT 5
+#else
+#define QOS_POLICYS_COUNT CONFIG_QOS_POLICY_MAX_NR
+#endif
+
+/*
+ * keep match with auth_status
+ *
+ * range (QOS_POLICY_SYSTEM, QOS_POLICY_MAX_NR) could defined by user
+ * use ctrl_qos_policy
+ */
+enum qos_policy_type {
+ QOS_POLICY_DEFAULT = 1, /* reserved for "NO QOS" */
+ QOS_POLICY_SYSTEM = 2, /* reserved for ROOT and SYSTEM */
+ QOS_POLICY_MAX_NR = QOS_POLICYS_COUNT,
+};
+
+struct qos_ctrl_data {
+ int pid;
+
+ /*
+ * type: operation type, see qos_manipulate_type
+ * level: valid from 1 to NR_QOS. Larger value, more aggressive supply
+ */
+ unsigned int type;
+
+ /*
+ * user space level, range from [1, NR_QOS]
+ *
+ * NOTICE!!!:
+ * minus 1 before use in kernel, so the kernel range is [0, NR_QOS)
+ */
+ unsigned int level;
+};
+
+struct qos_policy_data {
+ int nice;
+ int latency_nice;
+ int uclamp_min;
+ int uclamp_max;
+ int rt_sched_priority;
+};
+
+#define QOS_FLAG_NICE 0x01
+#define QOS_FLAG_LATENCY_NICE 0x02
+#define QOS_FLAG_UCLAMP 0x04
+#define QOS_FLAG_RT 0x08
+
+#define QOS_FLAG_ALL (QOS_FLAG_NICE | \
+ QOS_FLAG_LATENCY_NICE | \
+ QOS_FLAG_UCLAMP | \
+ QOS_FLAG_RT)
+
+struct qos_policy_datas {
+ /*
+ * policy_type: id for qos policy, valid from [1, QOS_POLICY_MAX_NR)
+ * policy_flag: control valid sched attr for policy, QOS_FLAG_ALL for whole access
+ * policys: sched params for specific level qos, minus 1 for matching struct in kerenl
+ */
+ int policy_type;
+ unsigned int policy_flag;
+ struct qos_policy_data policys[NR_QOS + 1];
+};
+
+struct auth_struct;
+
+int qos_apply(struct qos_ctrl_data *data);
+int qos_leave(struct qos_ctrl_data *data);
+
+void qos_switch(struct auth_struct *auth, int target_status);
+
+void init_task_qos(struct task_struct *p);
+void sched_exit_qos_list(struct task_struct *p);
+void remove_qos_tasks(struct auth_struct *auth);
+
+long do_qos_ctrl_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+
+#endif /* _QOS_CTRL_H */
+
diff --git a/qos_auth/include/rtg_auth.h b/qos_auth/include/rtg_auth.h
new file mode 100644
index 0000000000000000000000000000000000000000..c9326f75934e58e7fb24168f46d945cf087a3248
--- /dev/null
+++ b/qos_auth/include/rtg_auth.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * include/linux/sched/rtg_auth.h
+ *
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ */
+
+#ifndef _RTG_AUTH_H
+#define _RTG_AUTH_H
+
+#include
+#include
+
+/*
+ * RTG authority flags for SYSTEM or ROOT
+ *
+ * keep sync with rtg_sched_cmdid
+ * when add a new cmd to rtg_sched_cmdid
+ * keep new_flag = (old_flag << 1) + 1
+ * up to now, next flag value is 0x3fff
+ */
+#define AF_RTG_ALL 0x1fff
+
+/*
+ * delegated authority for normal uid
+ * trim access range for RTG
+ */
+#define AF_RTG_DELEGATED 0x1fff
+
+bool check_authorized(unsigned int func_id, unsigned int type);
+
+#endif /* _RTG_AUTH_H */
+