Skip to content

Commit 37a2f1a

Browse files
authored
Merge pull request #218 from smartobjectoriented/215-rework-thread
rework thread creation to match pthread
2 parents baaab35 + 7bf1139 commit 37a2f1a

File tree

15 files changed

+446
-464
lines changed

15 files changed

+446
-464
lines changed

so3/arch/arm32/asm-offsets.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ int main(void)
7878
DEFINE(OFFSET_PSR, offsetof(cpu_regs_t, psr));
7979
DEFINE(OFFSET_SP_USR, offsetof(cpu_regs_t, sp_usr));
8080
DEFINE(OFFSET_LR_USR, offsetof(cpu_regs_t, lr_usr));
81+
DEFINE(OFFSET_TLS_USR, offsetof(cpu_regs_t, tls_usr));
8182

8283
BLANK();
8384

so3/arch/arm32/context.S

Lines changed: 0 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,14 @@
3131

3232
.global __switch_context
3333
.global __thread_prologue_kernel
34-
.global __thread_prologue_user
3534
.global __exec_prologue_user
36-
.global __thread_prologue_user_pre_launch
3735

3836
.globl __get_syscall_args_ext
3937
.globl __get_syscall_arg
4038

4139
.global __mmu_switch_ttbr0
4240
.global __exec
4341
.global __write
44-
.global __save_context
4542

4643
.global __enable_vfp
4744

@@ -51,7 +48,6 @@
5148
#ifdef CONFIG_MMU
5249

5350
.extern __check_ptrace_traceme
54-
.extern ret_from_fork
5551
.extern pre_launch_proc
5652

5753
#endif
@@ -84,39 +80,6 @@ __thread_prologue_kernel:
8480

8581
bl thread_prologue
8682

87-
@ User thread initial entry point
88-
@ Called once per thread
89-
@ r4: th_fn, r5: th_arg, r6: user stack
90-
__thread_prologue_user:
91-
92-
@ Prepare to jump into C code
93-
mov r0, r4 @ tcb->th_fn
94-
mov r1, r5 @ tcb->th_arg
95-
96-
#ifdef CONFIG_MMU
97-
@ Check if the thread must stopped because of ptrace/tracee
98-
stmfd sp!, {r0, r1}
99-
bl __check_ptrace_traceme
100-
ldmfd sp!, {r0, r1}
101-
#endif
102-
103-
@ IRQ enabling - must be done in SVC mode of course ;-)
104-
@ We should take care about protecting against signal receipt:
105-
@ since the stack is not initialized yet, the signal processing should be kept disabled.
106-
cpsie i
107-
108-
@ Switch into user mode
109-
mrs r4, cpsr
110-
bic r4, r4, #PSR_MODE_MASK
111-
orr r4, r4, #PSR_USR_MODE
112-
msr cpsr, r4
113-
114-
@ User stack initialisation
115-
mov sp, r6
116-
117-
bl thread_prologue
118-
119-
12083
#ifdef CONFIG_AVZ
12184

12285
ENTRY(cpu_do_idle)
@@ -208,37 +171,6 @@ __mmu_switch_ttbr0:
208171
nop
209172
nop
210173

