Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions so3/arch/arm32/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ obj-y += thread.o
obj-y += vfp.o
obj-y += backtrace.o backtrace_asm.o
obj-y += smccc-call.o
obj-y += syscalls.o

obj-y += lib/

Expand Down
38 changes: 16 additions & 22 deletions so3/arch/arm32/exception.S
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@

.extern current_thread
.extern irq_handle
.extern syscall_handle
.extern arch_syscall_handle

.extern dumpstack

Expand Down Expand Up @@ -118,8 +118,8 @@ __prepare_sig_handler:
bne __stack_alignment_fault

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

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

Expand Down Expand Up @@ -203,8 +203,8 @@ syscall_interrupt:
stmia lr, {sp, lr}^

@ Save user space TLS context
mrc p15, 0, r0, c13, c0, 0
str r0, [sp, #OFFSET_TLS_USR]
mrc p15, 0, lr, c13, c0, 3
str lr, [sp, #OFFSET_TLS_USR]

cmp r7, #SYSCALL_sigreturn
beq __after_push_sp_usr
Expand All @@ -223,7 +223,7 @@ __after_push_sp_usr:
mov r0, sp

cpsie i @ Re-enable interrupts
bl syscall_handle
bl arch_syscall_handle
cpsid i @ Re-disable interrupts to be safe in regs manipulation

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

__no_sigreturn:
__ret_from_fork:

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

// Entry point for new user threads
ret_from_fork:

#ifdef CONFIG_IPC_SIGNAL
@ Is there any pending signals for this process?
check_pending_signal
#endif /* CONFIG_IPC_SIGNAL */

@ Restore user space TLS context
ldr lr, [sp, #OFFSET_TLS_USR]
mcr p15, 0, lr, c13, c0, 0
mcr p15, 0, lr, c13, c0, 3

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

ldmia sp, {sp, lr, pc}^



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

b __ret_from_fork

.align 5
prefetch_abort:

Expand Down Expand Up @@ -360,8 +354,8 @@ irq:
stmeqia lr, {sp, lr}^

@ Save user space TLS context
mrc p15, 0, r0, c13, c0, 0
str r0, [sp, #OFFSET_TLS_USR]
mrceq p15, 0, lr, c13, c0, 3
streq lr, [sp, #OFFSET_TLS_USR]

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

@ Restore user space TLS context
ldr lr, [sp, #OFFSET_TLS_USR]
mcr p15, 0, lr, c13, c0, 0

ldr lr, [sp, #OFFSET_PSR] @ get the saved spsr and adjust the stack pointer
msr spsr, lr

Expand All @@ -403,6 +393,10 @@ irq:
addeq lr, sp, #OFFSET_SP_USR
ldmeqia lr, {sp, lr}^

@ Restore user space TLS context
ldreq lr, [sp, #OFFSET_TLS_USR]
mcreq p15, 0, lr, c13, c0, 3

@ Restore registers
ldmia sp, {r0-r12}

Expand Down
49 changes: 49 additions & 0 deletions so3/arch/arm32/syscalls.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (C) 2026 Dieperink Clément <clement.dieperink@heig-vd.ch>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/

#include <syscall.h>
#include <thread.h>
#include <process.h>

/* ARM32 specific syscalls to manage TLS */
#define ARM_NR_set_tls 0x0f0005
#define ARM_NR_get_tls 0x0f0006

extern void __get_syscall_args_ext(long *syscall_no);

/**
* Handle special ARM32 syscalls, or fallback to generic syscall handling.
*/
long arch_syscall_handle(syscall_args_t *syscall_args)
{
long syscall_no;
cpu_regs_t *user_regs = (cpu_regs_t *) arch_get_kernel_stack_frame(current());

/* Get addtional args of the syscall according to the ARM & SO3 ABI */
__get_syscall_args_ext(&syscall_no);

switch (syscall_no) {
case ARM_NR_get_tls:
return user_regs->tls_usr;
case ARM_NR_set_tls:
user_regs->tls_usr = syscall_args->args[0];
return 0;
default:
return syscall_handle(syscall_args);
}
}
9 changes: 8 additions & 1 deletion so3/arch/arm32/thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ void arch_prepare_cpu_regs(tcb_t *tcb, clone_args_t *args)

if (args->flags & CLONE_SETTLS)
user_regs->tls_usr = args->tls;

/* Set return value to 0 to indicate new thread */
user_regs->r0 = 0;

/* Set kernel stack address used to restore stack on eret */
user_regs->sp = get_kernel_stack_top(tcb->stack_slotID);
}

tcb->cpu_regs.lr = (unsigned long) ret_from_fork;
Expand All @@ -79,8 +85,9 @@ void arch_restart_user_thread(tcb_t *tcb, th_fn_t fn_entry, addr_t stack_top)
*/
*user_regs = (cpu_regs_t) {
.pc = (u32) fn_entry,
.psr = PSR_USR_MODE,
.psr = PSR_USR_MODE | PSR_I_BIT,
.sp_usr = stack_top,
.sp = get_kernel_stack_top(tcb->stack_slotID),
};
}

Expand Down
11 changes: 3 additions & 8 deletions so3/arch/arm64/exception.S
Original file line number Diff line number Diff line change
Expand Up @@ -567,13 +567,13 @@ el01_sync_handler:
// Check if sigreturn has been called. In this case, we
// clean the stack frame which has been used to manage the user handler.
cmp x8, #SYSCALL_rt_sigreturn
bne __ret_from_fork
bne ret_from_fork

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


__ret_from_fork:
// Entry point for new user threads
ret_from_fork:

#ifdef CONFIG_IPC_SIGNAL
// Is there any pending signals for this process?
Expand Down Expand Up @@ -605,11 +605,6 @@ el01_1_irq_handler:

eret

// Used at entry point of a fork'd process (setting the return value to 0)
ret_from_fork:
str xzr, [sp, #OFFSET_X0]
b __ret_from_fork

#if !defined(CONFIG_AVZ) && defined(CONFIG_SOO)

.align 5
Expand Down
3 changes: 3 additions & 0 deletions so3/arch/arm64/thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ void arch_prepare_cpu_regs(tcb_t *tcb, clone_args_t *args)

if (args->flags & CLONE_SETTLS)
user_regs->tls_usr = args->tls;

/* Set return value to 0 to indicate new thread */
user_regs->x0 = 0;
}

tcb->cpu_regs.lr = (unsigned long) ret_from_fork;
Expand Down
30 changes: 0 additions & 30 deletions so3/devices/serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,38 +100,8 @@ int serial_write(char *str, int len)
/* This function will query the size of the serial terminal*/
int serial_gwinsize(struct winsize *wsz)
{
/*
* The following code strongly depends on a patched version of QEMU which reacts
* to the '\254' ASCII code. When the emulated UART interface get this code, qemu
* queries the host via ioctl(stdout, TIOCGWINSZ) to retrieve the window size.
*/

/* We want to reserve the access to the uart read. */

/* Prevent an interrupt on the UART generated by
* QEMU to read the two bytes. So far, we do not
* manage an internal buffer to read many chars.
*/

#if defined(CONFIG_VIRT32) && !defined(CONFIG_SOO)

serial_ops.disable_irq();

if (serial_write(SERIAL_GWINSZ, 1) == 0)
return -1;

wsz->ws_row = serial_ops.get_byte(true);
wsz->ws_col = serial_ops.get_byte(true);

serial_ops.enable_irq();

#else

wsz->ws_row = WINSIZE_ROW_SIZE_DEFAULT;
wsz->ws_col = WINSIZE_COL_SIZE_DEFAULT;

#endif

return 0;
}

Expand Down
14 changes: 12 additions & 2 deletions so3/fs/elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ void elf_load_sections(elf_img_info_t *elf_img_info)
void elf_load_segments(elf_img_info_t *elf_img_info)
{
size_t i;
size_t segment_start, segment_end;
size_t page_start, page_end;

/* Segments */
#ifdef CONFIG_ARCH_ARM32
Expand Down Expand Up @@ -199,8 +201,16 @@ void elf_load_segments(elf_img_info_t *elf_img_info)
sizeof(struct elf64_phdr));
#endif

if (elf_img_info->segments[i].p_type == PT_LOAD)
elf_img_info->segment_page_count += (elf_img_info->segments[i].p_memsz >> PAGE_SHIFT) + 1;
if (elf_img_info->segments[i].p_type == PT_LOAD) {
/* Don't use only p_memsz to get page count as p_vaddr can be unaligned and additionnal page will be needed. */
segment_start = elf_img_info->segments[i].p_vaddr;
segment_end = segment_start + elf_img_info->segments[i].p_memsz;

page_start = segment_start >> PAGE_SHIFT;
page_end = (segment_end + PAGE_SIZE) >> PAGE_SHIFT;

elf_img_info->segment_page_count += page_end - page_start;
}
}
LOG_DEBUG("segments use %d virtual pages\n", elf_img_info->segment_page_count);

Expand Down
7 changes: 7 additions & 0 deletions so3/include/device/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ struct timeval32 {
time32_t tv_usec; /* microseconds */
};

/* Time conversion units - Dynamic size (for nanosleep syscall). */

struct long_timespec {
long tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};

/* All timing information below must be express in nanoseconds. The underlying hardware is responsible
* to perform the necessary alignment on 64 bits. */

Expand Down
2 changes: 1 addition & 1 deletion so3/include/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ void clocksource_timer_reset(void);

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

SYSCALL_DECLARE(nanosleep, const struct timespec *req, struct timespec *rem);
SYSCALL_DECLARE(nanosleep, const struct long_timespec *req, struct long_timespec *rem);

SYSCALL_DECLARE(gettimeofday_time32, struct timeval32 *tv, void *tz);
SYSCALL_DECLARE(gettimeofday, struct timeval *tv, void *tz);
Expand Down
8 changes: 2 additions & 6 deletions so3/kernel/delay.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,8 @@ void sleep(u64 ns)
__sleep(ns);
}

SYSCALL_DEFINE2(nanosleep, const struct timespec *, req, struct timespec *, rem)
SYSCALL_DEFINE2(nanosleep, const struct long_timespec *, req, struct long_timespec *, rem)
{
if (req->tv_nsec != 0)
__sleep(req->tv_nsec);
else if (req->tv_sec != 0)
__sleep(SECONDS(req->tv_sec));

__sleep(SECONDS(req->tv_sec) + req->tv_nsec);
return 0;
}
4 changes: 3 additions & 1 deletion so3/kernel/futex.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,10 @@ static int do_futex_wait(uint32_t *futex_w, uint32_t val, const struct timespec

spin_lock(&pcb->futex_lock);

if (list_empty(&futex->f_element))
if (list_empty(&futex->f_element)) {
list_del(&futex->list);
free(futex);
}

spin_unlock_irqrestore(&pcb->futex_lock, flags);

Expand Down
4 changes: 2 additions & 2 deletions so3/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ static uint32_t pid_current = 1;
static pcb_t *root_process = NULL; /* root process */

/* only the following sections are supported */
#define SUPPORTED_SECTION_COUNT 8
#define SUPPORTED_SECTION_COUNT 10
static const char *supported_section_names[SUPPORTED_SECTION_COUNT] = {
".init", ".text", ".rodata", ".data", ".sbss", ".bss", ".scommon", ".fini",
".init", ".text", ".rodata", ".data", ".sbss", ".bss", ".scommon", ".fini", ".init_array", ".fini_array",
};

/*
Expand Down
Loading