diff --git a/compile_flags.txt b/compile_flags.txt index 571b7e0..fcfc9aa 100644 --- a/compile_flags.txt +++ b/compile_flags.txt @@ -2,21 +2,24 @@ -Wall -Wextra -Werror --D__ck_loader_limine__ +-Isrc/libs +-Isrc/kernel/klibs +-Isrc/kernel/archs -D__ck_toolchain_value=clang --D__ck_encoding_utf8__ --D__ck_sys_kernel__ --D__ck_freestanding__ -D__ck_loader_value=limine -D__ck_encoding_value=utf8 --D__ck_arch_x86_64__ +-D__ck_bits_64__ -D__ck_toolchain_clang__ --D__ck_bits_value=64 --D__ck_abi_sysv__ -D__ck_abi_value=sysv -D__ck_sys_value=kernel +-D__ck_loader_limine__ +-D__ck_sys_kernel__ +-D__ck_encoding_utf8__ +-D__ck_abi_sysv__ +-D__ck_freestanding__ -D__ck_arch_value=x86_64 --D__ck_bits_64__ +-D__ck_bits_value=64 +-D__ck_arch_x86_64__ -ffreestanding -fno-stack-protector -mno-80387 @@ -26,3 +29,4 @@ -mno-sse2 -mno-red-zone -Dauto=__auto_type +-Isrc/kernel/klibs diff --git a/src/kernel/archs/hal.h b/src/kernel/archs/hal.h new file mode 100644 index 0000000..879d8f0 --- /dev/null +++ b/src/kernel/archs/hal.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +void hal_setup(void); + +/* --- Assembly function --------------------------------------------------- */ + +void hal_disable_interrupts(void); + +void hal_enable_interrupts(void); + +void hal_pause(void); + +void hal_panic(void); + +/* --- I/O ---------------------------------------------------------------- */ + +Stream hal_dbg_stream(void); \ No newline at end of file diff --git a/src/kernel/archs/x86_64/asm.c b/src/kernel/archs/x86_64/asm.c new file mode 100644 index 0000000..a8b4c4f --- /dev/null +++ b/src/kernel/archs/x86_64/asm.c @@ -0,0 +1,19 @@ +void hal_disable_interrupts(void) +{ + asm volatile("cli"); +} + +void hal_enable_interrupts(void) +{ + asm volatile("sti"); +} + +void hal_pause(void) +{ + asm volatile("pause"); +} + +void hal_panic(void) +{ + asm volatile("int $1"); +} diff --git a/src/kernel/archs/x86_64/e9.c b/src/kernel/archs/x86_64/e9.c new file mode 100644 index 0000000..547fb70 --- /dev/null +++ b/src/kernel/archs/x86_64/e9.c @@ -0,0 +1,19 @@ +#include + +#include "e9.h" + +Res e9_putc(char c) +{ + asm volatile("outb %0, $0xe9" : : "a"(c) : "memory"); + return ok$(); +} + +Res e9_puts(size_t n, char const *s) +{ + for (size_t i = 0; i < n; i++) + { + e9_putc(s[i]); + } + + return ok$(); +} \ No newline at end of file diff --git a/src/kernel/archs/x86_64/e9.h b/src/kernel/archs/x86_64/e9.h new file mode 100644 index 0000000..9218d5f --- /dev/null +++ b/src/kernel/archs/x86_64/e9.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +Res e9_putc(char c); + +Res e9_puts(size_t n, char const *s); \ No newline at end of file diff --git a/src/kernel/archs/x86_64/manifest.json b/src/kernel/archs/x86_64/manifest.json new file mode 100644 index 0000000..027cde4 --- /dev/null +++ b/src/kernel/archs/x86_64/manifest.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1", + "type": "lib", + "id": "arch (x86_64)", + "enableIf": { + "arch": [ + "x86_64" + ] + }, + "provides": [ + "arch" + ], + "requires": [ + "dbg" + ] +} \ No newline at end of file diff --git a/src/kernel/archs/x86_64/mod.c b/src/kernel/archs/x86_64/mod.c new file mode 100644 index 0000000..9951b8f --- /dev/null +++ b/src/kernel/archs/x86_64/mod.c @@ -0,0 +1,14 @@ +#include + +#include "e9.h" + +Stream hal_dbg_stream(void) +{ + return (Stream){ + .write = e9_puts, + }; +} + +void hal_setup(void) +{ +} \ No newline at end of file diff --git a/src/kernel/core/main.c b/src/kernel/core/main.c index 84392b7..10f157b 100644 --- a/src/kernel/core/main.c +++ b/src/kernel/core/main.c @@ -1,5 +1,8 @@ +#include + _Noreturn int _start() { + log$("Hello, world!"); for (;;) ; } \ No newline at end of file diff --git a/src/kernel/core/manifest.json b/src/kernel/core/manifest.json index 804a88b..28739c4 100644 --- a/src/kernel/core/manifest.json +++ b/src/kernel/core/manifest.json @@ -1,5 +1,17 @@ { "$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1", "type": "exe", - "id": "core" + "id": "core", + "requires": [ + "arch", + "dbg", + "stdc-shim" + ], + "tools": { + "cc": { + "args": [ + "-Isrc/kernel/klibs" + ] + } + } } \ No newline at end of file diff --git a/src/kernel/klibs/dbg/log.c b/src/kernel/klibs/dbg/log.c new file mode 100644 index 0000000..cb7f7ad --- /dev/null +++ b/src/kernel/klibs/dbg/log.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include + +#include "log.h" + +static Spinlock _lock = SPINLOCK_INIT; + +static char const *level_names[LOG_EVENT_LENGTH] = { + [LOG_NONE] = "", + [LOG_INFO] = "INFO", + [LOG_WARN] = "WARN", + [LOG_ERROR] = "ERROR", + [LOG_CRIT] = "CRITIC", +}; + +static char const *level_colors[LOG_EVENT_LENGTH] = { + [LOG_NONE] = "", + [LOG_INFO] = "\e[1;34m", + [LOG_WARN] = "\e[1;33m", + [LOG_ERROR] = "\e[1;31m", + [LOG_CRIT] = "\e[1;35m", +}; + +void _log(LogEvent event, Loc loc, char const *format, ...) +{ + spinlock_acquire(&_lock); + va_list args; + va_start(args, format); + + if (event != LOG_NONE) + { + fmt(hal_dbg_stream(), "%s%s\e[0m %s:%d ", level_colors[event], level_names[event], loc.file, loc.line); + } + + vfmt(hal_dbg_stream(), format, args); + + if (event != LOG_NONE) + { + hal_dbg_stream().write(1, "\n"); + } + + va_end(args); + spinlock_release(&_lock); +} \ No newline at end of file diff --git a/src/kernel/klibs/dbg/log.h b/src/kernel/klibs/dbg/log.h new file mode 100644 index 0000000..3c4ea29 --- /dev/null +++ b/src/kernel/klibs/dbg/log.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +#include "loc.h" + +typedef enum +{ + LOG_NONE, + LOG_INFO, + LOG_WARN, + LOG_ERROR, + LOG_CRIT, + + LOG_EVENT_LENGTH +} LogEvent; + +#define log$(...) _log(LOG_INFO, loc$(), __VA_ARGS__) +#define warn$(...) _log(LOG_WARN, loc$(), __VA_ARGS__) +#define error$(...) _log(LOG_ERROR, loc$(), __VA_ARGS__) +#define critical$(...) _log(LOG_CRIT, loc$(), __VA_ARGS__) +#define print$(...) _log(LOG_NONE, (Loc){}, __VA_ARGS__) + +void _log(LogEvent event, Loc loc, char const *format, ...); \ No newline at end of file diff --git a/src/kernel/klibs/dbg/manifest.json b/src/kernel/klibs/dbg/manifest.json new file mode 100644 index 0000000..2bca110 --- /dev/null +++ b/src/kernel/klibs/dbg/manifest.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1", + "type": "lib", + "id": "dbg", + "enableIf": { + "freestanding": [ + true + ] + }, + "requires": [ + "sync", + "fmt" + ] +} \ No newline at end of file diff --git a/src/kernel/klibs/stdc-shim/manifest.json b/src/kernel/klibs/stdc-shim/manifest.json new file mode 100644 index 0000000..2c80d77 --- /dev/null +++ b/src/kernel/klibs/stdc-shim/manifest.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1", + "type": "lib", + "id": "stdc-shim", + "props": { + "cpp-root-include": true + }, + "enableIf": { + "freestanding": [ + true + ] + } +} \ No newline at end of file diff --git a/src/kernel/klibs/stdc-shim/string.c b/src/kernel/klibs/stdc-shim/string.c new file mode 100644 index 0000000..87605db --- /dev/null +++ b/src/kernel/klibs/stdc-shim/string.c @@ -0,0 +1,51 @@ +#include "string.h" + +size_t strlen(char const str[static 1]) +{ + size_t len = 0; + + while (*str++) + { + len++; + } + + return len; +} + +void *memcpy(void *restrict dst, void const *restrict src, size_t n) +{ + char *restrict d = dst; + char const *restrict s = src; + + while (n--) + { + *d++ = *s++; + } + + return dst; +} + +void *memset(void *dest, int c, size_t n) +{ + char *d = dest; + + while (n--) + { + *d++ = c; + } + + return dest; +} + +int memcmp(const void *s1, const void *s2, size_t n) +{ + for (size_t i = 0; i < n; i++) + { + if (((const char *)s1)[i] != ((const char *)s2)[i]) + { + return ((const char *)s1)[i] - ((const char *)s2)[i]; + } + } + + return 0; +} \ No newline at end of file diff --git a/src/kernel/klibs/stdc-shim/string.h b/src/kernel/klibs/stdc-shim/string.h new file mode 100644 index 0000000..2776ce9 --- /dev/null +++ b/src/kernel/klibs/stdc-shim/string.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +size_t strlen(char const s[static 1]); + +void *memcpy(void *restrict dest, void const *restrict src, size_t n); + +void *memset(void *dest, int c, size_t n); + +int memcmp(void const *s1, void const *s2, size_t n); \ No newline at end of file diff --git a/src/kernel/klibs/sync/manifest.json b/src/kernel/klibs/sync/manifest.json new file mode 100644 index 0000000..1372208 --- /dev/null +++ b/src/kernel/klibs/sync/manifest.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1", + "type": "lib", + "id": "sync", + "enableIf": { + "freestanding": [ + true + ] + } +} \ No newline at end of file diff --git a/src/kernel/klibs/sync/spinlock.c b/src/kernel/klibs/sync/spinlock.c new file mode 100644 index 0000000..5fdb312 --- /dev/null +++ b/src/kernel/klibs/sync/spinlock.c @@ -0,0 +1,30 @@ +#include + +#include "spinlock.h" + +static _Atomic int retain_count = 0; + +static void retain_interrupts(void) +{ + retain_count++; +} + +static void release_interrupt(void) +{ + retain_count--; +} + +void spinlock_acquire(Spinlock spinlock[static 1]) +{ + retain_interrupts(); + while (atomic_flag_test_and_set(&spinlock->lock)) + { + hal_pause(); + } +} + +void spinlock_release(Spinlock spinlock[static 1]) +{ + atomic_flag_clear(&spinlock->lock); + release_interrupt(); +} \ No newline at end of file diff --git a/src/kernel/klibs/sync/spinlock.h b/src/kernel/klibs/sync/spinlock.h new file mode 100644 index 0000000..e03dd71 --- /dev/null +++ b/src/kernel/klibs/sync/spinlock.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +typedef struct +{ + volatile atomic_flag lock; +} Spinlock; + +#define SPINLOCK_INIT \ + (Spinlock) { .lock = ATOMIC_FLAG_INIT } + +Spinlock spinlock_new(void); + +void spinlock_acquire(Spinlock spinlock[static 1]); + +void spinlock_release(Spinlock spinlock[static 1]); \ No newline at end of file diff --git a/src/libs/fmt/fmt.c b/src/libs/fmt/fmt.c new file mode 100644 index 0000000..9151c1d --- /dev/null +++ b/src/libs/fmt/fmt.c @@ -0,0 +1,191 @@ +#include +#include + +#include "fmt.h" + +static char *strrev(char *str) +{ + int start; + int end; + char tmp; + + end = strlen(str) - 1; + start = 0; + + while (start < end) + { + tmp = str[start]; + str[start] = str[end]; + str[end] = tmp; + start++; + end--; + } + return str; +} + +static char *itoa(int64_t value, char *str, int base) +{ + int i = 0; + bool isNegative = false; + + if (value == 0) + { + str[i++] = '0'; + str[i] = '\0'; + return str; + } + + if (value < 0 && base == 10) + { + isNegative = true; + value = -value; + } + + while (value != 0) + { + int rem = value % base; + str[i++] = (rem > 9) ? (rem - 10) + 'a' : rem + '0'; + value = value / base; + } + + if (isNegative) + { + str[i++] = '-'; + } + + str[i] = '\0'; + + return strrev(str); +} + +char *utoa(uint64_t value, char *str, int base) +{ + int i = 0; + + if (value == 0) + { + str[i++] = '0'; + str[i] = '\0'; + return str; + } + + while (value != 0) + { + int rem = value % base; + str[i++] = (rem > 9) ? (rem - 10) + 'a' : rem + '0'; + value = value / base; + } + + str[i] = '\0'; + + return strrev(str); +} + +Res fmt(Stream stream, char const fmt[static 1], ...) +{ + va_list args; + va_start(args, fmt); + Res res = vfmt(stream, fmt, args); + va_end(args); + return res; +} + +Res vfmt(Stream stream, char const fmt[static 1], va_list args) +{ + const char *s = fmt; + + while (*s) + { + if (*s == '%') + { + switch (*++s) + { + case 'd': + { + s++; + char buf[100]; + int64_t value = va_arg(args, int64_t); + + itoa(value, buf, 10); + stream.write(strlen(buf), buf); + break; + } + + case 'u': + { + s++; + char buf[100]; + uint64_t value = va_arg(args, int64_t); + + utoa(value, buf, 10); + stream.write(strlen(buf), buf); + break; + } + + case 'p': + { + s++; + char buf[100]; + uint64_t value = va_arg(args, uint64_t); + + utoa(value, buf, 16); + stream.write(2, "0x"); + + for (size_t i = 0; i < 16 - strlen(buf); i++) + { + stream.write(1, "0"); + } + + stream.write(strlen(buf), buf); + break; + } + + case 'x': + { + s++; + char buf[100]; + uint64_t value = va_arg(args, uint64_t); + + utoa(value, buf, 16); + stream.write(strlen(buf), buf); + break; + } + + case 's': + { + s++; + char *value = va_arg(args, char *); + stream.write(strlen(value), value); + break; + } + + case 'c': + { + s++; + char value = va_arg(args, int); + stream.write(1, &value); + break; + } + + case '%': + { + s++; + stream.write(1, "%"); + break; + } + + default: + { + return err$(RES_INVAL); + } + } + } + else + { + char sub[2] = {*s++, '\0'}; + stream.write(1, sub); + } + } + + return uok$(0); +} \ No newline at end of file diff --git a/src/libs/fmt/fmt.h b/src/libs/fmt/fmt.h new file mode 100644 index 0000000..280c0f1 --- /dev/null +++ b/src/libs/fmt/fmt.h @@ -0,0 +1,8 @@ +#pragma once + +#include +#include +#include + +Res fmt(Stream stream, char const fmt[static 1], ...); +Res vfmt(Stream stream, char const fmt[static 1], va_list args); \ No newline at end of file diff --git a/src/libs/fmt/manifest.json b/src/libs/fmt/manifest.json new file mode 100644 index 0000000..1be8a38 --- /dev/null +++ b/src/libs/fmt/manifest.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1", + "type": "lib", + "id": "fmt" +} \ No newline at end of file diff --git a/src/libs/io/manifest.json b/src/libs/io/manifest.json new file mode 100644 index 0000000..c05276c --- /dev/null +++ b/src/libs/io/manifest.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1", + "type": "lib", + "id": "io" +} \ No newline at end of file diff --git a/src/libs/io/stream.h b/src/libs/io/stream.h new file mode 100644 index 0000000..b152c3d --- /dev/null +++ b/src/libs/io/stream.h @@ -0,0 +1,9 @@ +#pragma once + +#include "res.h" + +typedef struct +{ + Res (*write)(size_t n, char const buf[static n]); + Res (*read)(size_t n, char buf[static n]); +} Stream; \ No newline at end of file diff --git a/src/libs/loc.h b/src/libs/loc.h new file mode 100644 index 0000000..fdf16d6 --- /dev/null +++ b/src/libs/loc.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +typedef struct +{ + char const *file; + const char *full; + const char *func; + size_t line; +} Loc; + +#define loc$() ((Loc){ \ + .file = __FILE_NAME__, \ + .full = __FILE__, \ + .func = __func__, \ + .line = __LINE__, \ +}) \ No newline at end of file diff --git a/src/libs/res.h b/src/libs/res.h new file mode 100644 index 0000000..b3e8efd --- /dev/null +++ b/src/libs/res.h @@ -0,0 +1,56 @@ +#pragma once + +#include + +#include "loc.h" +#include "utils.h" + +#define RES_TYPE(F) \ + F(RES_OK) \ + F(RES_INVAL) \ + F(RES_NOMEM) \ + F(RES_BADALIGN) \ + F(RES_NOENT) + +enum res_type +{ + RES_TYPE(make_enum$) +}; + +static char const *res_type_str[] = {RES_TYPE(make_str$)}; + +typedef struct +{ + enum res_type type; + Loc loc; + union + { + size_t uvalue; + ptrdiff_t ivalue; + }; +} Res; + +#define ok$() \ + (Res) { .type = RES_OK, .uvalue = 0, .loc = loc$() } + +#define uok$(u) \ + (Res) { .type = RES_OK, .uvalue = (u), .loc = loc$() } + +#define iok$(i) \ + (Res) { .type = RES_OK, .ivalue = (i), .loc = loc$() } + +#define err$(t) \ + (Res) { .type = (t), .uvalue = 0, .loc = loc$() } + +#define try$(EXPR) \ + ({ \ + Res __result = (Res)(EXPR); \ + if (__result.type != RES_OK) \ + return __result; \ + __result.ivalue; \ + }) + +static inline char const *res_to_str(Res res) +{ + return res_type_str[res.type]; +} \ No newline at end of file diff --git a/src/libs/utils.h b/src/libs/utils.h new file mode 100644 index 0000000..88dccd8 --- /dev/null +++ b/src/libs/utils.h @@ -0,0 +1,9 @@ +#pragma once + +#define max$(a, b) (((a) > (b)) ? (a) : (b)) + +#define min$(a, b) (((a) < (b)) ? (a) : (b)) + +#define make_enum$(enum) enum, + +#define make_str$(str) #str, \ No newline at end of file