From 65a410a01e51c8bf6823de7bf6f811a4f9b6c210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Sat, 29 Mar 2025 20:03:12 +0100 Subject: [PATCH 1/6] fix(spinlock): use uint64 so we can align it in aarch64 --- so3/arch/arm64/include/asm/spinlock.h | 12 ++++++------ so3/include/spinlock.h | 13 ++++++++++++- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/so3/arch/arm64/include/asm/spinlock.h b/so3/arch/arm64/include/asm/spinlock.h index dc25db3fd..618af12f1 100644 --- a/so3/arch/arm64/include/asm/spinlock.h +++ b/so3/arch/arm64/include/asm/spinlock.h @@ -37,13 +37,13 @@ static inline int spin_trylock(spinlock_t *lock) { uint32_t tmp; - __asm__ __volatile__(" ldaxr %w0, [%1]\n" - " tbnz %w0, #0, 1f\n" + __asm__ __volatile__(" ldaxr %x0, [%1]\n" + " cbnz %x0, 1f\n" " stxr %w0, %2, [%1]\n" "1:" : "=&r"(tmp) - : "r"(&lock->lock), "r"(1) - : "cc"); + : "r"(&lock->lock), "r"(1ULL) + : "cc", "memory"); if (tmp == 0) { smp_mb(); @@ -66,10 +66,10 @@ static inline void spin_unlock(spinlock_t *lock) { smp_mb(); - __asm__ __volatile__(" stlr wzr, [%0]\n" + __asm__ __volatile__(" stlr xzr, [%0]\n" " sev" : : "r"(&lock->lock) - : "cc"); + : "cc", "memory"); } #endif /* ASM_SPINLOCK_H */ diff --git a/so3/include/spinlock.h b/so3/include/spinlock.h index b445fdc63..5a49f80cd 100644 --- a/so3/include/spinlock.h +++ b/so3/include/spinlock.h @@ -21,13 +21,24 @@ #include +#ifdef CONFIG_ARCH_ARM32 +typedef struct { + volatile uint32_t lock; +} spinlock_t; + +#elif CONFIG_ARCH_ARM64 + /* * On Aarch64, the field has to be 64-bit aligned apparently. */ typedef struct { - __attribute__((aligned(8))) volatile uint32_t lock; + volatile uint64_t lock; } spinlock_t; +#else +#error "Invalid ARCH config" +#endif + #include #define DEFINE_SPINLOCK(l) spinlock_t l = { 0 }; From e7edf0207c1f47a843484dd9935ff611392624be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Sat, 29 Mar 2025 20:03:53 +0100 Subject: [PATCH 2/6] fix(mutex): reorder attributes for better alignment --- so3/include/mutex.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/so3/include/mutex.h b/so3/include/mutex.h index 28b0a753a..a93051af5 100644 --- a/so3/include/mutex.h +++ b/so3/include/mutex.h @@ -30,10 +30,10 @@ #include struct mutex { - /* 1: unlocked, 0: locked, negative: locked, possible waiters */ - atomic_t count; tcb_t *owner; spinlock_t wait_lock; + /* 1: unlocked, 0: locked, negative: locked, possible waiters */ + atomic_t count; /* Allow to manage recursive locking */ uint32_t recursive_count; From d6b2e659b6677711ce2bd15494048d93c6fc3d20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Sat, 29 Mar 2025 20:04:32 +0100 Subject: [PATCH 3/6] fix(process): put locks in heap so we can align them --- so3/include/process.h | 4 ++-- so3/kernel/process.c | 13 +++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/so3/include/process.h b/so3/include/process.h index 0f88103e5..cdbd933cf 100644 --- a/so3/include/process.h +++ b/so3/include/process.h @@ -38,7 +38,7 @@ #define PROC_STACK_SIZE (PROC_THREAD_MAX * THREAD_STACK_SIZE) #define FD_MAX 64 -#define N_MUTEX 10 +#define N_MUTEX 5 typedef enum { PROC_STATE_NEW, @@ -126,7 +126,7 @@ struct pcb { enum __ptrace_request ptrace_pending_req; /* Mutex lock to be used in conjunction with the user space (very temporary) */ - mutex_t lock[N_MUTEX]; + mutex_t *lock; }; typedef struct pcb pcb_t; diff --git a/so3/kernel/process.c b/so3/kernel/process.c index 6b37220d8..961dd124f 100644 --- a/so3/kernel/process.c +++ b/so3/kernel/process.c @@ -193,10 +193,19 @@ pcb_t *new_process(void) /* Reset the ptrace request indicator */ pcb->ptrace_pending_req = PTRACE_NO_REQUEST; + /* The spinlock inside the mutex must aligned in aarch64 */ + pcb->lock = memalign(N_MUTEX * sizeof(mutex_t), 8); + + if (!pcb->lock) { + printk("%s: failed to allocate memory for process mutex\n", + __func__); + kernel_panic(); + } + /* Initialize the mutex belonging to this process */ - for (i = 0; i < N_MUTEX; i++) + for (i = 0; i < N_MUTEX; i++) { mutex_init(&pcb->lock[i]); - + } /* Init the list of pages */ INIT_LIST_HEAD(&pcb->page_list); From fb76d88b7cf6c6dd9540ac153e679cd40b9045a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Sat, 29 Mar 2025 20:05:22 +0100 Subject: [PATCH 4/6] fix: check mutex index in mutex lock/unlock syscalls --- so3/include/mutex.h | 4 ++-- so3/kernel/mutex.c | 19 +++++++++++++------ so3/kernel/syscalls.c | 4 ++-- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/so3/include/mutex.h b/so3/include/mutex.h index a93051af5..98723b1de 100644 --- a/so3/include/mutex.h +++ b/so3/include/mutex.h @@ -58,7 +58,7 @@ void mutex_unlock(struct mutex *lock); void mutex_init(struct mutex *lock); int do_mutex_init(void); -int do_mutex_lock(mutex_t *lock); -int do_mutex_unlock(mutex_t *lock); +int do_mutex_lock(unsigned long number); +int do_mutex_unlock(unsigned long number); #endif /* MUTEX_H */ diff --git a/so3/kernel/mutex.c b/so3/kernel/mutex.c index 291272367..6dc735849 100644 --- a/so3/kernel/mutex.c +++ b/so3/kernel/mutex.c @@ -22,6 +22,7 @@ * */ +#include #include #include #include @@ -149,17 +150,23 @@ void mutex_unlock(struct mutex *lock) /* * The following syscall implementation are a first attempt, mainly used for debugging kernel mutexes. */ -int do_mutex_lock(mutex_t *lock) +int do_mutex_lock(unsigned long number) { - mutex_lock(lock); - + if (number >= N_MUTEX) { + set_errno(EINVAL); + return -1; + } + mutex_lock(¤t()->pcb->lock[number]); return 0; } -int do_mutex_unlock(mutex_t *lock) +int do_mutex_unlock(unsigned long number) { - mutex_unlock(lock); - + if (number >= N_MUTEX) { + set_errno(EINVAL); + return -1; + } + mutex_unlock(¤t()->pcb->lock[number]); return 0; } diff --git a/so3/kernel/syscalls.c b/so3/kernel/syscalls.c index 4e028a779..37e1a3d35 100644 --- a/so3/kernel/syscalls.c +++ b/so3/kernel/syscalls.c @@ -218,11 +218,11 @@ long syscall_handle(syscall_args_t *a) * Mainly used for debugging purposes (kernel mutex validation) at the moment ... */ case SYSCALL_MUTEX_LOCK: - result = do_mutex_lock(¤t()->pcb->lock[a->args[0]]); + result = do_mutex_lock(a->args[0]); break; case SYSCALL_MUTEX_UNLOCK: - result = do_mutex_unlock(¤t()->pcb->lock[a->args[0]]); + result = do_mutex_unlock(a->args[0]); break; #ifdef CONFIG_MMU From 94cf9652e5adeba90bfaff1fcd33ec2e3434559e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Tue, 1 Apr 2025 19:55:53 +0200 Subject: [PATCH 5/6] refactor(syscalls): rename parameter for clarity --- so3/kernel/syscalls.c | 184 +++++++++++++++++++++++++----------------- 1 file changed, 110 insertions(+), 74 deletions(-) diff --git a/so3/kernel/syscalls.c b/so3/kernel/syscalls.c index 37e1a3d35..08a87596f 100644 --- a/so3/kernel/syscalls.c +++ b/so3/kernel/syscalls.c @@ -66,7 +66,7 @@ void set_errno(uint32_t val) * According to SO3 ABI, the syscall arguments are passed in r0-r5 on ARM and x0-x5 on ARM64. */ -long syscall_handle(syscall_args_t *a) +long syscall_handle(syscall_args_t *syscall_args) { long result = -1; uint32_t syscall_no, *__errno_addr; @@ -86,13 +86,15 @@ long syscall_handle(syscall_args_t *a) /* a->args[1] contains a pointer to the timezone structure. */ /* Currently, this is not supported yet. */ - result = do_get_time_of_day((struct timespec *)a->args[0]); + result = do_get_time_of_day( + (struct timespec *)syscall_args->args[0]); break; case SYSCALL_CLOCK_GETTIME: - result = do_get_clock_time(a->args[0], - (struct timespec *)a->args[1]); + result = do_get_clock_time( + syscall_args->args[0], + (struct timespec *)syscall_args->args[1]); break; case SYSCALL_SETTIMEOFDAY: @@ -104,12 +106,13 @@ long syscall_handle(syscall_args_t *a) break; case SYSCALL_EXIT: - do_exit(a->args[0]); + do_exit(syscall_args->args[0]); break; case SYSCALL_EXECVE: - result = do_execve((const char *)a->args[0], - (char **)a->args[1], (char **)a->args[2]); + result = do_execve((const char *)syscall_args->args[0], + (char **)syscall_args->args[1], + (char **)syscall_args->args[2]); break; case SYSCALL_FORK: @@ -117,39 +120,48 @@ long syscall_handle(syscall_args_t *a) break; case SYSCALL_WAITPID: - result = do_waitpid(a->args[0], (uint32_t *)a->args[1], - a->args[2]); + result = do_waitpid(syscall_args->args[0], + (uint32_t *)syscall_args->args[1], + syscall_args->args[2]); break; #endif /* CONFIG_MMU */ case SYSCALL_READ: - result = do_read(a->args[0], (void *)a->args[1], a->args[2]); + result = do_read(syscall_args->args[0], + (void *)syscall_args->args[1], + syscall_args->args[2]); break; case SYSCALL_WRITE: - result = do_write(a->args[0], (void *)a->args[1], a->args[2]); + result = do_write(syscall_args->args[0], + (void *)syscall_args->args[1], + syscall_args->args[2]); break; case SYSCALL_OPEN: - result = do_open((const char *)a->args[0], a->args[1]); + result = do_open((const char *)syscall_args->args[0], + syscall_args->args[1]); break; case SYSCALL_CLOSE: - do_close((int)a->args[0]); + do_close((int)syscall_args->args[0]); result = 0; break; case SYSCALL_THREAD_CREATE: - result = do_thread_create((uint32_t *)a->args[0], a->args[1], - a->args[2], a->args[3]); + result = do_thread_create((uint32_t *)syscall_args->args[0], + syscall_args->args[1], + syscall_args->args[2], + syscall_args->args[3]); break; case SYSCALL_THREAD_JOIN: - result = do_thread_join(a->args[0], (int **)a->args[1]); + result = do_thread_join(syscall_args->args[0], + (int **)syscall_args->args[1]); break; case SYSCALL_THREAD_EXIT: - do_thread_exit((int *)a->args[0]); + do_thread_exit((int *)syscall_args->args[0]); result = 0; break; @@ -159,57 +171,66 @@ long syscall_handle(syscall_args_t *a) break; case SYSCALL_READDIR: - result = do_readdir((int)a->args[0], (char *)a->args[1], - a->args[2]); + result = do_readdir((int)syscall_args->args[0], + (char *)syscall_args->args[1], + syscall_args->args[2]); break; case SYSCALL_IOCTL: - result = do_ioctl((int)a->args[0], (unsigned long)a->args[1], - (unsigned long)a->args[2]); + result = do_ioctl((int)syscall_args->args[0], + (unsigned long)syscall_args->args[1], + (unsigned long)syscall_args->args[2]); break; case SYSCALL_FCNTL: - result = do_fcntl((int)a->args[0], (int)a->args[1], - (unsigned long)a->args[2]); + result = do_fcntl((int)syscall_args->args[0], + (int)syscall_args->args[1], + (unsigned long)syscall_args->args[2]); break; case SYSCALL_LSEEK: - result = do_lseek((int)a->args[0], (off_t)a->args[1], - (int)a->args[2]); + result = do_lseek((int)syscall_args->args[0], + (off_t)syscall_args->args[1], + (int)syscall_args->args[2]); break; #ifdef CONFIG_IPC_PIPE case SYSCALL_PIPE: - result = do_pipe((int *)a->args[0]); + result = do_pipe((int *)syscall_args->args[0]); break; #endif /* CONFIG_IPC_PIPE */ case SYSCALL_DUP: - result = do_dup((int)a->args[0]); + result = do_dup((int)syscall_args->args[0]); break; case SYSCALL_DUP2: - result = do_dup2((int)a->args[0], (int)a->args[1]); + result = do_dup2((int)syscall_args->args[0], + (int)syscall_args->args[1]); break; case SYSCALL_STAT: - result = do_stat((char *)a->args[0], (struct stat *)a->args[1]); + result = do_stat((char *)syscall_args->args[0], + (struct stat *)syscall_args->args[1]); break; case SYSCALL_MMAP: - result = (long)do_mmap((addr_t)a->args[0], (size_t)a->args[1], - (int)a->args[2], (int)a->args[3], - (off_t)a->args[4]); + result = (long)do_mmap((addr_t)syscall_args->args[0], + (size_t)syscall_args->args[1], + (int)syscall_args->args[2], + (int)syscall_args->args[3], + (off_t)syscall_args->args[4]); break; case SYSCALL_NANOSLEEP: - result = do_nanosleep((const struct timespec *)a->args[0], - (struct timespec *)a->args[1]); + result = do_nanosleep( + (const struct timespec *)syscall_args->args[0], + (struct timespec *)syscall_args->args[1]); break; #ifdef CONFIG_PROC_ENV case SYSCALL_SBRK: - result = do_sbrk((unsigned long)a->args[0]); + result = do_sbrk((unsigned long)syscall_args->args[0]); break; #endif /* CONFIG_PROC_ENV */ @@ -218,30 +239,32 @@ long syscall_handle(syscall_args_t *a) * Mainly used for debugging purposes (kernel mutex validation) at the moment ... */ case SYSCALL_MUTEX_LOCK: - result = do_mutex_lock(a->args[0]); + result = do_mutex_lock(syscall_args->args[0]); break; case SYSCALL_MUTEX_UNLOCK: - result = do_mutex_unlock(a->args[0]); + result = do_mutex_unlock(syscall_args->args[0]); break; #ifdef CONFIG_MMU case SYSCALL_PTRACE: - result = do_ptrace((enum __ptrace_request)a->args[0], - (uint32_t)a->args[1], (void *)a->args[2], - (void *)a->args[3]); + result = do_ptrace((enum __ptrace_request)syscall_args->args[0], + (uint32_t)syscall_args->args[1], + (void *)syscall_args->args[2], + (void *)syscall_args->args[3]); break; #endif #ifdef CONFIG_IPC_SIGNAL case SYSCALL_SIGACTION: - result = do_sigaction((int)a->args[0], - (sigaction_t *)a->args[1], - (sigaction_t *)a->args[2]); + result = do_sigaction((int)syscall_args->args[0], + (sigaction_t *)syscall_args->args[1], + (sigaction_t *)syscall_args->args[2]); break; case SYSCALL_KILL: - result = do_kill((int)a->args[0], (int)a->args[1]); + result = do_kill((int)syscall_args->args[0], + (int)syscall_args->args[1]); break; case SYSCALL_SIGRETURN: @@ -252,68 +275,81 @@ long syscall_handle(syscall_args_t *a) #ifdef CONFIG_NET case SYSCALL_SOCKET: - result = do_socket((int)a->args[0], (int)a->args[1], - (int)a->args[2]); + result = do_socket((int)syscall_args->args[0], + (int)syscall_args->args[1], + (int)syscall_args->args[2]); break; case SYSCALL_BIND: - result = do_bind((int)a->args[0], - (const struct sockaddr *)a->args[1], - (socklen_t)a->args[2]); + result = do_bind((int)syscall_args->args[0], + (const struct sockaddr *)syscall_args->args[1], + (socklen_t)syscall_args->args[2]); break; case SYSCALL_LISTEN: - result = do_listen((int)a->args[0], (int)a->args[1]); + result = do_listen((int)syscall_args->args[0], + (int)syscall_args->args[1]); break; case SYSCALL_ACCEPT: - result = do_accept((int)a->args[0], - (struct sockaddr *)a->args[1], - (socklen_t *)a->args[2]); + result = do_accept((int)syscall_args->args[0], + (struct sockaddr *)syscall_args->args[1], + (socklen_t *)syscall_args->args[2]); break; case SYSCALL_CONNECT: - result = do_connect((int)a->args[0], - (const struct sockaddr *)a->args[1], - (socklen_t)a->args[2]); + result = do_connect( + (int)syscall_args->args[0], + (const struct sockaddr *)syscall_args->args[1], + (socklen_t)syscall_args->args[2]); break; case SYSCALL_RECV: - result = do_recv((int)a->args[0], (void *)a->args[1], - (size_t)a->args[2], (int)a->args[3]); + result = do_recv((int)syscall_args->args[0], + (void *)syscall_args->args[1], + (size_t)syscall_args->args[2], + (int)syscall_args->args[3]); break; case SYSCALL_SEND: - result = do_send((int)a->args[0], (const void *)a->args[1], - (size_t)a->args[2], (int)a->args[3]); + result = do_send((int)syscall_args->args[0], + (const void *)syscall_args->args[1], + (size_t)syscall_args->args[2], + (int)syscall_args->args[3]); break; case SYSCALL_SENDTO: - result = do_sendto((int)a->args[0], (const void *)a->args[1], - (size_t)a->args[2], (int)a->args[3], - (const struct sockaddr *)a->args[4], - (socklen_t)a->args[5]); + result = do_sendto( + (int)syscall_args->args[0], + (const void *)syscall_args->args[1], + (size_t)syscall_args->args[2], + (int)syscall_args->args[3], + (const struct sockaddr *)syscall_args->args[4], + (socklen_t)syscall_args->args[5]); break; case SYSCALL_SETSOCKOPT: - result = do_setsockopt((int)a->args[0], (int)a->args[1], - (int)a->args[2], - (const void *)a->args[3], - (socklen_t)a->args[4]); + result = do_setsockopt((int)syscall_args->args[0], + (int)syscall_args->args[1], + (int)syscall_args->args[2], + (const void *)syscall_args->args[3], + (socklen_t)syscall_args->args[4]); break; case SYSCALL_RECVFROM: - result = do_recvfrom((int)a->args[0], (void *)a->args[1], - (size_t)a->args[2], (int)a->args[3], - (struct sockaddr *)a->args[4], - (socklen_t *)a->args[5]); + result = do_recvfrom((int)syscall_args->args[0], + (void *)syscall_args->args[1], + (size_t)syscall_args->args[2], + (int)syscall_args->args[3], + (struct sockaddr *)syscall_args->args[4], + (socklen_t *)syscall_args->args[5]); break; #endif /* CONFIG_NET */ /* Sysinfo syscalls */ case SYSCALL_SYSINFO: - switch (a->args[0]) { + switch (syscall_args->args[0]) { case SYSINFO_DUMP_HEAP: dump_heap("Heap info asked from user.\n"); break; @@ -334,7 +370,7 @@ long syscall_handle(syscall_args_t *a) break; #endif case SYSINFO_PRINTK: - printk("%s", (char *)a->args[1]); + printk("%s", (char *)syscall_args->args[1]); break; } result = 0; From ee203e99c8346c7e7e093021051268edbc6146f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Wed, 2 Apr 2025 15:44:04 +0200 Subject: [PATCH 6/6] feat(spinlock): check for the lock memory alignment --- so3/arch/arm64/include/asm/spinlock.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/so3/arch/arm64/include/asm/spinlock.h b/so3/arch/arm64/include/asm/spinlock.h index 618af12f1..605fed059 100644 --- a/so3/arch/arm64/include/asm/spinlock.h +++ b/so3/arch/arm64/include/asm/spinlock.h @@ -37,6 +37,8 @@ static inline int spin_trylock(spinlock_t *lock) { uint32_t tmp; + /* The spinlock must aligned in aarch64 */ + BUG_ON((((uint64_t)&lock->lock) & 0x7) != 0); __asm__ __volatile__(" ldaxr %x0, [%1]\n" " cbnz %x0, 1f\n" " stxr %w0, %2, [%1]\n"