rust-kernel
Rustbelt: a hobby x86_64 kernel written in Rust
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | //! System calls via the `syscall` / `sysret` instructions.
//!
//! ABI (like Linux x86_64): number in rax, arguments in rdi, rsi, rdx (r10,
//! r8 for 4th/5th), result in rax; negative results are `-errno`. The
//! `syscall` instruction itself clobbers rcx (return address) and r11 (saved
//! RFLAGS); every other register is preserved for the caller.
//!
//! | nr | name | arguments | note |
//! |----|-------------|--------------------------------|------|
//! | 0 | read | fd, buf, len | fd 0 blocks until a line is typed |
//! | 1 | write | fd, buf, len | fd 1/2 = console |
//! | 2 | open | path_ptr, path_len, flags | Linux takes a C string; we take ptr+len. flags: O_CREAT = 0o100 |
//! | 3 | close | fd | |
//! | 24 | sched_yield | | |
//! | 39 | getpid | | |
//! | 60 | exit | code | |
//!
//! What happens on `syscall` (the CPU does steps 1-3 in one instruction):
//! 1. rcx = user RIP (next instruction), r11 = user RFLAGS
//! 2. RFLAGS &= !SFMASK (we mask IF -> interrupts off)
//! 3. CS/SS = kernel selectors from STAR, RIP = LSTAR (`syscall_entry`), CPL = 0
//! ...but RSP is still the *user* stack! The CPU doesn't switch stacks for
//! `syscall` (unlike interrupts, which use TSS.RSP0). So `syscall_entry`
//! must do it first: stash the user RSP, load this thread's kernel stack,
//! save registers, re-enable interrupts and call `syscall_dispatch` in Rust.
//! `sysretq` reverses it: RIP = rcx, RFLAGS = r11, CPL = 3.
//!
//! Single CPU only: the "current kernel stack" and the user-RSP scratch slot
//! are plain globals. (Multi-core kernels use per-CPU data via `swapgs`.)
//!
//! Why not `int 0x80`? It also works (and is simpler: the CPU switches stacks
//! via TSS.RSP0 for us), but `syscall` is what Linux and every modern x86_64
//! OS use, and it's faster.
use crateErrno;
use crate;
use crate::;
use Arc;
use global_asm;
use ;
pub const SYS_READ: u64 = 0;
pub const SYS_WRITE: u64 = 1;
pub const SYS_OPEN: u64 = 2;
pub const SYS_CLOSE: u64 = 3;
pub const SYS_SCHED_YIELD: u64 = 24;
pub const SYS_GETPID: u64 = 39;
pub const SYS_EXIT: u64 = 60;
pub const O_CREAT: u64 = 0o100;
/// Kernel stack top of the running thread (set by the scheduler).
static SYSCALL_KERNEL_RSP: AtomicU64 = new;
/// Scratch slot for the user RSP during the first instructions of the entry.
static SYSCALL_USER_RSP: AtomicU64 = new;
/// Called by the scheduler when switching threads.
/// Program the MSRs that make `syscall` work.
unsafe extern "C"
global_asm!;
/// Rust side of every system call. Returns the value for rax.
extern "C"
/// Turn a user pointer + length into a slice, after checking that the user
/// may really access that memory. Never trust pointers from user space!
/// Like `user_slice`, but the user must be allowed to *write* the memory.
|