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 function force_inline u64 100 syscall5(LinuxSyscall n, s64 a1, s64 a2, s64 a3, s64 a4, s64 a5) 101 { 102 u64 result; 103 register s64 r10 asm("r10") = a4; 104 register s64 r8 asm("r8") = a5; 105 asm volatile ("syscall" 106 : "=a"(result) 107 : "a"(n), "D"(a1), "S"(a2), "d"(a3), "r"(r10), "r"(r8) 108 : "rcx", "r11", "memory" 109 ); 110 return result; 111 } 112 113 function force_inline u64 114 syscall6(LinuxSyscall n, s64 a1, s64 a2, s64 a3, s64 a4, s64 a5, s64 a6) 115 { 116 s64 result; 117 register s64 r10 asm("r10") = a4; 118 register s64 r8 asm("r8") = a5; 119 register s64 r9 asm("r9") = a6; 120 asm volatile ("syscall" 121 : "=a"(result) 122 : "a"(n), "D"(a1), "S"(a2), "d"(a3), "r"(r10), "r"(r8), "r"(r9) 123 : "rcx", "r11", "memory" 124 ); 125 return result; 126 } 127 128 #elif ARCH_ARM64 129 130 typedef enum { 131 LinuxSyscall_openat = 56, 132 LinuxSyscall_close = 57, 133 LinuxSyscall_read = 63, 134 LinuxSyscall_write = 64, 135 LinuxSyscall_exit = 93, 136 } LinuxSyscall; 137 138 function force_inline s64 139 syscall1(s64 n, s64 a1) 140 { 141 register s64 x8 asm("x8") = n; 142 register s64 x0 asm("x0") = a1; 143 asm volatile ("svc 0" 144 : "=r"(x0) 145 : "0"(x0), "r"(x8) 146 : "memory", "cc" 147 ); 148 return x0; 149 } 150 151 function force_inline s64 152 syscall2(s64 n, s64 a1, s64 a2) 153 { 154 register s64 x8 asm("x8") = n; 155 register s64 x0 asm("x0") = a1; 156 register s64 x1 asm("x1") = a2; 157 asm volatile ("svc 0" 158 : "=r"(x0) 159 : "0"(x0), "r"(x8), "r"(x1) 160 : "memory", "cc" 161 ); 162 return x0; 163 } 164 165 function force_inline s64 166 syscall3(s64 n, s64 a1, s64 a2, s64 a3) 167 { 168 register s64 x8 asm("x8") = n; 169 register s64 x0 asm("x0") = a1; 170 register s64 x1 asm("x1") = a2; 171 register s64 x2 asm("x2") = a3; 172 asm volatile ("svc 0" 173 : "=r"(x0) 174 : "0"(x0), "r"(x8), "r"(x1), "r"(x2) 175 : "memory", "cc" 176 ); 177 return x0; 178 } 179 180 function force_inline s64 181 syscall4(s64 n, s64 a1, s64 a2, s64 a3, s64 a4) 182 { 183 register s64 x8 asm("x8") = n; 184 register s64 x0 asm("x0") = a1; 185 register s64 x1 asm("x1") = a2; 186 register s64 x2 asm("x2") = a3; 187 register s64 x3 asm("x3") = a4; 188 asm volatile ("svc 0" 189 : "=r"(x0) 190 : "0"(x0), "r"(x8), "r"(x1), "r"(x2), "r"(x3) 191 : "memory", "cc" 192 ); 193 return x0; 194 } 195 196 function force_inline s64 197 syscall5(s64 n, s64 a1, s64 a2, s64 a3, s64 a4, s64 a5) 198 { 199 register s64 x8 asm("x8") = n; 200 register s64 x0 asm("x0") = a1; 201 register s64 x1 asm("x1") = a2; 202 register s64 x2 asm("x2") = a3; 203 register s64 x3 asm("x3") = a4; 204 register s64 x4 asm("x4") = a5; 205 asm volatile ("svc 0" 206 : "=r"(x0) 207 : "0"(x0), "r"(x8), "r"(x1), "r"(x2), "r"(x3), "r"(x4), 208 : "memory", "cc" 209 ); 210 return x0; 211 } 212 213 function force_inline s64 214 syscall6(s64 n, s64 a1, s64 a2, s64 a3, s64 a4, s64 a5, s64 a6) 215 { 216 register s64 x8 asm("x8") = n; 217 register s64 x0 asm("x0") = a1; 218 register s64 x1 asm("x1") = a2; 219 register s64 x2 asm("x2") = a3; 220 register s64 x3 asm("x3") = a4; 221 register s64 x4 asm("x4") = a5; 222 register s64 x5 asm("x5") = a6; 223 asm volatile ("svc 0" 224 : "=r"(x0) 225 : "0"(x0), "r"(x8), "r"(x1), "r"(x2), "r"(x3), "r"(x4), "r"(x5) 226 : "memory", "cc" 227 ); 228 return x0; 229 } 230 231 #else 232 #error Architecture not supported on Linux 233 #endif 234 235 function FileHandle 236 sys_stdout_handle(void) 237 { 238 FileHandle result = {1}; 239 return result; 240 } 241 242 function void 243 sys_close(FileHandle h) 244 { 245 u64 sysret; 246 LINUX_EINTR_LOOP(sysret, syscall1(LinuxSyscall_close, (s64)h.value[0])); 247 } 248 249 function FileHandle 250 sys_open_file_at(str8 path, FileHandle directory, FileOpenFlags flags) 251 { 252 char cpath[MaxPathLength]; 253 254 u64 path_length = Min(path.length, countof(cpath) - 1); 255 memory_copy(cpath, path.data, path_length); 256 cpath[path_length] = 0; 257 258 s32 linux_flags = 0; 259 if (flags & FileOpenFlag_Write) { 260 linux_flags |= (flags & FileOpenFlag_Read) ? LinuxConstant_O_RDWR : LinuxConstant_O_WRONLY; 261 } else if (flags & FileOpenFlag_Read) { 262 linux_flags |= LinuxConstant_O_RDONLY; 263 } 264 265 if (flags & FileOpenFlag_Create) linux_flags |= LinuxConstant_O_CREAT; 266 if (flags & FileOpenFlag_Reset) linux_flags |= LinuxConstant_O_TRUNC; 267 else linux_flags |= LinuxConstant_O_APPEND; 268 269 FileHandle result = InvalidHandle; 270 s64 directory_descriptor = directory.value[0]; 271 if (directory_descriptor == -1) directory_descriptor = LinuxConstant_AT_FDCWD; 272 273 u64 sysret; 274 LINUX_EINTR_LOOP(sysret, syscall4(LinuxSyscall_openat, directory_descriptor, (s64)cpath, linux_flags, 0644)); 275 if ValidLinuxResult(sysret) 276 result.value[0] = sysret; 277 278 return result; 279 } 280 281 function s64 282 sys_read(FileHandle h, void *output_buffer, s64 read_length) 283 { 284 u64 result; 285 LINUX_EINTR_LOOP(result, syscall3(LinuxSyscall_read, (s64)h.value[0], (s64)output_buffer, read_length)); 286 return result; 287 } 288 289 function s64 290 sys_write(FileHandle h, void *data, s64 write_length) 291 { 292 u64 result; 293 LINUX_EINTR_LOOP(result, syscall3(LinuxSyscall_write, (s64)h.value[0], (s64)data, write_length)); 294 return (s64)result; 295 } 296 297 function no_return void 298 sys_exit(s64 exit_status) 299 { 300 syscall1(LinuxSyscall_exit, exit_status); 301 unreachable(); 302 } 303 304 #endif /* OS_LINUX */ 305 306 #endif /* RSTD_PLATFORM_H */