04 - System Call Subsystem (Linux x86_64 ABI)
BangOS implements the native Linux x86_64 System Call Interface using the hardware syscall / sysret instruction mechanism. This enables unmodified binaries compiled statically with musl-gcc to execute directly on the bare-metal kernel.
⚡ Hardware MSR Configuration (kernel/syscall/syscall.c)
In Long Mode, system calls do not use slow software interrupt gates (int 0x80). Instead, the CPU executes the native syscall instruction, which switches from Ring 3 to Ring 0 in a few clock cycles by reading four Model-Specific Registers (MSRs):
| MSR Address | MSR Constant | Configured Value | Purpose |
|---|---|---|---|
0xC0000080 |
IA32_EFER |
EFER.SCE = 1 (Bit 0) |
System Call Enable (activates syscall/sysret instructions). |
0xC0000081 |
MSR_STAR |
0x0010000800000000 |
Defines target GDT segment selectors for Kernel (0x08/0x10) and User (0x18/0x20). |
0xC0000082 |
MSR_LSTAR |
&syscall_entry |
Ring 0 target RIP address jumped to when syscall is executed. |
0xC0000084 |
MSR_SFMASK |
0x200 (Bit 9) |
RFLAGS mask: automatically clears the Interrupt Flag (IF) on syscall entry. |
void syscall_init_msrs(void) {
uint64_t efer = read_msr(0xC0000080);
efer |= 1ULL; // Enable SCE (System Call Extension)
write_msr(0xC0000080, efer);
// STAR MSR: Bits 32-47 = Kernel CS (0x08), Bits 48-63 = User CS/SS Base (0x10)
uint64_t star = ((uint64_t)0x0010 << 48) | ((uint64_t)0x0008 << 32);
write_msr(0xC0000081, star);
// LSTAR MSR: Target 64-bit RIP address for syscall_entry
write_msr(0xC0000082, (uint64_t)&syscall_entry);
// SFMASK MSR: Mask IF (Interrupt Flag 0x200) to disable interrupts upon entry
write_msr(0xC0000084, 0x200);
}
📋 System V AMD64 ABI Register Passing Convention
When a userland binary invokes syscall:
- Syscall Number: Loaded into register
RAX. - Arguments (Up to 6):
RDI(Argument 1)RSI(Argument 2)RDX(Argument 3)R10(Argument 4 — note thatR10is used instead ofRCXbecausesyscallclobbersRCX)R8(Argument 5)R9(Argument 6)- Hardware Saved State:
RCX: Saves userlandRIP.R11: Saves userlandRFLAGS.- Return Code: Evaluated in
RAX. Positive integers or0denote success; negative numbers denote standard Linux-ERRNOcodes (e.g.-EINVAL = -22).
⚙️ Assembly Trampoline (kernel/arch/x86_64/syscall_entry.s)
Because userland stack pointers (RSP) cannot be trusted by the kernel, syscall_entry immediately swaps to the active process's kernel stack before invoking C handlers:
.global syscall_entry
syscall_entry:
// 1. Temporarily stash user RSP and switch to process kernel stack
movq %rsp, user_rsp_temp(%rip)
movq kernel_rsp_temp(%rip), %rsp
// 2. Construct context_frame_t on kernel stack
pushq $0x1B // User SS (0x18 | 3)
pushq user_rsp_temp(%rip) // User RSP
pushq %r11 // User RFLAGS (saved by hardware)
pushq $0x23 // User CS (0x20 | 3)
pushq %rcx // User RIP (saved by hardware)
pushq $0 // Error Code
pushq $0 // Vector Number
pushq %rax
pushq %rbx
pushq %rcx
pushq %rdx
pushq %rsi
pushq %rdi
pushq %rbp
pushq %r8
pushq %r9
pushq %r10
pushq %r11
pushq %r12
pushq %r13
pushq %r14
pushq %r15
// 3. Align stack to 16-byte boundary for C calling convention
movq %rsp, %r9 // 6th arg: context_frame_t*
subq $8, %rsp
// 4. Pass syscall arguments to do_syscall(sys_num, arg1, arg2, arg3, arg4, frame)
movq %rax, %rdi // Arg 1: Syscall number
movq %rsi, %rdx // Arg 3: 2nd syscall arg
movq %r10, %r8 // Arg 5: 4th syscall arg
movq 120(%rsp), %rsi // Arg 2: 1st syscall arg (RDI saved in frame)
movq 104(%rsp), %rcx // Arg 4: 3rd syscall arg (RDX saved in frame)
call do_syscall
addq $8, %rsp
movq %rax, 112(%rsp) // Store return value in frame->rax
// 5. Restore registers and return to userland via sysretq
popq %r15
popq %r14
popq %r13
popq %r12
popq %r11
popq %r10
popq %r9
popq %r8
popq %rbp
popq %rdi
popq %rsi
popq %rdx
popq %rcx
popq %rbx
popq %rax
addq $16, %rsp // Pop vector and error code
popq %rcx // Restore user RIP into RCX
addq $8, %rsp // Skip CS
popq %r11 // Restore user RFLAGS into R11
popq %rsp // Restore user RSP
sysretq // Return to Ring 3 (loads RIP from RCX, RFLAGS from R11)
🛠️ Implemented System Calls Reference (kernel/syscall/syscall.c)
| Syscall # | Constant | Arguments | Return / Behavior |
|---|---|---|---|
0 |
SYS_READ |
int fd, char *buf, size_t count |
Reads from UART (fd 0) or VFS file descriptors (fd >= 3). Returns bytes read, -EBADF (-9), or -EFAULT (-14). |
1 |
SYS_WRITE |
int fd, const char *buf, size_t count |
Writes to UART (fd 1,2) or VFS files (fd >= 3). Returns bytes written. |
2 |
SYS_OPEN |
const char *path, int flags, int mode |
Opens or creates file node via VFS; allocates new file descriptor (fd >= 3). |
3 |
SYS_CLOSE |
int fd |
Closes open file descriptor and releases VFS node reference. |
4 |
SYS_STAT |
const char *path, struct stat *statbuf |
Populates file size, permissions, and mode for given pathname. |
5 |
SYS_FSTAT |
int fd, struct stat *statbuf |
Populates file metadata for open file descriptor. |
7 |
SYS_POLL |
struct pollfd *fds, nfds_t nfds, int timeout |
Non-blocking poll; returns 1 (I/O ready). |
8 |
SYS_LSEEK |
int fd, off_t offset, int whence |
Repositions file read/write offset (SEEK_SET, SEEK_CUR, SEEK_END). |
9 |
SYS_MMAP |
void *addr, size_t len, int prot, int flags, int fd, off_t off |
Allocates a Virtual Memory Area (VMA) and memory pages dynamically. |
10 |
SYS_MPROTECT |
void *addr, size_t len, int prot |
Modifies VMA permissions and updates hardware page table entry flags. |
11 |
SYS_MUNMAP |
void *addr, size_t len |
Releases virtual memory range, reclaims physical frames, and trims VMAs. |
12 |
SYS_BRK |
uint64_t brk_addr |
Queries current heap pointer (brk(0)) or expands process heap dynamically. |
13 |
SYS_RT_SIGACTION |
int sig, const struct sigaction *act, ... |
Signal handler registration stub (returns 0). |
14 |
SYS_RT_SIGPROCMASK |
int how, const sigset_t *set, ... |
Signal mask configuration stub (returns 0). |
16 |
SYS_IOCTL |
int fd, unsigned long cmd, void *arg |
Handles terminal attributes (e.g. TIOCGWINSZ returning 80x24 window size). |
20 |
SYS_WRITEV |
int fd, const struct iovec *iov, int iovcnt |
Vectorized scatter-gather output used by printf() / vfprintf(). |
24 |
SYS_SCHED_YIELD |
none | Cooperatively yields remaining CPU quantum to next ready task. |
35 |
SYS_NANOSLEEP |
const struct timespec *req, struct timespec *rem |
High-precision sleep using calibrated timestamp counter (TSC) and PIT timer ticks. |
39 |
SYS_GETPID |
none | Returns current process group / process ID (proc->tgid). |
41 |
SYS_SOCKET |
int domain, int type, int protocol |
Allocates network socket endpoint (AF_INET, SOCK_STREAM / SOCK_DGRAM) and wraps in VFS file descriptor. |
42 |
SYS_CONNECT |
int sockfd, const struct sockaddr *addr, socklen_t addrlen |
Initiates TCP 3-way handshake (SYN/SYN+ACK/ACK) to remote host. |
44 |
SYS_SENDTO |
int fd, const void *buf, size_t len, int flags, ... |
Transmits network stream or datagram payload via TCP/IP or UDP. |
45 |
SYS_RECVFROM |
int fd, void *buf, size_t len, int flags, ... |
Receives incoming payload from socket ring buffer. |
46 |
SYS_SENDMSG |
int fd, const struct msghdr *msg, int flags |
Message send stub for POSIX network compatibility. |
47 |
SYS_RECVMSG |
int fd, struct msghdr *msg, int flags |
Message receive stub for POSIX network compatibility. |
48 |
SYS_SHUTDOWN |
int sockfd, int how |
Shuts down reading, writing, or both on a connected socket. |
49 |
SYS_BIND |
int sockfd, const struct sockaddr *addr, socklen_t addrlen |
Binds local network address. |
50 |
SYS_LISTEN |
int sockfd, int backlog |
Configures socket for listening. |
51 |
SYS_GETSOCKNAME |
int sockfd, struct sockaddr *addr, socklen_t *addrlen |
Returns local socket endpoint information. |
52 |
SYS_GETPEERNAME |
int sockfd, struct sockaddr *addr, socklen_t *addrlen |
Returns remote peer address information. |
54 |
SYS_SETSOCKOPT |
int sockfd, int level, int optname, const void *optval, socklen_t optlen |
Sets socket options. |
55 |
SYS_GETSOCKOPT |
int sockfd, int level, int optname, void *optval, socklen_t *optlen |
Queries socket options. |
56 |
SYS_CLONE |
unsigned long flags, void *child_stack, int *ptid, int *ctid, void *newtls |
Creates execution context: processes or threads (CLONE_VM). |
57 |
SYS_FORK |
none | Creates child process with duplicated memory mappings and execution state. |
58 |
SYS_VFORK |
none | Creates child process context. |
59 |
SYS_EXECVE |
const char *path, char *const argv[], char *const envp[] |
Replaces current process with new standalone ELF from TarFS ramdisk. |
60 |
SYS_EXIT |
int status |
Terminates process/thread, notifies parent via wait4, or halts system if PID 1. |
61 |
SYS_WAIT4 |
pid_t pid, int *status, int options, struct rusage *ru |
Waits for child process termination and retrieves exit status code. |
62 |
SYS_KILL |
pid_t pid, int sig |
Sends termination signal to target process by PID; transitions process to zombie and wakes parent. |
63 |
SYS_UNAME |
struct utsname *buf |
Populates system name ("BangOS"), release ("0.3.0"), architecture ("x86_64"). |
99 |
SYS_SYSINFO |
struct sysinfo *info |
Populates total RAM, free RAM, uptime in seconds, and active process count. |
158 |
SYS_ARCH_PRCTL |
int code, unsigned long addr |
Sets Thread Local Storage (TLS) by updating MSR_FS_BASE (0xC0000100). |
186 |
SYS_GETTID |
none | Returns thread ID (proc->pid). |
202 |
SYS_FUTEX |
uint32_t *uaddr, int op, uint32_t val, ... |
Fast user-space sleeping and waking synchronization primitive (FUTEX_WAIT, FUTEX_WAKE). |
217 |
SYS_GETDENTS64 |
int fd, struct linux_dirent64 *dirp, size_t count |
Enumerates directory entries from open directory file descriptors. |
218 |
SYS_SET_TID_ADDRESS |
int *tidptr |
Registers thread clear address upon exit; returns thread TID. |
228 |
SYS_CLOCK_GETTIME |
clockid_t clk_id, struct timespec *tp |
Returns monotonic and realtime timestamps with nanosecond precision. |
231 |
SYS_EXIT_GROUP |
int status |
Terminates process or cleanly halts machine if PID 1. |
257 |
SYS_OPENAT |
int dirfd, const char *path, int flags, int mode |
Relative / absolute file open via VFS. |
262 |
SYS_NEWFSTATAT |
int dirfd, const char *path, struct stat *statbuf, int flags |
Relative / absolute stat via VFS. |
| Default | Unhandled | any | Evaluates to -ENOSYS (-38). |