summaryrefslogtreecommitdiff
path: root/arch/arm64/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm64/kernel')
-rw-r--r--arch/arm64/kernel/signal.c58
-rw-r--r--arch/arm64/kernel/signal32.c24
-rw-r--r--arch/arm64/kernel/smp.c65
3 files changed, 70 insertions, 77 deletions
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 6357b9c6c90e..6fa792137eda 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -209,19 +209,13 @@ static int setup_sigframe(struct rt_sigframe __user *sf,
return err;
}
-static struct rt_sigframe __user *get_sigframe(struct k_sigaction *ka,
+static struct rt_sigframe __user *get_sigframe(struct ksignal *ksig,
struct pt_regs *regs)
{
unsigned long sp, sp_top;
struct rt_sigframe __user *frame;
- sp = sp_top = regs->sp;
-
- /*
- * This is the X/Open sanctioned signal stack switching.
- */
- if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
- sp = sp_top = current->sas_ss_sp + current->sas_ss_size;
+ sp = sp_top = sigsp(regs->sp, ksig);
sp = (sp - sizeof(struct rt_sigframe)) & ~15;
frame = (struct rt_sigframe __user *)sp;
@@ -253,13 +247,13 @@ static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
regs->regs[30] = (unsigned long)sigtramp;
}
-static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
- sigset_t *set, struct pt_regs *regs)
+static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
+ struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
int err = 0;
- frame = get_sigframe(ka, regs);
+ frame = get_sigframe(ksig, regs);
if (!frame)
return 1;
@@ -269,9 +263,9 @@ static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
err |= setup_sigframe(frame, regs, set);
if (err == 0) {
- setup_return(regs, ka, frame, usig);
- if (ka->sa.sa_flags & SA_SIGINFO) {
- err |= copy_siginfo_to_user(&frame->info, info);
+ setup_return(regs, &ksig->ka, frame, usig);
+ if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
+ err |= copy_siginfo_to_user(&frame->info, &ksig->info);
regs->regs[1] = (unsigned long)&frame->info;
regs->regs[2] = (unsigned long)&frame->uc;
}
@@ -291,13 +285,12 @@ static void setup_restart_syscall(struct pt_regs *regs)
/*
* OK, we're invoking a handler
*/
-static void handle_signal(unsigned long sig, struct k_sigaction *ka,
- siginfo_t *info, struct pt_regs *regs)
+static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
{
struct thread_info *thread = current_thread_info();
struct task_struct *tsk = current;
sigset_t *oldset = sigmask_to_save();
- int usig = sig;
+ int usig = ksig->sig;
int ret;
/*
@@ -310,13 +303,12 @@ static void handle_signal(unsigned long sig, struct k_sigaction *ka,
* Set up the stack frame
*/
if (is_compat_task()) {
- if (ka->sa.sa_flags & SA_SIGINFO)
- ret = compat_setup_rt_frame(usig, ka, info, oldset,
- regs);
+ if (ksig->ka.sa.sa_flags & SA_SIGINFO)
+ ret = compat_setup_rt_frame(usig, ksig, oldset, regs);
else
- ret = compat_setup_frame(usig, ka, oldset, regs);
+ ret = compat_setup_frame(usig, ksig, oldset, regs);
} else {
- ret = setup_rt_frame(usig, ka, info, oldset, regs);
+ ret = setup_rt_frame(usig, ksig, oldset, regs);
}
/*
@@ -324,18 +316,14 @@ static void handle_signal(unsigned long sig, struct k_sigaction *ka,
*/
ret |= !valid_user_regs(&regs->user_regs);
- if (ret != 0) {
- force_sigsegv(sig, tsk);
- return;
- }
-
/*
* Fast forward the stepping logic so we step into the signal
* handler.
*/
- user_fastforward_single_step(tsk);
+ if (!ret)
+ user_fastforward_single_step(tsk);
- signal_delivered(sig, info, ka, regs, 0);
+ signal_setup_done(ret, ksig, 0);
}
/*
@@ -350,10 +338,9 @@ static void handle_signal(unsigned long sig, struct k_sigaction *ka,
static void do_signal(struct pt_regs *regs)
{
unsigned long continue_addr = 0, restart_addr = 0;
- struct k_sigaction ka;
- siginfo_t info;
- int signr, retval = 0;
+ int retval = 0;
int syscall = (int)regs->syscallno;
+ struct ksignal ksig;
/*
* If we were from a system call, check for system call restarting...
@@ -387,8 +374,7 @@ static void do_signal(struct pt_regs *regs)
* Get the signal to deliver. When running under ptrace, at this point
* the debugger may change all of our registers.
*/
- signr = get_signal_to_deliver(&info, &ka, regs, NULL);
- if (signr > 0) {
+ if (get_signal(&ksig)) {
/*
* Depending on the signal settings, we may need to revert the
* decision to restart the system call, but skip this if a
@@ -398,12 +384,12 @@ static void do_signal(struct pt_regs *regs)
(retval == -ERESTARTNOHAND ||
retval == -ERESTART_RESTARTBLOCK ||
(retval == -ERESTARTSYS &&
- !(ka.sa.sa_flags & SA_RESTART)))) {
+ !(ksig.ka.sa.sa_flags & SA_RESTART)))) {
regs->regs[0] = -EINTR;
regs->pc = continue_addr;
}
- handle_signal(signr, &ka, &info, regs);
+ handle_signal(&ksig, regs);
return;
}
diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
index c5ee208321c3..1b9ad02837cf 100644
--- a/arch/arm64/kernel/signal32.c
+++ b/arch/arm64/kernel/signal32.c
@@ -407,20 +407,14 @@ badframe:
return 0;
}
-static void __user *compat_get_sigframe(struct k_sigaction *ka,
+static void __user *compat_get_sigframe(struct ksignal *ksig,
struct pt_regs *regs,
int framesize)
{
- compat_ulong_t sp = regs->compat_sp;
+ compat_ulong_t sp = sigsp(regs->compat_sp, ksig);
void __user *frame;
/*
- * This is the X/Open sanctioned signal stack switching.
- */
- if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
- sp = current->sas_ss_sp + current->sas_ss_size;
-
- /*
* ATPCS B01 mandates 8-byte alignment
*/
frame = compat_ptr((compat_uptr_t)((sp - framesize) & ~7));
@@ -520,18 +514,18 @@ static int compat_setup_sigframe(struct compat_sigframe __user *sf,
/*
* 32-bit signal handling routines called from signal.c
*/
-int compat_setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
+int compat_setup_rt_frame(int usig, struct ksignal *ksig,
sigset_t *set, struct pt_regs *regs)
{
struct compat_rt_sigframe __user *frame;
int err = 0;
- frame = compat_get_sigframe(ka, regs, sizeof(*frame));
+ frame = compat_get_sigframe(ksig, regs, sizeof(*frame));
if (!frame)
return 1;
- err |= copy_siginfo_to_user32(&frame->info, info);
+ err |= copy_siginfo_to_user32(&frame->info, &ksig->info);
__put_user_error(0, &frame->sig.uc.uc_flags, err);
__put_user_error(0, &frame->sig.uc.uc_link, err);
@@ -541,7 +535,7 @@ int compat_setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
err |= compat_setup_sigframe(&frame->sig, regs, set);
if (err == 0) {
- compat_setup_return(regs, ka, frame->sig.retcode, frame, usig);
+ compat_setup_return(regs, &ksig->ka, frame->sig.retcode, frame, usig);
regs->regs[1] = (compat_ulong_t)(unsigned long)&frame->info;
regs->regs[2] = (compat_ulong_t)(unsigned long)&frame->sig.uc;
}
@@ -549,13 +543,13 @@ int compat_setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
return err;
}
-int compat_setup_frame(int usig, struct k_sigaction *ka, sigset_t *set,
+int compat_setup_frame(int usig, struct ksignal *ksig, sigset_t *set,
struct pt_regs *regs)
{
struct compat_sigframe __user *frame;
int err = 0;
- frame = compat_get_sigframe(ka, regs, sizeof(*frame));
+ frame = compat_get_sigframe(ksig, regs, sizeof(*frame));
if (!frame)
return 1;
@@ -564,7 +558,7 @@ int compat_setup_frame(int usig, struct k_sigaction *ka, sigset_t *set,
err |= compat_setup_sigframe(frame, regs, set);
if (err == 0)
- compat_setup_return(regs, ka, frame->retcode, frame, usig);
+ compat_setup_return(regs, &ksig->ka, frame->retcode, frame, usig);
return err;
}
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 3e2f5ebbf63e..474339718105 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -51,6 +51,9 @@
#include <asm/tlbflush.h>
#include <asm/ptrace.h>
+#define CREATE_TRACE_POINTS
+#include <trace/events/ipi.h>
+
/*
* as from 2.5, kernels no longer have an init_tasks structure
* so we need some other way of telling a new secondary core
@@ -313,8 +316,6 @@ void __init smp_prepare_boot_cpu(void)
set_my_cpu_offset(per_cpu_offset(smp_processor_id()));
}
-static void (*smp_cross_call)(const struct cpumask *, unsigned int);
-
/*
* Enumerate the possible CPU set from the device tree and build the
* cpu logical map array containing MPIDR values related to logical
@@ -469,32 +470,15 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
}
}
+static void (*__smp_cross_call)(const struct cpumask *, unsigned int);
void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int))
{
- smp_cross_call = fn;
+ __smp_cross_call = fn;
}
-void arch_send_call_function_ipi_mask(const struct cpumask *mask)
-{
- smp_cross_call(mask, IPI_CALL_FUNC);
-}
-
-void arch_send_call_function_single_ipi(int cpu)
-{
- smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);
-}
-
-#ifdef CONFIG_IRQ_WORK
-void arch_irq_work_raise(void)
-{
- if (smp_cross_call)
- smp_cross_call(cpumask_of(smp_processor_id()), IPI_IRQ_WORK);
-}
-#endif
-
-static const char *ipi_types[NR_IPI] = {
-#define S(x,s) [x - IPI_RESCHEDULE] = s
+static const char *ipi_types[NR_IPI] __tracepoint_string = {
+#define S(x,s) [x] = s
S(IPI_RESCHEDULE, "Rescheduling interrupts"),
S(IPI_CALL_FUNC, "Function call interrupts"),
S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"),
@@ -503,12 +487,18 @@ static const char *ipi_types[NR_IPI] = {
S(IPI_IRQ_WORK, "IRQ work interrupts"),
};
+static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
+{
+ trace_ipi_raise(target, ipi_types[ipinr]);
+ __smp_cross_call(target, ipinr);
+}
+
void show_ipi_list(struct seq_file *p, int prec)
{
unsigned int cpu, i;
for (i = 0; i < NR_IPI; i++) {
- seq_printf(p, "%*s%u:%s", prec - 1, "IPI", i + IPI_RESCHEDULE,
+ seq_printf(p, "%*s%u:%s", prec - 1, "IPI", i,
prec >= 4 ? " " : "");
for_each_online_cpu(cpu)
seq_printf(p, "%10u ",
@@ -528,6 +518,24 @@ u64 smp_irq_stat_cpu(unsigned int cpu)
return sum;
}
+void arch_send_call_function_ipi_mask(const struct cpumask *mask)
+{
+ smp_cross_call(mask, IPI_CALL_FUNC);
+}
+
+void arch_send_call_function_single_ipi(int cpu)
+{
+ smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);
+}
+
+#ifdef CONFIG_IRQ_WORK
+void arch_irq_work_raise(void)
+{
+ if (__smp_cross_call)
+ smp_cross_call(cpumask_of(smp_processor_id()), IPI_IRQ_WORK);
+}
+#endif
+
static DEFINE_RAW_SPINLOCK(stop_lock);
/*
@@ -559,8 +567,10 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
unsigned int cpu = smp_processor_id();
struct pt_regs *old_regs = set_irq_regs(regs);
- if (ipinr >= IPI_RESCHEDULE && ipinr < IPI_RESCHEDULE + NR_IPI)
- __inc_irq_stat(cpu, ipi_irqs[ipinr - IPI_RESCHEDULE]);
+ if ((unsigned)ipinr < NR_IPI) {
+ trace_ipi_entry(ipi_types[ipinr]);
+ __inc_irq_stat(cpu, ipi_irqs[ipinr]);
+ }
switch (ipinr) {
case IPI_RESCHEDULE:
@@ -605,6 +615,9 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr);
break;
}
+
+ if ((unsigned)ipinr < NR_IPI)
+ trace_ipi_exit(ipi_types[ipinr]);
set_irq_regs(old_regs);
}