Skip to content

Commit e740936

Browse files
author
Vasily Gorbik
committed
s390/test_unwind: add irq context tests
Add unwinding from irq context tests. Unwinder should be able to unwind through irq stack to task stack up to task pt_regs. Reviewed-by: Heiko Carstens <[email protected]> Signed-off-by: Vasily Gorbik <[email protected]>
1 parent 0610154 commit e740936

File tree

1 file changed

+45
-0
lines changed

1 file changed

+45
-0
lines changed

arch/s390/lib/test_unwind.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
#include <linux/module.h>
1212
#include <linux/string.h>
1313
#include <linux/wait.h>
14+
#include <asm/irq.h>
15+
#include <asm/delay.h>
1416

1517
#define BT_BUF_SIZE (PAGE_SIZE * 4)
1618

@@ -100,18 +102,23 @@ static noinline int test_unwind(struct task_struct *task, struct pt_regs *regs,
100102
/* State of the task being unwound. */
101103
struct unwindme {
102104
int flags;
105+
int ret;
106+
struct task_struct *task;
103107
struct completion task_ready;
104108
wait_queue_head_t task_wq;
105109
unsigned long sp;
106110
};
107111

112+
static struct unwindme *unwindme;
113+
108114
/* Values of unwindme.flags. */
109115
#define UWM_DEFAULT 0x0
110116
#define UWM_THREAD 0x1 /* Unwind a separate task. */
111117
#define UWM_REGS 0x2 /* Pass regs to test_unwind(). */
112118
#define UWM_SP 0x4 /* Pass sp to test_unwind(). */
113119
#define UWM_CALLER 0x8 /* Unwind starting from caller. */
114120
#define UWM_SWITCH_STACK 0x10 /* Use CALL_ON_STACK. */
121+
#define UWM_IRQ 0x20 /* Unwind from irq context. */
115122

116123
static __always_inline unsigned long get_psw_addr(void)
117124
{
@@ -173,6 +180,34 @@ static noinline int unwindme_func1(void *u)
173180
return unwindme_func2((struct unwindme *)u);
174181
}
175182

183+
static void unwindme_irq_handler(struct ext_code ext_code,
184+
unsigned int param32,
185+
unsigned long param64)
186+
{
187+
struct unwindme *u = READ_ONCE(unwindme);
188+
189+
if (u && u->task == current) {
190+
unwindme = NULL;
191+
u->task = NULL;
192+
u->ret = unwindme_func1(u);
193+
}
194+
}
195+
196+
static int test_unwind_irq(struct unwindme *u)
197+
{
198+
preempt_disable();
199+
if (register_external_irq(EXT_IRQ_CLK_COMP, unwindme_irq_handler)) {
200+
pr_info("Couldn't reqister external interrupt handler");
201+
return -1;
202+
}
203+
u->task = current;
204+
unwindme = u;
205+
udelay(1);
206+
unregister_external_irq(EXT_IRQ_CLK_COMP, unwindme_irq_handler);
207+
preempt_enable();
208+
return u->ret;
209+
}
210+
176211
/* Spawns a task and passes it to test_unwind(). */
177212
static int test_unwind_task(struct unwindme *u)
178213
{
@@ -211,6 +246,8 @@ static int test_unwind_flags(int flags)
211246
u.flags = flags;
212247
if (u.flags & UWM_THREAD)
213248
return test_unwind_task(&u);
249+
else if (u.flags & UWM_IRQ)
250+
return test_unwind_irq(&u);
214251
else
215252
return unwindme_func1(&u);
216253
}
@@ -241,6 +278,14 @@ do { \
241278
TEST(UWM_THREAD);
242279
TEST(UWM_THREAD | UWM_SP);
243280
TEST(UWM_THREAD | UWM_CALLER | UWM_SP);
281+
TEST(UWM_IRQ);
282+
TEST(UWM_IRQ | UWM_SWITCH_STACK);
283+
TEST(UWM_IRQ | UWM_SP);
284+
TEST(UWM_IRQ | UWM_REGS);
285+
TEST(UWM_IRQ | UWM_SP | UWM_REGS);
286+
TEST(UWM_IRQ | UWM_CALLER | UWM_SP);
287+
TEST(UWM_IRQ | UWM_CALLER | UWM_SP | UWM_REGS);
288+
TEST(UWM_IRQ | UWM_CALLER | UWM_SP | UWM_REGS | UWM_SWITCH_STACK);
244289
#undef TEST
245290

246291
return ret;

0 commit comments

Comments
 (0)