Kernel/LibC: Rework userspace syscall interface

Kernel syscall API no longer zeros all unused argument registers and
libc now uses inlined syscall macro internally. This significantly
cleans up generated code for basic syscall wrapper functions.
This commit is contained in:
2026-04-07 03:43:35 +03:00
parent 279ac6b2b6
commit 2f9b8b6fc9
9 changed files with 66 additions and 67 deletions

View File

@@ -1,44 +1,34 @@
#pragma once
#include <kernel/Attributes.h>
#include <kernel/IDT.h>
#include <stdint.h>
#include <sys/syscall.h>
#include <BAN/MacroUtils.h>
namespace Kernel
{
ALWAYS_INLINE long syscall(int syscall, uintptr_t arg1 = 0, uintptr_t arg2 = 0, uintptr_t arg3 = 0, uintptr_t arg4 = 0, uintptr_t arg5 = 0)
{
long ret;
#if ARCH(x86_64)
register uintptr_t r10 asm("r10") = arg3;
register uintptr_t r8 asm( "r8") = arg4;
register uintptr_t r9 asm( "r9") = arg5;
asm volatile(
"syscall"
: "=a"(ret)
, "+D"(syscall)
, "+S"(arg1)
, "+d"(arg2)
, "+r"(r10)
, "+r"(r8)
, "+r"(r9)
:: "rcx", "r11", "memory");
#elif ARCH(i686)
asm volatile(
"int %[irq]"
: "=a"(ret)
: [irq]"i"(static_cast<int>(IRQ_SYSCALL)) // WTF GCC 15
, "a"(syscall)
, "b"(arg1)
, "c"(arg2)
, "d"(arg3)
, "S"(arg4)
, "D"(arg5)
: "memory");
#if defined(__x86_64__)
#define _kas_instruction "syscall"
#define _kas_result rax
#define _kas_arguments rdi, rsi, rdx, r10, r8, r9
#define _kas_globbers rcx, rdx, rdi, rsi, r8, r9, r10, r11
#elif defined(__i686__)
#define _kas_instruction "int $0xF0"
#define _kas_result eax
#define _kas_arguments eax, ebx, ecx, edx, esi, edi
#define _kas_globbers
#endif
return ret;
}
}
#define _kas_argument_var(index, value) register long _kas_a##index asm(_ban_stringify(_ban_get(index, _kas_arguments))) = (long)value;
#define _kas_dummy_var(index, value) register long _kas_d##index asm(#value);
#define _kas_input(index, _) "r"(_kas_a##index)
#define _kas_output(index, _) , "=r"(_kas_d##index)
#define _kas_globber(_, value) #value
#define _kas_syscall(...) ({ \
register long _kas_ret asm(_ban_stringify(_kas_result)); \
_ban_for_each(_kas_argument_var, __VA_ARGS__) \
_ban_for_each(_kas_dummy_var, _kas_globbers) \
asm volatile( \
_kas_instruction \
: "=r"(_kas_ret) _ban_for_each(_kas_output, _kas_globbers) \
: _ban_for_each_comma(_kas_input, __VA_ARGS__) \
: "cc", "memory"); \
(void)_kas_a0; /* require 1 argument */ \
_kas_ret; \
})

View File

@@ -20,7 +20,7 @@ namespace Kernel
constexpr uint8_t IRQ_MSI_BASE = 0x80;
constexpr uint8_t IRQ_MSI_END = 0xF0;
#if ARCH(i686)
constexpr uint8_t IRQ_SYSCALL = 0xF0;
constexpr uint8_t IRQ_SYSCALL = 0xF0; // hard coded in kernel/API/Syscall.h
#endif
constexpr uint8_t IRQ_IPI = 0xF1;
constexpr uint8_t IRQ_TIMER = 0xF2;

View File

@@ -7,6 +7,7 @@
#include <kernel/Timer/Timer.h>
#include <termios.h>
#include <sys/syscall.h>
#define DUMP_ALL_SYSCALLS 0
#define DUMP_LONG_SYSCALLS 0

View File

@@ -74,7 +74,7 @@ set(LIBC_SOURCES
)
add_library(objlibc OBJECT ${LIBC_SOURCES})
target_compile_definitions(objlibc PRIVATE __arch=${BANAN_ARCH})
target_compile_definitions(objlibc PRIVATE __arch=${BANAN_ARCH} __is_libc)
target_compile_options(objlibc PRIVATE -O2 -g -Wstack-usage=512 -fno-exceptions -fno-rtti -fpic)
target_compile_options(objlibc PUBLIC -Wall -Wextra -Werror -Wno-error=stack-usage=)