211-
@ Store the current registers into a cpu_regs structure passed in r0 (as first argument)
212-
__save_context:
213-
214-
@ Adjust the kernel stack pointer so that we can proceed with ret_from_fork
215-
@ SVC_STACK_FRAME_SIZE/4 registers are preserved when at the syscall vector entry point
216-
217-
@ Adjust the sp which is stored on the stack. Make sure
218-
@ it refers to this stack and not the one issue from the copy
219-
@ as during fork().
220-
221-
str r1, [r1, #(OFFSET_SP-SVC_STACK_FRAME_SIZE)]
222-
223-
sub r2, r1, #SVC_STACK_FRAME_SIZE
224-
225-
@ Prepare to configure sp during the context switch.
226-
str r2, [r0, #(OFFSET_TCB_CPU_REGS + OFFSET_SP)]
227-
228-
@ Prepare the lr to branch to ret_from_fork
229-
ldr r1, .LCret_from_fork
230-
str r1, [r0, #(OFFSET_TCB_CPU_REGS + OFFSET_LR)]
231-
232-
@ Preserve r7 which contains the syscall number (used to compare against SIG_RETURN)
233-
str r7, [r0, #(OFFSET_TCB_CPU_REGS + OFFSET_R7)]
234-
235-
@ The other registers are not important.
236-
237-
mov pc, lr
238-
239-
.LCret_from_fork:
240-
.word ret_from_fork
241-
242174
.LCcurrent:
243175
.word current_thread
244176

so3/arch/arm32/exception.S

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ __prepare_sig_handler:
118118
tst sp, #0x7 @ 8-bytes aligned
119119
bne __stack_alignment_fault
120120

121+
@ Copy TLS to the new stack frame
122+
ldr r0, [sp, #OFFSET_TLS_USR]
123+
str r0, [sp, #(-SVC_STACK_FRAME_SIZE + OFFSET_TLS_USR)]
124+
121125
str sp, [sp, #(-SVC_STACK_FRAME_SIZE + OFFSET_SP)] @ save sp
122126

123127
@ Build a new stack frame based on the current
@@ -169,7 +173,7 @@ __prepare_sig_handler:
169173
@ ARM EABI: the syscall nr is stored in r7
170174
.align 5
171175
syscall_interrupt:
172-
176+
173177
@ At the exception entry, the stack must be 8-byte aligned.
174178
@ If it is not the case (gcc might not respect the AAPCS convention for optimization purposes),
175179
@ sp will be adjusted. The original sp is preserved and will be correctly restored at the exit.
@@ -199,9 +203,13 @@ syscall_interrupt:
199203
add lr, sp, #OFFSET_SP_USR
200204
stmia lr, {sp, lr}^
201205

206+
@ Save user space TLS context
207+
mrc p15, 0, r0, c13, c0, 0
208+
str r0, [sp, #OFFSET_TLS_USR]
209+
202210
cmp r7, #SYSCALL_sigreturn
203211
beq __after_push_sp_usr
204-
212+
205213
ldr r0, [sp, #OFFSET_SP_USR]
206214
ldr r1, .LCcurrent
207215
ldr r1, [r1]
@@ -254,6 +262,10 @@ __ret_from_fork:
254262
check_pending_signal
255263
#endif /* CONFIG_IPC_SIGNAL */
256264

265+
@ Restore user space TLS context
266+
ldr lr, [sp, #OFFSET_TLS_USR]
267+
mcr p15, 0, lr, c13, c0, 0
268+
257269
@ get the saved spsr and adjust the stack pointer
258270
ldr lr, [sp, #OFFSET_PSR]
259271
msr spsr, lr
@@ -270,14 +282,14 @@ __ret_from_fork:
270282

271283
ldmia sp, {sp, lr, pc}^
272284

273-
285+
274286

275287
@ Used at entry point of a fork'd process (setting the return value to 0)
276288
ret_from_fork:
277289
mov r0, #0
278290

279291
b __ret_from_fork
280-
292+
281293
.align 5
282294
prefetch_abort:
283295

@@ -363,6 +375,10 @@ irq:
363375
addeq lr, sp, #OFFSET_SP_USR
364376
stmeqia lr, {sp, lr}^
365377

378+
@ Save user space TLS context
379+
mrc p15, 0, r0, c13, c0, 0
380+
str r0, [sp, #OFFSET_TLS_USR]
381+
366382
@ Retrieve the lr_irq to set the pc out of this routine
367383
ldr lr, [r0, #4] @ retrieve lr_irq to set lr_svc
368384
sub lr, lr, #4 @ Adjust the lr since it is automatically set from pc (in advance of 2 instructions due to the pipeline)
@@ -388,6 +404,10 @@ irq:
388404
check_pending_signal
389405
#endif /* CONFIG_IPC_SIGNAL */
390406

407+
@ Restore user space TLS context
408+
ldr lr, [sp, #OFFSET_TLS_USR]
409+
mcr p15, 0, lr, c13, c0, 0
410+
391411
ldr lr, [sp, #OFFSET_PSR] @ get the saved spsr and adjust the stack pointer
392412
msr spsr, lr
393413

so3/arch/arm32/include/asm/processor.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -349,9 +349,10 @@ typedef struct cpu_regs {
349349
__u32 lr;
350350
__u32 pc;
351351
__u32 psr;
352-
__u32 sp_usr;
352+
__u32 sp_usr;
353353
__u32 lr_usr;
354-
__u32 padding; /* padding to keep 8-bytes alignment */
354+
__u32 tls_usr;
355+
/* Already aligned to 8-bytes, no padding required */
355356
} cpu_regs_t;
356357

357358
#define cpu_relax() wfe()

so3/arch/arm32/thread.c

Lines changed: 68 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Copyright (C) 2022 Daniel Rossier <daniel.rossier@heig-vd.ch>
3-
*
3+
*
44
* This program is free software; you can redistribute it and/or modify
55
* it under the terms of the GNU General Public License version 2 as
66
* published by the Free Software Foundation.
@@ -16,21 +16,72 @@
1616
*
1717
*/
1818

19+
#include <process.h>
1920
#include <thread.h>
2021
#include <memory.h>
2122

2223
/**
2324
* Set the CPU registers with thread related information
2425
*
25-
* @param tcb
26+
* @param tcb Thread to set registers.
27+
* @param args Clone arguments with values to set to registers.
2628
*/
27-
void arch_prepare_cpu_regs(tcb_t *tcb)
29+
void arch_prepare_cpu_regs(tcb_t *tcb, clone_args_t *args)
2830
{
29-
tcb->cpu_regs.r4 = (unsigned long) tcb->th_fn;
30-
tcb->cpu_regs.r5 = (unsigned long) tcb->th_arg; /* First argument */
31+
cpu_regs_t *user_regs;
32+
33+
if (args->pcb == NULL) {
34+
/* Kernel thread must have a function to call */
35+
BUG_ON(args->fn == NULL);
36+
tcb->cpu_regs.r4 = (unsigned long) args->fn;
37+
tcb->cpu_regs.r5 = (unsigned long) args->fn_arg;
38+
39+
tcb->cpu_regs.lr = (unsigned long) __thread_prologue_kernel;
40+
tcb->cpu_regs.sp = get_kernel_stack_top(tcb->stack_slotID);
41+
} else {
42+
user_regs = (cpu_regs_t *) arch_get_kernel_stack_frame(tcb);
43+
44+
if (args->fn) {
45+
/* Special userspace case to start root process. */
46+
BUG_ON(args->stack == 0);
47+
arch_restart_user_thread(tcb, args->fn, args->stack);
48+
} else {
49+
/* Normal userspace that will copy userspace registers */
50+
if (args->stack)
51+
user_regs->sp_usr = args->stack;
52+
53+
if (args->flags & CLONE_SETTLS)
54+
user_regs->tls_usr = args->tls;
3155

32-
if (tcb->pcb)
33-
tcb->cpu_regs.r6 = get_user_stack_top(tcb->pcb, tcb->pcb_stack_slotID);
56+
/* Copy userspace registers */
57+
*user_regs = *(cpu_regs_t *) arch_get_kernel_stack_frame(current());
58+
}
59+
60+
tcb->cpu_regs.lr = (unsigned long) ret_from_fork;
61+
/* Take into account the user registers frame on the kernel stack */
62+
tcb->cpu_regs.sp = (addr_t) user_regs;
63+
}
64+
}
65+
66+
/**
67+
* Restart a user thread by reseting all registers to 0 and settings entry point and stack.
68+
*
69+
* @param tcb Thread to restart.
70+
* @param fn_entry Userspace entry point of the thread.
71+
* @param stack_top New top address of the userspace stack.
72+
*/
73+
void arch_restart_user_thread(tcb_t *tcb, th_fn_t fn_entry, addr_t stack_top)
74+
{
75+
cpu_regs_t *user_regs = (cpu_regs_t *) arch_get_kernel_stack_frame(tcb);
76+
77+
/* Reset all user's registers to zero except for PC, PSTATE and SP
78+
* which needs to be set to the properly start the thread.
79+
*/
80+
*user_regs = (cpu_regs_t) {
81+
.pc = (u32) fn_entry,
82+
.psr = PSR_USR_MODE,
83+
.sp_usr = stack_top,
84+
};
3485
}
3586

3687
/**
@@ -41,3 +92,13 @@ addr_t arch_get_args_base(void)
4192
{
4293
return (CONFIG_KERNEL_VADDR - PAGE_SIZE);
4394
}
95+
96+
/**
97+
* Get the top address of the kernel stack of a user thread with space for registers values.
98+
*
99+
* @param tcb Thread to get the stack address.
100+
*/
101+
addr_t arch_get_kernel_stack_frame(tcb_t *tcb)
102+
{
103+
return get_kernel_stack_top(tcb->stack_slotID) - SVC_STACK_FRAME_SIZE;
104+
}

so3/arch/arm64/asm-offsets.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ int main(void)
8585
DEFINE(OFFSET_SP, offsetof(struct cpu_regs, sp));
8686
DEFINE(OFFSET_PC, offsetof(struct cpu_regs, pc));
8787
DEFINE(OFFSET_PSTATE, offsetof(struct cpu_regs, pstate));
88+
DEFINE(OFFSET_TLS_USR, offsetof(struct cpu_regs, tls_usr));
8889

8990
BLANK();
9091

0 commit comments

Comments
 (0)