rstd_platform.h (7056B)
1 ////////////////////////////////////// 2 // NOTE: Wrappable Platform Syscalls 3 #ifndef RSTD_PLATFORM_H 4 #define RSTD_PLATFORM_H 5 6 #define MaxPathLength (1024UL) 7 8 #define InvalidHandleValue (-1ULL) 9 #define InvalidHandle {InvalidHandleValue} 10 11 typedef struct { u64 value[1]; } FileHandle; 12 13 typedef enum { 14 FileOpenFlag_Write = 1 << 0, 15 FileOpenFlag_Read = 1 << 1, 16 FileOpenFlag_Reset = 1 << 2, 17 FileOpenFlag_Create = 1 << 3, 18 } FileOpenFlags; 19 20 #if OS_LINUX 21 22 #define ValidLinuxResult(r) ((r) <= -4096UL) 23 #define InvalidLinuxResult(r) ((r) > -4096UL) 24 25 #define LinuxConstant_O_RDONLY (0x0000) 26 #define LinuxConstant_O_WRONLY (0x0001) 27 #define LinuxConstant_O_RDWR (0x0002) 28 #define LinuxConstant_O_CREAT (0x0040) 29 #define LinuxConstant_O_TRUNC (0x0200) 30 #define LinuxConstant_O_APPEND (0x0400) 31 32 #define LinuxConstant_EINTR (-4UL) 33 34 #define LinuxConstant_AT_FDCWD (-100) 35 36 #define LINUX_EINTR_LOOP(result, expr) do { \ 37 (result) = (expr); \ 38 } while (InvalidLinuxResult(result) && (result) == LinuxConstant_EINTR) 39 40 #if ARCH_X64 41 42 typedef enum { 43 LinuxSyscall_read = 0, 44 LinuxSyscall_write = 1, 45 LinuxSyscall_close = 3, 46 LinuxSyscall_exit = 60, 47 LinuxSyscall_openat = 257, 48 } LinuxSyscall; 49 50 function force_inline u64 51 syscall1(LinuxSyscall n, s64 a1) 52 { 53 u64 result; 54 asm volatile ("syscall" 55 : "=a"(result) 56 : "a"(n), "D"(a1) 57 : "rcx", "r11", "memory" 58 ); 59 return result; 60 } 61 62 function force_inline u64 63 syscall2(LinuxSyscall n, s64 a1, s64 a2) 64 { 65 s64 result; 66 asm volatile ("syscall" 67 : "=a"(result) 68 : "a"(n), "D"(a1), "S"(a2) 69 : "rcx", "r11", "memory" 70 ); 71 return result; 72 } 73 74 function force_inline u64 75 syscall3(LinuxSyscall n, s64 a1, s64 a2, s64 a3) 76 { 77 u64 result; 78 asm volatile ("syscall" 79 : "=a"(result) 80 : "a"(n), "D"(a1), "S"(a2), "d"(a3) 81 : "rcx", "r11", "memory" 82 ); 83 return result; 84 } 85 86 function force_inline u64 87 syscall4(LinuxSyscall n, s64 a1, s64 a2, s64 a3, s64 a4) 88 { 89 u64 result; 90 register s64 r10 asm("r10") = a4; 91 asm volatile ("syscall" 92 : "=a"(result) 93 : "a"(n), "D"(a1), "S"(a2), "d"(a3), "r"(r10) 94 : "rcx", "r11", "memory" 95 ); 96 return result; 97 } 98 99 100 function force_inline u64 101 syscall5(LinuxSyscall n, s64 a1, s64 a2, s64 a3, s64 a4, s64 a5) 102 { 103 u64 result; 104 register s64 r10 asm("r10") = a4; 105 register s64 r8 asm("r8") = a5; 106 asm volatile ("syscall" 107 : "=a"(result) 108 : "a"(n), "D"(a1), "S"(a2), "d"(a3), "r"(r10), "r"(r8) 109 : "rcx", "r11", "memory" 110 ); 111 return result; 112 } 113 114 function force_inline u64 115 syscall6(LinuxSyscall n, s64 a1, s64 a2, s64 a3, s64 a4, s64 a5, s64 a6) 116 { 117 s64 result; 118 register s64 r10 asm("r10") = a4; 119 register s64 r8 asm("r8") = a5; 120 register s64 r9 asm("r9") = a6; 121 asm volatile ("syscall" 122 : "=a"(result) 123 : "a"(n), "D"(a1), "S"(a2), "d"(a3), "r"(r10), "r"(r8), "r"(r9) 124 : "rcx", "r11", "memory" 125 ); 126 return result; 127 } 128 129 #elif ARCH_ARM64 130 131 typedef enum { 132 LinuxSyscall_openat = 56, 133 LinuxSyscall_close = 57, 134 LinuxSyscall_read = 63, 135 LinuxSyscall_write = 64, 136 LinuxSyscall_exit = 93, 137 } LinuxSyscall; 138 139 function force_inline s64 140 syscall1(s64 n, s64 a1) 141 { 142 register s64 x8 asm("x8") = n; 143 register s64 x0 asm("x0") = a1; 144 asm volatile ("svc 0" 145 : "=r"(x0) 146 : "0"(x0), "r"(x8) 147 : "memory", "cc" 148 ); 149 return x0; 150 } 151 152 function force_inline s64 153 syscall2(s64 n, s64 a1, s64 a2) 154 { 155 register s64 x8 asm("x8") = n; 156 register s64 x0 asm("x0") = a1; 157 register s64 x1 asm("x1") = a2; 158 asm volatile ("svc 0" 159 : "=r"(x0) 160 : "0"(x0), "r"(x8), "r"(x1) 161 : "memory", "cc" 162 ); 163 return x0; 164 } 165 166 function force_inline s64 167 syscall3(s64 n, s64 a1, s64 a2, s64 a3) 168 { 169 register s64 x8 asm("x8") = n; 170 register s64 x0 asm("x0") = a1; 171 register s64 x1 asm("x1") = a2; 172 register s64 x2 asm("x2") = a3; 173 asm volatile ("svc 0" 174 : "=r"(x0) 175 : "0"(x0), "r"(x8), "r"(x1), "r"(x2) 176 : "memory", "cc" 177 ); 178 return x0; 179 } 180 181 function force_inline s64 182 syscall4(s64 n, s64 a1, s64 a2, s64 a3, s64 a4) 183 { 184 register s64 x8 asm("x8") = n; 185 register s64 x0 asm("x0") = a1; 186 register s64 x1 asm("x1") = a2; 187 register s64 x2 asm("x2") = a3; 188 register s64 x3 asm("x3") = a4; 189 asm volatile ("svc 0" 190 : "=r"(x0) 191 : "0"(x0), "r"(x8), "r"(x1), "r"(x2), "r"(x3) 192 : "memory", "cc" 193 ); 194 return x0; 195 } 196 197 function force_inline s64 198 syscall5(s64 n, s64 a1, s64 a2, s64 a3, s64 a4, s64 a5) 199 { 200 register s64 x8 asm("x8") = n; 201 register s64 x0 asm("x0") = a1; 202 register s64 x1 asm("x1") = a2; 203 register s64 x2 asm("x2") = a3; 204 register s64 x3 asm("x3") = a4; 205 register s64 x4 asm("x4") = a5; 206 asm volatile ("svc 0" 207 : "=r"(x0) 208 : "0"(x0), "r"(x8), "r"(x1), "r"(x2), "r"(x3), "r"(x4), 209 : "memory", "cc" 210 ); 211 return x0; 212 } 213 214 function force_inline s64 215 syscall6(s64 n, s64 a1, s64 a2, s64 a3, s64 a4, s64 a5, s64 a6) 216 { 217 register s64 x8 asm("x8") = n; 218 register s64 x0 asm("x0") = a1; 219 register s64 x1 asm("x1") = a2; 220 register s64 x2 asm("x2") = a3; 221 register s64 x3 asm("x3") = a4; 222 register s64 x4 asm("x4") = a5; 223 register s64 x5 asm("x5") = a6; 224 asm volatile ("svc 0" 225 : "=r"(x0) 226 : "0"(x0), "r"(x8), "r"(x1), "r"(x2), "r"(x3), "r"(x4), "r"(x5) 227 : "memory", "cc" 228 ); 229 return x0; 230 } 231 232 #else 233 #error Architecture not supported on Linux 234 #endif 235 236 function FileHandle 237 sys_stdout_handle(void) 238 { 239 FileHandle result = {1}; 240 return result; 241 } 242 243 function void 244 sys_close(FileHandle h) 245 { 246 u64 sysret; 247 LINUX_EINTR_LOOP(sysret, syscall1(LinuxSyscall_close, (s64)h.value[0])); 248 } 249 250 function FileHandle 251 sys_open_file_at(str8 path, FileHandle directory, FileOpenFlags flags) 252 { 253 char cpath[MaxPathLength]; 254 255 u64 path_length = Min(path.length, countof(cpath) - 1); 256 memory_copy(cpath, path.str, path_length); 257 cpath[path_length] = 0; 258 259 s32 linux_flags = 0; 260 if (flags & FileOpenFlag_Write) { 261 linux_flags |= (flags & FileOpenFlag_Read) ? LinuxConstant_O_RDWR : LinuxConstant_O_WRONLY; 262 } else if (flags & FileOpenFlag_Read) { 263 linux_flags |= LinuxConstant_O_RDONLY; 264 } 265 266 if (flags & FileOpenFlag_Create) linux_flags |= LinuxConstant_O_CREAT; 267 if (flags & FileOpenFlag_Reset) linux_flags |= LinuxConstant_O_TRUNC; 268 else linux_flags |= LinuxConstant_O_APPEND; 269 270 FileHandle result = InvalidHandle; 271 s64 directory_descriptor = directory.value[0]; 272 if (directory_descriptor == -1) directory_descriptor = LinuxConstant_AT_FDCWD; 273 274 u64 sysret; 275 LINUX_EINTR_LOOP(sysret, syscall4(LinuxSyscall_openat, directory_descriptor, (s64)cpath, linux_flags, 0644)); 276 if ValidLinuxResult(sysret) 277 result.value[0] = sysret; 278 279 return result; 280 } 281 282 function s64 283 sys_read(FileHandle h, void *output_buffer, s64 read_length) 284 { 285 u64 result; 286 LINUX_EINTR_LOOP(result, syscall3(LinuxSyscall_read, (s64)h.value[0], (s64)output_buffer, read_length)); 287 return result; 288 } 289 290 function s64 291 sys_write(FileHandle h, void *data, s64 write_length) 292 { 293 u64 result; 294 LINUX_EINTR_LOOP(result, syscall3(LinuxSyscall_write, (s64)h.value[0], (s64)data, write_length)); 295 return (s64)result; 296 } 297 298 function no_return void 299 sys_exit(s64 exit_status) 300 { 301 syscall1(LinuxSyscall_exit, exit_status); 302 unreachable(); 303 } 304 305 #endif /* OS_LINUX */ 306 307 #endif /* RSTD_PLATFORM_H */