main
1#ifndef NOTLIBC_HEADER_INCLUDED
2#define NOTLIBC_HEADER_INCLUDED
3
4/******************************************************************************/
5/* PLATFORM CORE */
6/******************************************************************************/
7
8
9/*===================== Name/ID macros for important things ==================*/
10
11/* -DBUILD_TYPE */
12#define BUILD_DEBUG 1
13#define BUILD_RELEASE 2
14
15#define ARCH_I386 1
16#define ARCH_X86_64 2
17
18#define OS_NONE 0
19#define OS_LINUX 1
20#define OS_WINDOWS 2
21
22#define COMPILER_GCC 1
23#define COMPILER_CLANG 2
24#define COMPILER_TCC 3
25#define COMPILER_MSVC 4
26
27#define HEAP_HEADER_GUARD_NUMBER 0xc0dedeaddeadc0de
28#define HEAP_OVERRUN_GUARD_NUMBER 0xeeeedeaddeadeeee
29#define HEAP_XOR_KEY 0x0e1e2e3e4e5e6e7e
30
31#define ARRAY_XOR_KEY 0x0a1a2a3a4a5a6a7a
32
33#define MAGIC_UNINITIALIZED_MEM 0xf0
34#define MAGIC_POISONED_MEM 0xfc
35#define MAGIC_FREED_MEM 0xfe
36
37
38/*============================== Build info =================================*/
39
40#ifndef BUILD_TYPE
41#define BUILD_TYPE 0
42#endif
43
44#if BUILD_TYPE == 1
45 #define BUILD BUILD_DEBUG
46 #define DEBUG(...) __VA_ARGS__
47 #define RELEASE(...)
48#elif BUILD_TYPE == 2
49 #define BUILD BUILD_RELEASE
50 #define RELEASE(...) __VA_ARGS__
51 #define DEBUG(...)
52#else
53 #error No build type was specified. There is no defaulting to debug builds.
54#endif
55
56
57/*========================== Architecture info ==============================*/
58
59#ifndef ARCH
60 #if defined(__x86_64__) || defined(_M_X64)
61 #define ARCH ARCH_X86_64
62 #define ARCH_NAME "x86_64"
63 #define X86_64(...) __VA_ARGS__
64 #elif defined(__i386__) || defined(_M_IX86)
65 #define ARCH ARCH_I386
66 #define ARCH_NAME "i386"
67 #define I386(...) __VA_ARGS__
68 #endif
69#endif
70
71#if !defined(ARCH) || !defined(ARCH_NAME)
72 #error Failed to identify architecture. Please specify it via -DARCH=number (choose the most compatible option from above) and -DARCH_NAME=name to override the automatic detection.
73#endif
74
75/* These are only for in-macro use, in case they are absolutely necessary. Not to be abused. They lead to messy code in debuggers */
76#ifndef X86_64
77#define X86_64(...)
78#endif
79
80#ifndef I386
81#define I386(...)
82#endif
83
84
85/*======================== Operating System Info =============================*/
86
87#ifndef OS
88 #if defined(__linux__)
89 #define OS OS_LINUX
90 #define OS_NAME "linux"
91
92 #elif defined(_WIN32) || defined(_WIN64)
93 #define OS OS_WINDOWS
94 #define OS_NAME "windows"
95
96 #endif
97#endif
98
99#if !defined(OS) || !defined(OS_NAME)
100 #error Failed to identify operating system. Please specify it via \
101 -DOS=number (choose the most compatible option from above) and \
102 -DOS_NAME=name to override the automatic detection.
103#endif
104
105
106/*====================== Compiler-specific abstractions ======================*/
107
108#ifndef COMPILER /* skip if -DCOMPILER=<something> was used */
109 #if defined(__clang__) || defined(__llvm__)
110 #define COMPILER COMPILER_CLANG
111 #define COMPILER_NAME "clang"
112
113 #elif defined(__GNUC__) && !defined(__clang__) && \
114 !defined(__llvm__) && !defined(__INTEL_COMPILER)
115 #define COMPILER COMPILER_GCC
116 #define COMPILER_NAME "gcc"
117
118 #elif defined(__TINYC__)
119 #define COMPILER COMPILER_TCC
120 #define COMPILER_NAME "tcc"
121
122 #elif defined( _MSC_VER )
123 #define COMPILER_MSVC
124 #define COMPILER_NAME "msvc"
125 #endif
126#endif
127
128#if !defined(COMPILER) || !defined(COMPILER_NAME)
129 #error Failed to identify compiler. Please specify it via \
130 -DCOMPILER=number (choose the most compatible option from above) and \
131 -DCOMPILER_NAME=name to override the automatic detection.
132#endif
133
134#if COMPILER == COMPILER_GCC
135 #define PRESERVE_WITH_LTO __attribute__((used))
136#else
137 #define PRESERVE_WITH_LTO
138#endif
139
140/* Struct and union macros */
141#define STRUCT( name, ...) \
142typedef struct _##name { \
143 __VA_ARGS__ \
144} name
145
146
147/* Packed struct */
148#if COMPILER == COMPILER_GCC || COMPILER == COMPILER_CLANG \
149 || COMPILER == COMPILER_TCC
150 #define PACKED_STRUCT( name, ...) \
151 typedef struct __attribute__((packed)) _##name { \
152 __VA_ARGS__ \
153 } name
154#elif COMPILER == COMPILER_MSVC
155 #define PACKED_STRUCT( name, ...) \
156 PRAGMA(pack(push, 1)) \
157 typedef struct _##name { \
158 __VA_ARGS__ \
159 } name; \
160 PRAGMA(pack(pop))
161#else
162 #error PACKED_STRUCT macro undefined.
163#endif
164
165#define STRUCT_FIELD_OFFSET( T, fieldname ) \
166 ((usize)&(((T*)0)->fieldname))
167
168
169#define UNION( name, ...) \
170typedef union _##name { \
171 __VA_ARGS__ \
172} name
173
174
175/* Warnings and errors */
176
177#if COMPILER == COMPILER_GCC || COMPILER == COMPILER_CLANG
178 #define PRAGMA(pragma) _Pragma(#pragma)
179#elif COMPILER == COMPILER_MSVC
180 #define PRAGMA(pragma) __pragma(pragma)
181#endif
182
183#if COMPILER == COMPILER_GCC || COMPILER == COMPILER_CLANG
184 #define WARNING(...) PRAGMA(GCC warning __VA_ARGS__)
185 #define ERROR(...) PRAGMA(GCC error __VA_ARGS__)
186#elif COMPILER == COMPILER_TCC
187 #define WARN(...)
188 #define ERROR(...) (*(void*)0 = 0)
189 #ifndef NOTLIBC_SILENCE
190 #warning Compiling with tcc. Pragmas are not supported, \
191 so warnings will just not be printed and errors will give an \
192 'assignment to void' error, but the line number should \
193 still point to the right location.
194 #endif
195#else
196 #define WARNING(...)
197 #ifndef NOTLIBC_SILENCE
198 #warning No warning directive is implemented for this compiler. \
199 No warnings will be emitted from the code.
200 #endif
201 #error No error directive is implemented for this compiler, \
202 thus errors can not be emitted.
203#endif
204
205
206#if COMPILER == COMPILER_GCC || COMPILER == COMPILER_CLANG
207 #define UNREACHABLE __builtin_unreachable()
208#elif COMPILER == COPMILER_MSVC
209 #define UNREACHABLE __assume(0)
210#else
211 #if !defined(NOTLIBC_SILENCE)
212 #warning UNREACHABLE is not defined for the current compiler. \
213 Compiler may not perform all optimizations it could based on \
214 unreachability in some special cases.
215 #endif
216 #define UNREACHABLE
217#endif
218
219
220/*============================= Macro Tricks =================================*/
221
222#define MACRO_EMPTY()
223
224#define MACRO_DEFER( macro ) macro MACRO_EMPTY()
225#define MACRO_OBSTRUCT( ... ) __VA_ARGS__ MACRO_DEFER( MACRO_EMPTY )()
226#define MACRO_EXPAND( ... ) __VA_ARGS__
227
228#define MACRO_STRING_JOIN( str1, str2 ) str1##str2
229
230#define UNIQUE_NAME( name ) \
231 MACRO_EXPAND(MACRO_DEFER(MACRO_STRING_JOIN)(name, __LINE__))
232
233/* Compile-time assertion */
234#define ASSERT( ... ) \
235 typedef char UNIQUE_NAME(compile_time_assert)[(__VA_ARGS__)? 1 : -1]
236
237
238/*=========================== Core Datatypes =================================*/
239
240#if OS == OS_LINUX || OS == OS_WINDOWS
241 typedef unsigned char u8;
242 typedef unsigned short u16;
243 typedef unsigned int u32;
244 typedef unsigned long long u64;
245
246 typedef signed char s8;
247 typedef signed short s16;
248 typedef signed int s32;
249 typedef signed long long s64;
250
251 typedef float f32;
252 typedef double f64;
253#endif
254
255#if ARCH == ARCH_X86_64
256
257 typedef u64 usize;
258 typedef s64 ssize;
259
260 typedef struct _Page {
261 u8 data[4096];
262 } Page;
263
264#elif ARCH == ARCH_I386
265
266 typedef u32 usize;
267 typedef s32 ssize;
268
269 typedef struct _Page {
270 u8 data[4096];
271 } Page;
272
273#endif
274
275ASSERT( sizeof( u8 ) == 1 );
276ASSERT( sizeof( u16 ) == 2 );
277ASSERT( sizeof( u32 ) == 4 );
278ASSERT( sizeof( u64 ) == 8 );
279
280ASSERT( sizeof( s8 ) == 1 );
281ASSERT( sizeof( s16 ) == 2 );
282ASSERT( sizeof( s32 ) == 4 );
283ASSERT( sizeof( s64 ) == 8 );
284
285ASSERT( sizeof( f32 ) == 4 );
286ASSERT( sizeof( f64 ) == 8 );
287
288
289void *memset( void* ptr, int value, unsigned long count );
290void *memcpy( void *dest, const void *src, unsigned long n );
291
292
293
294/*========================== Derived Datatypes ===============================*/
295
296
297/* Pointers */
298
299#define GEN_POINTER_TYPE( T ) \
300typedef T* T##p
301
302GEN_POINTER_TYPE( u8 );
303GEN_POINTER_TYPE( u16 );
304GEN_POINTER_TYPE( u32 );
305GEN_POINTER_TYPE( u64 );
306GEN_POINTER_TYPE( usize );
307
308GEN_POINTER_TYPE( void );
309
310GEN_POINTER_TYPE( s8 );
311GEN_POINTER_TYPE( s16 );
312GEN_POINTER_TYPE( s32 );
313GEN_POINTER_TYPE( s64 );
314GEN_POINTER_TYPE( ssize );
315
316GEN_POINTER_TYPE( f32 );
317GEN_POINTER_TYPE( f64 );
318
319
320/* Status */
321
322/* Errors work in a very specific way in this library.
323 * All function that can fail take a Status * as their first argument.
324 * If this is already a failure, they must return, usually 0.
325 * Otherwise they execute and optionally store their own errors into
326 * that Status value.
327 * NOTE: When the operation is mutating an object no mutation should be done
328 * if an error is already present, but if the function is expected to return
329 * a reference to the mutated object it should directly return the original.
330 *
331 * Moreover, any _create function (constructor) must return a fully zeroed
332 * return value in such an error case. Also, all types MUST support just
333 * being zeroed. If really necessary there could be an exception here,
334 * but mainly if hardware dictates a different default value.
335 *
336 * All _destroy functions must check their args and if they are all zero
337 * (or default value) then they must just return. Otherwise they must
338 * free said resources, even if the error is set beforehand.
339 * Destroy functions can also set the error if the resource could not be
340 * freed for some reason. (invalid non-zero reference, some other
341 * state got messed up along the way or whatever reason).
342 *
343 * These simple rules allow for very nice error-directed control flow, where
344 * the first failure leads to falling through the rest, but still allowing for
345 * guaranteed resource cleanup.
346 *
347 * Normally such behaviour would be difficult to debug, this is why in debug
348 * mode any error setting code should breakpoint() before returning 0.
349 *
350 * Under the Erroring function helpers below you will find some helper macros
351 * for this creating these functions more easily.
352 *
353 * */
354
355typedef u32 Status;
356
357#define S_MASK (3 << 30)
358
359/* Requested action performed. */
360#define S_SUCCESS (1 << 30)
361/* Action didn't need to be performed - desired state is already present/active. */
362#define S_COMPLETION (0 << 30)
363/* Action failed. */
364#define S_FAILURE (2 << 30)
365
366#define S_SOURCE_MASK (0x3ff << 20)
367enum _ErrorSources {
368
369 ERRSRC_ARG_1 = (0x1 << 20),
370 ERRSRC_ARG_2 = (0x2 << 20),
371 ERRSRC_ARG_3 = (0x3 << 20),
372 ERRSRC_ARG_4 = (0x4 << 20),
373 ERRSRC_ARG_5 = (0x5 << 20),
374 ERRSRC_ARG_6 = (0x6 << 20),
375 ERRSRC_ARG_7 = (0x7 << 20),
376 ERRSRC_ARG_8 = (0x8 << 20),
377 ERRSRC_ARG_9 = (0x9 << 20),
378 ERRSRC_ARG_10 = (0xa << 20),
379 ERRSRC_ARG_11 = (0xb << 20),
380 ERRSRC_ARG_12 = (0xc << 20),
381
382 ERRSRC_PLATFORM = (0x10 << 20), /* The error resulted inside platform code. */
383};
384
385#define S_REASON_MASK (0xfffff)
386enum _ErrorReasons {
387 /* Even numbers are for the implementations, odd are for user-defined errors */
388 ERR_GENERIC = 0x0,
389
390 ERR_INVALID_ARGUMENT = 0x2,
391
392 ERR_OVERFLOW = 0x4,
393
394/* a value is out of bounds or the operation would violate certain bounds \
395 * with the current arguments */
396 ERR_OUT_OF_BOUND = 0x6,
397
398 ERR_PERMISSION_DENIED = 0x8,
399
400
401 ERR_MEM_MAP_FAILURE = 0x100,
402 ERR_MEM_UNMAP_FAILURE = 0x102,
403 ERR_MEM_SETPERM_FAILURE = 0x104,
404 ERR_MEM_SETHINT_FAILURE = 0x106,
405
406 ERR_FILE_ALREADY_EXISTS = 0x110,
407 ERR_FILE_DOESNT_EXIST = 0x112,
408
409 ERR_NO_DISK_SPACE = 0x114,
410
411};
412
413#define S_OK(...) ( ((__VA_ARGS__) & S_MASK) != (Status)S_FAILURE ) /* != FAILURE, cause otherwise the expression will appear twice, which is a great footgun when it's stateful... we are having none of that here */
414#define S_NOK(...) ( ((__VA_ARGS__) & S_MASK) == (Status)S_FAILURE )
415
416#define S_SUCCESSFUL(...) ( ((__VA_ARGS__) & S_MASK) == (Status)S_SUCCESS )
417#define S_COMPLETED(...) ( ((__VA_ARGS__) & S_MASK) == (Status)S_COMPLETION )
418#define S_FAILED(...) ( ((__VA_ARGS__) & S_MASK) == (Status)S_FAILURE )
419
420#define TRY(...) do { \
421 Status _res = (__VA_ARGS__); \
422 if( S_NOK(_res) ) { \
423 return _res; \
424 } \
425} while(0)
426
427/* Erroring function helpers */
428
429/* If the error is already set turn into a no-op.
430 * None of the parameters are usable in this case.
431 * All of them could be just garbage.
432 * */
433#define ERRORING_PROLOGUE( status_varname, ret_type ) \
434 if( S_NOK( *status_varname ) ) { \
435 return (ret_type){0}; \
436 }
437
438/* Destructors must always destroy non-zero values and
439 * never overwrite errors with success.
440 * Success can be overwritten by completion.
441 * Ignoring a zero reference is considered completion.
442 * */
443#define ERRORING_DESTRUCTOR_PROLOGUE( status_varname, destroyed_value ) \
444 if( destroyed_value == 0 ) { \
445 if( S_OK( *status_varname ) ) { \
446 *status_varname = S_COMPLETION; \
447 } \
448 return; \
449 }
450
451/* On failure a breakpoint must be raised in debug builds. */
452#define ERRORING_FAIL( value ) \
453 DEBUG(breakpoint();); \
454 *s = value; \
455
456#define ENCHAIN( status_expr, ... ) \
457 if( S_OK(status_expr) ) { \
458 __VA_ARGS__ \
459 }
460
461#define GEN_VALUE_BY_STATUS( T ) \
462 static inline T T##_by_status( Status *s, T v1, T v2 ) { \
463 return (S_OK(*s))? v1 : v2; \
464 }
465
466#define END_IF_NOK( status_value ) \
467 if( S_NOK( status_value ) ) { \
468 goto end; \
469 }
470
471GEN_VALUE_BY_STATUS( u8 )
472GEN_VALUE_BY_STATUS( u16 )
473GEN_VALUE_BY_STATUS( u32 )
474GEN_VALUE_BY_STATUS( u64 )
475GEN_VALUE_BY_STATUS( usize )
476GEN_VALUE_BY_STATUS( voidp )
477
478GEN_VALUE_BY_STATUS( s8 )
479GEN_VALUE_BY_STATUS( s16 )
480GEN_VALUE_BY_STATUS( s32 )
481GEN_VALUE_BY_STATUS( s64 )
482GEN_VALUE_BY_STATUS( ssize )
483
484
485/* Generic function types */
486
487typedef s8 (CmpFunc)(const void*, const void*);
488GEN_POINTER_TYPE( CmpFunc );
489
490typedef usize (SearchFunc)( Status *s, const void *restrict el, usize el_size, const void *restrict data, usize count, CmpFunc *cmp );
491/* Returns the index and S_SUCCESS if the element was found.
492 * Returns the index after which a given element would belong and S_COMPLETION if the element was not found */
493GEN_POINTER_TYPE( SearchFunc );
494
495typedef void (SortFunc)(Status *s, void *const data, usize count, usize el_size, CmpFunc *cmp);
496GEN_POINTER_TYPE( SortFunc );
497
498typedef void (FallbackingSortFunc)(Status *s, void *const data, usize count, usize el_size, CmpFunc *cmp, usize fallback_at_count, SortFunc* fallback_algo);
499GEN_POINTER_TYPE( FallbackingSortFunc );
500
501
502/******************************************************************************/
503/* MATH STUFF */
504/******************************************************************************/
505
506#define u8_MIN 0
507#define u16_MIN 0
508#define u32_MIN 0
509#define u64_MIN 0
510
511#define u8_MAX ((u8)-1)
512#define u16_MAX ((u16)-1)
513#define u32_MAX ((u32)-1)
514#define u64_MAX ((u64)-1)
515
516/* We assume 2's complement */
517ASSERT( (-1^1) == -2 );
518
519#define s8_MAX ((s8)( (u8)-1 >> 1))
520#define s16_MAX ((s16)((u16)-1 >> 1))
521#define s32_MAX ((s32)((u32)-1 >> 1))
522#define s64_MAX ((s64)((u64)-1 >> 1))
523
524#define s8_MIN (- s8_MAX - 1)
525#define s16_MIN (-s16_MAX - 1)
526#define s32_MIN (-s32_MAX - 1)
527#define s64_MIN (-s64_MAX - 1)
528
529
530/* Ensure limit sanity - at least for unsigned */
531ASSERT( u64_MAX == 0xffffffffffffffff );
532ASSERT( u32_MAX == 0xffffffff );
533ASSERT( u16_MAX == 0xffff );
534ASSERT( u8_MAX == 0xff );
535
536/* Addition */
537
538#define GEN_ADD_DECLARATION( T ) \
539 static inline T T##_add( Status *s, T n1, T n2 );
540
541GEN_ADD_DECLARATION( u8 )
542GEN_ADD_DECLARATION( u16 )
543GEN_ADD_DECLARATION( u32 )
544GEN_ADD_DECLARATION( u64 )
545
546GEN_ADD_DECLARATION( s8 )
547GEN_ADD_DECLARATION( s16 )
548GEN_ADD_DECLARATION( s32 )
549GEN_ADD_DECLARATION( s64 )
550
551static inline usize usize_add( Status *s, usize n1, usize n2 ) {
552 #if ARCH == ARCH_X86_64
553 return u64_add( s, n1, n2 );
554 #elif ARCH == ARCH_I386
555 return u32_add( s, n1, n2 );
556 #endif
557}
558
559static inline ssize ssize_add( Status *s, ssize n1, ssize n2 ) {
560 #if ARCH == ARCH_X86_64
561 return u64_add( s, n1, n2 );
562 #elif ARCH == ARCH_I386
563 return u32_add( s, n1, n2 );
564 #endif
565}
566
567#if COMPILER == COMPILER_GCC || COMPILER == COMPILER_CLANG
568 #define GEN_UADD_DEFINITION( T ) \
569 static inline T T##_add( Status *s, T n1, T n2 ) { \
570 ERRORING_PROLOGUE( s, T ); \
571 T out; \
572 if( __builtin_add_overflow( n1, n2, &out ) ) { \
573 *s = S_FAILURE | ERR_OVERFLOW; \
574 return 0; \
575 } \
576 *s = S_SUCCESS; \
577 return out; \
578 }
579
580 #define GEN_SADD_DEFINITION( T ) GEN_UADD_DEFINITION( T )
581
582 #define GEN_USUB_DEFINITION( T ) \
583 static inline T T##_sub( Status *s, T n1, T n2 ) { \
584 ERRORING_PROLOGUE( s, T ); \
585 T out; \
586 if( __builtin_sub_overflow( n1, n2, &out ) ) { \
587 *s = S_FAILURE | ERR_OVERFLOW; \
588 return 0; \
589 } \
590 *s = S_SUCCESS; \
591 return out; \
592 }
593
594 #define GEN_SSUB_DEFINITION( T ) GEN_USUB_DEFINITION( T )
595
596 #define GEN_UMUL_DEFINITION( T ) \
597 static inline T T##_mul( Status *s, T n1, T n2 ) { \
598 ERRORING_PROLOGUE( s, T ); \
599 T out; \
600 if( __builtin_mul_overflow( n1, n2, &out ) ) { \
601 *s = S_FAILURE | ERR_OVERFLOW; \
602 return 0; \
603 } \
604 *s = S_SUCCESS; \
605 return out; \
606 }
607
608 #define GEN_SMUL_DEFINITION( T ) GEN_UMUL_DEFINITION( T )
609
610#else
611
612 #define GEN_UADD_DEFINITION( T ) \
613 static inline T T##_add( Status *s, T n1, T n2 ) { \
614 ERRORING_PROLOGUE( s, T ); \
615 if( n1 > (T##_MAX) - n2 ) { \
616 *s = S_FAILURE | ERR_OVERFLOW; \
617 return 0; \
618 } \
619 *s = S_SUCCESS; \
620 return n1 + n2; \
621 }
622
623 #define GEN_USUB_DEFINITION( T ) \
624 static inline T T##_sub( Status *s, T n1, T n2 ) { \
625 ERRORING_PROLOGUE( s, T ); \
626 if( n2 > n1 ) { \
627 *s = S_FAILURE | ERR_OVERFLOW; \
628 return 0; \
629 } \
630 *s = S_SUCCESS; \
631 return n1 - n2; \
632 }
633
634 #define GEN_SADD_DEFINITION( T ) \
635 static inline T T##_add( Status *s, T n1, T n2 ) { \
636 ERRORING_PROLOGUE( s, T ); \
637 if( (n1 >= 0 && n2 > T##_MAX - n1) || (n1 < 0 && n2 < T##_MIN - n1) ) { \
638 *s = S_FAILURE | ERR_OVERFLOW; \
639 return 0; \
640 } \
641 return n1 + n2; \
642 }
643
644 #define GEN_SSUB_DEFINITION( T ) \
645 static inline T T##_sub( Status *s, T n1, T n2 ) { \
646 if( (n2 > 0 && n1 < T##_MIN + n2) || (n2 < 0 && n1 > T##_MAX + n2) ) { \
647 *s = S_FAILURE | ERR_OVERFLOW; \
648 return 0; \
649 } \
650 return n1 - n2; \
651 }
652
653 #define GEN_UMUL_DEFINITION( T ) \
654 static inline T T##_mul( Status *s, T n1, T n2 ) { \
655 if( n1 && n2 > (T##_MAX/n1) ) { \
656 *s = S_FAILURE | ERR_OVERFLOW; \
657 return 0; \
658 } \
659 *s = S_SUCCESS; \
660 return n1*n2; \
661 }
662
663 #define GEN_SMUL_DEFINITION( T ) \
664 static inline T T##_mul( Status *s, T n1, T n2 ) { \
665 ERRORING_PROLOGUE( s, T ); \
666 if( \
667 ( n2 > 0 && n1 >= T##_MIN/n2 && n1 <= T##_MAX/n2 ) || \
668 ( n2 == 0 ) || \
669 ( n2 == -1 && n1 >= -T##_MAX ) || \
670 ( n2 < -1 && n1 >= T##_MAX/n2 && n1 <= T##_MIN/n2 ) \
671 ) { \
672 return n1*n2; \
673 *s = S_SUCCESS; \
674 } \
675 *s = S_FAILURE | ERR_OVERFLOW; \
676 return 0; \
677 }
678#endif
679
680
681/* Subtraction */
682
683#define GEN_SUB_DECLARATION( T ) \
684 static inline T T##_sub( Status *s, T n1, T n2 );
685
686GEN_SUB_DECLARATION( u8 )
687GEN_SUB_DECLARATION( u16 )
688GEN_SUB_DECLARATION( u32 )
689GEN_SUB_DECLARATION( u64 )
690
691GEN_SUB_DECLARATION( s8 )
692GEN_SUB_DECLARATION( s16 )
693GEN_SUB_DECLARATION( s32 )
694GEN_SUB_DECLARATION( s64 )
695
696static inline usize usize_sub( Status *s, usize n1, usize n2 ) {
697 #if ARCH == ARCH_X86_64
698 return u64_sub( s, n1, n2 );
699 #elif ARCH == ARCH_I386
700 return u32_sub( s, n1, n2 );
701 #endif
702}
703
704static inline ssize ssize_sub( Status *s, ssize n1, ssize n2 ) {
705 #if ARCH == ARCH_X86_64
706 return u64_sub( s, n1, n2 );
707 #elif ARCH == ARCH_I386
708 return u32_sub( s, n1, n2 );
709 #endif
710}
711
712
713/* Multiplication */
714
715#define GEN_MUL_DECLARATION( T ) \
716 static inline T T##_mul( Status *s, T n1, T n2 );
717
718GEN_MUL_DECLARATION( u8 )
719GEN_MUL_DECLARATION( u16 )
720GEN_MUL_DECLARATION( u32 )
721GEN_MUL_DECLARATION( u64 )
722
723GEN_MUL_DECLARATION( s8 )
724GEN_MUL_DECLARATION( s16 )
725GEN_MUL_DECLARATION( s32 )
726GEN_MUL_DECLARATION( s64 )
727
728static inline usize usize_mul( Status *s, usize n1, usize n2 ) {
729 #if ARCH == ARCH_X86_64
730 return u64_mul( s, n1, n2 );
731 #elif ARCH == ARCH_I386
732 return u32_mul( s, n1, n2 );
733 #endif
734}
735
736static inline ssize ssize_mul( Status *s, ssize n1, ssize n2 ) {
737 #if ARCH == ARCH_X86_64
738 return u64_mul( s, n1, n2 );
739 #elif ARCH == ARCH_I386
740 return u32_mul( s, n1, n2 );
741 #endif
742}
743
744
745/* Maximum */
746
747#define GEN_MAX_DEFINITION( T ) \
748 static inline T T##_max( T n1, T n2 ) { \
749 return (n1 >= n2)? n1 : n2; \
750 }
751
752GEN_MAX_DEFINITION( u8 )
753GEN_MAX_DEFINITION( u16 )
754GEN_MAX_DEFINITION( u32 )
755GEN_MAX_DEFINITION( u64 )
756GEN_MAX_DEFINITION( usize )
757
758GEN_MAX_DEFINITION( s8 )
759GEN_MAX_DEFINITION( s16 )
760GEN_MAX_DEFINITION( s32 )
761GEN_MAX_DEFINITION( s64 )
762GEN_MAX_DEFINITION( ssize )
763
764
765/* Minimum */
766
767#define GEN_MIN_DEFINITION( T ) \
768 static inline T T##_min( T n1, T n2 ) { \
769 return (n2 >= n1)? n1 : n2; \
770 }
771
772GEN_MIN_DEFINITION( u8 )
773GEN_MIN_DEFINITION( u16 )
774GEN_MIN_DEFINITION( u32 )
775GEN_MIN_DEFINITION( u64 )
776GEN_MIN_DEFINITION( usize )
777
778GEN_MIN_DEFINITION( s8 )
779GEN_MIN_DEFINITION( s16 )
780GEN_MIN_DEFINITION( s32 )
781GEN_MIN_DEFINITION( s64 )
782GEN_MIN_DEFINITION( ssize )
783
784
785/* Round Down */
786
787#define GEN_UROUND_DOWN_DECLARATION( T ) \
788 static inline T T##_round_down( Status *s, T number, T multiple );
789
790#define GEN_UROUND_DOWN_DEFINITION( T ) \
791 static inline T T##_round_down( Status *s, T number, T multiple ) { \
792 ERRORING_PROLOGUE( s, T ); \
793 if( multiple == 0 ) { \
794 ERRORING_FAIL( S_FAILURE | ERRSRC_ARG_2 | ERR_INVALID_ARGUMENT ); \
795 return (T){0}; \
796 }; \
797 *s = S_SUCCESS; \
798 return number - (number%multiple); \
799 }
800
801GEN_UROUND_DOWN_DECLARATION( u8 )
802GEN_UROUND_DOWN_DECLARATION( u16 )
803GEN_UROUND_DOWN_DECLARATION( u32 )
804GEN_UROUND_DOWN_DECLARATION( u64 )
805GEN_UROUND_DOWN_DECLARATION( usize )
806
807
808/* Round Up */
809
810#define GEN_UROUND_UP_DECLARATION( T ) \
811 static inline T T##_round_up( Status *s, T number, T multiple );
812
813#define GEN_UROUND_UP_DEFINITION( T ) \
814 static inline T T##_round_up( Status *s, T number, T multiple ) { \
815 if( multiple == 0 ) { \
816 ERRORING_FAIL( S_FAILURE | ERRSRC_ARG_2 | ERR_INVALID_ARGUMENT ); \
817 return 0; \
818 } \
819 T rem = number%multiple; \
820 if( rem == 0 ) { \
821 *s = S_SUCCESS; \
822 return number; \
823 } else { \
824 return T##_add( s, number, multiple - rem ); \
825 } \
826 }
827
828GEN_UROUND_UP_DECLARATION( u8 )
829GEN_UROUND_UP_DECLARATION( u16 )
830GEN_UROUND_UP_DECLARATION( u32 )
831GEN_UROUND_UP_DECLARATION( u64 )
832GEN_UROUND_UP_DECLARATION( usize )
833
834/* Is Power Of Two */
835
836#define GEN_IS_POWER_OF_TWO( T ) \
837static inline u8 T##_is_power_of_two( T num ) { \
838 return num && !(num & (num - 1)); \
839}
840
841GEN_IS_POWER_OF_TWO(u8)
842GEN_IS_POWER_OF_TWO(u16)
843GEN_IS_POWER_OF_TWO(u32)
844GEN_IS_POWER_OF_TWO(u64)
845GEN_IS_POWER_OF_TWO(usize)
846
847
848/* Arena */
849
850STRUCT( Arena,
851 Page *start; /* The address where the arena starts */
852 usize claimed; /* Total size of the arena */
853 usize occupied; /* The actually occupied (backed) range */
854 usize taken; /* The top of the arena */
855);
856
857Arena Arena_create( Status *s, usize size );
858void Arena_destroy( Status *s, Arena *a );
859
860void* Arena_take( Status *s, Arena *a, usize amount );
861void Arena_give( Status *s, Arena *a, usize amount );
862void Arena_align( Status *s, Arena *a, usize alignment );
863
864/* Heap */
865
866#if BUILD_TYPE == BUILD_RELEASE
867 STRUCT( HeapEntry,
868 usize size; /* The next pointer is stored in the data when the block
869 is added to the freelist */
870 );
871
872 STRUCT( Heap,
873 Arena arena; /* Heap is built on top of arena. It's just an arena +
874 a freelist with metadata */
875 HeapEntry freelist;
876 HeapEntry *freelist_data;
877 );
878
879#elif BUILD_TYPE == BUILD_DEBUG
880 STRUCT( HeapEntry,
881 u64 header_start_guard;
882 usize allowed_size;
883 struct _HeapEntry *next; /* unlike in release, in debug we have
884 a separate next pointer for linking into the freelist */
885 u64 checksum; /* size xor'd with next, allowed size and the
886 guard magic number - (likely) detects overwriting of metadata */
887 usize size;
888 u64 header_end_guard;
889 );
890
891 STRUCT( Heap,
892 Arena arena; /* Heap is built on top of arena. It's just an arena +
893 a freelist with metadata */
894 HeapEntry freelist;
895 HeapEntry blocklist; /* The existing blocks in a list */
896 );
897#endif
898ASSERT( sizeof(HeapEntry)%sizeof(usize) == 0 );
899
900Heap Heap_create( Status *s, usize size ); /* size - size of underlying arena.
901 The heap will hold less, due to bookkeeping overhead for allocations. */
902void Heap_destroy( Status *s, Heap *h );
903
904void* Heap_alloc( Status *s, Heap *h, usize amount );
905void Heap_free( Status *s, Heap *h, void *ptr );
906
907usize Heap_get_asize( Heap *h, const void *ptr );
908
909/* Arrays */
910
911#define ARR_FOREACH( T, varname, arr) \
912 for( T *varname = &arr->data[0]; varname < &arr->data[arr->a.len]; varname += 1 )
913
914STRUCT( AnyArr,
915 usize len;
916 DEBUG(
917 Heap *heap;
918 usize checksum;
919 u32
920 sorted : 1;
921 CmpFunc *sortfunc;
922 )
923);
924
925AnyArr* AnyArr_create( Status *s, usize count, Heap *h, usize elem_size );
926void AnyArr_destroy( Status *s, AnyArr** arr, Heap *h );
927
928AnyArr* AnyArr_inflate( Status *s, AnyArr *arr, usize additional_count, Heap *h, usize elem_size );
929AnyArr* AnyArr_deflate( Status *s, AnyArr *arr, Heap *h, usize elem_size ); /* reallocate to just fit the currently contained elements - we assume it's on the same heap */
930
931void AnyArr_truncate( Status *s, AnyArr *arr, usize cutlen, usize elem_size );
932
933
934AnyArr* AnyArr_push( Status *s, AnyArr *restrict arr, void *restrict el, Heap *h, usize elem_size );
935void AnyArr_pop( Status *s, AnyArr *restrict arr, void *restrict el_out, usize elem_size );
936
937AnyArr* AnyArr_insert_at( Status *s, AnyArr *arr, usize index, const void *element, Heap *h, usize elem_size);
938
939AnyArr* AnyArr_dup( Status *s, const AnyArr *arr, Heap *h, usize elem_size );
940
941void AnyArr_sort( Status *s, AnyArr *arr, CmpFunc *cmp, usize elem_size );
942AnyArr* AnyArr_insert_sorted( Status *s, AnyArr *arr, const void *elem, CmpFunc *cmp, Heap *h, usize elem_size );
943
944DEBUG(
945 void _AnyArr_update_checksum( AnyArr *arr );
946 void _AnyArr_validate( const AnyArr *arr );
947)
948
949#define GEN_ARRAY_TYPE( T ) \
950 STRUCT( T##s, \
951 usize len; \
952 DEBUG( \
953 Heap *heap; \
954 usize checksum; \
955 u32 \
956 sorted : 1; \
957 CmpFunc *sortfunc; \
958 ) \
959 T data[]; \
960 ); \
961 ASSERT( sizeof(T##s)%sizeof(usize) == 0 ); \
962 ASSERT( sizeof(T##s) == sizeof(AnyArr) ); \
963 \
964static inline T##s* T##s_create( Status *s, Heap *h, usize count ) { \
965 return (T##s*)AnyArr_create( s, count, h, sizeof(T) ); \
966} \
967 \
968static inline void T##s_destroy( Status *s, T##s **arr, Heap *h ) { \
969 AnyArr_destroy( s, (AnyArr**)arr, h ); \
970} \
971 \
972static inline T##s* T##s_push( Status *s, T##s *arr, T* el, Heap *h ) { \
973 return (T##s*)AnyArr_push( s, (AnyArr*)arr, el, h, sizeof(T) ); \
974} \
975 \
976static inline void T##s_pop( Status *s, T##s *arr, T* el ) { \
977 AnyArr_pop( s, (AnyArr*)arr, el, sizeof(T) ); \
978} \
979 \
980static inline void T##s_truncate( Status *s, T##s *arr, usize cutlen ) { \
981 AnyArr_truncate( s, (AnyArr*)arr, cutlen, sizeof(T) ); \
982} \
983 \
984static inline T##s* T##s_inflate( Status *s, T##s *arr, usize additional_count, Heap *h ) { \
985 return (T##s*)AnyArr_inflate( s, (AnyArr*)arr, additional_count, h, sizeof(T) ); \
986} \
987 \
988static inline T##s* T##s_deflate( Status *s, T##s *arr, Heap *h ) { \
989 return (T##s*)AnyArr_deflate( s, (AnyArr*)arr, h, sizeof(T) ); \
990} \
991 \
992static inline T##s* T##s_dup( Status *s, const T##s *arr, Heap *h ) { \
993 return (T##s*)AnyArr_dup( s, (AnyArr*)arr, h, sizeof(T) ); \
994} \
995 \
996static inline T##s* T##s_insert_at( Status *s, T##s *arr, usize index, T *element, Heap *h ) { \
997 return (T##s*)AnyArr_insert_at( s, (AnyArr*)arr, index, element, h, sizeof(T) ); \
998} \
999 \
1000static inline void T##s_sort( Status *s, T##s *arr, s8 (*cmp)(const T* el1, const T* el2) ) { \
1001 AnyArr_sort( s, (AnyArr*)arr, (CmpFunc *)cmp, sizeof(T) ); \
1002} \
1003 \
1004static inline T##s* T##s_insert_sorted( Status *s, T##s *arr, const T *elem, s8 (*cmp)(const T* el1, const T* el2), Heap *h ) { \
1005 return (T##s*)AnyArr_insert_sorted( s, (AnyArr*)arr, elem, (CmpFunc *)cmp, h, sizeof(T) ); \
1006} \
1007 \
1008
1009GEN_ARRAY_TYPE( u8 )
1010GEN_ARRAY_TYPE( u16 )
1011GEN_ARRAY_TYPE( u32 )
1012GEN_ARRAY_TYPE( u64 )
1013GEN_ARRAY_TYPE( usize )
1014
1015GEN_ARRAY_TYPE( s8 )
1016GEN_ARRAY_TYPE( s16 )
1017GEN_ARRAY_TYPE( s32 )
1018GEN_ARRAY_TYPE( s64 )
1019GEN_ARRAY_TYPE( ssize )
1020
1021GEN_ARRAY_TYPE( f32 )
1022GEN_ARRAY_TYPE( f64 )
1023
1024GEN_ARRAY_TYPE( u8p )
1025GEN_ARRAY_TYPE( u16p )
1026GEN_ARRAY_TYPE( u32p )
1027GEN_ARRAY_TYPE( u64p )
1028GEN_ARRAY_TYPE( usizep )
1029
1030GEN_ARRAY_TYPE( s8p )
1031GEN_ARRAY_TYPE( s16p )
1032GEN_ARRAY_TYPE( s32p )
1033GEN_ARRAY_TYPE( s64p )
1034GEN_ARRAY_TYPE( ssizep )
1035
1036GEN_ARRAY_TYPE( f32p )
1037GEN_ARRAY_TYPE( f64p )
1038
1039
1040
1041
1042/* String */
1043
1044STRUCT( Str,
1045 usize len;
1046 u8 data[];
1047);
1048
1049GEN_POINTER_TYPE( Str );
1050GEN_ARRAY_TYPE( Strp )
1051
1052STRUCT( StrSlc,
1053 usize len;
1054 const u8 *data;
1055);
1056
1057GEN_ARRAY_TYPE( StrSlc )
1058
1059/* On typical platforms that already have/need nul-termination we keep the
1060 * nul-termination alongside the explicit length notation.
1061 * Hacky, but no one wants to copy strings/paths for syscalls.
1062 * NOTE: on these platforms len MUST NOT include the NUL-terminator.
1063 * It is the indexable length of the string. */
1064#if PLATFORM == PLATFORM_LINUX || PLATFORM == PLATFORM_WINDOWS
1065
1066#define STRING( varname, string ) \
1067 struct { \
1068 u64 len; \
1069 u8 data[sizeof(string)]; \
1070 } varname = { .len = sizeof(string)-1, .data = string }
1071
1072#define STRING_SLICE( varname, stringname, start_index, len ) \
1073 StrSlc varname = { .len = len, .data = &stringname[start_index] };
1074
1075#define STRING_SLICE_LITERAL( varname, literal) \
1076 u8 varname_data[] = literal; \
1077 StrSlc varname = { .len = sizeof(literal) - 1, .data = &varname_data[0] };
1078#else
1079 #error Str not implemented for current platform.
1080
1081/* For bare metal, when we get there: */
1082
1083#define STATIC( varname, str ) \
1084 const struct { \
1085 u64 len; \
1086 u8 data[sizeof( str ) - 1] __attribute__((nonstring)); \
1087 } varname = { .len = sizeof(str) - 1, .data = str }
1088
1089#endif
1090
1091u8 Str_equals( const Str *s1, const Str *s2 );
1092
1093StrSlc StrSlc_from_Str( Status *s, const Str *str, usize start, usize len );
1094
1095u8 StrSlc_equals( const StrSlc sl1, const StrSlc sl2 );
1096u8 StrSlc_equals_by_ref( const StrSlc *sl1, const StrSlc *sl2 );
1097
1098u8 StrSlc_equals_Str( const StrSlc sl, const Str* s );
1099u8 StrSlc_equals_Str_by_ref( const StrSlc *sl, const Str *s );
1100
1101StrSlcs* StrSlc_split_by_u8( Status *s, const StrSlc *sl, u8 separator, Heap *h );
1102
1103/* String assembler */
1104STRUCT( StrAsm,
1105 Arena a;
1106);
1107
1108StrAsm StrAsm_create( Status *s, usize max_size );
1109void StrAsm_reset( Status *s, StrAsm *sa );
1110void StrAsm_destroy( Status *s, StrAsm *sa );
1111
1112void StrAsm_store_into_arena( Status *s, StrAsm *sa, Arena *dst, Str **out );
1113void StrAsm_store_onto_heap( Status *s, StrAsm *sa, Heap *dst, Str **out );
1114StrSlc StrAsm_as_StrSlc( const StrAsm *sa );
1115
1116/* String, character */
1117void StrAsm_cat_char ( Status *s, StrAsm *sa, u8 value );
1118void StrAsm_cat_Str( Status *s, StrAsm *sa, const Str *str );
1119void StrAsm_cat_StrSlc( Status *s, StrAsm *sa, StrSlc sl );
1120void StrAsm_cat_StrSlc_by_ref( Status *s, StrAsm *sa, const StrSlc *sl );
1121
1122extern u8 _halfbyte_to_hex_ascii[16];
1123
1124static inline void _bin_to_hex_ascii( u8 *data, u8 *out, usize count ) {
1125 #if ARCH == ARCH_X86_64 || ARCH == ARCH_I386
1126 for( u64 i = 0; i < count; ++i ) {
1127 u8 byte = data[count - i - 1];
1128
1129 out[2 * i] = _halfbyte_to_hex_ascii[( byte >> 4 ) & 0x0f];
1130 out[2 * i + 1] = _halfbyte_to_hex_ascii[byte & 0x0f];
1131 }
1132 #else
1133 #error Unimpleneted for big endian.
1134 #endif
1135}
1136
1137/* Hex */
1138void StrAsm_fmtx_u8 ( Status *s, StrAsm *sa, u8 value);
1139void StrAsm_fmtx_u16( Status *s, StrAsm *sa, u16 value);
1140void StrAsm_fmtx_u32( Status *s, StrAsm *sa, u32 value);
1141void StrAsm_fmtx_u64( Status *s, StrAsm *sa, u64 value);
1142
1143static inline void StrAsm_fmtx_usize( Status *s, StrAsm *sa, usize value) {
1144 #if ARCH == ARCH_X86_64
1145 StrAsm_fmtx_u64( s, sa, value );
1146 #elif ARCH == ARCH_I386
1147 StrAsm_fmtx_u32( s, sa, value );
1148 #else
1149 #error Unimplemented for current arch.
1150 #endif
1151}
1152
1153/* Decimal */
1154void StrAsm_fmtd_u8 ( Status *s, StrAsm *sa, u8 value);
1155void StrAsm_fmtd_u16( Status *s, StrAsm *sa, u16 value);
1156void StrAsm_fmtd_u32( Status *s, StrAsm *sa, u32 value);
1157void StrAsm_fmtd_u64( Status *s, StrAsm *sa, u64 value);
1158void StrAsm_fmtd_usize( Status *s, StrAsm *sa, usize value) {
1159 #if ARCH == ARCH_X86_64
1160 StrAsm_fmtd_u64( s, sa, value );
1161 #elif ARCH == ARCH_I386
1162 StrAsm_fmtd_u32( s, sa, value );
1163 #else
1164 #error Unimplemented for current arch.
1165 #endif
1166}
1167
1168void StrAsm_fmtd_s8 ( Status *s, StrAsm *sa, s8 value);
1169void StrAsm_fmtd_s16( Status *s, StrAsm *sa, s16 value);
1170void StrAsm_fmtd_s32( Status *s, StrAsm *sa, s32 value);
1171void StrAsm_fmtd_s64( Status *s, StrAsm *sa, s64 value);
1172void StrAsm_fmtd_ssize( Status *s, StrAsm *sa, ssize value) {
1173 #if ARCH == ARCH_X86_64
1174 StrAsm_fmtd_s64( s, sa, value );
1175 #elif ARCH == ARCH_I386
1176 StrAsm_fmtd_s32( s, sa, value );
1177 #else
1178 #error Unimplemented for current arch.
1179 #endif
1180}
1181
1182
1183/* File */
1184
1185#if OS == OS_LINUX
1186 STRUCT( File,
1187 s32 fd;
1188 );
1189#else
1190 #error File not defined.
1191#endif
1192
1193
1194enum FileOpenFlags {
1195
1196 FILE_ACCESS_READ = ((usize)1 << 1),
1197 FILE_ACCESS_WRITE = ((usize)1 << 2),
1198 FILE_ACCESS_APPEND = ((usize)1 << 3),
1199
1200 FILE_ACCESS_MASK =
1201 (FILE_ACCESS_READ | FILE_ACCESS_WRITE | FILE_ACCESS_APPEND),
1202
1203 FILE_EXISTING_OPEN = ((usize)1 << 4),
1204 FILE_EXISTING_TRUNCATE = ((usize)1 << 5),
1205 FILE_EXISTING_FAIL = ((usize)1 << 6),
1206
1207 FILE_EXISTING_MASK =
1208 (FILE_EXISTING_OPEN | FILE_EXISTING_TRUNCATE | FILE_EXISTING_FAIL),
1209
1210 FILE_MISSING_CREATE = ((usize)1 << 7),
1211 FILE_MISSING_FAIL = ((usize)1 << 8),
1212
1213 FILE_MISSING_MASK = (FILE_MISSING_CREATE | FILE_MISSING_FAIL),
1214
1215 FILE_LINK_FOLLOW = ((usize)1 << 9),
1216 FILE_LINK_FAIL = ((usize)1 << 10), /* os-dependent option -
1217 whatever the os guarantees. O_NOFOLLOW on linux. */
1218
1219 FILE_LINK_MASK = (FILE_LINK_FOLLOW | FILE_LINK_FAIL),
1220
1221};
1222
1223static inline void File_open_validate_flags( Status *s, usize flags, Status err_source );
1224
1225File File_open( Status *s, const Str *name, usize flags );
1226void File_close( Status *s, File *f );
1227
1228usize File_read( Status *s, const File *f, usize max_amount, u8 *out );
1229usize File_write( Status *s, const File *f, usize amount, const u8 *buf );
1230
1231void File_seek( Status *s, const File *f, usize position );
1232
1233void File_delete( Status *s, const Str *name );
1234
1235STRUCT( FileView,
1236 File file;
1237 Page *start;
1238 usize claimed;
1239 usize filesize;
1240 usize flags;
1241);
1242
1243enum FileViewFlags {
1244 FILEVIEW_OWN_FILE = (1 << 1),
1245/* FILEVIEW_PAGE_ALIGNED_EXTEND = (1 << 2), */
1246};
1247
1248FileView FileView_from_file( Status *s, File *file, usize claim_amount, usize flags );
1249/* if claim_amount == 0 => claims exact filesize */
1250
1251/* This is for quick and easy mmaping of files. If you actually want
1252 * control over the opening flags use FileView_from_file */
1253FileView FileView_from_path( Status *s, const Str *path, usize claim_amount, usize flags );
1254
1255StrSlc FileView_as_StrSlc( const FileView *fv );
1256
1257/* Extend the file's end by amount */
1258void FileView_extend_file( Status *s, FileView *fv, usize amount );
1259
1260void FileView_destroy( Status *s, FileView *fv );
1261
1262
1263/*=========================== Core functions =================================*/
1264
1265void terminate(u32 code); /* aka exit */
1266
1267/* force exit, fault, anything that terminates forcefully */
1268void terminate_forced(void);
1269
1270/* raise a debug breakpoint, if possible on the target */
1271void breakpoint(void);
1272
1273static inline void assert( usize condition ) {
1274 if( !condition ) {
1275 breakpoint();
1276 }
1277}
1278
1279/*=============================== Memory =====================================*/
1280#define KiB(n) ((u64)(n) << 10)
1281#define MiB(n) ((u64)(n) << 20)
1282#define GiB(n) ((u64)(n) << 30)
1283#define TiB(n) ((u64)(n) << 40)
1284
1285static inline void mem_copy( const void *restrict source, void *restrict destination, u64 len ) {
1286 const u8 *src = source;
1287 u8 *dst = destination;
1288 u64 i = 0;
1289
1290 for( ; i < len; ++i ) {
1291 dst[i] = src[i];
1292 }
1293}
1294
1295static inline void mem_move( const void *source, void *destination, u64 len ) {
1296 const u8 *src = source;
1297 u8 *dst = destination;
1298 u64 i;
1299
1300 if( src > dst ) {
1301 for( i = 0; i < len; ++i ) {
1302 dst[i] = src[i];
1303 }
1304 } else {
1305 for( i = len; i >= 1; --i ) {
1306 dst[i - 1] = src[i - 1];
1307 }
1308 }
1309}
1310
1311static inline void* mem_set( void *start, u64 len, u8 value ) {
1312 assert(start != 0);
1313 u8 *s = start;
1314 u64 i = 0;
1315
1316 for( ; i < len; ++i ) {
1317 s[i] = value;
1318 }
1319
1320 return &s[len];
1321}
1322
1323/* Request virtual memory range */
1324Page* mem_claim( Status *s, u32 page_count );
1325/* Free virtual memory range */
1326void mem_relinquish( Status *s, Page *start, u32 page_count );
1327
1328/* Set up physical backing */
1329void mem_occupy( Status *s, Page *start, u32 page_count );
1330/* Allow removal of physical backing */
1331void mem_vacate( Status *s, Page *start, u32 page_count );
1332
1333/* Bits and pieces */
1334static inline void swap( void *restrict el1, void *restrict el2, usize el_size );
1335
1336#define SWAP_STACK_BUFFER_SIZE 128
1337static inline void swap( void *restrict el1, void *restrict el2, usize el_size ) {
1338 register u64 tmp;
1339 switch( el_size ) {
1340 case sizeof(u8):
1341 tmp = *(u8*)el1;
1342 *(u8*)el1 = *(u8*)el2;
1343 *(u8*)el2 = (u8)tmp;
1344 break;
1345 case sizeof(u16):
1346 tmp = *(u16*)el1;
1347 *(u16*)el1 = *(u16*)el2;
1348 *(u16*)el2 = (u16)tmp;
1349 break;
1350 case sizeof(u32):
1351 tmp = *(u32*)el1;
1352 *(u32*)el1 = *(u32*)el2;
1353 *(u32*)el2 = (u32)tmp;
1354 break;
1355 case sizeof(u64):
1356 tmp = *(u64*)el1;
1357 *(u64*)el1 = *(u64*)el2;
1358 *(u64*)el2 = (u64)tmp;
1359 break;
1360
1361 default: {
1362 u8 local[SWAP_STACK_BUFFER_SIZE];
1363
1364 while( el_size >= SWAP_STACK_BUFFER_SIZE ) {
1365 u64 offset = el_size - SWAP_STACK_BUFFER_SIZE;
1366 mem_copy( (u8*)el1 + offset, local, SWAP_STACK_BUFFER_SIZE );
1367 mem_copy( (u8*)el2 + offset, (u8*)el1 + offset, SWAP_STACK_BUFFER_SIZE );
1368 mem_copy( local, (u8*)el2 + offset, SWAP_STACK_BUFFER_SIZE );
1369 el_size -= SWAP_STACK_BUFFER_SIZE;
1370 }
1371
1372 if( el_size ) {
1373 mem_copy( (u8*)el1, local, el_size );
1374 mem_copy( (u8*)el2, (u8*)el1, el_size );
1375 mem_copy( local, (u8*)el2, el_size );
1376 }
1377 }
1378 }
1379}
1380
1381/* Algorithms */
1382
1383SearchFunc algo_binary_search;
1384SortFunc algo_sort_generic;
1385SortFunc algo_insertionsort;
1386FallbackingSortFunc algo_quicksort;
1387
1388
1389/******************************************************************************/
1390/* COMMON PLATFORM IMPLEMENTATION */
1391/******************************************************************************/
1392
1393static inline void File_open_validate_flags( Status *s, usize flags, Status err_source ) {
1394 END_IF_NOK( *s );
1395
1396 usize existing_flags = flags & FILE_EXISTING_MASK;
1397 usize existing_flags_multiple_set = !usize_is_power_of_two( existing_flags );
1398
1399 usize missing_flags = flags & FILE_MISSING_MASK;
1400 usize missing_flags_multiple_set = !usize_is_power_of_two( missing_flags );
1401
1402 usize link_flags = flags & FILE_LINK_MASK;
1403 usize link_flags_multiple_set = !usize_is_power_of_two( link_flags );
1404
1405 usize write_append_flags = flags & (FILE_ACCESS_WRITE | FILE_ACCESS_APPEND);
1406 usize write_append_flags_multiple_set = !usize_is_power_of_two( write_append_flags );
1407
1408 if( existing_flags_multiple_set |
1409 missing_flags_multiple_set |
1410 link_flags_multiple_set |
1411 (write_append_flags && write_append_flags_multiple_set)
1412 ) {
1413 DEBUG(breakpoint());
1414 ERRORING_FAIL( S_FAILURE | ERR_INVALID_ARGUMENT | err_source );
1415 return;
1416 }
1417
1418end:
1419 return;
1420}
1421
1422/******************************************************************************/
1423/* MATH STUFF IMPLEMENTATION */
1424/******************************************************************************/
1425
1426GEN_UADD_DEFINITION( u8 )
1427GEN_UADD_DEFINITION( u16 )
1428GEN_UADD_DEFINITION( u32 )
1429GEN_UADD_DEFINITION( u64 )
1430
1431GEN_SADD_DEFINITION( s8 )
1432GEN_SADD_DEFINITION( s16 )
1433GEN_SADD_DEFINITION( s32 )
1434GEN_SADD_DEFINITION( s64 )
1435
1436GEN_USUB_DEFINITION( u8 )
1437GEN_USUB_DEFINITION( u16 )
1438GEN_USUB_DEFINITION( u32 )
1439GEN_USUB_DEFINITION( u64 )
1440
1441GEN_SSUB_DEFINITION( s8 )
1442GEN_SSUB_DEFINITION( s16 )
1443GEN_SSUB_DEFINITION( s32 )
1444GEN_SSUB_DEFINITION( s64 )
1445
1446GEN_UMUL_DEFINITION( u8 )
1447GEN_UMUL_DEFINITION( u16 )
1448GEN_UMUL_DEFINITION( u32 )
1449GEN_UMUL_DEFINITION( u64 )
1450
1451GEN_SMUL_DEFINITION( s8 )
1452GEN_SMUL_DEFINITION( s16 )
1453GEN_SMUL_DEFINITION( s32 )
1454GEN_SMUL_DEFINITION( s64 )
1455
1456GEN_UROUND_DOWN_DEFINITION( u8 )
1457GEN_UROUND_DOWN_DEFINITION( u16 )
1458GEN_UROUND_DOWN_DEFINITION( u32 )
1459GEN_UROUND_DOWN_DEFINITION( u64 )
1460GEN_UROUND_DOWN_DEFINITION( usize )
1461
1462GEN_UROUND_UP_DEFINITION( u8 )
1463GEN_UROUND_UP_DEFINITION( u16 )
1464GEN_UROUND_UP_DEFINITION( u32 )
1465GEN_UROUND_UP_DEFINITION( u64 )
1466GEN_UROUND_UP_DEFINITION( usize )
1467
1468
1469#if OS == OS_LINUX
1470/******************************************************************************/
1471/* LINUX PLATFORM IMPLEMENTATION */
1472/******************************************************************************/
1473
1474
1475/*============================= Entrypoint ===================================*/
1476
1477extern u8* _linux_startup_sp;
1478extern void entry(void);
1479
1480#ifndef NOTLIBC_NOMAIN
1481 extern Heap _linux_heap;
1482 extern Status c_main( StrSlcs *args, StrSlcs *env );
1483#endif
1484
1485/*============================ Linux defines =================================*/
1486
1487#define LINUX_SYSCALL_ERROR_RANGE_START ((usize)-4095)
1488#define LINUX_SYSCALL_ERROR(value) ((usize)value >= LINUX_SYSCALL_ERROR_RANGE_START)
1489
1490#define EPERM 1 /* Operation not permitted */
1491#define ENOENT 2 /* No such file or directory */
1492#define ESRCH 3 /* No such process */
1493#define EINTR 4 /* Interrupted system call */
1494#define EIO 5 /* I/O error */
1495#define ENXIO 6 /* No such device or address */
1496#define E2BIG 7 /* Argument list too long */
1497#define ENOEXEC 8 /* Exec format error */
1498#define EBADF 9 /* Bad file number */
1499#define ECHILD 10 /* No child processes */
1500#define EAGAIN 11 /* Try again */
1501#define ENOMEM 12 /* Out of memory */
1502#define EACCES 13 /* Permission denied */
1503#define EFAULT 14 /* Bad address */
1504#define ENOTBLK 15 /* Block device required */
1505#define EBUSY 16 /* Device or resource busy */
1506#define EEXIST 17 /* File exists */
1507#define EXDEV 18 /* Cross-device link */
1508#define ENODEV 19 /* No such device */
1509#define ENOTDIR 20 /* Not a directory */
1510#define EISDIR 21 /* Is a directory */
1511#define EINVAL 22 /* Invalid argument */
1512#define ENFILE 23 /* File table overflow */
1513#define EMFILE 24 /* Too many open files */
1514#define ENOTTY 25 /* Not a typewriter */
1515#define ETXTBSY 26 /* Text file busy */
1516#define EFBIG 27 /* File too large */
1517#define ENOSPC 28 /* No space left on device */
1518#define ESPIPE 29 /* Illegal seek */
1519#define EROFS 30 /* Read-only file system */
1520#define EMLINK 31 /* Too many links */
1521#define EPIPE 32 /* Broken pipe */
1522#define EDOM 33 /* Math argument out of domain of func */
1523#define ERANGE 34 /* Math result not representable */
1524#define EDEADLK 35 /* Resource deadlock would occur */
1525#define ENAMETOOLONG 36 /* File name too long */
1526#define ENOLCK 37 /* No record locks available */
1527#define ENOSYS 38 /* Invalid system call number */
1528#define ENOTEMPTY 39 /* Directory not empty */
1529#define ELOOP 40 /* Too many symbolic links encountered */
1530#define EWOULDBLOCK EAGAIN /* Operation would block */
1531#define ENOMSG 42 /* No message of desired type */
1532#define EIDRM 43 /* Identifier removed */
1533#define ECHRNG 44 /* Channel number out of range */
1534#define EL2NSYNC 45 /* Level 2 not synchronized */
1535#define EL3HLT 46 /* Level 3 halted */
1536#define EL3RST 47 /* Level 3 reset */
1537#define ELNRNG 48 /* Link number out of range */
1538#define EUNATCH 49 /* Protocol driver not attached */
1539#define ENOCSI 50 /* No CSI structure available */
1540#define EL2HLT 51 /* Level 2 halted */
1541#define EBADE 52 /* Invalid exchange */
1542#define EBADR 53 /* Invalid request descriptor */
1543#define EXFULL 54 /* Exchange full */
1544#define ENOANO 55 /* No anode */
1545#define EBADRQC 56 /* Invalid request code */
1546#define EBADSLT 57 /* Invalid slot */
1547#define EDEADLOCK EDEADLK
1548#define EBFONT 59 /* Bad font file format */
1549#define ENOSTR 60 /* Device not a stream */
1550#define ENODATA 61 /* No data available */
1551#define ETIME 62 /* Timer expired */
1552#define ENOSR 63 /* Out of streams resources */
1553#define ENONET 64 /* Machine is not on the network */
1554#define ENOPKG 65 /* Package not installed */
1555#define EREMOTE 66 /* Object is remote */
1556#define ENOLINK 67 /* Link has been severed */
1557#define EADV 68 /* Advertise error */
1558#define ESRMNT 69 /* Srmount error */
1559#define ECOMM 70 /* Communication error on send */
1560#define EPROTO 71 /* Protocol error */
1561#define EMULTIHOP 72 /* Multihop attempted */
1562#define EDOTDOT 73 /* RFS specific error */
1563#define EBADMSG 74 /* Not a data message */
1564#define EFSBADCRC EBADMSG /* Bad CRC detected */
1565#define EOVERFLOW 75 /* Value too large for defined data type */
1566#define ENOTUNIQ 76 /* Name not unique on network */
1567#define EBADFD 77 /* File descriptor in bad state */
1568#define EREMCHG 78 /* Remote address changed */
1569#define ELIBACC 79 /* Can not access a needed shared library */
1570#define ELIBBAD 80 /* Accessing a corrupted shared library */
1571#define ELIBSCN 81 /* .lib section in a.out corrupted */
1572#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
1573#define ELIBEXEC 83 /* Cannot exec a shared library directly */
1574#define EILSEQ 84 /* Illegal byte sequence */
1575#define ERESTART 85 /* Interrupted system call should be restarted */
1576#define ESTRPIPE 86 /* Streams pipe error */
1577#define EUSERS 87 /* Too many users */
1578#define ENOTSOCK 88 /* Socket operation on non-socket */
1579#define EDESTADDRREQ 89 /* Destination address required */
1580#define EMSGSIZE 90 /* Message too long */
1581#define EPROTOTYPE 91 /* Protocol wrong type for socket */
1582#define ENOPROTOOPT 92 /* Protocol not available */
1583#define EPROTONOSUPPORT 93 /* Protocol not supported */
1584#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
1585#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
1586#define EPFNOSUPPORT 96 /* Protocol family not supported */
1587#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
1588#define EADDRINUSE 98 /* Address already in use */
1589#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
1590#define ENETDOWN 100 /* Network is down */
1591#define ENETUNREACH 101 /* Network is unreachable */
1592#define ENETRESET 102 /* Network dropped connection because of reset */
1593#define ECONNABORTED 103 /* Software caused connection abort */
1594#define ECONNRESET 104 /* Connection reset by peer */
1595#define ENOBUFS 105 /* No buffer space available */
1596#define EISCONN 106 /* Transport endpoint is already connected */
1597#define ENOTCONN 107 /* Transport endpoint is not connected */
1598#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
1599#define ETOOMANYREFS 109 /* Too many references: cannot splice */
1600#define ETIMEDOUT 110 /* Connection timed out */
1601#define ECONNREFUSED 111 /* Connection refused */
1602#define EHOSTDOWN 112 /* Host is down */
1603#define EHOSTUNREACH 113 /* No route to host */
1604#define EALREADY 114 /* Operation already in progress */
1605#define EINPROGRESS 115 /* Operation now in progress */
1606#define ESTALE 116 /* Stale file handle */
1607#define EUCLEAN 117 /* Structure needs cleaning */
1608#define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */
1609#define ENOTNAM 118 /* Not a XENIX named type file */
1610#define ENAVAIL 119 /* No XENIX semaphores available */
1611#define EISNAM 120 /* Is a named type file */
1612#define EREMOTEIO 121 /* Remote I/O error */
1613#define EDQUOT 122 /* Quota exceeded */
1614#define ENOMEDIUM 123 /* No medium found */
1615#define EMEDIUMTYPE 124 /* Wrong medium type */
1616#define ECANCELED 125 /* Operation Canceled */
1617#define ENOKEY 126 /* Required key not available */
1618#define EKEYEXPIRED 127 /* Key has expired */
1619#define EKEYREVOKED 128 /* Key has been revoked */
1620#define EKEYREJECTED 129 /* Key was rejected by service */
1621#define EOWNERDEAD 130 /* Owner died */
1622#define ENOTRECOVERABLE 131 /* State not recoverable */
1623#define ERFKILL 132 /* Operation not possible due to RF-kill */
1624#define EHWPOISON 133 /* Memory page has hardware error */
1625
1626/* Copied from some header included by linux/fcntl */
1627#define O_RDONLY 00
1628#define O_WRONLY 01
1629#define O_RDWR 02
1630#define O_ACCMODE 03
1631#define O_CREAT 0100
1632#define O_EXCL 0200
1633#define O_NOCTTY 0400
1634#define O_TRUNC 01000
1635#define O_APPEND 02000
1636#define O_NONBLOCK 04000
1637#define O_DSYNC 010000
1638#define FASYNC 020000
1639#define O_DIRECT 040000
1640#define O_LARGEFILE 0100000
1641#define O_DIRECTORY 0200000
1642#define O_NOFOLLOW 0400000
1643#define O_NOATIME 01000000
1644#define O_CLOEXEC 02000000
1645#define __O_SYNC 04000000
1646#define O_SYNC (__O_SYNC|O_DSYNC)
1647#define O_PATH 010000000
1648#define __O_TMPFILE 020000000
1649#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
1650
1651#define SEEK_SET 0
1652#define SEEK_CUR 1
1653#define SEEK_END 2
1654
1655#if ARCH == ARCH_X86_64
1656struct stat {
1657 u64 st_dev;
1658 u64 st_ino;
1659 u64 st_nlink;
1660
1661 u32 st_mode;
1662 u32 st_uid;
1663 u32 st_gid;
1664 u32 __pad0;
1665
1666 u64 st_rdev;
1667
1668 s64 st_size;
1669 s64 st_blksize;
1670 s64 st_blocks;
1671
1672 u64 st_atime;
1673 u64 st_atime_nsec;
1674 u64 st_mtime;
1675 u64 st_mtime_nsec;
1676 u64 st_ctime;
1677 u64 st_ctime_nsec;
1678
1679 s64 __unused[3];
1680};
1681
1682#else
1683 #error struct stat is not defined
1684#endif
1685
1686#define LINUX_PROT_NONE (0x0)
1687#define LINUX_PROT_READ (0x1)
1688#define LINUX_PROT_WRITE (0x2)
1689#define LINUX_PROT_EXEC (0x4)
1690
1691#define MMAP_MAP_SHARED (0x1)
1692#define MMAP_MAP_PRIVATE (0x2)
1693#define MMAP_MAP_SHARED_VALIDATE (0x3)
1694#define MMAP_MAP_SHARED_DROPPABLE (0x08)
1695#define MMAP_MAP_FIXED (0x10)
1696#define MMAP_MAP_ANONYMOUS (0x20)
1697
1698#define MMAP_MAP_FAILED ((void *)-1)
1699
1700#define MADV_NORMAL 0
1701#define MADV_RANDOM 1
1702#define MADV_SEQUENTIAL 2
1703#define MADV_WILLNEED 3
1704#define MADV_DONTNEED 4
1705#define MADV_FREE 8
1706#define MADV_REMOVE 9
1707#define MADV_DONTFORK 10
1708#define MADV_DOFORK 11
1709#define MADV_MERGEABLE 12
1710#define MADV_UNMERGEABLE 13
1711#define MADV_HUGEPAGE 14
1712#define MADV_NOHUGEPAGE 15
1713#define MADV_DONTDUMP 16
1714#define MADV_DODUMP 17
1715#define MADV_WIPEONFORK 18
1716#define MADV_KEEPONFORK 19
1717#define MADV_COLD 20
1718#define MADV_PAGEOUT 21
1719#define MADV_POPULATE_READ 22
1720#define MADV_POPULATE_WRITE 23
1721#define MADV_DONTNEED_LOCKED 24
1722#define MADV_COLLAPSE 25
1723#define MADV_HWPOISON 100
1724#define MADV_GUARD_INSTALL 102
1725#define MADV_GUARD_REMOVE 103
1726
1727
1728/*============================ System calls ==================================*/
1729
1730/* System call assembly wrappers */
1731ssize linux_syscall1(usize num, usize arg1);
1732ssize linux_syscall2(usize num, usize arg1, usize arg2);
1733ssize linux_syscall3(usize num, usize arg1, usize arg2, usize arg3);
1734ssize linux_syscall4(usize num, usize arg1, usize arg2, usize arg3, usize arg4);
1735ssize linux_syscall5(usize num, usize arg1, usize arg2, usize arg3, usize arg4, usize arg5);
1736ssize linux_syscall6(usize num, usize arg1, usize arg2, usize arg3, usize arg4, usize arg5, usize arg6);
1737
1738/* Actual system calls */
1739Status linux_read( u32 fd, usize max_amount, usize *out_amount, u8 *out );
1740Status linux_write( u32 fd, usize amount, usize *out_amount, const u8 *buf );
1741Status linux_open( const u8* path, s32 flags, s32 mode, s32 *out_fd );
1742Status linux_close( s32 *fd );
1743Status linux_lseek( u32 fd, usize offset, usize whence );
1744ssize linux_stat( const char* path, struct stat *statbuf );
1745Status linux_fstat( s32 fd, struct stat *statbuf );
1746void linux_exit( s32 exitcode );
1747Status linux_mmap( usize addr, usize len, usize prot, usize flags, usize fd, usize offset, void **out );
1748Status linux_munmap( usize start, usize len );
1749Status linux_mprotect( usize start, usize len, usize prot );
1750Status linux_madvise( usize start, usize len, s32 behaviour );
1751ssize linux_unlink( const u8 *path );
1752Status linux_fallocate( s32 fd, s32 mode, usize offset, usize len );
1753
1754#endif
1755
1756#endif
1757