* [PATCH v2] ARM: avoid Cortex-A9 livelock on tight dmb loops
From: Russell King @ 2018-06-01 11:00 UTC (permalink / raw)
To: linux-arm-kernel
Executing loops such as:
while (1)
cpu_relax();
with interrupts disabled results in a livelock of the entire system,
as other CPUs are prevented making progress. This is most noticable
as a failure of crashdump kexec, which stops just after issuing:
Loading crashdump kernel...
to the system console. Two other locations of these loops within the
ARM code have been identified and fixed up.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
v2: use wfe() instead of cpu_do_idle
arch/arm/include/asm/barrier.h | 2 ++
arch/arm/kernel/machine_kexec.c | 5 ++++-
arch/arm/kernel/smp.c | 4 +++-
arch/arm/mach-omap2/prm_common.c | 4 +++-
4 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/arch/arm/include/asm/barrier.h b/arch/arm/include/asm/barrier.h
index 69772e742a0a..83ae97c049d9 100644
--- a/arch/arm/include/asm/barrier.h
+++ b/arch/arm/include/asm/barrier.h
@@ -11,6 +11,8 @@
#define sev() __asm__ __volatile__ ("sev" : : : "memory")
#define wfe() __asm__ __volatile__ ("wfe" : : : "memory")
#define wfi() __asm__ __volatile__ ("wfi" : : : "memory")
+#else
+#define wfe() do { } while (0)
#endif
#if __LINUX_ARM_ARCH__ >= 7
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
index dd2eb5f76b9f..76300f3813e8 100644
--- a/arch/arm/kernel/machine_kexec.c
+++ b/arch/arm/kernel/machine_kexec.c
@@ -91,8 +91,11 @@ void machine_crash_nonpanic_core(void *unused)
set_cpu_online(smp_processor_id(), false);
atomic_dec(&waiting_for_crash_ipi);
- while (1)
+
+ while (1) {
cpu_relax();
+ wfe();
+ }
}
void crash_smp_send_stop(void)
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 9ec9a366ef44..a39fe6ab89a2 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -570,8 +570,10 @@ static void ipi_cpu_stop(unsigned int cpu)
local_fiq_disable();
local_irq_disable();
- while (1)
+ while (1) {
cpu_relax();
+ wfe();
+ }
}
static DEFINE_PER_CPU(struct completion *, cpu_completion);
diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c
index 021b5a8b9c0a..bb15a9eec05c 100644
--- a/arch/arm/mach-omap2/prm_common.c
+++ b/arch/arm/mach-omap2/prm_common.c
@@ -522,8 +522,10 @@ void omap_prm_reset_system(void)
prm_ll_data->reset_system();
- while (1)
+ while (1) {
cpu_relax();
+ wfe();
+ }
}
/**
--
2.7.4
^ permalink raw reply related
* [PATCH 0/4] lib/vsprintf: Remove atomic-unsafe support for printk format %pCr
From: Linus Torvalds @ 2018-06-01 11:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1527845302-12159-1-git-send-email-geert+renesas@glider.be>
On Fri, Jun 1, 2018 at 4:29 AM Geert Uytterhoeven
<geert+renesas@glider.be> wrote:
>
> This patch series:
> - Changes all existing users of "%pCr" to print the result of
> clk_get_rate() directly, which is safe as they all do this in task
> context only,
> - Removes support for the "%pCr" printk format.
Looks good to me.
What tree will this go through? The normal printk one? Just checking
that this doesn't end up falling through the cracks because nobody
knows who would take it...
Linus
^ permalink raw reply
* [PATCH 0/4] lib/vsprintf: Remove atomic-unsafe support for printk format %pCr
From: Andy Shevchenko @ 2018-06-01 11:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CA+55aFxHHSRnDbbNGq6SwNAwEt0EhX15n_pNqon3MzGYJgMJmA@mail.gmail.com>
On Fri, Jun 1, 2018 at 2:00 PM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
> On Fri, Jun 1, 2018 at 4:29 AM Geert Uytterhoeven
> <geert+renesas@glider.be> wrote:
>>
>> This patch series:
>> - Changes all existing users of "%pCr" to print the result of
>> clk_get_rate() directly, which is safe as they all do this in task
>> context only,
>> - Removes support for the "%pCr" printk format.
>
> Looks good to me.
>
> What tree will this go through? The normal printk one? Just checking
> that this doesn't end up falling through the cracks because nobody
> knows who would take it...
We discussed few month before with Petr that he would take care of the
patches against vsprintf.c.
I think this is the case here.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* [PATCH] coresight: Fix check in coresight_tmc_etr_buf_insert_barrier_packet
From: Suzuki K Poulose @ 2018-06-01 11:08 UTC (permalink / raw)
To: linux-arm-kernel
We request for "CORESIGHT_BARRIER_PKT_SIZE" length and we should
be happy when we get that size.
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
Mathieu,
Please could you pull this patch, if you are happy with it ?
This fixes a problem in the ETR buf series, which I just
noticed while testing the part2 of the series.
Suzuki
---
drivers/hwtracing/coresight/coresight-tmc-etr.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index e2bcef3..c736250 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -862,7 +862,7 @@ tmc_etr_buf_insert_barrier_packet(struct etr_buf *etr_buf, u64 offset)
len = tmc_etr_buf_get_data(etr_buf, offset,
CORESIGHT_BARRIER_PKT_SIZE, &bufp);
- if (WARN_ON(len <= CORESIGHT_BARRIER_PKT_SIZE))
+ if (WARN_ON(len < CORESIGHT_BARRIER_PKT_SIZE))
return -EINVAL;
coresight_insert_barrier_packet(bufp);
return offset + CORESIGHT_BARRIER_PKT_SIZE;
--
2.7.4
^ permalink raw reply related
* [PATCH 04/13] staging: vc04_services: no need to check debugfs return values
From: Greg Kroah-Hartman @ 2018-06-01 11:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <874lioorbj.fsf@anholt.net>
On Wed, May 30, 2018 at 12:51:12PM -0700, Eric Anholt wrote:
> Greg Kroah-Hartman <gregkh@linuxfoundation.org> writes:
>
> > When calling debugfs functions, there is no need to ever check the
> > return value. The function can work or not, but the code logic should
> > never do something different based on this.
> >
> > Clean up the vchiq_arm code by not caring about the value of debugfs
> > calls. This ends up removing a number of lines of code that are not
> > needed.
> >
> > Cc: Eric Anholt <eric@anholt.net>
> > Cc: Stefan Wahren <stefan.wahren@i2se.com>
> > Cc: Kees Cook <keescook@chromium.org>
> > Cc: Dan Carpenter <dan.carpenter@oracle.com>
> > Cc: Arnd Bergmann <arnd@arndb.de>
> > Cc: Keerthi Reddy <keerthigd4990@gmail.com>
> > Cc: linux-rpi-kernel at lists.infradead.org
> > Cc: linux-arm-kernel at lists.infradead.org
> > Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > ---
> > .../interface/vchiq_arm/vchiq_arm.c | 13 +---
> > .../interface/vchiq_arm/vchiq_debugfs.c | 72 +++----------------
> > .../interface/vchiq_arm/vchiq_debugfs.h | 4 +-
> > 3 files changed, 15 insertions(+), 74 deletions(-)
> >
>
> > diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
> > index 766b4fe5f32c..103fec955e2c 100644
> > --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
> > +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
>
> > @@ -314,31 +284,13 @@ void vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance)
> > debugfs_remove_recursive(node->dentry);
> > }
> >
> > -int vchiq_debugfs_init(void)
> > +void vchiq_debugfs_init(void)
> > {
> > - BUG_ON(debugfs_info.vchiq_cfg_dir != NULL);
> > -
> > debugfs_info.vchiq_cfg_dir = debugfs_create_dir("vchiq", NULL);
> > - if (debugfs_info.vchiq_cfg_dir == NULL)
> > - goto fail;
> > -
>
> I think now that we allow successful probe with this value NULL, module
> remove could vchiq_debugfs_deinit() -> vchiq_debugfs_top() -> BUG_ON().
> I think the right solution would be to just drop that BUG_ON(). With
> that change (and probably just garbage-collecting that function), this
> will be enthusiastically:
>
> Reviewed-by: Eric Anholt <eric@anholt.net>
Much better idea, I just did that and will send out the patch series
now. The end result is nicer:
3 files changed, 42 insertions(+), 140 deletions(-)
thanks for the suggestion.
greg k-h
^ permalink raw reply
* [PATCH 1/6] staging: vc04_services: no need to check debugfs return values
From: Greg Kroah-Hartman @ 2018-06-01 11:09 UTC (permalink / raw)
To: linux-arm-kernel
When calling debugfs functions, there is no need to ever check the
return value. The function can work or not, but the code logic should
never do something different based on this.
Clean up the vchiq_arm code by not caring about the value of debugfs
calls. This ends up removing a number of lines of code that are not
needed.
Cc: Eric Anholt <eric@anholt.net>
Cc: Stefan Wahren <stefan.wahren@i2se.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Dan Carpenter <dan.carpenter@oracle.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Keerthi Reddy <keerthigd4990@gmail.com>
Cc: linux-rpi-kernel at lists.infradead.org
Cc: linux-arm-kernel at lists.infradead.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
.../interface/vchiq_arm/vchiq_arm.c | 13 +---
.../interface/vchiq_arm/vchiq_debugfs.c | 72 +++----------------
.../interface/vchiq_arm/vchiq_debugfs.h | 4 +-
3 files changed, 15 insertions(+), 74 deletions(-)
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
index aaa264f3b598..bc05c69383b8 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
@@ -2018,7 +2018,6 @@ vchiq_open(struct inode *inode, struct file *file)
vchiq_log_info(vchiq_arm_log_level, "vchiq_open");
switch (dev) {
case VCHIQ_MINOR: {
- int ret;
VCHIQ_STATE_T *state = vchiq_get_state();
VCHIQ_INSTANCE_T instance;
@@ -2035,11 +2034,7 @@ vchiq_open(struct inode *inode, struct file *file)
instance->state = state;
instance->pid = current->tgid;
- ret = vchiq_debugfs_add_instance(instance);
- if (ret != 0) {
- kfree(instance);
- return ret;
- }
+ vchiq_debugfs_add_instance(instance);
sema_init(&instance->insert_event, 0);
sema_init(&instance->remove_event, 0);
@@ -3630,9 +3625,7 @@ static int vchiq_probe(struct platform_device *pdev)
goto failed_device_create;
/* create debugfs entries */
- err = vchiq_debugfs_init();
- if (err != 0)
- goto failed_debugfs_init;
+ vchiq_debugfs_init();
vchiq_log_info(vchiq_arm_log_level,
"vchiq: initialised - version %d (min %d), device %d.%d",
@@ -3645,8 +3638,6 @@ static int vchiq_probe(struct platform_device *pdev)
return 0;
-failed_debugfs_init:
- device_destroy(vchiq_class, vchiq_devid);
failed_device_create:
class_destroy(vchiq_class);
failed_class_create:
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
index 766b4fe5f32c..103fec955e2c 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
@@ -158,15 +158,12 @@ static const struct file_operations debugfs_log_fops = {
};
/* create an entry under <debugfs>/vchiq/log for each log category */
-static int vchiq_debugfs_create_log_entries(struct dentry *top)
+static void vchiq_debugfs_create_log_entries(struct dentry *top)
{
struct dentry *dir;
size_t i;
- int ret = 0;
dir = debugfs_create_dir("log", vchiq_debugfs_top());
- if (!dir)
- return -ENOMEM;
debugfs_info.log_categories = dir;
for (i = 0; i < n_log_entries; i++) {
@@ -177,14 +174,8 @@ static int vchiq_debugfs_create_log_entries(struct dentry *top)
debugfs_info.log_categories,
levp,
&debugfs_log_fops);
- if (!dir) {
- ret = -ENOMEM;
- break;
- }
-
vchiq_debugfs_log_entries[i].dir = dir;
}
- return ret;
}
static int debugfs_usecount_show(struct seq_file *f, void *offset)
@@ -268,43 +259,22 @@ static const struct file_operations debugfs_trace_fops = {
};
/* add an instance (process) to the debugfs entries */
-int vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance)
+void vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance)
{
char pidstr[16];
- struct dentry *top, *use_count, *trace;
+ struct dentry *top;
struct dentry *clients = vchiq_clients_top();
snprintf(pidstr, sizeof(pidstr), "%d",
vchiq_instance_get_pid(instance));
top = debugfs_create_dir(pidstr, clients);
- if (!top)
- goto fail_top;
-
- use_count = debugfs_create_file("use_count",
- 0444, top,
- instance,
- &debugfs_usecount_fops);
- if (!use_count)
- goto fail_use_count;
-
- trace = debugfs_create_file("trace",
- 0644, top,
- instance,
- &debugfs_trace_fops);
- if (!trace)
- goto fail_trace;
-
- vchiq_instance_get_debugfs_node(instance)->dentry = top;
- return 0;
+ debugfs_create_file("use_count", 0444, top, instance,
+ &debugfs_usecount_fops);
+ debugfs_create_file("trace", 0644, top, instance, &debugfs_trace_fops);
-fail_trace:
- debugfs_remove(use_count);
-fail_use_count:
- debugfs_remove(top);
-fail_top:
- return -ENOMEM;
+ vchiq_instance_get_debugfs_node(instance)->dentry = top;
}
void vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance)
@@ -314,31 +284,13 @@ void vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance)
debugfs_remove_recursive(node->dentry);
}
-int vchiq_debugfs_init(void)
+void vchiq_debugfs_init(void)
{
- BUG_ON(debugfs_info.vchiq_cfg_dir != NULL);
-
debugfs_info.vchiq_cfg_dir = debugfs_create_dir("vchiq", NULL);
- if (debugfs_info.vchiq_cfg_dir == NULL)
- goto fail;
-
debugfs_info.clients = debugfs_create_dir("clients",
vchiq_debugfs_top());
- if (!debugfs_info.clients)
- goto fail;
- if (vchiq_debugfs_create_log_entries(vchiq_debugfs_top()) != 0)
- goto fail;
-
- return 0;
-
-fail:
- vchiq_debugfs_deinit();
- vchiq_log_error(vchiq_arm_log_level,
- "%s: failed to create debugfs directory",
- __func__);
-
- return -ENOMEM;
+ vchiq_debugfs_create_log_entries(vchiq_debugfs_top());
}
/* remove all the debugfs entries */
@@ -360,18 +312,16 @@ static struct dentry *vchiq_debugfs_top(void)
#else /* CONFIG_DEBUG_FS */
-int vchiq_debugfs_init(void)
+void vchiq_debugfs_init(void)
{
- return 0;
}
void vchiq_debugfs_deinit(void)
{
}
-int vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance)
+void vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance)
{
- return 0;
}
void vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance)
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.h
index 1d95e3d70621..3af6397ada19 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.h
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.h
@@ -40,11 +40,11 @@ typedef struct vchiq_debugfs_node_struct {
struct dentry *dentry;
} VCHIQ_DEBUGFS_NODE_T;
-int vchiq_debugfs_init(void);
+void vchiq_debugfs_init(void);
void vchiq_debugfs_deinit(void);
-int vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance);
+void vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance);
void vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance);
--
2.17.1
^ permalink raw reply related
* [PATCH 2/6] staging: vc04_services: remove odd vchiq_debugfs_top() wrapper
From: Greg Kroah-Hartman @ 2018-06-01 11:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180601111004.1670-1-gregkh@linuxfoundation.org>
vchiq_debugfs_top() is only a wrapper around a pointer to a dentry, so
just use the dentry directly instead, making it a static variable
instead of part of a static structure.
This also removes the pointless BUG_ON() when checking that dentry as no
one should ever care if debugfs is working or not, and the kernel should
really not panic over something as trivial as that.
Suggested-by: Eric Anholt <eric@anholt.net>
Cc: Stefan Wahren <stefan.wahren@i2se.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Dan Carpenter <dan.carpenter@oracle.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Keerthi Reddy <keerthigd4990@gmail.com>
Cc: linux-rpi-kernel at lists.infradead.org
Cc: linux-arm-kernel at lists.infradead.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
.../interface/vchiq_arm/vchiq_debugfs.c | 24 +++++++------------
1 file changed, 8 insertions(+), 16 deletions(-)
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
index 103fec955e2c..8b46256a97fc 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
@@ -53,9 +53,6 @@
/* Top-level debug info */
struct vchiq_debugfs_info {
- /* Global 'vchiq' debugfs entry used by all instances */
- struct dentry *vchiq_cfg_dir;
-
/* one entry per client process */
struct dentry *clients;
@@ -65,6 +62,9 @@ struct vchiq_debugfs_info {
static struct vchiq_debugfs_info debugfs_info;
+/* Global 'vchiq' debugfs entry used by all instances */
+struct dentry *vchiq_dbg_dir;
+
/* Log category debugfs entries */
struct vchiq_debugfs_log_entry {
const char *name;
@@ -82,7 +82,6 @@ static struct vchiq_debugfs_log_entry vchiq_debugfs_log_entries[] = {
static int n_log_entries = ARRAY_SIZE(vchiq_debugfs_log_entries);
static struct dentry *vchiq_clients_top(void);
-static struct dentry *vchiq_debugfs_top(void);
static int debugfs_log_show(struct seq_file *f, void *offset)
{
@@ -163,7 +162,7 @@ static void vchiq_debugfs_create_log_entries(struct dentry *top)
struct dentry *dir;
size_t i;
- dir = debugfs_create_dir("log", vchiq_debugfs_top());
+ dir = debugfs_create_dir("log", vchiq_dbg_dir);
debugfs_info.log_categories = dir;
for (i = 0; i < n_log_entries; i++) {
@@ -286,17 +285,16 @@ void vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance)
void vchiq_debugfs_init(void)
{
- debugfs_info.vchiq_cfg_dir = debugfs_create_dir("vchiq", NULL);
- debugfs_info.clients = debugfs_create_dir("clients",
- vchiq_debugfs_top());
+ vchiq_dbg_dir = debugfs_create_dir("vchiq", NULL);
+ debugfs_info.clients = debugfs_create_dir("clients", vchiq_dbg_dir);
- vchiq_debugfs_create_log_entries(vchiq_debugfs_top());
+ vchiq_debugfs_create_log_entries(vchiq_dbg_dir);
}
/* remove all the debugfs entries */
void vchiq_debugfs_deinit(void)
{
- debugfs_remove_recursive(vchiq_debugfs_top());
+ debugfs_remove_recursive(vchiq_dbg_dir);
}
static struct dentry *vchiq_clients_top(void)
@@ -304,12 +302,6 @@ static struct dentry *vchiq_clients_top(void)
return debugfs_info.clients;
}
-static struct dentry *vchiq_debugfs_top(void)
-{
- BUG_ON(debugfs_info.vchiq_cfg_dir == NULL);
- return debugfs_info.vchiq_cfg_dir;
-}
-
#else /* CONFIG_DEBUG_FS */
void vchiq_debugfs_init(void)
--
2.17.1
^ permalink raw reply related
* [PATCH 3/6] staging: vc04_services: move client dbg directory into static variable
From: Greg Kroah-Hartman @ 2018-06-01 11:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180601111004.1670-1-gregkh@linuxfoundation.org>
This does not need to be part of a wrapper function, or in a structure,
just properly reference it directly as a single variable.
The whole variable will be going away soon anyway, this is just a step
toward that direction.
Suggested-by: Eric Anholt <eric@anholt.net>
Cc: Stefan Wahren <stefan.wahren@i2se.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Dan Carpenter <dan.carpenter@oracle.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Keerthi Reddy <keerthigd4990@gmail.com>
Cc: linux-rpi-kernel at lists.infradead.org
Cc: linux-arm-kernel at lists.infradead.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
.../interface/vchiq_arm/vchiq_debugfs.c | 18 ++++--------------
1 file changed, 4 insertions(+), 14 deletions(-)
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
index 8b46256a97fc..12ed560c95a7 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
@@ -53,17 +53,15 @@
/* Top-level debug info */
struct vchiq_debugfs_info {
- /* one entry per client process */
- struct dentry *clients;
-
/* log categories */
struct dentry *log_categories;
};
static struct vchiq_debugfs_info debugfs_info;
-/* Global 'vchiq' debugfs entry used by all instances */
+/* Global 'vchiq' debugfs and clients entry used by all instances */
struct dentry *vchiq_dbg_dir;
+struct dentry *vchiq_dbg_clients;
/* Log category debugfs entries */
struct vchiq_debugfs_log_entry {
@@ -81,8 +79,6 @@ static struct vchiq_debugfs_log_entry vchiq_debugfs_log_entries[] = {
};
static int n_log_entries = ARRAY_SIZE(vchiq_debugfs_log_entries);
-static struct dentry *vchiq_clients_top(void);
-
static int debugfs_log_show(struct seq_file *f, void *offset)
{
int *levp = f->private;
@@ -262,12 +258,11 @@ void vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance)
{
char pidstr[16];
struct dentry *top;
- struct dentry *clients = vchiq_clients_top();
snprintf(pidstr, sizeof(pidstr), "%d",
vchiq_instance_get_pid(instance));
- top = debugfs_create_dir(pidstr, clients);
+ top = debugfs_create_dir(pidstr, vchiq_dbg_clients);
debugfs_create_file("use_count", 0444, top, instance,
&debugfs_usecount_fops);
@@ -286,7 +281,7 @@ void vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance)
void vchiq_debugfs_init(void)
{
vchiq_dbg_dir = debugfs_create_dir("vchiq", NULL);
- debugfs_info.clients = debugfs_create_dir("clients", vchiq_dbg_dir);
+ vchiq_dbg_clients = debugfs_create_dir("clients", vchiq_dbg_dir);
vchiq_debugfs_create_log_entries(vchiq_dbg_dir);
}
@@ -297,11 +292,6 @@ void vchiq_debugfs_deinit(void)
debugfs_remove_recursive(vchiq_dbg_dir);
}
-static struct dentry *vchiq_clients_top(void)
-{
- return debugfs_info.clients;
-}
-
#else /* CONFIG_DEBUG_FS */
void vchiq_debugfs_init(void)
--
2.17.1
^ permalink raw reply related
* [PATCH 4/6] staging: vc04_services: remove struct vchiq_debugfs_info
From: Greg Kroah-Hartman @ 2018-06-01 11:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180601111004.1670-1-gregkh@linuxfoundation.org>
This structure, and the one static variable that was declared with it,
were not being used for anything. The log_categories field was being
set, but never used again. So just remove it entirely as it is not
needed at all.
Suggested-by: Eric Anholt <eric@anholt.net>
Cc: Stefan Wahren <stefan.wahren@i2se.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Dan Carpenter <dan.carpenter@oracle.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Keerthi Reddy <keerthigd4990@gmail.com>
Cc: linux-rpi-kernel at lists.infradead.org
Cc: linux-arm-kernel at lists.infradead.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
.../interface/vchiq_arm/vchiq_debugfs.c | 14 +-------------
1 file changed, 1 insertion(+), 13 deletions(-)
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
index 12ed560c95a7..f18cd56c3634 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
@@ -51,14 +51,6 @@
#define VCHIQ_LOG_INFO_STR "info"
#define VCHIQ_LOG_TRACE_STR "trace"
-/* Top-level debug info */
-struct vchiq_debugfs_info {
- /* log categories */
- struct dentry *log_categories;
-};
-
-static struct vchiq_debugfs_info debugfs_info;
-
/* Global 'vchiq' debugfs and clients entry used by all instances */
struct dentry *vchiq_dbg_dir;
struct dentry *vchiq_dbg_clients;
@@ -159,16 +151,12 @@ static void vchiq_debugfs_create_log_entries(struct dentry *top)
size_t i;
dir = debugfs_create_dir("log", vchiq_dbg_dir);
- debugfs_info.log_categories = dir;
for (i = 0; i < n_log_entries; i++) {
void *levp = (void *)vchiq_debugfs_log_entries[i].plevel;
dir = debugfs_create_file(vchiq_debugfs_log_entries[i].name,
- 0644,
- debugfs_info.log_categories,
- levp,
- &debugfs_log_fops);
+ 0644, dir, levp, &debugfs_log_fops);
vchiq_debugfs_log_entries[i].dir = dir;
}
}
--
2.17.1
^ permalink raw reply related
* [PATCH 5/6] staging: vc04_services: vchiq_debugfs_log_entry can be a void *
From: Greg Kroah-Hartman @ 2018-06-01 11:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180601111004.1670-1-gregkh@linuxfoundation.org>
There's no need to set this to be int * when it is only used as a void *.
This lets us remove the unneeded cast, and unneeded temporary variable
the one place it is referenced in the code.
Suggested-by: Eric Anholt <eric@anholt.net>
Cc: Stefan Wahren <stefan.wahren@i2se.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Dan Carpenter <dan.carpenter@oracle.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Keerthi Reddy <keerthigd4990@gmail.com>
Cc: linux-rpi-kernel at lists.infradead.org
Cc: linux-arm-kernel at lists.infradead.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
.../vc04_services/interface/vchiq_arm/vchiq_debugfs.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
index f18cd56c3634..2b353d2d25ce 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
@@ -58,7 +58,7 @@ struct dentry *vchiq_dbg_clients;
/* Log category debugfs entries */
struct vchiq_debugfs_log_entry {
const char *name;
- int *plevel;
+ void *plevel;
struct dentry *dir;
};
@@ -153,10 +153,10 @@ static void vchiq_debugfs_create_log_entries(struct dentry *top)
dir = debugfs_create_dir("log", vchiq_dbg_dir);
for (i = 0; i < n_log_entries; i++) {
- void *levp = (void *)vchiq_debugfs_log_entries[i].plevel;
-
dir = debugfs_create_file(vchiq_debugfs_log_entries[i].name,
- 0644, dir, levp, &debugfs_log_fops);
+ 0644, dir,
+ vchiq_debugfs_log_entries[i].plevel,
+ &debugfs_log_fops);
vchiq_debugfs_log_entries[i].dir = dir;
}
}
--
2.17.1
^ permalink raw reply related
* [PATCH 6/6] staging: vc04_services: no need to save the log debufs dentries
From: Greg Kroah-Hartman @ 2018-06-01 11:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180601111004.1670-1-gregkh@linuxfoundation.org>
The log entry dentries are only set, never referenced, so no need to
keep them around. Remove the pointer from struct
vchiq_debugfs_log_entry as it is not needed anymore and get rid of the
separate vchiq_debugfs_create_log_entries() function as it is only used
in one place.
Suggested-by: Eric Anholt <eric@anholt.net>
Cc: Stefan Wahren <stefan.wahren@i2se.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Dan Carpenter <dan.carpenter@oracle.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Keerthi Reddy <keerthigd4990@gmail.com>
Cc: linux-rpi-kernel at lists.infradead.org
Cc: linux-arm-kernel at lists.infradead.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
.../interface/vchiq_arm/vchiq_debugfs.c | 29 +++++++------------
1 file changed, 10 insertions(+), 19 deletions(-)
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
index 2b353d2d25ce..38805504d462 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
@@ -59,7 +59,6 @@ struct dentry *vchiq_dbg_clients;
struct vchiq_debugfs_log_entry {
const char *name;
void *plevel;
- struct dentry *dir;
};
static struct vchiq_debugfs_log_entry vchiq_debugfs_log_entries[] = {
@@ -144,23 +143,6 @@ static const struct file_operations debugfs_log_fops = {
.release = single_release,
};
-/* create an entry under <debugfs>/vchiq/log for each log category */
-static void vchiq_debugfs_create_log_entries(struct dentry *top)
-{
- struct dentry *dir;
- size_t i;
-
- dir = debugfs_create_dir("log", vchiq_dbg_dir);
-
- for (i = 0; i < n_log_entries; i++) {
- dir = debugfs_create_file(vchiq_debugfs_log_entries[i].name,
- 0644, dir,
- vchiq_debugfs_log_entries[i].plevel,
- &debugfs_log_fops);
- vchiq_debugfs_log_entries[i].dir = dir;
- }
-}
-
static int debugfs_usecount_show(struct seq_file *f, void *offset)
{
VCHIQ_INSTANCE_T instance = f->private;
@@ -268,10 +250,19 @@ void vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance)
void vchiq_debugfs_init(void)
{
+ struct dentry *dir;
+ int i;
+
vchiq_dbg_dir = debugfs_create_dir("vchiq", NULL);
vchiq_dbg_clients = debugfs_create_dir("clients", vchiq_dbg_dir);
- vchiq_debugfs_create_log_entries(vchiq_dbg_dir);
+ /* create an entry under <debugfs>/vchiq/log for each log category */
+ dir = debugfs_create_dir("log", vchiq_dbg_dir);
+
+ for (i = 0; i < n_log_entries; i++)
+ debugfs_create_file(vchiq_debugfs_log_entries[i].name, 0644,
+ dir, vchiq_debugfs_log_entries[i].plevel,
+ &debugfs_log_fops);
}
/* remove all the debugfs entries */
--
2.17.1
^ permalink raw reply related
* [PATCHv2 00/19] arm64: invoke syscalls with pt_regs
From: Mark Rutland @ 2018-06-01 11:24 UTC (permalink / raw)
To: linux-arm-kernel
This series reworks arm64's syscall handling to minimize the propagation
of user-controlled register values into speculated code paths. As with
x86 [1], a wrapper is generated for each syscall, which extracts the
argument from a struct pt_regs. During kernel entry from userspace,
registers are zeroed.
The arm64 kernel code directly invokes some syscalls which the x86 code
doesn't, so I've added ksys_* wrappers for these, following the x86
example. The rest of the series is arm64-specific.
I've pushed the series out to my arm64/syscall-regs branch [2] on
kernel.org.
Since v1 [3]:
* Rebase atop of arm64 for-next/core (for SSBD conflicts)
* Move ksys_personality logic into <linux/syscalls.h>
* Move kcompat_sys_* wrappers to <linux/compat.h>
* Fix scno bounds check to use unisgned comparison
* Fix sve_user_reset() call in el0_svc_handler()
* Add BUILD_BUG() to the !CONFIG_ARM64_SVE stubs
* Accumulate acked-by / reviewed-by tags
Thanks,
Mark.
[1] https://lkml.kernel.org/r/20180330093720.6780-1-linux at dominikbrodowski.net
[2] git://git.kernel.org/pub/scm/linux/kernel/git/mark/linux.git
[3] https://lkml.kernel.org/r/20180514094640.27569-1-mark.rutland at arm.com
Mark Rutland (19):
arm64: consistently use unsigned long for thread flags
arm64: move SCTLR_EL{1,2} assertions to <asm/sysreg.h>
arm64: introduce sysreg_clear_set()
arm64: kill config_sctlr_el1()
arm64: kill change_cpacr()
arm64: move sve_user_{enable,disable} to <asm/fpsimd.h>
arm64: remove sigreturn wrappers
arm64: convert raw syscall invocation to C
arm64: convert syscall trace logic to C
arm64: convert native/compat syscall entry to C
arm64: don't reload GPRs after apply_ssbd
arm64: zero GPRs upon entry from EL0
kernel: add ksys_personality()
kernel: add kcompat_sys_{f,}statfs64()
arm64: remove in-kernel call to sys_personality()
arm64: use {COMPAT,}SYSCALL_DEFINE0 for sigreturn
arm64: use SYSCALL_DEFINE6() for mmap
arm64: convert compat wrappers to C
arm64: implement syscall wrappers
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/fpsimd.h | 17 +++-
arch/arm64/include/asm/syscall_wrapper.h | 80 +++++++++++++++++
arch/arm64/include/asm/sysreg.h | 33 ++++---
arch/arm64/include/asm/unistd32.h | 26 +++---
arch/arm64/kernel/Makefile | 5 +-
arch/arm64/kernel/armv8_deprecated.c | 8 +-
arch/arm64/kernel/cpu_errata.c | 3 +-
arch/arm64/kernel/entry.S | 145 ++++---------------------------
arch/arm64/kernel/entry32.S | 121 --------------------------
arch/arm64/kernel/fpsimd.c | 19 ----
arch/arm64/kernel/signal.c | 5 +-
arch/arm64/kernel/signal32.c | 6 +-
arch/arm64/kernel/sys.c | 19 ++--
arch/arm64/kernel/sys32.c | 127 ++++++++++++++++++++++++---
arch/arm64/kernel/syscall.c | 114 ++++++++++++++++++++++++
arch/arm64/kernel/traps.c | 4 +-
arch/arm64/mm/fault.c | 2 +-
fs/statfs.c | 14 ++-
include/linux/compat.h | 11 +++
include/linux/syscalls.h | 11 +++
21 files changed, 437 insertions(+), 334 deletions(-)
create mode 100644 arch/arm64/include/asm/syscall_wrapper.h
delete mode 100644 arch/arm64/kernel/entry32.S
create mode 100644 arch/arm64/kernel/syscall.c
--
2.11.0
^ permalink raw reply
* [PATCHv2 01/19] arm64: consistently use unsigned long for thread flags
From: Mark Rutland @ 2018-06-01 11:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180601112441.37810-1-mark.rutland@arm.com>
In do_notify_resume, we manipulate thread_flags as a 32-bit unsigned
int, whereas thread_info::flags is a 64-bit unsigned long, and elsewhere
(e.g. in the entry assembly) we manipulate the flags as a 64-bit
quantity.
For consistency, and to avoid problems if we end up with more than 32
flags, let's make do_notify_resume take the flags as a 64-bit unsigned
long.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Dave Martin <dave.martin@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
arch/arm64/kernel/signal.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 154b7d30145d..8e624fec4707 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -896,7 +896,7 @@ static void do_signal(struct pt_regs *regs)
}
asmlinkage void do_notify_resume(struct pt_regs *regs,
- unsigned int thread_flags)
+ unsigned long thread_flags)
{
/*
* The assembly code enters us with IRQs off, but it hasn't
--
2.11.0
^ permalink raw reply related
* [PATCHv2 02/19] arm64: move SCTLR_EL{1, 2} assertions to <asm/sysreg.h>
From: Mark Rutland @ 2018-06-01 11:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180601112441.37810-1-mark.rutland@arm.com>
Currently we assert that the SCTLR_EL{1,2}_{SET,CLEAR} bits are
self-consistent with an assertion in config_sctlr_el1(). This is a bit
unusual, since config_sctlr_el1() doesn't make use of these definitions,
and is far away from the definitions themselves.
We can use the CPP #error directive to have equivalent assertions in
<asm/sysreg.h>, next to the definitions of the set/clear bits, which is
a bit clearer and simpler.
The preprocessor handles literals differently than regular C, e.g. ~0 is
equivalent to ~(intmax_t)0 rather than ~(int)0. Therefore, instead of ~0
we use 0xffffffff, which is unambiguous.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Dave Martin <dave.martin@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: James Morse <james.morse@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
arch/arm64/include/asm/sysreg.h | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 6171178075dc..bd1d1194a5e7 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -452,9 +452,9 @@
SCTLR_ELx_SA | SCTLR_ELx_I | SCTLR_ELx_WXN | \
ENDIAN_CLEAR_EL2 | SCTLR_EL2_RES0)
-/* Check all the bits are accounted for */
-#define SCTLR_EL2_BUILD_BUG_ON_MISSING_BITS BUILD_BUG_ON((SCTLR_EL2_SET ^ SCTLR_EL2_CLEAR) != ~0)
-
+#if (SCTLR_EL2_SET ^ SCTLR_EL2_CLEAR) != 0xffffffff
+#error "Inconsistent SCTLR_EL2 set/clear bits"
+#endif
/* SCTLR_EL1 specific flags. */
#define SCTLR_EL1_UCI (1 << 26)
@@ -492,8 +492,9 @@
SCTLR_EL1_UMA | SCTLR_ELx_WXN | ENDIAN_CLEAR_EL1 |\
SCTLR_EL1_RES0)
-/* Check all the bits are accounted for */
-#define SCTLR_EL1_BUILD_BUG_ON_MISSING_BITS BUILD_BUG_ON((SCTLR_EL1_SET ^ SCTLR_EL1_CLEAR) != ~0)
+#if (SCTLR_EL1_SET ^ SCTLR_EL1_CLEAR) != 0xffffffff
+#error "Inconsistent SCTLR_EL1 set/clear bits"
+#endif
/* id_aa64isar0 */
#define ID_AA64ISAR0_TS_SHIFT 52
@@ -732,9 +733,6 @@ static inline void config_sctlr_el1(u32 clear, u32 set)
{
u32 val;
- SCTLR_EL2_BUILD_BUG_ON_MISSING_BITS;
- SCTLR_EL1_BUILD_BUG_ON_MISSING_BITS;
-
val = read_sysreg(sctlr_el1);
val &= ~clear;
val |= set;
--
2.11.0
^ permalink raw reply related
* [PATCHv2 03/19] arm64: introduce sysreg_clear_set()
From: Mark Rutland @ 2018-06-01 11:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180601112441.37810-1-mark.rutland@arm.com>
Currently we have a couple of helpers to manipulate bits in particular
sysregs:
* config_sctlr_el1(u32 clear, u32 set)
* change_cpacr(u64 val, u64 mask)
The parameters of these differ in naming convention, order, and size,
which is unfortunate. They also differ slightly in behaviour, as
change_cpacr() skips the sysreg write if the bits are unchanged, which
is a useful optimization when sysreg writes are expensive.
Before we gain more yet another sysreg manipulation function, let's
unify these with a common helper, providing a consistent order for
clear/set operands, and the write skipping behaviour from
change_cpacr(). Code will be migrated to the new helper in subsequent
patches.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Dave Martin <dave.martin@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
---
arch/arm64/include/asm/sysreg.h | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index bd1d1194a5e7..b52762769329 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -729,6 +729,17 @@ asm(
asm volatile("msr_s " __stringify(r) ", %x0" : : "rZ" (__val)); \
} while (0)
+/*
+ * Modify bits in a sysreg. Bits in the clear mask are zeroed, then bits in the
+ * set mask are set. Other bits are left as-is.
+ */
+#define sysreg_clear_set(sysreg, clear, set) do { \
+ u64 __scs_val = read_sysreg(sysreg); \
+ u64 __scs_new = (__scs_val & ~(u64)(clear)) | (set); \
+ if (__scs_new != __scs_val) \
+ write_sysreg(__scs_new, sysreg); \
+} while (0)
+
static inline void config_sctlr_el1(u32 clear, u32 set)
{
u32 val;
--
2.11.0
^ permalink raw reply related
* [PATCHv2 04/19] arm64: kill config_sctlr_el1()
From: Mark Rutland @ 2018-06-01 11:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180601112441.37810-1-mark.rutland@arm.com>
Now that we have sysreg_clear_set(), we can consistently use this
instead of config_sctlr_el1().
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Dave Martin <dave.martin@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: James Morse <james.morse@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
arch/arm64/include/asm/sysreg.h | 10 ----------
arch/arm64/kernel/armv8_deprecated.c | 8 ++++----
arch/arm64/kernel/cpu_errata.c | 3 +--
arch/arm64/kernel/traps.c | 2 +-
arch/arm64/mm/fault.c | 2 +-
5 files changed, 7 insertions(+), 18 deletions(-)
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index b52762769329..3493c7048994 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -740,16 +740,6 @@ asm(
write_sysreg(__scs_new, sysreg); \
} while (0)
-static inline void config_sctlr_el1(u32 clear, u32 set)
-{
- u32 val;
-
- val = read_sysreg(sctlr_el1);
- val &= ~clear;
- val |= set;
- write_sysreg(val, sctlr_el1);
-}
-
#endif
#endif /* __ASM_SYSREG_H */
diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
index 97d45d5151d4..c15847521394 100644
--- a/arch/arm64/kernel/armv8_deprecated.c
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -511,9 +511,9 @@ static int cp15barrier_handler(struct pt_regs *regs, u32 instr)
static int cp15_barrier_set_hw_mode(bool enable)
{
if (enable)
- config_sctlr_el1(0, SCTLR_EL1_CP15BEN);
+ sysreg_clear_set(sctlr_el1, 0, SCTLR_EL1_CP15BEN);
else
- config_sctlr_el1(SCTLR_EL1_CP15BEN, 0);
+ sysreg_clear_set(sctlr_el1, SCTLR_EL1_CP15BEN, 0);
return 0;
}
@@ -548,9 +548,9 @@ static int setend_set_hw_mode(bool enable)
return -EINVAL;
if (enable)
- config_sctlr_el1(SCTLR_EL1_SED, 0);
+ sysreg_clear_set(sctlr_el1, SCTLR_EL1_SED, 0);
else
- config_sctlr_el1(0, SCTLR_EL1_SED);
+ sysreg_clear_set(sctlr_el1, 0, SCTLR_EL1_SED);
return 0;
}
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index cf37ca6fa5f2..b99e492c44b5 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -74,8 +74,7 @@ has_mismatched_cache_line_size(const struct arm64_cpu_capabilities *entry,
static void
cpu_enable_trap_ctr_access(const struct arm64_cpu_capabilities *__unused)
{
- /* Clear SCTLR_EL1.UCT */
- config_sctlr_el1(SCTLR_EL1_UCT, 0);
+ sysreg_clear_set(sctlr_el1, SCTLR_EL1_UCT, 0);
}
atomic_t arm64_el2_vector_last_slot = ATOMIC_INIT(-1);
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index 8bbdc17e49df..b8d3e0d8c616 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -411,7 +411,7 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
void cpu_enable_cache_maint_trap(const struct arm64_cpu_capabilities *__unused)
{
- config_sctlr_el1(SCTLR_EL1_UCI, 0);
+ sysreg_clear_set(sctlr_el1, SCTLR_EL1_UCI, 0);
}
#define __user_cache_maint(insn, address, res) \
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 27cbe0b38960..07926ee00053 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -822,7 +822,7 @@ void cpu_enable_pan(const struct arm64_cpu_capabilities *__unused)
*/
WARN_ON_ONCE(in_interrupt());
- config_sctlr_el1(SCTLR_EL1_SPAN, 0);
+ sysreg_clear_set(sctlr_el1, SCTLR_EL1_SPAN, 0);
asm(SET_PSTATE_PAN(1));
}
#endif /* CONFIG_ARM64_PAN */
--
2.11.0
^ permalink raw reply related
* [PATCHv2 05/19] arm64: kill change_cpacr()
From: Mark Rutland @ 2018-06-01 11:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180601112441.37810-1-mark.rutland@arm.com>
Now that we have sysreg_clear_set(), we can use this instead of
change_cpacr().
Note that the order of the set and clear arguments differs between
change_cpacr() and sysreg_clear_set(), so these are flipped as part of
the conversion. Also, sve_user_enable() redundantly clears
CPACR_EL1_ZEN_EL0EN before setting it; this is removed for clarity.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Dave Martin <dave.martin@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: James Morse <james.morse@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
arch/arm64/kernel/fpsimd.c | 13 ++-----------
1 file changed, 2 insertions(+), 11 deletions(-)
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 3db8ed530e56..c135cff8f882 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -171,23 +171,14 @@ static void *sve_pffr(struct task_struct *task)
sve_ffr_offset(task->thread.sve_vl);
}
-static void change_cpacr(u64 val, u64 mask)
-{
- u64 cpacr = read_sysreg(CPACR_EL1);
- u64 new = (cpacr & ~mask) | val;
-
- if (new != cpacr)
- write_sysreg(new, CPACR_EL1);
-}
-
static void sve_user_disable(void)
{
- change_cpacr(0, CPACR_EL1_ZEN_EL0EN);
+ sysreg_clear_set(cpacr_el1, CPACR_EL1_ZEN_EL0EN, 0);
}
static void sve_user_enable(void)
{
- change_cpacr(CPACR_EL1_ZEN_EL0EN, CPACR_EL1_ZEN_EL0EN);
+ sysreg_clear_set(cpacr_el1, 0, CPACR_EL1_ZEN_EL0EN);
}
/*
--
2.11.0
^ permalink raw reply related
* [PATCHv2 06/19] arm64: move sve_user_{enable, disable} to <asm/fpsimd.h>
From: Mark Rutland @ 2018-06-01 11:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180601112441.37810-1-mark.rutland@arm.com>
In subsequent patches, we'll want to make use of sve_user_enable() and
sve_user_disable() outside of kernel/fpsimd.c. Let's move these to
<asm/fpsimd.h> where we can make use of them.
To avoid ifdeffery in sequences like:
if (system_supports_sve() && some_condition
sve_user_disable();
... empty stubs are provided when support for SVE is not enabled. Note
that system_supports_sve() contains as IS_ENABLED(CONFIG_ARM64_SVE), so
the sve_user_disable() call should be optimized away entirely when
CONFIG_ARM64_SVE is not selected.
To ensure that this is the case, the stub definitions contain a
BUILD_BUG(), as we do for other stubs for which calls should always be
optimized away when the relevant config option is not selected.
At the same time, the include list of <asm/fpsimd.h> is sorted while
adding <asm/sysreg.h>.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Dave Martin <dave.martin@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
arch/arm64/include/asm/fpsimd.h | 17 ++++++++++++++++-
arch/arm64/kernel/fpsimd.c | 10 ----------
2 files changed, 16 insertions(+), 11 deletions(-)
diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index aa7162ae93e3..c9acc6ad9b75 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -16,11 +16,13 @@
#ifndef __ASM_FP_H
#define __ASM_FP_H
-#include <asm/ptrace.h>
#include <asm/errno.h>
+#include <asm/ptrace.h>
+#include <asm/sysreg.h>
#ifndef __ASSEMBLY__
+#include <linux/build_bug.h>
#include <linux/cache.h>
#include <linux/init.h>
#include <linux/stddef.h>
@@ -81,6 +83,16 @@ extern int sve_set_vector_length(struct task_struct *task,
extern int sve_set_current_vl(unsigned long arg);
extern int sve_get_current_vl(void);
+static inline void sve_user_disable(void)
+{
+ sysreg_clear_set(cpacr_el1, CPACR_EL1_ZEN_EL0EN, 0);
+}
+
+static inline void sve_user_enable(void)
+{
+ sysreg_clear_set(cpacr_el1, 0, CPACR_EL1_ZEN_EL0EN);
+}
+
/*
* Probing and setup functions.
* Calls to these functions must be serialised with one another.
@@ -107,6 +119,9 @@ static inline int sve_get_current_vl(void)
return -EINVAL;
}
+static inline void sve_user_disable(void) { BUILD_BUG(); }
+static inline void sve_user_enable(void) { BUILD_BUG(); }
+
static inline void sve_init_vq_map(void) { }
static inline void sve_update_vq_map(void) { }
static inline int sve_verify_vq_map(void) { return 0; }
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index c135cff8f882..86f2eef428e0 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -171,16 +171,6 @@ static void *sve_pffr(struct task_struct *task)
sve_ffr_offset(task->thread.sve_vl);
}
-static void sve_user_disable(void)
-{
- sysreg_clear_set(cpacr_el1, CPACR_EL1_ZEN_EL0EN, 0);
-}
-
-static void sve_user_enable(void)
-{
- sysreg_clear_set(cpacr_el1, 0, CPACR_EL1_ZEN_EL0EN);
-}
-
/*
* TIF_SVE controls whether a task can use SVE without trapping while
* in userspace, and also the way a task's FPSIMD/SVE state is stored
--
2.11.0
^ permalink raw reply related
* [PATCHv2 07/19] arm64: remove sigreturn wrappers
From: Mark Rutland @ 2018-06-01 11:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180601112441.37810-1-mark.rutland@arm.com>
The arm64 sigreturn* syscall handlers are non-standard. Rather than
taking a number of user parameters in registers as per the AAPCS,
they expect the pt_regs as their sole argument.
To make this work, we override the syscall definitions to invoke
wrappers written in assembly, which mov the SP into x0, and branch to
their respective C functions.
On other architectures (such as x86), the sigreturn* functions take no
argument and instead use current_pt_regs() to acquire the user
registers. This requires less boilerplate code, and allows for other
features such as interposing C code in this path.
This patch takes the same approach for arm64.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Tentatively-reviewed-by: Dave Martin <dave.martin@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
arch/arm64/include/asm/unistd32.h | 4 ++--
arch/arm64/kernel/entry.S | 8 --------
arch/arm64/kernel/entry32.S | 10 ----------
arch/arm64/kernel/signal.c | 3 ++-
arch/arm64/kernel/signal32.c | 6 ++++--
arch/arm64/kernel/sys.c | 3 +--
arch/arm64/kernel/sys32.c | 4 ++--
7 files changed, 11 insertions(+), 27 deletions(-)
diff --git a/arch/arm64/include/asm/unistd32.h b/arch/arm64/include/asm/unistd32.h
index ef292160748c..ab95554b1734 100644
--- a/arch/arm64/include/asm/unistd32.h
+++ b/arch/arm64/include/asm/unistd32.h
@@ -260,7 +260,7 @@ __SYSCALL(117, sys_ni_syscall)
#define __NR_fsync 118
__SYSCALL(__NR_fsync, sys_fsync)
#define __NR_sigreturn 119
-__SYSCALL(__NR_sigreturn, compat_sys_sigreturn_wrapper)
+__SYSCALL(__NR_sigreturn, compat_sys_sigreturn)
#define __NR_clone 120
__SYSCALL(__NR_clone, sys_clone)
#define __NR_setdomainname 121
@@ -368,7 +368,7 @@ __SYSCALL(__NR_getresgid, sys_getresgid16)
#define __NR_prctl 172
__SYSCALL(__NR_prctl, sys_prctl)
#define __NR_rt_sigreturn 173
-__SYSCALL(__NR_rt_sigreturn, compat_sys_rt_sigreturn_wrapper)
+__SYSCALL(__NR_rt_sigreturn, compat_sys_rt_sigreturn)
#define __NR_rt_sigaction 174
__SYSCALL(__NR_rt_sigaction, compat_sys_rt_sigaction)
#define __NR_rt_sigprocmask 175
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 28ad8799406f..62f2876f9c63 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -1138,14 +1138,6 @@ __entry_tramp_data_start:
#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
/*
- * Special system call wrappers.
- */
-ENTRY(sys_rt_sigreturn_wrapper)
- mov x0, sp
- b sys_rt_sigreturn
-ENDPROC(sys_rt_sigreturn_wrapper)
-
-/*
* Register switch for AArch64. The callee-saved registers need to be saved
* and restored. On entry:
* x0 = previous task_struct (must be preserved across the switch)
diff --git a/arch/arm64/kernel/entry32.S b/arch/arm64/kernel/entry32.S
index f332d5d1f6b4..f9461696dde4 100644
--- a/arch/arm64/kernel/entry32.S
+++ b/arch/arm64/kernel/entry32.S
@@ -30,16 +30,6 @@
* System call wrappers for the AArch32 compatibility layer.
*/
-ENTRY(compat_sys_sigreturn_wrapper)
- mov x0, sp
- b compat_sys_sigreturn
-ENDPROC(compat_sys_sigreturn_wrapper)
-
-ENTRY(compat_sys_rt_sigreturn_wrapper)
- mov x0, sp
- b compat_sys_rt_sigreturn
-ENDPROC(compat_sys_rt_sigreturn_wrapper)
-
ENTRY(compat_sys_statfs64_wrapper)
mov w3, #84
cmp w1, #88
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 8e624fec4707..caa7a68cf2d2 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -538,8 +538,9 @@ static int restore_sigframe(struct pt_regs *regs,
return err;
}
-asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
+asmlinkage long sys_rt_sigreturn(void)
{
+ struct pt_regs *regs = current_pt_regs();
struct rt_sigframe __user *frame;
/* Always make any pending restarted system calls return -EINTR */
diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
index 77b91f478995..cb10588a7cb2 100644
--- a/arch/arm64/kernel/signal32.c
+++ b/arch/arm64/kernel/signal32.c
@@ -282,8 +282,9 @@ static int compat_restore_sigframe(struct pt_regs *regs,
return err;
}
-asmlinkage int compat_sys_sigreturn(struct pt_regs *regs)
+asmlinkage int compat_sys_sigreturn(void)
{
+ struct pt_regs *regs = current_pt_regs();
struct compat_sigframe __user *frame;
/* Always make any pending restarted system calls return -EINTR */
@@ -312,8 +313,9 @@ asmlinkage int compat_sys_sigreturn(struct pt_regs *regs)
return 0;
}
-asmlinkage int compat_sys_rt_sigreturn(struct pt_regs *regs)
+asmlinkage int compat_sys_rt_sigreturn(void)
{
+ struct pt_regs *regs = current_pt_regs();
struct compat_rt_sigframe __user *frame;
/* Always make any pending restarted system calls return -EINTR */
diff --git a/arch/arm64/kernel/sys.c b/arch/arm64/kernel/sys.c
index 72981bae10eb..31045f3fed92 100644
--- a/arch/arm64/kernel/sys.c
+++ b/arch/arm64/kernel/sys.c
@@ -48,8 +48,7 @@ SYSCALL_DEFINE1(arm64_personality, unsigned int, personality)
/*
* Wrappers to pass the pt_regs argument.
*/
-asmlinkage long sys_rt_sigreturn_wrapper(void);
-#define sys_rt_sigreturn sys_rt_sigreturn_wrapper
+asmlinkage long sys_rt_sigreturn(void);
#define sys_personality sys_arm64_personality
#undef __SYSCALL
diff --git a/arch/arm64/kernel/sys32.c b/arch/arm64/kernel/sys32.c
index a40b1343b819..1ef103c95410 100644
--- a/arch/arm64/kernel/sys32.c
+++ b/arch/arm64/kernel/sys32.c
@@ -25,8 +25,8 @@
#include <linux/compiler.h>
#include <linux/syscalls.h>
-asmlinkage long compat_sys_sigreturn_wrapper(void);
-asmlinkage long compat_sys_rt_sigreturn_wrapper(void);
+asmlinkage long compat_sys_sigreturn(void);
+asmlinkage long compat_sys_rt_sigreturn(void);
asmlinkage long compat_sys_statfs64_wrapper(void);
asmlinkage long compat_sys_fstatfs64_wrapper(void);
asmlinkage long compat_sys_pread64_wrapper(void);
--
2.11.0
^ permalink raw reply related
* [PATCHv2 08/19] arm64: convert raw syscall invocation to C
From: Mark Rutland @ 2018-06-01 11:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180601112441.37810-1-mark.rutland@arm.com>
As a first step towards invoking syscalls with a pt_regs argument,
convert the raw syscall invocation logic to C. We end up with a bit more
register shuffling, but the unified invocation logic means we can unify
the tracing paths, too.
Previously, assembly had to open-code calls to ni_sys() when the system
call number was out-of-bounds for the relevant syscall table. This case
is now handled by invoke_syscall(), and the assembly no longer need to
handle this case explicitly. This allows the tracing paths to be
simplfiied and unified, as we no longer need the __ni_sys_trace path and
the __sys_trace_return label.
This only converts the invocation of the syscall. The rest of the
syscall triage and tracing is left in assembly for now, and will be
converted in subsequent patches.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
arch/arm64/kernel/Makefile | 3 ++-
arch/arm64/kernel/entry.S | 36 ++++++++++--------------------------
arch/arm64/kernel/syscall.c | 30 ++++++++++++++++++++++++++++++
3 files changed, 42 insertions(+), 27 deletions(-)
create mode 100644 arch/arm64/kernel/syscall.c
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 0025f8691046..4e24d2244bd1 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -18,7 +18,8 @@ arm64-obj-y := debug-monitors.o entry.o irq.o fpsimd.o \
hyp-stub.o psci.o cpu_ops.o insn.o \
return_address.o cpuinfo.o cpu_errata.o \
cpufeature.o alternative.o cacheinfo.o \
- smp.o smp_spin_table.o topology.o smccc-call.o
+ smp.o smp_spin_table.o topology.o smccc-call.o \
+ syscall.o
extra-$(CONFIG_EFI) := efi-entry.o
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 62f2876f9c63..46543f34b9dc 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -903,7 +903,6 @@ ENDPROC(el0_error)
*/
ret_fast_syscall:
disable_daif
- str x0, [sp, #S_X0] // returned x0
ldr x1, [tsk, #TSK_TI_FLAGS] // re-check for syscall tracing
and x2, x1, #_TIF_SYSCALL_WORK
cbnz x2, ret_fast_syscall_trace
@@ -976,15 +975,11 @@ el0_svc_naked: // compat entry point
tst x16, #_TIF_SYSCALL_WORK // check for syscall hooks
b.ne __sys_trace
- cmp wscno, wsc_nr // check upper syscall limit
- b.hs ni_sys
- mask_nospec64 xscno, xsc_nr, x19 // enforce bounds for syscall number
- ldr x16, [stbl, xscno, lsl #3] // address in the syscall table
- blr x16 // call sys_* routine
- b ret_fast_syscall
-ni_sys:
mov x0, sp
- bl do_ni_syscall
+ mov w1, wscno
+ mov w2, wsc_nr
+ mov x3, stbl
+ bl invoke_syscall
b ret_fast_syscall
ENDPROC(el0_svc)
@@ -1001,29 +996,18 @@ __sys_trace:
bl syscall_trace_enter
cmp w0, #NO_SYSCALL // skip the syscall?
b.eq __sys_trace_return_skipped
- mov wscno, w0 // syscall number (possibly new)
- mov x1, sp // pointer to regs
- cmp wscno, wsc_nr // check upper syscall limit
- b.hs __ni_sys_trace
- ldp x0, x1, [sp] // restore the syscall args
- ldp x2, x3, [sp, #S_X2]
- ldp x4, x5, [sp, #S_X4]
- ldp x6, x7, [sp, #S_X6]
- ldr x16, [stbl, xscno, lsl #3] // address in the syscall table
- blr x16 // call sys_* routine
-__sys_trace_return:
- str x0, [sp, #S_X0] // save returned x0
+ mov x0, sp
+ mov w1, wscno
+ mov w2, wsc_nr
+ mov x3, stbl
+ bl invoke_syscall
+
__sys_trace_return_skipped:
mov x0, sp
bl syscall_trace_exit
b ret_to_user
-__ni_sys_trace:
- mov x0, sp
- bl do_ni_syscall
- b __sys_trace_return
-
.popsection // .entry.text
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
new file mode 100644
index 000000000000..b463b962d597
--- /dev/null
+++ b/arch/arm64/kernel/syscall.c
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/nospec.h>
+#include <linux/ptrace.h>
+
+long do_ni_syscall(struct pt_regs *regs);
+
+typedef long (*syscall_fn_t)(unsigned long, unsigned long,
+ unsigned long, unsigned long,
+ unsigned long, unsigned long);
+
+static void __invoke_syscall(struct pt_regs *regs, syscall_fn_t syscall_fn)
+{
+ regs->regs[0] = syscall_fn(regs->regs[0], regs->regs[1],
+ regs->regs[2], regs->regs[3],
+ regs->regs[4], regs->regs[5]);
+}
+
+asmlinkage void invoke_syscall(struct pt_regs *regs, unsigned int scno,
+ unsigned int sc_nr,
+ syscall_fn_t syscall_table[])
+{
+ if (scno < sc_nr) {
+ syscall_fn_t syscall_fn;
+ syscall_fn = syscall_table[array_index_nospec(scno, sc_nr)];
+ __invoke_syscall(regs, syscall_fn);
+ } else {
+ regs->regs[0] = do_ni_syscall(regs);
+ }
+}
--
2.11.0
^ permalink raw reply related
* [PATCHv2 09/19] arm64: convert syscall trace logic to C
From: Mark Rutland @ 2018-06-01 11:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180601112441.37810-1-mark.rutland@arm.com>
Currently syscall tracing is a tricky assembly state machine, which can
be rather difficult to follow, and even harder to modify. Before we
start fiddling with it for pt_regs syscalls, let's convert it to C.
This is not intended to have any functional change.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
arch/arm64/kernel/entry.S | 53 ++---------------------------------------
arch/arm64/kernel/syscall.c | 58 ++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 57 insertions(+), 54 deletions(-)
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 46543f34b9dc..05b9f03f3e00 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -896,24 +896,6 @@ el0_error_naked:
b ret_to_user
ENDPROC(el0_error)
-
-/*
- * This is the fast syscall return path. We do as little as possible here,
- * and this includes saving x0 back into the kernel stack.
- */
-ret_fast_syscall:
- disable_daif
- ldr x1, [tsk, #TSK_TI_FLAGS] // re-check for syscall tracing
- and x2, x1, #_TIF_SYSCALL_WORK
- cbnz x2, ret_fast_syscall_trace
- and x2, x1, #_TIF_WORK_MASK
- cbnz x2, work_pending
- enable_step_tsk x1, x2
- kernel_exit 0
-ret_fast_syscall_trace:
- enable_daif
- b __sys_trace_return_skipped // we already saved x0
-
/*
* Ok, we need to do extra processing, enter the slow path.
*/
@@ -969,44 +951,13 @@ alternative_else_nop_endif
#endif
el0_svc_naked: // compat entry point
- stp x0, xscno, [sp, #S_ORIG_X0] // save the original x0 and syscall number
- enable_daif
- ct_user_exit 1
-
- tst x16, #_TIF_SYSCALL_WORK // check for syscall hooks
- b.ne __sys_trace
mov x0, sp
mov w1, wscno
mov w2, wsc_nr
mov x3, stbl
- bl invoke_syscall
- b ret_fast_syscall
-ENDPROC(el0_svc)
-
- /*
- * This is the really slow path. We're going to be doing context
- * switches, and waiting for our parent to respond.
- */
-__sys_trace:
- cmp wscno, #NO_SYSCALL // user-issued syscall(-1)?
- b.ne 1f
- mov x0, #-ENOSYS // set default errno if so
- str x0, [sp, #S_X0]
-1: mov x0, sp
- bl syscall_trace_enter
- cmp w0, #NO_SYSCALL // skip the syscall?
- b.eq __sys_trace_return_skipped
-
- mov x0, sp
- mov w1, wscno
- mov w2, wsc_nr
- mov x3, stbl
- bl invoke_syscall
-
-__sys_trace_return_skipped:
- mov x0, sp
- bl syscall_trace_exit
+ bl el0_svc_common
b ret_to_user
+ENDPROC(el0_svc)
.popsection // .entry.text
diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index b463b962d597..2adf1a073398 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -1,8 +1,13 @@
// SPDX-License-Identifier: GPL-2.0
+#include <linux/compiler.h>
+#include <linux/context_tracking.h>
#include <linux/nospec.h>
#include <linux/ptrace.h>
+#include <asm/daifflags.h>
+#include <asm/thread_info.h>
+
long do_ni_syscall(struct pt_regs *regs);
typedef long (*syscall_fn_t)(unsigned long, unsigned long,
@@ -16,9 +21,9 @@ static void __invoke_syscall(struct pt_regs *regs, syscall_fn_t syscall_fn)
regs->regs[4], regs->regs[5]);
}
-asmlinkage void invoke_syscall(struct pt_regs *regs, unsigned int scno,
- unsigned int sc_nr,
- syscall_fn_t syscall_table[])
+static void invoke_syscall(struct pt_regs *regs, unsigned int scno,
+ unsigned int sc_nr,
+ syscall_fn_t syscall_table[])
{
if (scno < sc_nr) {
syscall_fn_t syscall_fn;
@@ -28,3 +33,50 @@ asmlinkage void invoke_syscall(struct pt_regs *regs, unsigned int scno,
regs->regs[0] = do_ni_syscall(regs);
}
}
+
+static inline bool has_syscall_work(unsigned long flags)
+{
+ return unlikely(flags & _TIF_SYSCALL_WORK);
+}
+
+int syscall_trace_enter(struct pt_regs *regs);
+void syscall_trace_exit(struct pt_regs *regs);
+
+asmlinkage void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
+ syscall_fn_t syscall_table[])
+{
+ unsigned long flags = current_thread_info()->flags;
+
+ regs->orig_x0 = regs->regs[0];
+ regs->syscallno = scno;
+
+ local_daif_restore(DAIF_PROCCTX);
+ user_exit();
+
+ if (has_syscall_work(flags)) {
+ /* set default errno for user-issued syscall(-1) */
+ if (scno == NO_SYSCALL)
+ regs->regs[0] = -ENOSYS;
+ scno = syscall_trace_enter(regs);
+ if (scno == NO_SYSCALL)
+ goto trace_exit;
+ }
+
+ invoke_syscall(regs, scno, sc_nr, syscall_table);
+
+ /*
+ * The tracing status may have changed under our feet, so we have to
+ * check again. However, if we were tracing entry, then we always trace
+ * exit regardless, as the old entry assembly did.
+ */
+ if (!has_syscall_work(flags)) {
+ local_daif_mask();
+ flags = current_thread_info()->flags;
+ if (!has_syscall_work(flags))
+ return;
+ local_daif_restore(DAIF_PROCCTX);
+ }
+
+trace_exit:
+ syscall_trace_exit(regs);
+}
--
2.11.0
^ permalink raw reply related
* [PATCHv2 10/19] arm64: convert native/compat syscall entry to C
From: Mark Rutland @ 2018-06-01 11:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180601112441.37810-1-mark.rutland@arm.com>
Now that the syscall invocation logic is in C, we can migrate the rest
of the syscall entry logic over, so that the entry assembly needn't look
at the register values at all.
The SVE reset across syscall logic now unconditionally clears TIF_SVE,
but sve_user_disable() will only write back to CPACR_EL1 when SVE is
actually enabled.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
arch/arm64/kernel/entry.S | 42 ++++--------------------------------------
arch/arm64/kernel/syscall.c | 40 ++++++++++++++++++++++++++++++++++++++--
2 files changed, 42 insertions(+), 40 deletions(-)
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 05b9f03f3e00..156c4e3fd1a4 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -720,14 +720,9 @@ el0_sync_compat:
b.ge el0_dbg
b el0_inv
el0_svc_compat:
- /*
- * AArch32 syscall handling
- */
- ldr x16, [tsk, #TSK_TI_FLAGS] // load thread flags
- adrp stbl, compat_sys_call_table // load compat syscall table pointer
- mov wscno, w7 // syscall number in w7 (r7)
- mov wsc_nr, #__NR_compat_syscalls
- b el0_svc_naked
+ mov x0, sp
+ bl el0_svc_compat_handler
+ b ret_to_user
.align 6
el0_irq_compat:
@@ -925,37 +920,8 @@ ENDPROC(ret_to_user)
*/
.align 6
el0_svc:
- ldr x16, [tsk, #TSK_TI_FLAGS] // load thread flags
- adrp stbl, sys_call_table // load syscall table pointer
- mov wscno, w8 // syscall number in w8
- mov wsc_nr, #__NR_syscalls
-
-#ifdef CONFIG_ARM64_SVE
-alternative_if_not ARM64_SVE
- b el0_svc_naked
-alternative_else_nop_endif
- tbz x16, #TIF_SVE, el0_svc_naked // Skip unless TIF_SVE set:
- bic x16, x16, #_TIF_SVE // discard SVE state
- str x16, [tsk, #TSK_TI_FLAGS]
-
- /*
- * task_fpsimd_load() won't be called to update CPACR_EL1 in
- * ret_to_user unless TIF_FOREIGN_FPSTATE is still set, which only
- * happens if a context switch or kernel_neon_begin() or context
- * modification (sigreturn, ptrace) intervenes.
- * So, ensure that CPACR_EL1 is already correct for the fast-path case:
- */
- mrs x9, cpacr_el1
- bic x9, x9, #CPACR_EL1_ZEN_EL0EN // disable SVE for el0
- msr cpacr_el1, x9 // synchronised by eret to el0
-#endif
-
-el0_svc_naked: // compat entry point
mov x0, sp
- mov w1, wscno
- mov w2, wsc_nr
- mov x3, stbl
- bl el0_svc_common
+ bl el0_svc_handler
b ret_to_user
ENDPROC(el0_svc)
diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index 2adf1a073398..6a31bb2a382b 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -6,7 +6,9 @@
#include <linux/ptrace.h>
#include <asm/daifflags.h>
+#include <asm/fpsimd.h>
#include <asm/thread_info.h>
+#include <asm/unistd.h>
long do_ni_syscall(struct pt_regs *regs);
@@ -42,8 +44,8 @@ static inline bool has_syscall_work(unsigned long flags)
int syscall_trace_enter(struct pt_regs *regs);
void syscall_trace_exit(struct pt_regs *regs);
-asmlinkage void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
- syscall_fn_t syscall_table[])
+static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
+ syscall_fn_t syscall_table[])
{
unsigned long flags = current_thread_info()->flags;
@@ -80,3 +82,37 @@ asmlinkage void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
trace_exit:
syscall_trace_exit(regs);
}
+
+static inline void sve_user_reset(void)
+{
+ if (!system_supports_sve())
+ return;
+
+ /*
+ * task_fpsimd_load() won't be called to update CPACR_EL1 in
+ * ret_to_user unless TIF_FOREIGN_FPSTATE is still set, which only
+ * happens if a context switch or kernel_neon_begin() or context
+ * modification (sigreturn, ptrace) intervenes.
+ * So, ensure that CPACR_EL1 is already correct for the fast-path case.
+ */
+ clear_thread_flag(TIF_SVE);
+ sve_user_disable();
+}
+
+extern syscall_fn_t sys_call_table[];
+
+asmlinkage void el0_svc_handler(struct pt_regs *regs)
+{
+ sve_user_reset();
+ el0_svc_common(regs, regs->regs[8], __NR_syscalls, sys_call_table);
+}
+
+#ifdef CONFIG_COMPAT
+extern syscall_fn_t compat_sys_call_table[];
+
+asmlinkage void el0_svc_compat_handler(struct pt_regs *regs)
+{
+ el0_svc_common(regs, regs->regs[7], __NR_compat_syscalls,
+ compat_sys_call_table);
+}
+#endif
--
2.11.0
^ permalink raw reply related
* [PATCHv2 11/19] arm64: don't reload GPRs after apply_ssbd
From: Mark Rutland @ 2018-06-01 11:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180601112441.37810-1-mark.rutland@arm.com>
Now that all of the syscall logic works on the saved pt_regs, apply_ssbd
can safely corrupt x0-x3 in the entry paths, and we no longer need to
restore them. So let's remotve the logic doing so.
With that logic gone, we can fold the branch target into the macro, so
that callers need not deal with this. GAS provides \@, which provides a
unique value per macro invocation, which we can use to create a unique
label.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
arch/arm64/kernel/entry.S | 20 +++++++-------------
1 file changed, 7 insertions(+), 13 deletions(-)
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 156c4e3fd1a4..22c58e7dfc0f 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -140,20 +140,21 @@ alternative_else_nop_endif
// This macro corrupts x0-x3. It is the caller's duty
// to save/restore them if required.
- .macro apply_ssbd, state, targ, tmp1, tmp2
+ .macro apply_ssbd, state, tmp1, tmp2
#ifdef CONFIG_ARM64_SSBD
alternative_cb arm64_enable_wa2_handling
- b \targ
+ b skip_apply_ssbd\@
alternative_cb_end
ldr_this_cpu \tmp2, arm64_ssbd_callback_required, \tmp1
- cbz \tmp2, \targ
+ cbz \tmp2, skip_apply_ssbd\@
ldr \tmp2, [tsk, #TSK_TI_FLAGS]
- tbnz \tmp2, #TIF_SSBD, \targ
+ tbnz \tmp2, #TIF_SSBD, skip_apply_ssbd\@
mov w0, #ARM_SMCCC_ARCH_WORKAROUND_2
mov w1, #\state
alternative_cb arm64_update_smccc_conduit
nop // Patched to SMC/HVC #0
alternative_cb_end
+skip_apply_ssbd\@:
#endif
.endm
@@ -183,13 +184,7 @@ alternative_cb_end
ldr x19, [tsk, #TSK_TI_FLAGS] // since we can unmask debug
disable_step_tsk x19, x20 // exceptions when scheduling.
- apply_ssbd 1, 1f, x22, x23
-
-#ifdef CONFIG_ARM64_SSBD
- ldp x0, x1, [sp, #16 * 0]
- ldp x2, x3, [sp, #16 * 1]
-#endif
-1:
+ apply_ssbd 1, x22, x23
mov x29, xzr // fp pointed to user-space
.else
@@ -331,8 +326,7 @@ alternative_if ARM64_WORKAROUND_845719
alternative_else_nop_endif
#endif
3:
- apply_ssbd 0, 5f, x0, x1
-5:
+ apply_ssbd 0, x0, x1
.endif
msr elr_el1, x21 // set up the return data
--
2.11.0
^ permalink raw reply related
* [PATCHv2 12/19] arm64: zero GPRs upon entry from EL0
From: Mark Rutland @ 2018-06-01 11:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180601112441.37810-1-mark.rutland@arm.com>
We can zero GPRs x0 - x29 upon entry from EL0 to make it harder for
userspace to control values consumed by speculative gadgets.
We don't blat x30, since this is stashed much later, and we'll blat it
before invoking C code.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
arch/arm64/kernel/entry.S | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 22c58e7dfc0f..39440c2ee66d 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -63,6 +63,12 @@
#endif
.endm
+ .macro clear_gp_regs
+ .irp n,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29
+ mov x\n, xzr
+ .endr
+ .endm
+
/*
* Bad Abort numbers
*-----------------
@@ -179,6 +185,7 @@ skip_apply_ssbd\@:
stp x28, x29, [sp, #16 * 14]
.if \el == 0
+ clear_gp_regs
mrs x21, sp_el0
ldr_this_cpu tsk, __entry_task, x20 // Ensure MDSCR_EL1.SS is clear,
ldr x19, [tsk, #TSK_TI_FLAGS] // since we can unmask debug
@@ -186,7 +193,6 @@ skip_apply_ssbd\@:
apply_ssbd 1, x22, x23
- mov x29, xzr // fp pointed to user-space
.else
add x21, sp, #S_FRAME_SIZE
get_thread_info tsk
--
2.11.0
^ permalink raw reply related
* [PATCHv2 13/19] kernel: add ksys_personality()
From: Mark Rutland @ 2018-06-01 11:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180601112441.37810-1-mark.rutland@arm.com>
Using this helper allows us to avoid the in-kernel call to the
sys_personality() syscall. The ksys_ prefix denotes that this function
is meant as a drop-in replacement for the syscall. In particular, it
uses the same calling convention as sys_personality().
Since ksys_personality is trivial, it is implemented directly in
<linux/syscalls.h>, as we do for ksys_close() and friends.
This helper is necessary to enable conversion of arm64's syscall
handling to use pt_regs wrappers.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Dave Martin <dave.martin@arm.com>
Cc: Dominik Brodowski <linux@dominikbrodowski.net>
---
include/linux/syscalls.h | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 70fcda1a9049..652e166deb64 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -79,6 +79,7 @@ union bpf_attr;
#include <linux/unistd.h>
#include <linux/quota.h>
#include <linux/key.h>
+#include <linux/personality.h>
#include <trace/syscall.h>
#ifdef CONFIG_ARCH_HAS_SYSCALL_WRAPPER
@@ -1268,4 +1269,14 @@ static inline long ksys_truncate(const char __user *pathname, loff_t length)
return do_sys_truncate(pathname, length);
}
+static inline unsigned int ksys_personality(unsigned int personality)
+{
+ unsigned int old = current->personality;
+
+ if (personality != 0xffffffff)
+ set_personality(personality);
+
+ return old;
+}
+
#endif
--
2.11.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox