rstdlib

Generic Base Layer for writing C Programs
git clone anongit@rnpnr.xyz:rstdlib.git
Log | Files | Refs | Feed | README | LICENSE

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 */