View File

@@ -608,6 +608,22 @@ char* getpass(const char* prompt);
long syscall(long syscall, ...);
#ifdef __is_libc
#include <kernel/API/Syscall.h>
#include <errno.h>
#define _syscall(...) ({ \
long _ret = -ERESTART; \
while (_ret == -ERESTART) \
_ret = _kas_syscall(__VA_ARGS__); \
if (_ret < 0) { \
errno = -_ret; \
_ret = -1; \
} \
_ret; \
})
#define syscall _syscall
#endif
extern char** environ;
__END_DECLS

View File

@@ -254,32 +254,21 @@ void _exit(int status)
ASSERT_NOT_REACHED();
}
#undef syscall
long syscall(long syscall, ...)
{
va_list args;
va_start(args, syscall);
uintptr_t arg1 = va_arg(args, uintptr_t);
uintptr_t arg2 = va_arg(args, uintptr_t);
uintptr_t arg3 = va_arg(args, uintptr_t);
uintptr_t arg4 = va_arg(args, uintptr_t);
uintptr_t arg5 = va_arg(args, uintptr_t);
va_end(args);
long ret;
do
ret = Kernel::syscall(syscall, arg1, arg2, arg3, arg4, arg5);
while (ret == -ERESTART);
if (ret < 0)
{
errno = -ret;
return -1;
}
return ret;
return _syscall(syscall, arg1, arg2, arg3, arg4, arg5);
}
#define syscall _syscall
int close(int fd)
{

View File

@@ -223,14 +223,14 @@ constexpr uintptr_t SYM_NOT_FOUND = -1;
static void lock_global_lock()
{
const pthread_t tid = syscall<>(SYS_PTHREAD_SELF);
const pthread_t tid = syscall(SYS_PTHREAD_SELF);
pthread_t expected = 0;
while (!s_global_locker.compare_exchange(expected, tid))
{
if (expected == tid)
break;
syscall<>(SYS_YIELD);
syscall(SYS_YIELD);
expected = 0;
}
@@ -1393,7 +1393,7 @@ static void initialize_tls(MasterTLS master_tls)
.master_tls_module_count = master_tls.module_count,
.dynamic_tls = s_dynamic_tls,
.cleanup_stack = nullptr,
.id = static_cast<pthread_t>(syscall<>(SYS_PTHREAD_SELF)),
.id = static_cast<pthread_t>(syscall(SYS_PTHREAD_SELF)),
.errno_ = 0,
.cancel_type = PTHREAD_CANCEL_DEFERRED,
.cancel_state = PTHREAD_CANCEL_ENABLE,
@@ -1565,7 +1565,7 @@ static void load_dynamic_tls(LoadedElf& elf)
int expected = 0;
while (!BAN::atomic_compare_exchange(s_dynamic_tls->lock, expected, 1))
{
syscall<>(SYS_YIELD);
syscall(SYS_YIELD);
expected = 0;
}

View File

@@ -2,6 +2,7 @@
#include <errno.h>
#include <fcntl.h>
#include <sys/syscall.h>
#include <unistd.h>
void print(int fd, const char* buffer)

View File

@@ -1,10 +1,18 @@
#pragma once
#include <BAN/Traits.h>
#include <unistd.h> // make sure syscall function is declared before defining it
#include <errno.h>
#include <kernel/API/Syscall.h>
#include <stddef.h>
#include <stdint.h>
#define syscall(...) ({ \
long _ret = -ERESTART; \
while (_ret == -ERESTART) \
_ret = _kas_syscall(__VA_ARGS__); \
_ret; \
})
template<typename T>
inline constexpr T min(T a, T b)
@@ -18,12 +26,6 @@ inline constexpr T max(T a, T b)
return a > b ? a : b;
}
template<typename... Ts> requires (sizeof...(Ts) <= 5) && ((BAN::is_integral_v<Ts> || BAN::is_pointer_v<Ts>) && ...)
inline auto syscall(long syscall, Ts... args)
{
return Kernel::syscall(syscall, (uintptr_t)args...);
}
void print(int fd, const char* buffer);
[[noreturn]] void print_error_and_exit(const char* message, int error);