From 7ab05c20ad43a958fa481b854eae225076e1e076 Mon Sep 17 00:00:00 2001 From: Sarangdhar Joshi Date: Thu, 11 Feb 2016 16:39:46 -0800 Subject: arm64: Add support for app specific settings Add support to provide an interface that can be used from userspace to decide whether app specific settings need to be applied / cleared when particular processes are running. CRs-Fixed: 981519 997757 Change-Id: Id81f8b70de64f291a8586150f4d2c7c8f8b4420f Signed-off-by: Sarangdhar Joshi [satyap@codeaurora.org: trivial merge conflict resolution and pull fixes for CR: 997757] Signed-off-by: Satya Durga Srinivasu Prabhala --- arch/arm64/Kconfig | 21 +++++++ arch/arm64/include/asm/app_api.h | 42 ++++++++++++++ arch/arm64/include/asm/fpsimd.h | 4 -- arch/arm64/kernel/Makefile | 2 + arch/arm64/kernel/app_api.c | 75 ++++++++++++++++++++++++ arch/arm64/kernel/app_setting.c | 120 +++++++++++++++++++++++++++++++++++++++ arch/arm64/kernel/entry-fpsimd.S | 16 ------ arch/arm64/kernel/fpsimd.c | 13 +++++ include/linux/mm_types.h | 4 ++ kernel/sched/core.c | 8 +++ mm/mmap.c | 9 +++ 11 files changed, 294 insertions(+), 20 deletions(-) create mode 100644 arch/arm64/include/asm/app_api.h create mode 100644 arch/arm64/kernel/app_api.c create mode 100644 arch/arm64/kernel/app_setting.c diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 706129c86096..69c9b84b367b 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -513,9 +513,20 @@ config ARM64_64K_PAGES endchoice +config MSM_APP_API + bool "API support to enable / disable app settings for MSM8996" + depends on ARCH_MSM8996 && (ENABLE_FP_SIMD_SETTINGS || MSM_APP_SETTINGS) + help + Add API support to enable / disable the app settings to be used + at runtime. These APIs are used to enable / disable app setting + when specific aarch32 or aarch64 processes are running. + + If you are not sure what to do, select 'N' here. + config ENABLE_FP_SIMD_SETTINGS bool "Enable FP(Floating Point) Settings for Qualcomm MSM8996" depends on ARCH_MSM8996 + select MSM_APP_API help Enable FP(Floating Point) and SIMD settings for the MSM8996 during the execution of the aarch32 processes and disable these settings @@ -523,6 +534,16 @@ config ENABLE_FP_SIMD_SETTINGS If you are not sure what to do, select 'N' here. +config MSM_APP_SETTINGS + bool "Support to enable / disable app settings for MSM8996" + depends on ARCH_MSM8996 + select MSM_APP_API + help + Expose an interface used by the userspace at runtime to + enable / disable the app specific settings. + + If you are not sure what to do, select 'N' here. + choice prompt "Virtual address space size" default ARM64_VA_BITS_39 if ARM64_4K_PAGES diff --git a/arch/arm64/include/asm/app_api.h b/arch/arm64/include/asm/app_api.h new file mode 100644 index 000000000000..2162400fde13 --- /dev/null +++ b/arch/arm64/include/asm/app_api.h @@ -0,0 +1,42 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __ASM_APP_API_H +#define __ASM_APP_API_H + +#include +#include +#include + +#define APP_SETTING_BIT 30 +#define MAX_ENTRIES 10 + +/* + * APIs to set / clear the app setting bits + * in the register. + */ +#ifdef CONFIG_MSM_APP_API +extern void set_app_setting_bit(uint32_t bit); +extern void clear_app_setting_bit(uint32_t bit); +#else +static inline void set_app_setting_bit(uint32_t bit) {} +static inline void clear_app_setting_bit(uint32_t bit) {} +#endif + +#ifdef CONFIG_MSM_APP_SETTINGS +extern void switch_app_setting_bit(struct task_struct *prev, + struct task_struct *next); +extern void apply_app_setting_bit(struct file *file); +extern bool use_app_setting; +#endif + +#endif diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h index 355871b7022f..3efaa5cebc03 100644 --- a/arch/arm64/include/asm/fpsimd.h +++ b/arch/arm64/include/asm/fpsimd.h @@ -84,13 +84,9 @@ extern void fpsimd_load_partial_state(struct fpsimd_partial_state *state); #ifdef CONFIG_ENABLE_FP_SIMD_SETTINGS extern void fpsimd_disable_trap(void); extern void fpsimd_enable_trap(void); -extern void fpsimd_settings_disable(void); -extern void fpsimd_settings_enable(void); #else static inline void fpsimd_disable_trap(void) {} static inline void fpsimd_enable_trap(void) {} -static inline void fpsimd_settings_disable(void) {} -static inline void fpsimd_settings_enable(void) {} #endif #endif diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 9f7794c5743f..57e55e4d5fcc 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -43,6 +43,8 @@ arm64-obj-$(CONFIG_EFI) += efi.o efi-entry.stub.o arm64-obj-$(CONFIG_PCI) += pci.o arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o arm64-obj-$(CONFIG_ACPI) += acpi.o +arm64-obj-$(CONFIG_MSM_APP_API) += app_api.o +arm64-obj-$(CONFIG_MSM_APP_SETTINGS) += app_setting.o obj-y += $(arm64-obj-y) vdso/ obj-m += $(arm64-obj-m) diff --git a/arch/arm64/kernel/app_api.c b/arch/arm64/kernel/app_api.c new file mode 100644 index 000000000000..39eeee1a9029 --- /dev/null +++ b/arch/arm64/kernel/app_api.c @@ -0,0 +1,75 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +#include + +static spinlock_t spinlock; +static DEFINE_PER_CPU(int, app_config_applied); +static unsigned long app_config_set[NR_CPUS]; +static unsigned long app_config_clear[NR_CPUS]; + +void set_app_setting_bit(uint32_t bit) +{ + unsigned long flags; + uint64_t reg; + int cpu; + + spin_lock_irqsave(&spinlock, flags); + asm volatile("mrs %0, S3_1_C15_C15_0" : "=r" (reg)); + reg = reg | BIT(bit); + isb(); + asm volatile("msr S3_1_C15_C15_0, %0" : : "r" (reg)); + isb(); + if (bit == APP_SETTING_BIT) { + cpu = raw_smp_processor_id(); + app_config_set[cpu]++; + + this_cpu_write(app_config_applied, 1); + } + spin_unlock_irqrestore(&spinlock, flags); + +} +EXPORT_SYMBOL(set_app_setting_bit); + +void clear_app_setting_bit(uint32_t bit) +{ + unsigned long flags; + uint64_t reg; + int cpu; + + spin_lock_irqsave(&spinlock, flags); + asm volatile("mrs %0, S3_1_C15_C15_0" : "=r" (reg)); + reg = reg & ~BIT(bit); + isb(); + asm volatile("msr S3_1_C15_C15_0, %0" : : "r" (reg)); + isb(); + if (bit == APP_SETTING_BIT) { + cpu = raw_smp_processor_id(); + app_config_clear[cpu]++; + + this_cpu_write(app_config_applied, 0); + } + spin_unlock_irqrestore(&spinlock, flags); +} +EXPORT_SYMBOL(clear_app_setting_bit); + +static int __init init_app_api(void) +{ + spin_lock_init(&spinlock); + return 0; +} +early_initcall(init_app_api); diff --git a/arch/arm64/kernel/app_setting.c b/arch/arm64/kernel/app_setting.c new file mode 100644 index 000000000000..6b4eb28d0e24 --- /dev/null +++ b/arch/arm64/kernel/app_setting.c @@ -0,0 +1,120 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +#include + +#define MAX_LEN 100 + +static char *lib_names[MAX_ENTRIES]; +static unsigned int count; +static struct mutex mutex; + +static char lib_str[MAX_LEN] = ""; +static struct kparam_string kps = { + .string = lib_str, + .maxlen = MAX_LEN, +}; +static int set_name(const char *str, struct kernel_param *kp); +module_param_call(lib_name, set_name, param_get_string, &kps, S_IWUSR); + +bool use_app_setting = true; +module_param(use_app_setting, bool, 0644); +MODULE_PARM_DESC(use_app_setting, "control use of app specific settings"); + +static int set_name(const char *str, struct kernel_param *kp) +{ + int len = strlen(str); + char *name; + + if (len >= MAX_LEN) { + pr_err("app_setting: name string too long\n"); + return -ENOSPC; + } + + /* + * echo adds '\n' which we need to chop off later + */ + name = kzalloc(len + 1, GFP_KERNEL); + if (!name) + return -ENOMEM; + + strlcpy(name, str, len + 1); + + if (name[len - 1] == '\n') + name[len - 1] = '\0'; + + mutex_lock(&mutex); + if (count < MAX_ENTRIES) { + lib_names[count] = name; + /* + * mb to ensure that the new lib_names entry is present + * before updating the view presented by get_lib_names + */ + mb(); + count++; + } else { + pr_err("app_setting: set name failed. Max entries reached\n"); + kfree(name); + mutex_unlock(&mutex); + return -EPERM; + } + mutex_unlock(&mutex); + + return 0; +} + +void switch_app_setting_bit(struct task_struct *prev, struct task_struct *next) +{ + if (prev->mm && unlikely(prev->mm->app_setting)) + clear_app_setting_bit(APP_SETTING_BIT); + + if (next->mm && unlikely(next->mm->app_setting)) + set_app_setting_bit(APP_SETTING_BIT); +} +EXPORT_SYMBOL(switch_app_setting_bit); + +void apply_app_setting_bit(struct file *file) +{ + bool found = false; + int i; + + if (file && file->f_path.dentry) { + const char *name = file->f_path.dentry->d_name.name; + + for (i = 0; i < count; i++) { + if (unlikely(!strcmp(name, lib_names[i]))) { + found = true; + break; + } + } + if (found) { + preempt_disable(); + set_app_setting_bit(APP_SETTING_BIT); + /* This will take care of child processes as well */ + current->mm->app_setting = 1; + preempt_enable(); + } + } +} +EXPORT_SYMBOL(apply_app_setting_bit); + +static int __init app_setting_init(void) +{ + mutex_init(&mutex); + return 0; +} +module_init(app_setting_init); diff --git a/arch/arm64/kernel/entry-fpsimd.S b/arch/arm64/kernel/entry-fpsimd.S index d90efa4852b2..1ffe15459c92 100644 --- a/arch/arm64/kernel/entry-fpsimd.S +++ b/arch/arm64/kernel/entry-fpsimd.S @@ -78,22 +78,6 @@ ENTRY(fpsimd_disable_trap) msr cpacr_el1, x0 ret ENDPROC(fpsimd_disable_trap) -ENTRY(fpsimd_settings_enable) - mrs x0, s3_1_c15_c15_0 - orr x0, x0, #(1 << 31) - isb - msr s3_1_c15_c15_0, x0 - isb - ret -ENDPROC(fpsimd_settings_enable) -ENTRY(fpsimd_settings_disable) - mrs x0, s3_1_c15_c15_0 - bic x0, x0, #(1 << 31) - isb - msr s3_1_c15_c15_0, x0 - isb - ret -ENDPROC(fpsimd_settings_disable) #endif #endif diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c index 74bc79e99717..2ed553f3a4ae 100644 --- a/arch/arm64/kernel/fpsimd.c +++ b/arch/arm64/kernel/fpsimd.c @@ -28,6 +28,7 @@ #include #include +#include #define FPEXC_IOF (1 << 0) #define FPEXC_DZF (1 << 1) @@ -36,6 +37,8 @@ #define FPEXC_IXF (1 << 4) #define FPEXC_IDF (1 << 7) +#define FP_SIMD_BIT 31 + /* * In order to reduce the number of times the FPSIMD state is needlessly saved * and restored, we need to keep track of two things: @@ -94,6 +97,16 @@ static DEFINE_PER_CPU(int, fpsimd_stg_enable); static int fpsimd_settings = 0x1; /* default = 0x1 */ module_param(fpsimd_settings, int, 0644); +void fpsimd_settings_enable(void) +{ + set_app_setting_bit(FP_SIMD_BIT); +} + +void fpsimd_settings_disable(void) +{ + clear_app_setting_bit(FP_SIMD_BIT); +} + /* * Trapped FP/ASIMD access. */ diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index ea0009064bbc..9f9e60736eba 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -522,6 +522,10 @@ struct mm_struct { #ifdef CONFIG_HUGETLB_PAGE atomic_long_t hugetlb_usage; #endif +#ifdef CONFIG_MSM_APP_SETTINGS + int app_setting; +#endif + }; static inline void mm_init_cpumask(struct mm_struct *mm) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 0a7db8a3bc16..e145b5640b12 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -85,6 +85,9 @@ #ifdef CONFIG_PARAVIRT #include #endif +#ifdef CONFIG_MSM_APP_SETTINGS +#include +#endif #include "sched.h" #include "../workqueue_internal.h" @@ -5874,6 +5877,11 @@ prepare_task_switch(struct rq *rq, struct task_struct *prev, fire_sched_out_preempt_notifiers(prev, next); prepare_lock_switch(rq, next); prepare_arch_switch(next); + +#ifdef CONFIG_MSM_APP_SETTINGS + if (use_app_setting) + switch_app_setting_bit(prev, next); +#endif } /** diff --git a/mm/mmap.c b/mm/mmap.c index 6c561acdca92..8b0a0ed2c466 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -48,6 +48,10 @@ #include #include +#ifdef CONFIG_MSM_APP_SETTINGS +#include +#endif + #include "internal.h" #ifndef arch_mmap_check @@ -1297,6 +1301,11 @@ unsigned long do_mmap(struct file *file, unsigned long addr, if (!len) return -EINVAL; +#ifdef CONFIG_MSM_APP_SETTINGS + if (use_app_setting) + apply_app_setting_bit(file); +#endif + /* * Does the application expect PROT_READ to imply PROT_EXEC? * -- cgit v1.2.3