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