Skip to content

Commit 46f2a3f

Browse files
authored
Merge pull request #239 from smartobjectoriented/144-fix-arm32
fix bug added by MUSL support for ARM32
2 parents 0fa9703 + 06b4ff1 commit 46f2a3f

16 files changed

Lines changed: 175 additions & 142 deletions

File tree

so3/arch/arm32/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ obj-y += thread.o
66
obj-y += vfp.o
77
obj-y += backtrace.o backtrace_asm.o
88
obj-y += smccc-call.o
9+
obj-y += syscalls.o
910

1011
obj-y += lib/
1112

so3/arch/arm32/exception.S

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939

4040
.extern current_thread
4141
.extern irq_handle
42-
.extern syscall_handle
42+
.extern arch_syscall_handle
4343

4444
.extern dumpstack
4545

@@ -118,8 +118,8 @@ __prepare_sig_handler:
118118
bne __stack_alignment_fault
119119

120120
@ Copy TLS to the new stack frame
121-
ldr r0, [sp, #OFFSET_TLS_USR]
122-
str r0, [sp, #(-SVC_STACK_FRAME_SIZE + OFFSET_TLS_USR)]
121+
ldr r1, [sp, #OFFSET_TLS_USR]
122+
str r1, [sp, #(-SVC_STACK_FRAME_SIZE + OFFSET_TLS_USR)]
123123

124124
str sp, [sp, #(-SVC_STACK_FRAME_SIZE + OFFSET_SP)] @ save sp
125125

@@ -203,8 +203,8 @@ syscall_interrupt:
203203
stmia lr, {sp, lr}^
204204

205205
@ Save user space TLS context
206-
mrc p15, 0, r0, c13, c0, 0
207-
str r0, [sp, #OFFSET_TLS_USR]
206+
mrc p15, 0, lr, c13, c0, 3
207+
str lr, [sp, #OFFSET_TLS_USR]
208208

209209
cmp r7, #SYSCALL_sigreturn
210210
beq __after_push_sp_usr
@@ -223,7 +223,7 @@ __after_push_sp_usr:
223223
mov r0, sp
224224

225225
cpsie i @ Re-enable interrupts
226-
bl syscall_handle
226+
bl arch_syscall_handle
227227
cpsid i @ Re-disable interrupts to be safe in regs manipulation
228228

229229
@ Check if sigreturn has been called. In this case, we
@@ -235,20 +235,22 @@ __after_push_sp_usr:
235235
add sp, sp, #SVC_STACK_FRAME_SIZE
236236

237237
__no_sigreturn:
238-
__ret_from_fork:
239238

240239
@ Store the return value on the stack frame
241240
cmp r7, #SYSCALL_sigreturn
242241
strne r0, [sp, #OFFSET_R0]
243242

243+
// Entry point for new user threads
244+
ret_from_fork:
245+
244246
#ifdef CONFIG_IPC_SIGNAL
245247
@ Is there any pending signals for this process?
246248
check_pending_signal
247249
#endif /* CONFIG_IPC_SIGNAL */
248250

249251
@ Restore user space TLS context
250252
ldr lr, [sp, #OFFSET_TLS_USR]
251-
mcr p15, 0, lr, c13, c0, 0
253+
mcr p15, 0, lr, c13, c0, 3
252254

253255
@ get the saved spsr and adjust the stack pointer
254256
ldr lr, [sp, #OFFSET_PSR]
@@ -266,14 +268,6 @@ __ret_from_fork:
266268

267269
ldmia sp, {sp, lr, pc}^
268270

269-
270-
271-
@ Used at entry point of a fork'd process (setting the return value to 0)
272-
ret_from_fork:
273-
mov r0, #0
274-
275-
b __ret_from_fork
276-
277271
.align 5
278272
prefetch_abort:
279273

@@ -360,8 +354,8 @@ irq:
360354
stmeqia lr, {sp, lr}^
361355

362356
@ Save user space TLS context
363-
mrc p15, 0, r0, c13, c0, 0
364-
str r0, [sp, #OFFSET_TLS_USR]
357+
mrceq p15, 0, lr, c13, c0, 3
358+
streq lr, [sp, #OFFSET_TLS_USR]
365359

366360
@ Retrieve the lr_irq to set the pc out of this routine
367361
ldr lr, [r0, #4] @ retrieve lr_irq to set lr_svc
@@ -388,10 +382,6 @@ irq:
388382
check_pending_signal
389383
#endif /* CONFIG_IPC_SIGNAL */
390384

391-
@ Restore user space TLS context
392-
ldr lr, [sp, #OFFSET_TLS_USR]
393-
mcr p15, 0, lr, c13, c0, 0
394-
395385
ldr lr, [sp, #OFFSET_PSR] @ get the saved spsr and adjust the stack pointer
396386
msr spsr, lr
397387

@@ -403,6 +393,10 @@ irq:
403393
addeq lr, sp, #OFFSET_SP_USR
404394
ldmeqia lr, {sp, lr}^
405395

396+
@ Restore user space TLS context
397+
ldreq lr, [sp, #OFFSET_TLS_USR]
398+
mcreq p15, 0, lr, c13, c0, 3
399+
406400
@ Restore registers
407401
ldmia sp, {r0-r12}
408402

so3/arch/arm32/syscalls.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright (C) 2026 Dieperink Clément <clement.dieperink@heig-vd.ch>
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License version 2 as
6+
* published by the Free Software Foundation.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
*
13+
* You should have received a copy of the GNU General Public License
14+
* along with this program; if not, write to the Free Software
15+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16+
*
17+
*/
18+
19+
#include <syscall.h>
20+
#include <thread.h>
21+
#include <process.h>
22+
23+
/* ARM32 specific syscalls to manage TLS */
24+
#define ARM_NR_set_tls 0x0f0005
25+
#define ARM_NR_get_tls 0x0f0006
26+
27+
extern void __get_syscall_args_ext(long *syscall_no);
28+
29+
/**
30+
* Handle special ARM32 syscalls, or fallback to generic syscall handling.
31+
*/
32+
long arch_syscall_handle(syscall_args_t *syscall_args)
33+
{
34+
long syscall_no;
35+
cpu_regs_t *user_regs = (cpu_regs_t *) arch_get_kernel_stack_frame(current());
36+
37+
/* Get addtional args of the syscall according to the ARM & SO3 ABI */
38+
__get_syscall_args_ext(&syscall_no);
39+
40+
switch (syscall_no) {
41+
case ARM_NR_get_tls:
42+
return user_regs->tls_usr;
43+
case ARM_NR_set_tls:
44+
user_regs->tls_usr = syscall_args->args[0];
45+
return 0;
46+
default:
47+
return syscall_handle(syscall_args);
48+
}
49+
}

so3/arch/arm32/thread.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ void arch_prepare_cpu_regs(tcb_t *tcb, clone_args_t *args)
5555

5656
if (args->flags & CLONE_SETTLS)
5757
user_regs->tls_usr = args->tls;
58+
59+
/* Set return value to 0 to indicate new thread */
60+
user_regs->r0 = 0;
61+
62+
/* Set kernel stack address used to restore stack on eret */
63+
user_regs->sp = get_kernel_stack_top(tcb->stack_slotID);
5864
}
5965

6066
tcb->cpu_regs.lr = (unsigned long) ret_from_fork;
@@ -79,8 +85,9 @@ void arch_restart_user_thread(tcb_t *tcb, th_fn_t fn_entry, addr_t stack_top)
7985
*/
8086
*user_regs = (cpu_regs_t) {
8187
.pc = (u32) fn_entry,
82-
.psr = PSR_USR_MODE,
88+
.psr = PSR_USR_MODE | PSR_I_BIT,
8389
.sp_usr = stack_top,
90+
.sp = get_kernel_stack_top(tcb->stack_slotID),
8491
};
8592
}
8693

so3/arch/arm64/exception.S

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -567,13 +567,13 @@ el01_sync_handler:
567567
// Check if sigreturn has been called. In this case, we
568568
// clean the stack frame which has been used to manage the user handler.
569569
cmp x8, #SYSCALL_rt_sigreturn
570-
bne __ret_from_fork
570+
bne ret_from_fork
571571

572572
// Reset the stack frame by removing the one issued from sigreturn
573573
add sp, sp, #S_FRAME_SIZE
574574

575-
576-
__ret_from_fork:
575+
// Entry point for new user threads
576+
ret_from_fork:
577577

578578
#ifdef CONFIG_IPC_SIGNAL
579579
// Is there any pending signals for this process?
@@ -605,11 +605,6 @@ el01_1_irq_handler:
605605

606606
eret
607607

608-
// Used at entry point of a fork'd process (setting the return value to 0)
609-
ret_from_fork:
610-
str xzr, [sp, #OFFSET_X0]
611-
b __ret_from_fork
612-
613608
#if !defined(CONFIG_AVZ) && defined(CONFIG_SOO)
614609

615610
.align 5

so3/arch/arm64/thread.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ void arch_prepare_cpu_regs(tcb_t *tcb, clone_args_t *args)
5454

5555
if (args->flags & CLONE_SETTLS)
5656
user_regs->tls_usr = args->tls;
57+
58+
/* Set return value to 0 to indicate new thread */
59+
user_regs->x0 = 0;
5760
}
5861

5962
tcb->cpu_regs.lr = (unsigned long) ret_from_fork;

so3/devices/serial.c

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -100,38 +100,8 @@ int serial_write(char *str, int len)
100100
/* This function will query the size of the serial terminal*/
101101
int serial_gwinsize(struct winsize *wsz)
102102
{
103-
/*
104-
* The following code strongly depends on a patched version of QEMU which reacts
105-
* to the '\254' ASCII code. When the emulated UART interface get this code, qemu
106-
* queries the host via ioctl(stdout, TIOCGWINSZ) to retrieve the window size.
107-
*/
108-
109-
/* We want to reserve the access to the uart read. */
110-
111-
/* Prevent an interrupt on the UART generated by
112-
* QEMU to read the two bytes. So far, we do not
113-
* manage an internal buffer to read many chars.
114-
*/
115-
116-
#if defined(CONFIG_VIRT32) && !defined(CONFIG_SOO)
117-
118-
serial_ops.disable_irq();
119-
120-
if (serial_write(SERIAL_GWINSZ, 1) == 0)
121-
return -1;
122-
123-
wsz->ws_row = serial_ops.get_byte(true);
124-
wsz->ws_col = serial_ops.get_byte(true);
125-
126-
serial_ops.enable_irq();
127-
128-
#else
129-
130103
wsz->ws_row = WINSIZE_ROW_SIZE_DEFAULT;
131104
wsz->ws_col = WINSIZE_COL_SIZE_DEFAULT;
132-
133-
#endif
134-
135105
return 0;
136106
}
137107

so3/fs/elf.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ void elf_load_sections(elf_img_info_t *elf_img_info)
165165
void elf_load_segments(elf_img_info_t *elf_img_info)
166166
{
167167
size_t i;
168+
size_t segment_start, segment_end;
169+
size_t page_start, page_end;
168170

169171
/* Segments */
170172
#ifdef CONFIG_ARCH_ARM32
@@ -199,8 +201,16 @@ void elf_load_segments(elf_img_info_t *elf_img_info)
199201
sizeof(struct elf64_phdr));
200202
#endif
201203

202-
if (elf_img_info->segments[i].p_type == PT_LOAD)
203-
elf_img_info->segment_page_count += (elf_img_info->segments[i].p_memsz >> PAGE_SHIFT) + 1;
204+
if (elf_img_info->segments[i].p_type == PT_LOAD) {
205+
/* Don't use only p_memsz to get page count as p_vaddr can be unaligned and additionnal page will be needed. */
206+
segment_start = elf_img_info->segments[i].p_vaddr;
207+
segment_end = segment_start + elf_img_info->segments[i].p_memsz;
208+
209+
page_start = segment_start >> PAGE_SHIFT;
210+
page_end = (segment_end + PAGE_SIZE) >> PAGE_SHIFT;
211+
212+
elf_img_info->segment_page_count += page_end - page_start;
213+
}
204214
}
205215
LOG_DEBUG("segments use %d virtual pages\n", elf_img_info->segment_page_count);
206216

so3/include/device/timer.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ struct timeval32 {
4949
time32_t tv_usec; /* microseconds */
5050
};
5151

52+
/* Time conversion units - Dynamic size (for nanosleep syscall). */
53+
54+
struct long_timespec {
55+
long tv_sec; /* seconds */
56+
long tv_nsec; /* nanoseconds */
57+
};
58+
5259
/* All timing information below must be express in nanoseconds. The underlying hardware is responsible
5360
* to perform the necessary alignment on 64 bits. */
5461

so3/include/timer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ void clocksource_timer_reset(void);
126126

127127
void clocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 maxsec);
128128

129-
SYSCALL_DECLARE(nanosleep, const struct timespec *req, struct timespec *rem);
129+
SYSCALL_DECLARE(nanosleep, const struct long_timespec *req, struct long_timespec *rem);
130130

131131
SYSCALL_DECLARE(gettimeofday_time32, struct timeval32 *tv, void *tz);
132132
SYSCALL_DECLARE(gettimeofday, struct timeval *tv, void *tz);

0 commit comments

Comments
 (0)