Skip to content

Commit 79131f2

Browse files
committed
lkl: host ops: fix jump buffer API and implementation
longjmp was called after the function which called setjmp exited (i.e. lkl_ops->jmp_buf_set), which rendered the context set by setjmp invalid. To avoid this issue this patch implements a different set jump buffer API by adding the function to execute as an argument to make sure that the setjmp context remains valid during the exection of the function. Thus, calles of the function can safely call longjmp. Signed-off-by: Octavian Purdila <tavi@cs.pub.ro>
1 parent 379f265 commit 79131f2

8 files changed

Lines changed: 51 additions & 43 deletions

File tree

arch/lkl/include/asm/sched.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#ifndef _ASM_LKL_SCHED_H
2+
#define _ASM_LKL_SCHED_H
3+
4+
#include <linux/sched.h>
5+
6+
static inline void thread_sched_jb(void)
7+
{
8+
set_ti_thread_flag(current_thread_info(), TIF_SCHED_JB);
9+
10+
if (test_ti_thread_flag(current_thread_info(), TIF_HOST_THREAD)) {
11+
set_current_state(TASK_UNINTERRUPTIBLE);
12+
lkl_ops->jmp_buf_set(&current_thread_info()->sched_jb,
13+
schedule);
14+
} else {
15+
lkl_ops->jmp_buf_set(&current_thread_info()->sched_jb,
16+
lkl_idle_tail_schedule);
17+
}
18+
}
19+
20+
static inline void thread_set_sched_exit(void)
21+
{
22+
set_ti_thread_flag(current_thread_info(), TIF_SCHED_EXIT);
23+
}
24+
25+
void switch_to_host_task(struct task_struct *);
26+
27+
#endif /* _ASM_LKL_SCHED_H */

arch/lkl/include/asm/thread_info.h

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -63,21 +63,6 @@ void threads_cnt_dec(void);
6363
#define TIF_HOST_THREAD 9
6464
#define TIF_IDLE 10
6565

66-
static inline void set_ti_thread_flag(struct thread_info *ti, int flag);
67-
68-
static inline int thread_set_sched_jmp(void)
69-
{
70-
set_ti_thread_flag(current_thread_info(), TIF_SCHED_JB);
71-
return lkl_ops->jmp_buf_set(&current_thread_info()->sched_jb);
72-
}
73-
74-
static inline void thread_set_sched_exit(void)
75-
{
76-
set_ti_thread_flag(current_thread_info(), TIF_SCHED_EXIT);
77-
}
78-
79-
void switch_to_host_task(struct task_struct *);
80-
8166
#define __HAVE_THREAD_FUNCTIONS
8267

8368
#define task_thread_info(task) ((struct thread_info *)(task)->stack)

arch/lkl/include/uapi/asm/host_ops.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,17 @@ struct lkl_jmp_buf {
7070
*
7171
* @gettid - returns the host thread id of the caller, which need not
7272
* be the same as the handle returned by thread_create
73+
*
74+
* @jmp_buf_set - runs the give function and setups a jump back point by saving
75+
* the context in the jump buffer; jmp_buf_longjmp can be called from the give
76+
* function or any callee in that function to return back to the jump back
77+
* point
78+
*
79+
* NOTE: we can't return from jmp_buf_set before calling jmp_buf_longjmp or
80+
* otherwise the saved context (stack) is not going to be valid, so we must pass
81+
* the function that will eventually call longjmp here
82+
*
83+
* @jmp_buf_longjmp - perform a jump back to the saved jump buffer
7384
*/
7485
struct lkl_host_operations {
7586
const char *virtio_devices;
@@ -114,7 +125,7 @@ struct lkl_host_operations {
114125

115126
long (*gettid)(void);
116127

117-
int (*jmp_buf_set)(struct lkl_jmp_buf *jmpb);
128+
void (*jmp_buf_set)(struct lkl_jmp_buf *jmpb, void (*f)(void));
118129
void (*jmp_buf_longjmp)(struct lkl_jmp_buf *jmpb, int val);
119130
};
120131

arch/lkl/kernel/cpu.c

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <asm/cpu.h>
88
#include <asm/thread_info.h>
99
#include <asm/unistd.h>
10+
#include <asm/sched.h>
1011
#include <asm/syscalls.h>
1112

1213

@@ -137,14 +138,7 @@ void lkl_cpu_put(void)
137138
if (in_interrupt())
138139
lkl_bug("%s: in interrupt\n", __func__);
139140
lkl_ops->mutex_unlock(cpu.lock);
140-
if (test_thread_flag(TIF_HOST_THREAD)) {
141-
set_current_state(TASK_UNINTERRUPTIBLE);
142-
if (!thread_set_sched_jmp())
143-
schedule();
144-
} else {
145-
if (!thread_set_sched_jmp())
146-
lkl_idle_tail_schedule();
147-
}
141+
thread_sched_jb();
148142
return;
149143
}
150144

@@ -242,10 +236,8 @@ void arch_cpu_idle_prepare(void)
242236
* We hijack the idle loop here so that we can let the idle thread
243237
* jump back to the beginning.
244238
*/
245-
while (1) {
246-
if (!lkl_ops->jmp_buf_set(&cpu.idle_jb))
247-
cpu_idle_loop();
248-
}
239+
while (1)
240+
lkl_ops->jmp_buf_set(&cpu.idle_jb, cpu_idle_loop);
249241
}
250242

