Commit 6f9ca10
Changed files (12)
platform
testing
platform/common/compiler.h
@@ -139,7 +139,7 @@ typedef struct _##name { \
#if COMPILER == COMPILER_GCC || COMPILER == COMPILER_CLANG
#define UNREACHABLE __builtin_unreachable()
-#elif COMPILER == MSVC
+#elif COMPILER == COPMILER_MSVC
#define UNREACHABLE __assume(0)
#endif
platform/common/corefunc.h
@@ -0,0 +1,15 @@
+#ifndef NOTLIBC_HEADER_PLATFORM_COREFUNC_INCLUDED
+#define NOTLIBC_HEADER_PLATFORM_COREFUNC_INCLUDED
+
+static inline void terminate(u32 code); /* aka exit */
+static inline void terminate_forced(void); /* force exit, fault, anything that terminates forcefully */
+
+static inline void breakpoint(void); /* raise a debug breakpoint, if possible on the target */
+
+static inline void assert( usize condition ) {
+ if( !condition ) {
+ breakpoint();
+ }
+}
+
+#endif
platform/common/error.h
@@ -0,0 +1,63 @@
+#ifndef NOTLIBC_HEADER_PLATFORM_ERROR_INCLUDED
+#define NOTLIBC_HEADER_PLATFORM_ERROR_INCLUDED
+
+typedef u32 Status;
+
+#define S_MASK (3 << 30)
+
+#define S_SUCCESS (1 << 30) /* Requested action performed. */
+#define S_COMPLETION (0 << 30) /* Action didn't need to be performed - desired state is already present/active. */
+#define S_FAILURE (2 << 30) /* Action failed. */
+
+#define S_SOURCE_MASK (0x3ff << 20)
+enum _ErrorSources {
+
+ ERR_ARG_1 = (0x1 << 20),
+ ERR_ARG_2 = (0x2 << 20),
+ ERR_ARG_3 = (0x3 << 20),
+ ERR_ARG_4 = (0x4 << 20),
+ ERR_ARG_5 = (0x5 << 20),
+ ERR_ARG_6 = (0x6 << 20),
+ ERR_ARG_7 = (0x7 << 20),
+ ERR_ARG_8 = (0x8 << 20),
+ ERR_ARG_9 = (0x9 << 20),
+ ERR_ARG_10 = (0xa << 20),
+ ERR_ARG_11 = (0xb << 20),
+ ERR_ARG_12 = (0xc << 20),
+
+ ERR_PLATFORM = (0x10 << 20), /* The error resulted inside platform code. */
+};
+
+#define S_REASON_MASK (0xfffff)
+enum _ErrorReasons {
+ ERR_GENERIC = 0, /* Even numbers are for the implementations, odd are for user-defined errors */
+
+ ERR_INVALID_ARGUMENT = 2,
+
+ ERR_OVERFLOW = 4,
+
+ ERR_OUT_OF_BOUND = 6, /* a value is out of bounds or the operation would violate certain bounds with the current arguments */
+
+ ERR_MEM_MAP_FAILURE = 0x100,
+ ERR_MEM_UNMAP_FAILURE = 0x102,
+ ERR_MEM_SETPERM_FAILURE = 0x104,
+ ERR_MEM_SETHINT_FAILURE = 0x106,
+
+};
+
+
+#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 */
+#define S_NOK(...) ( ((__VA_ARGS__) & S_MASK) == (Status)S_FAILURE )
+
+#define S_SUCCESSFUL(...) ( ((__VA_ARGS__) & S_MASK) == (Status)S_SUCCESS )
+#define S_COMPLETED(...) ( ((__VA_ARGS__) & S_MASK) == (Status)S_COMPLETION )
+#define S_FAILED(...) ( ((__VA_ARGS__) & S_MASK) == (Status)S_FAILURE )
+
+#define TRY(...) do { \
+ Status _res = (__VA_ARGS__); \
+ if( S_NOK(_res) ) { \
+ return _res; \
+ } \
+} while(0)
+
+#endif
platform/linux/entry.h
@@ -0,0 +1,28 @@
+#ifndef NOTLIBC_HEADER_PLATFORM_LINUX_ENTRY_INCLUDED
+#define NOTLIBC_HEADER_PLATFORM_LINUX_ENTRY_INCLUDED
+
+#include "../common/build.h"
+#include "./coretypes.h"
+
+u8* linux_startup_sp = 0;
+
+void entry(void); /* aka main */
+
+X86_64(
+ __asm__ (
+ ".section .text\n"
+ ".global _start\n"
+ ".type _start, @function\n"
+ "_start:\n"
+ "leaq linux_startup_sp(%rip), %rax\n"
+ "movq %rsp, (%rax)\n" /* save original stack pointer */
+ "xor %rax, %rax\n"
+ "call entry\n"
+ );
+)
+
+I386(
+ ERROR("i386 entrypoint not implemented")
+)
+
+#endif
platform/linux/linux_types.h
@@ -1,3 +0,0 @@
-#include "./coretypes.h"
-#include "../common/compiler.h"
-
platform/linux/syscall_wrappers_generic.h
@@ -3,88 +3,86 @@
#include "./coretypes.h"
-
-X86_64(
-
+#if ARCH == ARCH_X86_64
static inline isize linux_syscall1(usize num, usize arg1) {
__asm__ volatile (
- "mov %[a1], %%rdi\n"
+ "movq %[a1], %%rdi\n"
"syscall\n"
: [num]"+a"(num)
- : [a1]"r"(arg1)
- : "rcx", "r11", "memory"
+ : [a1]"m"(arg1) /* memory operands are forced, because otherwise tcc does not generate correct inline asm - it uses mm registers, which have bogus values... */
+ : "rcx", "r11", "memory", "rdi"
);
return num;
}
static inline isize linux_syscall2(usize num, usize arg1, usize arg2) {
__asm__ volatile (
- "mov %[a1], %%rdi\n"
- "mov %[a2], %%rsi\n"
+ "movq %[a1], %%rdi\n"
+ "movq %[a2], %%rsi\n"
"syscall\n"
: [num]"+a"(num)
- : [a1]"r"(arg1), [a2]"r"(arg2)
- : "rcx", "r11", "memory"
+ : [a1]"m"(arg1), [a2]"m"(arg2)
+ : "rcx", "r11", "memory", "rdi", "rsi"
);
return num;
}
static inline isize linux_syscall3(usize num, usize arg1, usize arg2, usize arg3) {
__asm__ volatile (
- "mov %[a1], %%rdi\n"
- "mov %[a2], %%rsi\n"
- "mov %[a3], %%rdx\n"
+ "movq %[a1], %%rdi\n"
+ "movq %[a2], %%rsi\n"
+ "movq %[a3], %%rdx\n"
"syscall\n"
: [num]"+a"(num)
- : [a1]"r"(arg1), [a2]"r"(arg2), [a3]"r"(arg3)
- : "rcx", "r11", "memory"
+ : [a1]"m"(arg1), [a2]"m"(arg2), [a3]"m"(arg3)
+ : "rcx", "r11", "memory", "rdi", "rsi", "rdx"
);
return num;
}
static inline isize linux_syscall4(usize num, usize arg1, usize arg2, usize arg3, usize arg4) {
__asm__ volatile (
- "mov %[a1], %%rdi\n"
- "mov %[a2], %%rsi\n"
- "mov %[a3], %%rdx\n"
- "mov %[a4], %%r10\n"
+ "movq %[a1], %%rdi\n"
+ "movq %[a2], %%rsi\n"
+ "movq %[a3], %%rdx\n"
+ "movq %[a4], %%r10\n"
"syscall\n"
: [num]"+a"(num)
- : [a1]"r"(arg1), [a2]"r"(arg2), [a3]"r"(arg3), [a4]"r"(arg4)
- : "rcx", "r11", "memory"
+ : [a1]"m"(arg1), [a2]"m"(arg2), [a3]"m"(arg3), [a4]"m"(arg4)
+ : "rcx", "r11", "memory", "rdi", "rsi", "rdx", "r10"
);
return num;
}
static inline isize linux_syscall5(usize num, usize arg1, usize arg2, usize arg3, usize arg4, usize arg5) {
__asm__ volatile (
- "mov %[a1], %%rdi\n"
- "mov %[a2], %%rsi\n"
- "mov %[a3], %%rdx\n"
- "mov %[a4], %%r10\n"
- "mov %[a5], %%r8\n"
+ "movq %[a1], %%rdi\n"
+ "movq %[a2], %%rsi\n"
+ "movq %[a3], %%rdx\n"
+ "movq %[a4], %%r10\n"
+ "movq %[a5], %%r8\n"
"syscall\n"
: [num]"+a"(num)
- : [a1]"r"(arg1), [a2]"r"(arg2), [a3]"r"(arg3), [a4]"r"(arg4), [a5]"r"(arg5)
- : "rcx", "r11", "memory"
+ : [a1]"m"(arg1), [a2]"m"(arg2), [a3]"m"(arg3), [a4]"m"(arg4), [a5]"m"(arg5)
+ : "rcx", "r11", "memory", "rdi", "rsi", "rdx", "r10", "r8"
);
return num;
}
static inline isize linux_syscall6(usize num, usize arg1, usize arg2, usize arg3, usize arg4, usize arg5, usize arg6) {
__asm__ volatile (
- "mov %[a1], %%rdi\n"
- "mov %[a2], %%rsi\n"
- "mov %[a3], %%rdx\n"
- "mov %[a4], %%r10\n"
- "mov %[a5], %%r8\n"
- "mov %[a6], %%r9\n"
+ "movq %[a1], %%rdi\n"
+ "movq %[a2], %%rsi\n"
+ "movq %[a3], %%rdx\n"
+ "movq %[a4], %%r10\n"
+ "movq %[a5], %%r8\n"
+ "movq %[a6], %%r9\n"
"syscall\n"
: [num]"+a"(num)
- : [a1]"r"(arg1), [a2]"r"(arg2), [a3]"r"(arg3), [a4]"r"(arg4), [a5]"r"(arg5), [a6]"r"(arg6)
- : "rcx", "r11", "memory"
+ : [a1]"m"(arg1), [a2]"m"(arg2), [a3]"m"(arg3), [a4]"m"(arg4), [a5]"m"(arg5), [a6]"m"(arg6)
+ : "rcx", "r11", "memory", "rdi", "rsi", "rdx", "r10", "r8", "r9"
);
return num;
}
+#endif
-)
I386(
ERROR("Linux syscalls not implemented for I386.");
platform/linux/syscalls.h
@@ -64,7 +64,7 @@ static inline isize linux_munmap( usize start, usize len ) {
}
static inline isize linux_mprotect( usize start, usize len, usize prot ) {
- return linux_syscall3( 11, start, len, prot );
+ return linux_syscall3( 10, start, len, prot );
}
platform/platform.h
@@ -10,9 +10,10 @@
LINUX("linux/coretypes.h") \
WINDOWS("windows/coretypes.h")
-/* Basic types - with sanity checks */
+/* Basic types */
#include HEADER_PLATFORM_CORETYPES
+/* Type sanity checks */
ASSERT( sizeof( u8 ) == 1 );
ASSERT( sizeof( u16 ) == 2 );
ASSERT( sizeof( u32 ) == 4 );
@@ -26,84 +27,23 @@ ASSERT( sizeof( s64 ) == 8 );
ASSERT( sizeof( f32 ) == 4 );
ASSERT( sizeof( f64 ) == 8 );
-/* Error handling types and macros. */
-
-typedef u32 Status;
-
-#define S_MASK (3 << 30)
-
-#define S_SUCCESS (1 << 30) /* Requested action performed. */
-#define S_COMPLETION (0 << 30) /* Action didn't need to be performed - desired state is already present/active. */
-#define S_FAILURE (2 << 30) /* Action failed. */
-
-#define S_SOURCE_MASK (0x3ff << 20)
-enum _ErrorSources {
-
- ERR_ARG_1 = (0x1 << 20),
- ERR_ARG_2 = (0x2 << 20),
- ERR_ARG_3 = (0x3 << 20),
- ERR_ARG_4 = (0x4 << 20),
- ERR_ARG_5 = (0x5 << 20),
- ERR_ARG_6 = (0x6 << 20),
- ERR_ARG_7 = (0x7 << 20),
- ERR_ARG_8 = (0x8 << 20),
- ERR_ARG_9 = (0x9 << 20),
- ERR_ARG_10 = (0xa << 20),
- ERR_ARG_11 = (0xb << 20),
- ERR_ARG_12 = (0xc << 20),
-
- ERR_PLATFORM = (0x10 << 20), /* The error resulted inside platform code. */
-};
-
-#define S_REASON_MASK (0xfffff)
-enum _ErrorReasons {
- ERR_GENERIC = 0, /* Even numbers are for the implementations, odd are for user-defined errors */
-
- ERR_INVALID_ARGUMENT = 2,
-
- ERR_OVERFLOW = 4,
-
- ERR_OUT_OF_BOUND = 6, /* a value is out of bounds or the operation would violate certain bounds with the current arguments */
-
- ERR_MEM_MAP_FAILURE = 0x100,
- ERR_MEM_UNMAP_FAILURE = 0x102,
- ERR_MEM_SETPERM_FAILURE = 0x104,
- ERR_MEM_SETHINT_FAILURE = 0x106,
-
-};
-
-
-#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 */
-#define S_NOK(...) ( ((__VA_ARGS__) & S_MASK) == (Status)S_FAILURE )
-
-#define S_SUCCESSFUL(...) ( ((__VA_ARGS__) & S_MASK) == (Status)S_SUCCESS )
-#define S_COMPLETED(...) ( ((__VA_ARGS__) & S_MASK) == (Status)S_COMPLETION )
-#define S_FAILED(...) ( ((__VA_ARGS__) & S_MASK) == (Status)S_FAILURE )
-
-#define TRY(...) do { \
- Status _res = (__VA_ARGS__); \
- if( S_NOK(_res) ) { \
- return _res; \
- } \
-} while(0)
-
/* Core platform functions */
+#include "./common/corefunc.h"
-static inline void terminate(u32 code); /* aka exit */
-static inline void terminate_forced(void); /* force exit, fault, anything that terminates forcefully */
+#define HEADER_PLATFORM_COREFUNC \
+ LINUX("./linux/corefunc.h") \
+ WINDOWS("./windows/corefunc.h")
-static inline void breakpoint(void); /* raise a debug breakpoint, if possible on the target */
+#include HEADER_PLATFORM_COREFUNC
-static inline void assert( usize condition ) {
- if( !condition ) {
- breakpoint();
- }
-}
+/* Platform-dependent entrypoint function */
+#define HEADER_PLATFORM_ENTRY \
+ LINUX("./linux/entry.h") \
+ WINDOWS("./windows/entry.h")
-#define HEADER_PLATFORM_COREFUNC \
- LINUX("linux/corefunc.h") \
- WINDOWS("windows/corefunc.h")
+#include HEADER_PLATFORM_ENTRY
-#include HEADER_PLATFORM_COREFUNC
+/* Error handling types and macros. */
+#include "./common/error.h"
#endif
testing/tests/000_entry_exit.c
@@ -0,0 +1,5 @@
+#include "platform/platform.h"
+
+void entry(void) {
+ terminate(0);
+}
testing/tests/001_mem_basic.c
@@ -0,0 +1,35 @@
+#include "memory/memory.h"
+#include "platform/platform.h"
+
+#define PAGECOUNT 2
+
+void entry(void) {
+ Page *mem = 0;
+
+ assert(S_OK(
+ mem_claim( PAGECOUNT, &mem )
+ ));
+
+ assert( mem != 0 );
+
+ assert(S_OK(
+ mem_occupy( mem, PAGECOUNT )
+ ));
+
+ mem_set( mem, PAGECOUNT*sizeof(Page), 0xde );
+
+ for( usize i = 0; i < PAGECOUNT*sizeof(Page); ++i ) {
+ assert( *(u8*)mem == 0xde );
+ }
+
+ assert(S_OK(
+ mem_vacate( mem, PAGECOUNT )
+ ));
+
+ assert(S_OK(
+ mem_relinquish( mem, PAGECOUNT )
+ ));
+
+
+ terminate(0);
+}
testing/test.sh
@@ -0,0 +1,80 @@
+#!/bin/bash
+
+FAILED=0
+
+rm -rf ./build/tests/*
+mkdir -p ./build/tests
+
+if [[ ! -v CC ]]; then
+ CC=cc
+fi
+
+# Debug test builds on Og, O2, O3 and release test builds on O2 and O3
+TESTDIRS="o0d ogd o2d o3d o2r o3r"
+
+for DIR in $TESTDIRS; do
+ mkdir -p "./build/tests/$DIR"
+done
+
+echo
+echo Compiling tests.
+echo
+
+for SRC in ./testing/tests/*.c; do
+
+ if ! $CC -nostdlib -I. -g -fno-builtin -O0 -DBUILD_TYPE=1 -DNOTLIBC_IMPLEMENT -fno-stack-protector -static $SRC -o ./build/tests/o0d/$(basename "$SRC" .c); then
+ echo
+ echo "Compilation failure for $SRC - O0D."
+ FAILURE=1
+ fi
+
+ if ! $CC -nostdlib -I. -g -fno-builtin -Og -DBUILD_TYPE=1 -DNOTLIBC_IMPLEMENT $SRC -o ./build/tests/ogd/$(basename "$SRC" .c); then
+ echo
+ echo "Compilation failure for $SRC - OgD."
+ FAILURE=1
+ fi
+
+ if ! $CC -nostdlib -I. -g -fno-builtin -O2 -DBUILD_TYPE=1 -DNOTLIBC_IMPLEMENT $SRC -o ./build/tests/o2d/$(basename "$SRC" .c); then
+ echo
+ echo "Compilation failure for $SRC - O2D."
+ FAILURE=1
+ fi
+
+ if ! $CC -nostdlib -I. -g -fno-builtin -O3 -DBUILD_TYPE=1 $SRC -o ./build/tests/o3d/$(basename "$SRC" .c); then
+ echo
+ echo "Compilation failure for $SRC - O3D."
+ FAILURE=1
+ fi
+
+ if ! $CC -nostdlib -I. -g -fno-builtin -O2 -DBUILD_TYPE=2 $SRC -o ./build/tests/o2r/$(basename "$SRC" .c); then
+ echo
+ echo "Compilation failure for $SRC - O2R."
+ FAILURE=1
+ fi
+
+ if ! $CC -nostdlib -I. -g -fno-builtin -O3 -DBUILD_TYPE=2 $SRC -o ./build/tests/o3r/$(basename "$SRC" .c); then
+ echo
+ echo "Compilation failure for $SRC - O3R."
+ FAILURE=1
+ fi
+done
+
+echo
+echo Running tests.
+echo
+
+for DIR in $TESTDIRS; do
+ for TEST in "./build/tests/$DIR/"*; do
+ "$TEST"
+ RET=$?
+
+ if [ "$RET" -ne 0 ]; then
+ echo "FAILURE: $(basename $TEST)@$(basename $DIR):$RET (./testing/tests/$(basename $TEST).c)"
+ FAILURE=1
+ fi
+ done
+done
+
+exit $FAILURE
+
+
.gitignore
@@ -2,3 +2,4 @@
Session.vim
main.c
compile_flags.txt
+build