251243
void lkl_cpu_wakeup_idle(void)

arch/lkl/kernel/syscalls.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <asm/syscalls.h>
1515
#include <asm/syscalls_32.h>
1616
#include <asm/cpu.h>
17+
#include <asm/sched.h>
1718

1819
static asmlinkage long sys_virtio_mmio_device_add(long base, long size,
1920
unsigned int irq);
@@ -114,9 +115,7 @@ long lkl_syscall(long no, long *params)
114115
ret = run_syscall(no, params);
115116

116117
if (no == __NR_reboot) {
117-
set_current_state(TASK_UNINTERRUPTIBLE);
118-
if (!thread_set_sched_jmp())
119-
schedule();
118+
thread_sched_jb();
120119
return ret;
121120
}
122121

arch/lkl/kernel/threads.c

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <linux/sched.h>
44
#include <asm/host_ops.h>
55
#include <asm/cpu.h>
6+
#include <asm/sched.h>
67

78
static volatile int threads_counter;
89

@@ -140,15 +141,7 @@ void switch_to_host_task(struct task_struct *task)
140141
task_thread_info(task)->tid = lkl_ops->thread_self();
141142

142143
wake_up_process(task);
143-
if (test_thread_flag(TIF_HOST_THREAD)) {
144-
set_current_state(TASK_UNINTERRUPTIBLE);
145-
if (!thread_set_sched_jmp())
146-
schedule();
147-
} else {
148-
if (!thread_set_sched_jmp())
149-
lkl_idle_tail_schedule();
150-
}
151-
144+
thread_sched_jb();
152145
lkl_ops->sem_down(task_thread_info(task)->sched_sem);
153146
schedule_tail(abs_prev);
154147
}

tools/lkl/lib/jmp_buf.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
#include <setjmp.h>
22
#include <lkl_host.h>
33

4-
int jmp_buf_set(struct lkl_jmp_buf *jmpb)
4+
void jmp_buf_set(struct lkl_jmp_buf *jmpb, void (*f)(void))
55
{
6-
return setjmp(*((jmp_buf *)jmpb->buf));
6+
if (!setjmp(*((jmp_buf *)jmpb->buf)))
7+
f();
78
}
89

910
void jmp_buf_longjmp(struct lkl_jmp_buf *jmpb, int val)

tools/lkl/lib/jmp_buf.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef _LKL_LIB_JMP_BUF_H
22
#define _LKL_LIB_JMP_BUF_H
33

4-
int jmp_buf_set(struct lkl_jmp_buf *jmpb);
4+
void jmp_buf_set(struct lkl_jmp_buf *jmpb, void (*f)(void));
55
void jmp_buf_longjmp(struct lkl_jmp_buf *jmpb, int val);
66

77
#endif

0 commit comments

Comments
 (0)