17 Commits

Author SHA1 Message Date
karina b7a4a90e63 fix: fix hot loader page reuse for overlapping init segments 2026-04-21 00:30:41 +04:00
karina 41578c29d6 build: fixed building on macOS 2026-04-21 00:09:30 +04:00
Karina d42fc79c25 WIP: Rust std for termos's userspace 2026-04-15 14:44:10 +04:00
Karina b44e1924ed wip: experimental rust support in runtime 2026-04-13 23:40:41 +04:00
Karina 4909e40cb1 docs: readme update again 2026-04-04 19:47:30 +04:00
Karina 7102edfa5a docs: readme update 2026-04-04 19:47:18 +04:00
Karina 47735bb1bd REF: Renamed kernel -> System; userspace -> Runtime; bootloader -> Boot
del: KSH
2026-04-04 19:44:39 +04:00
Karina 2f58f64175 feat(libkern): strrchr (StringFindLastOccurenceOfCharacter)
fix(OSServiceProcessSpawn): now it uses strrchr to get process name
2026-02-01 21:02:54 +04:00
Karina 4e10985909 ref(KSH): Renamed files and folder 2026-02-01 00:39:18 +04:00
Karina c72dbc763c chore(CPIO): changed panic text 2026-02-01 00:28:19 +04:00
Karina 02b36283a5 ref(libkern): changed to match libterm 2026-02-01 00:26:22 +04:00
Karina e21f5ef52f ref(libterm): now apple-styled too 2026-01-31 22:47:42 +04:00
Karina 2be7d3bd46 fix(scheduler): garbage collector now wakes up on process terminate
fix(scheduler/spawn): now its doesnt OSPanic's when VMHeapAllocate returned nullptr for stackBaseAddress. It wakes up GC, tries again and if it failed return nullptr
2026-01-31 21:28:02 +04:00
Karina 02dc35f0df feat(core): implement spinlocks, GC and keyboard safety
* Implemented Spinlocks and applied to VM/Scheduler

* Added Garbage Collector for tasks

* Moved Getchar to IOKeyboard with locking

* Cleanup panic messages
2026-01-31 20:50:27 +04:00
Karina ee67cef4f8 ref: initramfs -> StartupVolume; /bin -> /System/CoreServices;
ref(Kernel/VM/Heap): malloc -> VMHeapAllocate; free -> VMHeapFree; realloc -> VMHeapResize
2026-01-31 16:11:45 +04:00
Karina c30d57d06e fix(ksh/regs): now it doesnt panic when typing regs in ksh
fix(kmain): Now Dewar correctly OSPanic()'s instead of returnin IOConsoleLog when no framebuffer found
2026-01-31 02:49:34 +04:00
Karina 4e6794a6c2 chore: update copyrights 2026-01-31 01:57:28 +04:00
153 changed files with 1572 additions and 1259 deletions
+2
View File
@@ -1,7 +1,9 @@
.cache
.vscode
build*
.venv
initrd/image.cpio
initramfs/*
target
Cargo.lock
+1
View File
@@ -6,3 +6,4 @@ kernel/data
bootloader/
bootloader/src/uefi
initramfs/
kernel/inc/Data
@@ -1,5 +1,9 @@
project(termOS_Bootloader LANGUAGES C ASM)
if(APPLE)
set(CMAKE_C_LINK_FLAGS "")
endif()
set(UEFI_COMPILE_OPTIONS
-std=c23
-target x86_64-unknown-windows-msvc
@@ -20,14 +24,15 @@ set(POSIX_UEFI_SOURCES
src/uefi/unistd.c
)
add_library(posix_uefi_lib STATIC ${POSIX_UEFI_SOURCES})
add_library(posix_uefi_lib OBJECT ${POSIX_UEFI_SOURCES})
target_compile_options(posix_uefi_lib PRIVATE ${UEFI_COMPILE_OPTIONS})
target_include_directories(posix_uefi_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/uefi)
add_executable(BOOTX64 src/main.c)
target_compile_options(BOOTX64 PRIVATE ${UEFI_COMPILE_OPTIONS})
target_sources(BOOTX64 PRIVATE $<TARGET_OBJECTS:posix_uefi_lib>)
target_link_libraries(BOOTX64 PRIVATE posix_uefi_lib)
target_include_directories(BOOTX64 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/uefi)
target_link_options(BOOTX64 PRIVATE
-fuse-ld=lld
+3 -3
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2025 0xKarinyash
// Copyright (c) 2026 0xKarinyash
#include "uefi.h" // IWYU pragma: keep
#include "../../common/bootinfo.h"
@@ -78,10 +78,10 @@ int main()
efi_file_handle_t* initramfs_file;
uintn_t iinfo_size = 0;
efi_file_info_t* ifile_info = nullptr;
status = root->Open(root, &initramfs_file, L"initramfs.cpio", EFI_FILE_MODE_READ, 0);
status = root->Open(root, &initramfs_file, L"StartupVolume.cpio", EFI_FILE_MODE_READ, 0);
if (EFI_ERROR(status)) {
print_initramfs_warning(L"initramfs.cpio is missing");
print_initramfs_warning(L"StartupVolume.cpio is missing");
boot_info->initramfs.address = nullptr;
boot_info->initramfs.size = 0;
} else {
@@ -46,7 +46,7 @@ void __stdio_cleanup(void)
BS->FreePool(__argvutf8);
#endif
if(__blk_devs) {
free(__blk_devs);
MemoryFree(__blk_devs);
__blk_devs = NULL;
__blk_ndevs = 0;
}
@@ -127,7 +127,7 @@ int fclose (FILE *__stream)
if(__stream == (FILE*)__blk_devs[i].bio)
return 1;
status = __stream->Close(__stream);
free(__stream);
MemoryFree(__stream);
return !EFI_ERROR(status);
}
@@ -188,7 +188,7 @@ err: __stdio_seterrno(status);
return -1;
}
/* no need for fclose(f); */
free(f);
MemoryFree(f);
return 0;
}
@@ -250,7 +250,7 @@ FILE *fopen (const char_t *__filename, const char_t *__modes)
/* workaround a bug in TianoCore, it reports zero size even though the data is in the buffer */
if(handle_size < 1)
handle_size = (uintn_t)sizeof(handles) / sizeof(efi_handle_t);
__blk_devs = (block_file_t*)malloc(handle_size * sizeof(block_file_t));
__blk_devs = (block_file_t*)MemoryAllocate(handle_size * sizeof(block_file_t));
if(__blk_devs) {
memset(__blk_devs, 0, handle_size * sizeof(block_file_t));
for(i = __blk_ndevs = 0; i < handle_size; i++)
@@ -276,7 +276,7 @@ FILE *fopen (const char_t *__filename, const char_t *__modes)
errno = ENODEV;
return NULL;
}
ret = (FILE*)malloc(sizeof(FILE));
ret = (FILE*)MemoryAllocate(sizeof(FILE));
if(!ret) return NULL;
/* normally write means read,write,create. But for remove (internal '*' mode), we need read,write without create
* also mode 'w' in POSIX means write-only (without read), but that's not working on certain firmware, we must
@@ -292,16 +292,16 @@ FILE *fopen (const char_t *__filename, const char_t *__modes)
__modes[1] == CL('d') ? EFI_FILE_DIRECTORY : 0);
if(EFI_ERROR(status)) {
err: __stdio_seterrno(status);
free(ret); return NULL;
MemoryFree(ret); return NULL;
}
if(__modes[0] == CL('*')) return ret;
status = ret->GetInfo(ret, &infGuid, &fsiz, &info);
if(EFI_ERROR(status)) goto err;
if(__modes[1] == CL('d') && !(info.Attribute & EFI_FILE_DIRECTORY)) {
ret->Close(ret); free(ret); errno = ENOTDIR; return NULL;
ret->Close(ret); MemoryFree(ret); errno = ENOTDIR; return NULL;
}
if(__modes[1] != CL('d') && (info.Attribute & EFI_FILE_DIRECTORY)) {
ret->Close(ret); free(ret); errno = EISDIR; return NULL;
ret->Close(ret); MemoryFree(ret); errno = EISDIR; return NULL;
}
if(__modes[0] == CL('a')) fseek(ret, 0, SEEK_END);
if(__modes[0] == CL('w')) {
@@ -713,7 +713,7 @@ int sprintf(char_t *dst, const char_t* fmt, ...)
return ret;
}
int snprintf(char_t *dst, size_t maxlen, const char_t* fmt, ...)
int StringFormat(char_t *dst, size_t maxlen, const char_t* fmt, ...)
{
int ret;
__builtin_va_list args;
@@ -738,7 +738,7 @@ int vprintf(const char_t* fmt, __builtin_va_list args)
return ret;
}
int printf(const char_t* fmt, ...)
int ConsolePrint(const char_t* fmt, ...)
{
int ret;
__builtin_va_list args;
@@ -800,7 +800,7 @@ int getchar_ifany (void)
return EFI_ERROR(status) ? 0 : key.UnicodeChar;
}
int getchar (void)
int ConsoleGetCharacter (void)
{
uintn_t idx;
BS->WaitForEvent(1, &ST->ConIn->WaitForKey, &idx);
@@ -77,7 +77,7 @@ int64_t strtol (const char_t *s, char_t **__endptr, int __base)
return v * sign;
}
void *malloc (size_t __size)
void *MemoryAllocate (size_t __size)
{
void *ret = NULL;
efi_status_t status;
@@ -106,20 +106,20 @@ void *malloc (size_t __size)
void *calloc (size_t __nmemb, size_t __size)
{
void *ret = malloc(__nmemb * __size);
void *ret = MemoryAllocate(__nmemb * __size);
if(ret) memset(ret, 0, __nmemb * __size);
return ret;
}
void *realloc (void *__ptr, size_t __size)
void *MemoryReallocate (void *__ptr, size_t __size)
{
void *ret = NULL;
efi_status_t status;
#ifndef UEFI_NO_TRACK_ALLOC
uintn_t i;
#endif
if(!__ptr) return malloc(__size);
if(!__size) { free(__ptr); return NULL; }
if(!__ptr) return MemoryAllocate(__size);
if(!__size) { MemoryFree(__ptr); return NULL; }
#ifndef UEFI_NO_TRACK_ALLOC
/* get the slot which stores the old size for this buffer */
for(i = 0; i < __stdlib_numallocs && __stdlib_allocs[i] != (uintptr_t)__ptr; i += 2);
@@ -145,7 +145,7 @@ void *realloc (void *__ptr, size_t __size)
return ret;
}
void free (void *__ptr)
void MemoryFree (void *__ptr)
{
efi_status_t status;
#ifndef UEFI_NO_TRACK_ALLOC
@@ -341,7 +341,7 @@ uint8_t *getenv(char_t *name, uintn_t *len)
#else
status = RT->GetVariable(name, &globGuid, &attr, len, &tmp);
#endif
if(EFI_ERROR(status) || *len < 1 || !(ret = malloc((*len) + 1))) {
if(EFI_ERROR(status) || *len < 1 || !(ret = MemoryAllocate((*len) + 1))) {
*len = 0;
return NULL;
}
@@ -116,7 +116,7 @@ void *memrmem(const void *haystack, size_t hl, const void *needle, size_t nl)
return NULL;
}
char_t *strcpy(char_t *dst, const char_t *src)
char_t *StringCopy(char_t *dst, const char_t *src)
{
char_t *s = dst;
if(src && dst && src != dst) {
@@ -178,7 +178,7 @@ int strncmp(const char_t *s1, const char_t *s2, size_t n)
char_t *strdup(const char_t *s)
{
size_t i = (strlen(s)+1) * sizeof(char_t);
char_t *s2 = (char_t *)malloc(i);
char_t *s2 = (char_t *)MemoryAllocate(i);
if(s2 != NULL) memcpy(s2, (const void*)s, i);
return s2;
}
@@ -1314,10 +1314,10 @@ typedef int (*__compar_fn_t) (const void *, const void *);
extern int atoi (const char_t *__nptr);
extern int64_t atol (const char_t *__nptr);
extern int64_t strtol (const char_t *__nptr, char_t **__endptr, int __base);
extern void *malloc (size_t __size);
extern void *MemoryAllocate (size_t __size);
extern void *calloc (size_t __nmemb, size_t __size);
extern void *realloc (void *__ptr, size_t __size);
extern void free (void *__ptr);
extern void *MemoryReallocate (void *__ptr, size_t __size);
extern void MemoryFree (void *__ptr);
extern void abort (void);
extern void exit (int __status);
/* exit Boot Services function. Returns 0 on success. */
@@ -1355,14 +1355,14 @@ extern int fseek (FILE *__stream, long int __off, int __whence);
extern long int ftell (FILE *__stream);
extern int feof (FILE *__stream);
extern int fprintf (FILE *__stream, const char_t *__format, ...);
extern int printf (const char_t *__format, ...);
extern int ConsolePrint (const char_t *__format, ...);
extern int sprintf (char_t *__s, const char_t *__format, ...);
extern int vfprintf (FILE *__s, const char_t *__format, __builtin_va_list __arg);
extern int vprintf (const char_t *__format, __builtin_va_list __arg);
extern int vsprintf (char_t *__s, const char_t *__format, __builtin_va_list __arg);
extern int snprintf (char_t *__s, size_t __maxlen, const char_t *__format, ...);
extern int StringFormat (char_t *__s, size_t __maxlen, const char_t *__format, ...);
extern int vsnprintf (char_t *__s, size_t __maxlen, const char_t *__format, __builtin_va_list __arg);
extern int getchar (void);
extern int ConsoleGetCharacter (void);
/* non-blocking, only returns UNICODE if there's any key pressed, 0 otherwise */
extern int getchar_ifany (void);
extern int putchar (int __c);
@@ -1376,7 +1376,7 @@ extern void *memchr(const void *__s, int __c, size_t __n);
extern void *memrchr(const void *__s, int __c, size_t __n);
void *memmem(const void *haystack, size_t hl, const void *needle, size_t nl);
void *memrmem(const void *haystack, size_t hl, const void *needle, size_t nl);
extern char_t *strcpy (char_t *__dest, const char_t *__src);
extern char_t *StringCopy (char_t *__dest, const char_t *__src);
extern char_t *strncpy (char_t *__dest, const char_t *__src, size_t __n);
extern char_t *strcat (char_t *__dest, const char_t *__src);
extern char_t *strncat (char_t *__dest, const char_t *__src, size_t __n);
+28 -29
View File
@@ -10,7 +10,7 @@ find_program(MCOPY_EXE mcopy)
find_program(MKFS_EXE mkfs.fat)
find_program(CPIO_EXE cpio)
find_program(QEMU_EXE qemu-system-x86_64)
set(OVMF_PATH "/usr/share/edk2/ovmf/OVMF_CODE.fd" CACHE FILEPATH "Path to OVMF bios")
set(OVMF_PATH "/usr/share/edk2/x64/OVMF.4m.fd" CACHE FILEPATH "Path to OVMF bios")
execute_process(
COMMAND git describe --tags --always --dirty
@@ -26,48 +26,47 @@ endif()
message(STATUS "Building termOS version: ${KERNEL_VERSION}")
add_compile_definitions(TERMOS_VERSION=\"${KERNEL_VERSION}\")
add_subdirectory(bootloader)
add_subdirectory(kernel)
add_subdirectory(userspace)
add_subdirectory(Boot)
add_subdirectory(System)
add_subdirectory(Runtime)
if(MCOPY_EXE AND MKFS_EXE AND CPIO_EXE)
set(IMG_FILE "${CMAKE_BINARY_DIR}/termOS.img")
set(INITRAMFS_SRC_DIR "${CMAKE_SOURCE_DIR}/initramfs")
set(INITRAMFS_CPIO_FILE "${CMAKE_BINARY_DIR}/initramfs.cpio")
file(GLOB_RECURSE INIT_FILES "${INITRAMFS_SRC_DIR}/*")
add_custom_command(
OUTPUT ${INITRAMFS_CPIO_FILE}
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}
COMMAND sh -c "find . -mindepth 1 ! -name '*.cpio' -print0 | ${CPIO_EXE} --null -ov -H newc > \"${INITRAMFS_CPIO_FILE}\""
WORKING_DIRECTORY ${INITRAMFS_SRC_DIR}
DEPENDS ${INIT_FILES} init debug termosh
VERBATIM
COMMENT "Packing initramfs to cpio..."
set(SYSTEM_SERVICES
init
debug
termosh
rtest
)
add_custom_command(
OUTPUT ${IMG_FILE}
set(VOLUME_ROOT "${CMAKE_BINARY_DIR}/StartupVolume")
set(INITRAMFS_CPIO_FILE "${CMAKE_BINARY_DIR}/StartupVolume.cpio")
set(IMG_FILE "${CMAKE_BINARY_DIR}/termOS.img")
if(MCOPY_EXE AND MKFS_EXE AND CPIO_EXE)
add_custom_target(image ALL
COMMAND ${CMAKE_COMMAND} -E make_directory ${VOLUME_ROOT}
COMMAND sh -c "find . -mindepth 1 ! -name '*.cpio' -print0 | ${CPIO_EXE} --null -ov -H newc > \"${INITRAMFS_CPIO_FILE}\""
COMMAND dd if=/dev/zero of=${IMG_FILE} bs=1M count=64 status=none
COMMAND ${MKFS_EXE} -F 32 ${IMG_FILE}
COMMAND mmd -i ${IMG_FILE} ::/EFI ::/EFI/BOOT
COMMAND ${MCOPY_EXE} -i ${IMG_FILE} $<TARGET_FILE:BOOTX64> ::/EFI/BOOT/BOOTX64.EFI
COMMAND ${MCOPY_EXE} -i ${IMG_FILE} ${CMAKE_BINARY_DIR}/bin/kernel.bin ::/kernel.bin
COMMAND ${MCOPY_EXE} -i ${IMG_FILE} ${INITRAMFS_CPIO_FILE} ::/initramfs.cpio
DEPENDS BOOTX64 kernel ${INITRAMFS_CPIO_FILE}
VERBATIM
COMMENT "Generating bootable image: ${IMG_FILE}"
)
COMMAND ${MCOPY_EXE} -i ${IMG_FILE} ${INITRAMFS_CPIO_FILE} ::/StartupVolume.cpio
add_custom_target(image ALL DEPENDS ${IMG_FILE})
WORKING_DIRECTORY ${VOLUME_ROOT}
DEPENDS BOOTX64 kernel ${SYSTEM_SERVICES}
VERBATIM
COMMENT "Packing initramfs and generating bootable image: ${IMG_FILE}"
)
endif()
if(QEMU_EXE)
add_custom_target(run
COMMAND ${QEMU_EXE}
-enable-kvm
-bios ${OVMF_PATH}
#-enable-kvm
$<$<BOOL:${APPLE}>:-machine> $<$<BOOL:${APPLE}>:q35>
$<$<BOOL:${APPLE}>:-drive> $<$<BOOL:${APPLE}>:if=pflash,format=raw,readonly=on,file=${OVMF_PATH}>
$<$<NOT:$<BOOL:${APPLE}>>:-bios> $<$<NOT:$<BOOL:${APPLE}>>:${OVMF_PATH}>
-drive file=${IMG_FILE},format=raw
-vga std
-net none
+5 -5
View File
@@ -9,14 +9,14 @@
**termOS** is a 64-bit, UNIX-hating, bespoke operating system written from scratch in C.
Current Kernel: **Dewar** (v0.5.x)
Current Kernel: **Dewar** (v0.6.x)
## Philosophy
- **Zero Bloat:** We don't port libraries; we write them.
- **Custom Everything:** Why use ELF when you can invent **HOT!**? Why use GRUB when you can write your own bootloader (soon)?
- **Custom Everything:** Why use ELF when you can invent **HOT!**? Why use GRUB when you can write your own bootloader?
## Features (v0.5.2)
## Features (v0.6.*)
- **Architecture:** x86_64 / UEFI.
- **Memory Management:** PMM (Bitmap), VMM (PML4 + Higher Half Direct Map), Kernel Heap.
@@ -24,8 +24,8 @@ Current Kernel: **Dewar** (v0.5.x)
- **Isolation:** Ring 0 (Kernel) / Ring 3 (Userspace) protection.
- **Binaries:** Custom **HOT!** executable format (parsed via custom `elf2hot` toolchain).
- **Filesystem:** VFS abstraction with CPIO Initramfs support.
- **Graphics:** `ShitGUI` (yes, really) linear framebuffer driver.
- **Shell:** `ksh` (Kernel Shell) -> transitioning to userspace `ush`
- **Graphics:** linear framebuffer driver.
- **Shell:** `termosh`
## 🔥 The HOT! Format
+25
View File
@@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 3.20)
project(termOSuserspace LANGUAGES C ASM_NASM)
set(CMAKE_C_STANDARD 23)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
message(STATUS "Building termOS's userspace")
set(TERMOS_OBJCOPY objcopy)
if(APPLE)
find_program(TERMOS_LD_LLD NAMES ld.lld HINTS /usr/local/bin /opt/homebrew/bin REQUIRED)
find_program(TERMOS_OBJCOPY NAMES llvm-objcopy objcopy HINTS /usr/local/opt/llvm/bin /opt/homebrew/opt/llvm/bin REQUIRED)
set(CMAKE_C_LINK_FLAGS "")
set(CMAKE_ASM_NASM_COMPILE_OBJECT
"<CMAKE_ASM_NASM_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -MD <DEP_FILE> -MT <DEP_TARGET> -f elf64 -o <OBJECT> <SOURCE>")
set(CMAKE_C_LINK_EXECUTABLE
"${TERMOS_LD_LLD} <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
endif()
add_subdirectory(libterm)
add_subdirectory(init)
add_subdirectory(rust)
add_subdirectory(debug)
add_subdirectory(termosh)
+6
View File
@@ -0,0 +1,6 @@
#include <termOS.h>
int main() {
ConsolePrint("Test test test \n Meow meow meow \n");
return 0;
}
@@ -1,14 +1,13 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#include <process.h>
#include <malloc.h>
#include <termOS.h>
// TODO: read .cfg and spawn what stated there
int main() {
while (1) {
Int32 pid = spawn("/bin/termosh");
Int32 pid = ProcessSpawn("/System/CoreServices/termosh");
if (pid < 0) return pid;
wait(pid);
ProcessWait(pid);
}
}
@@ -19,32 +19,41 @@ set(USER_C_FLAGS
-O2
)
set(CMAKE_ASM_NASM_FLAGS "-f elf64")
if(APPLE)
list(APPEND USER_C_FLAGS --target=x86_64-none-elf)
endif()
set(USER_C_FLAGS "${USER_C_FLAGS}" PARENT_SCOPE)
set(CMAKE_ASM_NASM_OBJECT_FORMAT elf64)
set(LIBTERM_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/syscalls.asm
${CMAKE_CURRENT_SOURCE_DIR}/src/stdio.c
${CMAKE_CURRENT_SOURCE_DIR}/src/malloc.c
${CMAKE_CURRENT_SOURCE_DIR}/src/string.c
${CMAKE_CURRENT_SOURCE_DIR}/src/ctype.c
${CMAKE_CURRENT_SOURCE_DIR}/src/process.c
${CMAKE_CURRENT_SOURCE_DIR}/src/OSServices.asm
${CMAKE_CURRENT_SOURCE_DIR}/src/Console.c
${CMAKE_CURRENT_SOURCE_DIR}/src/Memory.c
${CMAKE_CURRENT_SOURCE_DIR}/src/String.c
${CMAKE_CURRENT_SOURCE_DIR}/src/Character.c
${CMAKE_CURRENT_SOURCE_DIR}/src/Process.c
)
add_library(term STATIC ${LIBTERM_SOURCES})
set_target_properties(term PROPERTIES NASM_OBJ_FORMAT elf64)
target_compile_options(term PRIVATE $<$<COMPILE_LANGUAGE:C>:${USER_C_FLAGS}>)
target_include_directories(term PUBLIC inc)
add_library(crt0_obj OBJECT src/crt0.asm)
target_compile_options(crt0_obj PRIVATE $<$<COMPILE_LANGUAGE:C>:${USER_C_FLAGS}>)
add_library(RuntimeEntryObject OBJECT src/RuntimeEntry.asm)
set_target_properties(RuntimeEntryObject PROPERTIES NASM_OBJ_FORMAT elf64)
target_compile_options(RuntimeEntryObject PRIVATE $<$<COMPILE_LANGUAGE:C>:${USER_C_FLAGS}>)
function(add_termos_executable NAME SOURCES)
add_executable(${NAME} ${SOURCES})
target_sources(${NAME} PRIVATE $<TARGET_OBJECTS:crt0_obj>)
target_sources(${NAME} PRIVATE $<TARGET_OBJECTS:RuntimeEntryObject>)
target_compile_options(${NAME} PRIVATE $<$<COMPILE_LANGUAGE:C>:${USER_C_FLAGS}>)
target_compile_options(${NAME} PRIVATE $<$<COMPILE_LANGUAGE:C>:${USER_C_FLAGS}>
-fno-stack-protector) # fixme: what the fuck. ugly this works user_c_flags apparently not
target_link_libraries(${NAME} PRIVATE term)
target_link_options(${NAME} PRIVATE
@@ -54,7 +63,9 @@ function(add_termos_executable NAME SOURCES)
)
set(ELF2HOT_DIR "${CMAKE_SOURCE_DIR}/tools/elf2hot")
set(FINAL_HOT_PATH "${CMAKE_SOURCE_DIR}/initramfs/bin/${NAME}")
set(STARTUP_VOLUME_DIR "${CMAKE_BINARY_DIR}/StartupVolume/System/CoreServices")
file(MAKE_DIRECTORY "${STARTUP_VOLUME_DIR}")
set(FINAL_HOT_PATH "${STARTUP_VOLUME_DIR}/${NAME}")
add_custom_command(TARGET ${NAME} POST_BUILD
COMMAND cargo run --release --quiet -- $<TARGET_FILE:${NAME}> ${FINAL_HOT_PATH}
+18
View File
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <Types.h>
enum {
kConsoleInput = 0,
kConsoleOutput = 1,
kConsoleEOF = -1,
kConsoleDefaultBufferSize = 1024
};
Int32 ConsolePrintString(const char* string);
Int32 ConsolePrint(const char* format, ...);
Int32 StringFormat(char* destination, UInt64 size, const char* format, ...);
Int32 ConsoleGetCharacter();
char* ConsoleReadLine(char* string, UInt64 size);
+23
View File
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <Types.h>
enum {
kMemoryBlockMagic = 0x1CE1CE,
kMemoryAlignment = 16,
kMemoryPageSize = 4096
};
typedef struct MemoryBlockHeader {
UInt64 magic;
struct MemoryBlockHeader* next;
struct MemoryBlockHeader* previous;
UInt64 size;
bool isFree;
} MemoryBlockHeader;
void* MemoryAllocate(UInt64 size);
void MemoryFree(void* pointer);
void* MemoryReallocate(void* pointer, UInt64 newSize);
@@ -2,7 +2,7 @@
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <types.h>
#include <Types.h>
Int32 spawn(const char* path);
Int32 wait(UInt64 pid);
Int32 ProcessSpawn(const char* path);
Int32 ProcessWait(UInt64 pid);
+16
View File
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <Types.h>
void* MemorySet(void* destination, UInt8 value, UInt64 count);
void* MemoryCopy(void* destination, const void* source, UInt64 count);
Int32 StringCompare(const char* firstString, const char* secondString);
Int32 StringCompareWithLimit(const char* firstString, const char* secondString, UInt64 limit);
char* StringCopy(char* destination, const char* source);
char* StringCopyWithLimit(char* destination, const char* source, UInt64 limit);
UInt64 StringGetLength(const char* string);
UInt64 StringGetInitialSpan(const char* string, const char* characterSet);
char* StringFindFirstCharacterFromSet(const char* string, const char* accept);
char* StringTokenize(char *s, const char* delim);
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2025 0xKarinyash
// Copyright (c) 2026 0xKarinyash
#pragma once
+8
View File
@@ -0,0 +1,8 @@
#pragma once
#include <Console.h>
#include <Memory.h>
#include <Process.h>
#include <String.h>
#include <Varargs.h>
#include <Types.h>
+160
View File
@@ -0,0 +1,160 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#include <Console.h>
#include <Varargs.h>
#include <String.h>
extern UInt64 OSServiceIORead(UInt64 fileDescriptor, void* buffer, UInt64 length);
extern UInt64 OSServiceIOWrite(UInt64 fileDescriptor, const void* buffer, UInt64 length);
static void sConsoleWriteCharacter(char character) {
OSServiceIOWrite(kConsoleOutput, &character, 1);
}
static inline void sConsoleBufferAdd(char* string, UInt64 size, UInt64* written, char character) {
if (*written < size - 1 && size > 0) {
string[*written] = character;
}
(*written)++;
}
static Int32 sStringFormatVariadic(char* string, UInt64 size, const char* format, va_list args) {
UInt64 written = 0;
for (UInt32 i = 0; format[i] != '\0'; i++) {
if (format[i] == '%') {
i++;
if (format[i] == '\0') break;
switch (format[i]) {
case 's': {
const char* vaArgString = va_arg(args, const char*);
if (!vaArgString) vaArgString = "(null)";
while (*vaArgString) sConsoleBufferAdd(string, size, &written, *vaArgString++);
break;
}
case 'c': {
char character = (char)va_arg(args, int);
sConsoleBufferAdd(string, size, &written, character);
break;
}
case 'd': {
Int64 number = va_arg(args, int);
if (number < 0) {
sConsoleBufferAdd(string, size, &written, '-');
number = -number;
}
UInt64 unsignedNumber = (UInt64)number;
char tempBuffer[32];
Int32 position = 0;
if (unsignedNumber == 0) tempBuffer[position++] = '0';
while (unsignedNumber > 0) {
tempBuffer[position++] = (unsignedNumber % 10) + '0';
unsignedNumber /= 10;
}
while (position > 0) sConsoleBufferAdd(string, size, &written, tempBuffer[--position]);
break;
}
case 'x':
case 'X': {
UInt64 unsignedNumber = va_arg(args, unsigned long long);
UInt8 padding = (format[i] == 'X') ? 16 : 0;
char tempBuffer[32];
int position = 0;
const char* hex = "0123456789ABCDEF";
if (unsignedNumber == 0 && padding == 0) tempBuffer[position++] = '0';
while (unsignedNumber > 0) {
tempBuffer[position++] = hex[unsignedNumber % 16];
unsignedNumber /= 16;
}
while (position < padding) tempBuffer[position++] = '0';
while (position > 0) sConsoleBufferAdd(string, size, &written, tempBuffer[--position]);
break;
}
case '%': {
sConsoleBufferAdd(string, size, &written, '%');
break;
}
default: {
sConsoleBufferAdd(string, size, &written, '%');
sConsoleBufferAdd(string, size, &written, format[i]);
break;
}
}
} else {
sConsoleBufferAdd(string, size, &written, format[i]);
}
}
if (size > 0) {
if (written < size) string[written] = '\0';
else string[size - 1] = '\0';
}
return (int)written;
}
Int32 StringFormat(char* destination, usize size, const char* format, ...) {
va_list args;
va_start(args, format);
int returnValue = sStringFormatVariadic(destination, size, format, args);
va_end(args);
return returnValue;
}
Int32 ConsolePrintString(const char* string) {
return OSServiceIOWrite(kConsoleOutput, string, StringGetLength(string));
}
Int32 ConsolePrint(const char *format, ...) {
char buffer[kConsoleDefaultBufferSize];
va_list args;
va_start(args, format);
int length = sStringFormatVariadic(buffer, sizeof(buffer), format, args);
va_end(args);
UInt64 writeLength = ((UInt64)length < sizeof(buffer)) ? length : (sizeof(buffer) - 1);
OSServiceIOWrite(kConsoleOutput, buffer, writeLength);
return (int)writeLength;
}
Int32 ConsoleGetCharacter() {
char character;
UInt64 serviceCallResult = OSServiceIORead(kConsoleInput, &character, 1);
if (serviceCallResult <= 0) return kConsoleEOF;
return (int)(unsigned char)character;
}
char* ConsoleReadLine(char* string, UInt64 size) {
if (size == 0) return string;
UInt64 i = 0;
int character;
while (i < size - 1) {
character = ConsoleGetCharacter();
if (character == kConsoleEOF || character == '\n' || character == '\r') break;
if (character == '\b') {
if (i > 0) {
i--;
ConsolePrint("\b \b");
}
continue;
}
string[i++] = (char)character;
sConsoleWriteCharacter(character);
}
string[i] = '\0';
sConsoleWriteCharacter('\n');
return string;
}
+104
View File
@@ -0,0 +1,104 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
// brutally copypasting from kernel/mm/heap.c
#include <Memory.h>
#include <String.h>
static MemoryBlockHeader* sMemoryHeapListHead = nullptr;
extern UInt64 OSServiceMemoryAllocate(UInt64 size);
static void sMemoryCombineForward(MemoryBlockHeader* current) {
if (!current->next || !current->next->isFree) return;
current->size += sizeof(MemoryBlockHeader) + current->next->size;
current->next = current->next->next;
if (current->next) current->next->previous = current;
}
void* MemoryAllocate(UInt64 size) {
if (size == 0) return nullptr;
UInt64 alignedSize = (size + (kMemoryAlignment-1)) & ~(kMemoryAlignment - 1);
MemoryBlockHeader* current = sMemoryHeapListHead;
MemoryBlockHeader* lastBlock = nullptr;
while (current) {
if (current->isFree && current->size >= alignedSize) {
if (current->size > alignedSize + sizeof(MemoryBlockHeader) + kMemoryAlignment) {
MemoryBlockHeader* newBlock = (MemoryBlockHeader*)((UInt64)current + sizeof(MemoryBlockHeader) + alignedSize);
newBlock->size = current->size - alignedSize - sizeof(MemoryBlockHeader);
newBlock->isFree = true;
newBlock->next = current->next;
newBlock->previous = current;
newBlock->magic = kMemoryBlockMagic;
if (current->next) current->next->previous = newBlock;
current->next = newBlock;
current->size = alignedSize;
}
current->isFree = false;
return (void*)((UInt64)current + sizeof(MemoryBlockHeader));
}
lastBlock = current;
current = current->next;
}
UInt64 sizeNeededToAllocate = alignedSize + sizeof(MemoryBlockHeader);
UInt64 pageAlignedSize = (sizeNeededToAllocate + (kMemoryPageSize-1)) & ~(kMemoryPageSize-1);
UInt64 newMemoryAddress = OSServiceMemoryAllocate(pageAlignedSize);
if (newMemoryAddress == 0) return nullptr;
MemoryBlockHeader* newBlock = (MemoryBlockHeader*)newMemoryAddress;
newBlock->size = pageAlignedSize - sizeof(MemoryBlockHeader);
newBlock->isFree = true;
newBlock->magic = kMemoryBlockMagic;
newBlock->next = nullptr;
newBlock->previous = lastBlock;
if (lastBlock) {
lastBlock->next = newBlock;
} else {
sMemoryHeapListHead = newBlock;
}
return MemoryAllocate(size);
}
void MemoryFree(void* pointer) {
if (!pointer) return;
MemoryBlockHeader* current = (MemoryBlockHeader*)((UInt64)pointer - sizeof(MemoryBlockHeader));
if (current->magic != kMemoryBlockMagic) return;
current->isFree = true;
if (current->next && current->next->isFree) sMemoryCombineForward(current);
if (current->previous && current->previous->isFree) sMemoryCombineForward(current->previous);
}
void* MemoryReallocate(void* pointer, UInt64 newSize) {
if (!pointer) return MemoryAllocate(newSize);
if (newSize == 0) {
MemoryFree(pointer);
return nullptr;
}
MemoryBlockHeader* current = (MemoryBlockHeader*)((UInt64)pointer - sizeof(MemoryBlockHeader));
if (current->size >= newSize) return pointer;
if (current->next &&
current->next->isFree &&
(current->size + sizeof(MemoryBlockHeader) + current->next->size) >= newSize) {
sMemoryCombineForward(current);
return pointer;
}
void* newPointer = MemoryAllocate(newSize);
if (!newPointer) return nullptr;
MemoryCopy(newPointer, pointer, current->size);
MemoryFree(pointer);
return newPointer;
}
@@ -5,39 +5,39 @@ bits 64
section .text
global sys_exit
global sys_spawn
global sys_mem
global sys_write
global sys_read
global sys_wait
global OSServiceProcessExit
global OSServiceProcessSpawn
global OSServiceMemoryAllocate
global OSServiceIOWrite
global OSServiceIORead
global OSServiceProcessWait
sys_exit:
OSServiceProcessExit:
mov rax, 0
syscall
ret
sys_spawn:
OSServiceProcessSpawn:
mov rax, 1
syscall
ret
sys_mem:
OSServiceMemoryAllocate:
mov rax, 2
syscall
ret
sys_write:
OSServiceIOWrite:
mov rax, 3
syscall
ret
sys_read:
OSServiceIORead:
mov rax, 4
syscall
ret
sys_wait:
OSServiceProcessWait:
mov rax, 5
syscall
ret
+15
View File
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#include <Process.h>
extern Int32 OSServiceProcessSpawn(const char* path);
extern Int32 OSServiceProcessWait(UInt64 pid);
Int32 ProcessSpawn(const char* path) {
return OSServiceProcessSpawn(path);
}
Int32 ProcessWait(UInt64 pid) {
return OSServiceProcessWait(pid);
}
@@ -6,9 +6,9 @@
section .text
global _start
extern main
extern sys_exit
extern OSServiceProcessExit
_start:
call main
mov rdi, rax
call sys_exit
call OSServiceProcessExit
+126
View File
@@ -0,0 +1,126 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#include <String.h>
static char* olds;
void* MemorySet(void* destination, UInt8 value, UInt64 count) {
UInt8* bytePointer = (UInt8*) destination;
while (count--) {
*bytePointer++ = (UInt8)value;
}
return destination;
}
void* MemoryCopy(void* destination, const void* source, UInt64 count) {
UInt8* destinationBuffer = (UInt8*)destination;
const UInt8* sourceBuffer = (const UInt8*)source;
while (count >= 8) {
*(UInt64*)destinationBuffer = *(const UInt64*)sourceBuffer;
destinationBuffer += 8;
sourceBuffer += 8;
count -= 8;
}
while (count > 0) {
*destinationBuffer++ = *sourceBuffer++;
count--;
}
return destination;
}
Int32 StringCompare(const char* firstString, const char* secondString) {
while (*firstString && (*firstString == *secondString)) {
firstString++;
secondString++;
}
return *(const unsigned char*)firstString - *(const unsigned char*)secondString;
}
Int32 StringCompareWithLimit(const char* firstString, const char* secondString, UInt64 limit) {
while (limit > 0) {
if (*firstString != *secondString) return *(unsigned char*)firstString - *(unsigned char*)secondString;
if (*firstString == '\0') return 0;
firstString++;
secondString++;
limit--;
}
return 0;
}
char* StringCopy(char* destination, const char* source) {
char* saved = destination;
while (*source) *destination++ = *source++;
*destination = 0;
return saved;
}
char* StringCopyWithLimit(char* destination, const char* source, UInt64 limit) {
char* saved = destination;
while (*source && limit > 0) {
*destination++ = *source++;
limit--;
}
while (limit > 0) {
*destination++ = 0;
limit--;
}
return saved;
}
UInt64 StringGetLength(const char* string) {
UInt64 result = 0;
for (result = 0; string[result]; result++);
return result;
}
static inline int sStringIsInSet(char character, const char* set) {
while (*set) {
if (*set == character) return 1;
set++;
}
return 0;
}
UInt64 StringGetInitialSpan(const char* string, const char* characterSet) {
UInt64 count = 0;
while (*string && sStringIsInSet(*string, characterSet)) {
count++;
string++;
}
return count;
}
char* StringFindFirstCharacterFromSet(const char* string, const char* set) {
while (*string) {
if (sStringIsInSet(*string, set)) {
return (char*)string;
}
string++;
}
return nullptr;
}
// took from https://github.com/walac/glibc/blob/master/string/strtok.c
char* StringTokenize(char* string, const char* delimiters) {
char* token;
if (string == nullptr) string = olds;
string += StringGetInitialSpan(string, delimiters);
if (*string == '\0') {
olds = string;
return nullptr;
}
token = string;
string = StringFindFirstCharacterFromSet(token, delimiters);
if (string == nullptr) olds = token + StringGetLength(token);
else {
*string = '\0';
olds = string + 1;
}
return token;
}
+15
View File
@@ -0,0 +1,15 @@
[env]
RUST_TARGET_PATH = { value = ".", relative = true }
[build]
target = "x86_64-termos"
[unstable]
build-std =["core", "alloc", "compiler_builtins"]
build-std-features = ["compiler-builtins-mem"]
[target.x86_64-termos]
rustflags =[
"-Z", "unstable-options",
"-C", "link-arg=-Tlinker.ld"
]
+33
View File
@@ -0,0 +1,33 @@
cmake_minimum_required(VERSION 3.16)
project(rustApps NONE)
function(add_rust_app NAME)
set(RUST_TARGET "x86_64-termos")
set(RUST_TARGET_DIR "${CMAKE_CURRENT_SOURCE_DIR}/target")
set(RUST_ELF_FILE "${RUST_TARGET_DIR}/${RUST_TARGET}/release/${NAME}")
set(STARTUP_VOLUME_DIR "${CMAKE_BINARY_DIR}/StartupVolume/System/CoreServices")
set(FINAL_HOT_PATH "${STARTUP_VOLUME_DIR}/${NAME}")
set(STRIPPED_ELF "${CMAKE_CURRENT_BINARY_DIR}/${NAME}.stripped")
set(ELF2HOT_DIR "${CMAKE_SOURCE_DIR}/tools/elf2hot")
file(MAKE_DIRECTORY "${STARTUP_VOLUME_DIR}")
add_custom_target(${NAME} ALL
COMMAND ${CMAKE_COMMAND} -E env
"CARGO_TARGET_DIR=${RUST_TARGET_DIR}"
cargo build --package ${NAME} --release --target ${RUST_TARGET}
COMMAND ${CMAKE_COMMAND} -E env
"PATH=/usr/local/opt/llvm/bin:/opt/homebrew/opt/llvm/bin:$ENV{PATH}"
llvm-objcopy --strip-all ${RUST_ELF_FILE} ${STRIPPED_ELF}
COMMAND ${CMAKE_COMMAND} -E chdir ${ELF2HOT_DIR} cargo run --release --quiet -- ${STRIPPED_ELF} ${FINAL_HOT_PATH}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Building, stripping and packing ${NAME} to initramfs..."
VERBATIM
)
endfunction()
add_rust_app(rtest)
+50
View File
@@ -0,0 +1,50 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "linked_list_allocator"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b23ac50abb8261cb38c6e2a7192d3302e0836dac1628f6a93b82b4fad185897"
dependencies = [
"spinning_top",
]
[[package]]
name = "lock_api"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
dependencies = [
"scopeguard",
]
[[package]]
name = "rtest"
version = "0.1.0"
dependencies = [
"std",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "spinning_top"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0"
dependencies = [
"lock_api",
]
[[package]]
name = "std"
version = "0.1.0"
dependencies = [
"linked_list_allocator",
]
+5
View File
@@ -0,0 +1,5 @@
[workspace]
members = ["std", "apps/rtest"]
[profile.release]
strip = true
+7
View File
@@ -0,0 +1,7 @@
[package]
name = "rtest"
version = "0.1.0"
edition = "2024"
[dependencies]
std = { path = "../../std" }
+4
View File
@@ -0,0 +1,4 @@
fn main() {
let anus = "jopa";
println!("meow");
}
+35
View File
@@ -0,0 +1,35 @@
ENTRY(_start)
SECTIONS
{
. = 0x400000;
.text : {
*(.text)
}
.rodata : {
*(.rodata)
}
.data : {
*(.data)
}
.bss : {
*(.bss)
*(COMMON)
}
/DISCARD/ : {
*(.note.gnu.build-id)
*(.note.GNU-stack)
*(.note.gnu.property)
*(.comment)
*(.interp)
*(.dynsym)
*(.dynstr)
*(.hash)
*(.gnu.hash)
}
}
+2
View File
@@ -0,0 +1,2 @@
[toolchain]
channel = "nightly"
+7
View File
@@ -0,0 +1,7 @@
[package]
name = "std"
version = "0.1.0"
edition = "2024"
[dependencies]
linked_list_allocator = "0.10.6"
+14
View File
@@ -0,0 +1,14 @@
extern crate alloc;
use core::alloc::{GlobalAlloc, Layout};
use linked_list_allocator::LockedHeap;
#[global_allocator]
static ALLOCATOR: LockedHeap = LockedHeap::empty();
pub unsafe fn init_heap() {
let heap_size = 1024 * 1024;
let heap_start = crate::syscall::memory_allocate(heap_size);
ALLOCATOR.lock().init(heap_start as *mut u8, heap_size);
}
+30
View File
@@ -0,0 +1,30 @@
use core::fmt::{self, Write};
pub struct Stdout;
impl Write for Stdout {
fn write_str(&mut self, s: &str) -> fmt::Result {
crate::syscall::io_write(1, s.as_ptr(), s.len());
Ok(())
}
}
#[doc(hidden)]
pub fn _print(args: core::fmt::Arguments) {
let mut stdout = crate::io::Stdout;
let _ = core::fmt::Write::write_fmt(&mut stdout, args);
}
#[macro_export]
macro_rules! print {
($($arg:tt)*) => ($crate::io::_print(core::format_args!($($arg)*)));
}
#[macro_export]
macro_rules! println {
() => ($crate::print!("\n"));
($($arg:tt)*) => {
$crate::print!($($arg)*);
$crate::print!("\n");
};
}
+49
View File
@@ -0,0 +1,49 @@
#![no_std]
#![feature(lang_items)]
pub use core::*;
extern crate alloc;
pub use alloc::*;
pub mod allocator;
pub mod io;
pub mod panic;
pub mod syscall;
pub mod prelude {
pub mod rust_2024 {
pub use core::prelude::rust_2024::*;
pub use alloc::string::{String, ToString};
pub use alloc::vec::Vec;
pub use alloc::vec;
pub use alloc::format;
pub use crate::{print, println};
}
}
core::arch::global_asm!(
".global _start",
"_start:",
"and rsp, ~0xF",
"xor rdi, rdi",
"xor rsi, rsi",
"call main",
"mov rdi, rax",
"mov rax, 0",
"syscall"
);
#[lang = "start"]
fn lang_start<T>(
user_main: fn() -> T,
_argc: isize,
_argv: *const *const u8,
_sigpipe: u8,
) -> isize {
unsafe { crate::allocator::init_heap() };
user_main();
crate::syscall::process_exit(0);
}
+9
View File
@@ -0,0 +1,9 @@
use core::panic::PanicInfo;
use crate::println;
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
println!("{}", info);
crate::syscall::process_exit(1);
}
+66
View File
@@ -0,0 +1,66 @@
use core::arch::asm;
pub const SYS_EXIT: usize = 0;
pub const SYS_SPAWN: usize = 1;
pub const SYS_ALLOC: usize = 2;
pub const SYS_WRITE: usize = 3;
pub const SYS_READ: usize = 4;
pub const SYS_WAIT: usize = 5;
#[inline(always)]
unsafe fn syscall1(num: usize, arg1: usize) -> usize {
let ret: usize;
unsafe {
asm!(
"syscall",
inout("rax") num => ret,
in("rdi") arg1,
out("rcx") _,
out("r11") _,
options(nostack, preserves_flags)
);
}
ret
}
#[inline(always)]
unsafe fn syscall3(num: usize, arg1: usize, arg2: usize, arg3: usize) -> usize {
let ret: usize;
core::arch::asm!(
"syscall",
in("rax") num,
in("rdi") arg1,
in("rsi") arg2,
in("rdx") arg3,
lateout("rax") ret,
out("rcx") _,
out("r11") _,
options(nostack)
);
ret
}
pub fn process_exit(code: usize) -> ! {
unsafe { syscall1(SYS_EXIT, code) };
loop {}
}
pub fn process_spawn(path: usize) -> usize {
unsafe { syscall1(SYS_SPAWN, path) }
}
pub fn process_wait(pid: usize) -> usize {
unsafe { syscall1(SYS_WAIT, pid) }
}
pub fn memory_allocate(size: usize) -> usize {
unsafe { syscall1(SYS_ALLOC, size) }
}
pub fn io_write(fd: usize, buf: *const u8, len: usize) -> usize {
unsafe { syscall3(SYS_WRITE, fd, buf as usize, len) }
}
pub fn io_read(fd: usize, buf: *const u8, len: usize) -> usize {
unsafe { syscall3(SYS_READ, fd, buf as usize, len) }
}
+15
View File
@@ -0,0 +1,15 @@
{
"llvm-target": "x86_64-unknown-none",
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
"arch": "x86_64",
"target-endian": "little",
"target-pointer-width": 64,
"target-c-int-width": 32,
"os": "termos",
"executables": true,
"linker-flavor": "ld.lld",
"linker": "rust-lld",
"panic-strategy": "abort",
"position-independent-executables": true,
"relocation-model": "pic"
}
+5
View File
@@ -0,0 +1,5 @@
#include <termOS.h>
void not_implemented_yet() {
ConsolePrint("Not implemented yet!\n");
}
+16
View File
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#include "handlers.h"
#include <termOS.h>
void cmd_spawn(const char* path) {
Int32 pid = ProcessSpawn(path);
if (pid < 0) {
switch (pid) {
case -1: ConsolePrint("\"%s\" not found.\n", path); break;
default: ConsolePrint("failed to spawn (%d)\n", pid); break;
}
} else {
ProcessWait(pid);
}
}
@@ -1,19 +1,17 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#include "tokens.h"
#include <termOS.h>
#include "parser.h"
#include "handlers.h"
#include <stdio.h>
#define BUFFER_SIZE 512
int main() {
while (true) {
printf("termosh_> ");
ConsolePrint("termosh_> ");
char cmdbuff[BUFFER_SIZE];
gets_s(cmdbuff, BUFFER_SIZE);
ConsoleReadLine(cmdbuff, BUFFER_SIZE);
char* tokens[BUFFER_SIZE];
int tokens_count = tokenize(cmdbuff, tokens, BUFFER_SIZE);
if (tokens_count < 1) continue;
@@ -25,7 +23,7 @@ int main() {
case TOKEN_SPAWN: if (tokens_count >= 2) cmd_spawn(tokens[1]); break;
default: {
char buff[256];
snprintf(buff, sizeof(buff), "/bin/%s", tokens[0]);
StringFormat(buff, sizeof(buff), "/System/CoreServices/%s", tokens[0]);
cmd_spawn(buff);
}
}
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#include <string.h>
#include <termOS.h>
#include "parser.h"
#include "tokens.h"
@@ -27,7 +27,7 @@ static const termosh_token_map token_map[] = {
termosh_token char2token(char* token) {
for (int i = 0; token_map[i].str != nullptr; i++) {
if (strcmp(token, token_map[i].str) == 0) {
if (StringCompare(token, token_map[i].str) == 0) {
return token_map[i].token;
}
}
@@ -36,12 +36,12 @@ termosh_token char2token(char* token) {
}
int tokenize(char* buffer, char* tokens[], int max_tokens) {
char* token = strtok(buffer, delim);
char* token = StringTokenize(buffer, delim);
int i = 0;
while (token != nullptr && i < max_tokens) {
tokens[i] = token;
token = strtok(nullptr, delim);
token = StringTokenize(nullptr, delim);
i++;
}
@@ -11,6 +11,17 @@ endif()
message(STATUS "Dewar kernel: Building for architecture '${ARCH}'")
set(TERMOS_OBJCOPY objcopy)
if(APPLE)
find_program(TERMOS_LD_LLD NAMES ld.lld HINTS /usr/local/bin /opt/homebrew/bin REQUIRED)
find_program(TERMOS_OBJCOPY NAMES llvm-objcopy objcopy HINTS /usr/local/opt/llvm/bin /opt/homebrew/opt/llvm/bin REQUIRED)
set(CMAKE_C_LINK_FLAGS "")
set(CMAKE_ASM_NASM_COMPILE_OBJECT
"<CMAKE_ASM_NASM_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -MD <DEP_FILE> -MT <DEP_TARGET> -f elf64 -o <OBJECT> <SOURCE>")
set(CMAKE_C_LINK_EXECUTABLE
"${TERMOS_LD_LLD} <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
endif()
file(GLOB_RECURSE KERNEL_SOURCES CMAKE_CONFIGURE_DEPENDS
"src/kmain.c"
@@ -24,13 +35,13 @@ file(GLOB_RECURSE KERNEL_SOURCES CMAKE_CONFIGURE_DEPENDS
"src/lib/*.c"
"src/IO/*.c"
"src/VM/*.c"
"src/shell/*.c"
"src/FS/*.c"
"Data/*.c"
)
add_executable(kernel ${KERNEL_SOURCES})
set_target_properties(kernel PROPERTIES NASM_OBJ_FORMAT elf64)
target_include_directories(kernel PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/../common"
@@ -41,6 +52,7 @@ target_include_directories(kernel PRIVATE
target_compile_options(kernel PRIVATE
$<$<COMPILE_LANGUAGE:C>:
$<$<BOOL:${APPLE}>:--target=x86_64-none-elf>
-ffreestanding
-mno-red-zone
-fno-stack-protector
@@ -48,7 +60,9 @@ target_compile_options(kernel PRIVATE
-Wall -Wextra
-mcmodel=kernel
-g
-mno-sse -mno-sse2 -msoft-float
>
$<$<AND:$<BOOL:${APPLE}>,$<COMPILE_LANGUAGE:ASM>>:--target=x86_64-none-elf>
)
target_link_options(kernel PRIVATE
@@ -65,6 +79,8 @@ set_target_properties(kernel PROPERTIES
)
add_custom_command(TARGET kernel POST_BUILD
COMMAND objcopy -O binary $<TARGET_FILE:kernel> $<TARGET_FILE_DIR:kernel>/kernel.bin
COMMAND ${CMAKE_COMMAND} -E env
"PATH=/usr/local/opt/llvm/bin:/opt/homebrew/opt/llvm/bin:$ENV{PATH}"
llvm-objcopy -O binary $<TARGET_FILE:kernel> $<TARGET_FILE_DIR:kernel>/kernel.bin
COMMENT "Generating raw binary kernel.bin..."
)
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2025 0xKarinyash
// Copyright (c) 2026 0xKarinyash
// cats licensed to their authors
// i took it from https://www.asciiart.eu/animals/cats
@@ -1,6 +1,6 @@
// Huge thanks to https://t.me/kinolenta2004 for this amazing logo
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2025 0xKarinyash
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <IO/IOGraphics.h>
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2025 0xKarinyash
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <IO/IOGraphics.h>
@@ -29,7 +29,6 @@ IOGraphicsSize IOConsoleGetDimensions();
void IOConsoleSetForegroundColor(IOGraphicsColor color);
void IOConsoleSetDefaultForegroundColor(UInt32 color);
void IOConsoleSetCursorPosition(IOGraphicsPoint* point);
char IOConsoleGetCharacter();
void IOConsoleReadLine(char* buffer, UInt32 limit);
void IOConsolePutcharacter(char character);
void IOConsolePrint(const char *string);
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2025 0xKarinyash
// Copyright (c) 2026 0xKarinyash
// RIP shitgui -- you started it all
#pragma once
+22
View File
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <types.h>
#include <OS/OSSpinlock.h>
enum {
kIOKeyboardBufferSize = 256,
};
typedef struct {
OSSpinlock lock;
char buffer[kIOKeyboardBufferSize];
volatile UInt16 head;
volatile UInt16 tail;
} IOKeyboardController;
extern IOKeyboardController gIOKeyboardController;
void IOKeyboardInterruptsHandler();
char IOKeyboardGetCharacter();
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2025 0xKarinyash
// Copyright (c) 2026 0xKarinyash
#pragma once
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2025 0xKarinyash
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <types.h>
@@ -6,4 +6,4 @@
#include <types.h>
Int32 OSLoaderProcessSpawn(const char* executablePath, const char* processName);
void init_task_entry();
void initTask();
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2025 0xKarinyash
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <types.h>
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2025 0xKarinyash
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <types.h>
@@ -29,6 +29,7 @@ typedef struct OSTask {
UInt32 sleepTicks;
OSProcessState taskState; // reusing process_state cuz wn
UInt64 kernelStackTop;
void* kernelStackBase;
OSProcess* process;
Int32 waitingForProcess;
} OSTask;
+19
View File
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <types.h>
typedef struct OSSpinlock {
volatile UInt32 lockValue;
} OSSpinlock;
typedef struct OSSpinlockState {
Boolean interruptsEnabled;
} OSSpinlockState;
void OSSpinlockLock(OSSpinlock* lock);
void OSSpinlockUnlock(OSSpinlock* lock);
void OSSpinlockLockIRQ(OSSpinlock* lock, OSSpinlockState* state);
void OSSpinlockUnlockIRQ(OSSpinlock *lock, OSSpinlockState* state);
+8
View File
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <types.h>
UInt64 OSServiceIOWrite(UInt64 fileDescriptor, UInt64 buffer, UInt64 length);
UInt64 OSServiceIORead(UInt64 fileDescriptor, UInt64 buffer, UInt64 count);
@@ -4,4 +4,4 @@
#pragma once
#include <types.h>
UInt64 OSServiceMemoryGet(UInt64 size);
UInt64 OSServiceMemoryAllocate(UInt64 size);
@@ -1,19 +1,17 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2025 0xKarinyash
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <types.h>
enum {
kVMKernelHeapStart = 0xFFFFFFFFC0000000,
kVMHeapSizePages = 1024
kVMHeapSizePages = 1024,
kVMHeapBlockHeaderMagic = 0x1CE
};
#define PHYS_TO_HEAP(phys) ((phys) + KERNEL_HEAP_START)
#define HEAP_TO_PHYS(phys) ((phys) - KERNEL_HEAP_START)
#define HEADER_MAGIC 0x1CE
typedef struct VMHeapBlockHeader {
UInt64 magic;
struct VMHeapBlockHeader* next;
@@ -23,6 +21,6 @@ typedef struct VMHeapBlockHeader {
} VMHeapBlockHeader;
void VMHeapInitialize();
void* malloc(UInt64 size);
void free(void* ptr);
void* realloc(void* ptr, UInt64 newSize);
void* VMHeapAllocate(UInt64 size);
void VMHeapFree(void* ptr);
void* VMHeapResize(void* ptr, UInt64 newSize);
+1 -1
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2025 0xKarinyash
// Copyright (c) 2026 0xKarinyash
#pragma once
#include "bootinfo.h"
+2 -1
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2025 0xKarinyash
// Copyright (c) 2026 0xKarinyash
#pragma once
#include "bootinfo.h"
@@ -37,6 +37,7 @@
void VMVirtualMemoryInitialize(Bootinfo* info);
UInt64* VMVirtualMemoryMapPage(UInt64* PML4, UInt64 physical, UInt64 virtual, UInt64 flags);
void* VMVirtualMemoryGetOrAllocatePage(UInt64* PML4, UInt64 virtual, UInt64 flags);
UInt64 VMVirtualMemoryCreateAddressSpace();
UInt64 VMGetCurrentCR3();
void VMLoadCR3(UInt64 PML4Address);
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2025 0xKarinyash
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <types.h>
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2025 0xKarinyash
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <types.h>
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2025 0xKarinyash
// Copyright (c) 2026 0xKarinyash
#pragma once
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2025 0xKarinyash
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <types.h>
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2025 0xKarinyash
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <types.h>
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2025 0xKarinyash
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <types.h>
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2025 0xKarinyash
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <IO/IOGraphics.h>
+14
View File
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <types.h>
void* MemorySet(void* destination, UInt8 value, UInt64 count);
void* MemoryCopy(void* destination, const void* source, UInt64 count);
Int32 StringCompare(const char* firstString, const char* secondString);
Int32 StringCompareWithLimit(const char* firstString, const char* secondString, UInt64 limit);
char* StringCopy(char* destination, const char* source);
char* StringCopyWithLimit(char* destination, const char* source, UInt64 limit);
UInt64 StringGetLength(const char* string);
const char* StringFindLastOccurrenceOfCharacter(const char* string, char separator);
+1 -1
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2025 0xKarinyash
// Copyright (c) 2026 0xKarinyash
#pragma once
+1 -1
View File
@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
Copyright (c) 2025 0xKarinyash */
Copyright (c) 2026 0xKarinyash */
ENTRY(_start)
+10 -10
View File
@@ -51,7 +51,7 @@ UInt64 FSCPIORead(FSVNode* node, UInt64 offset, UInt64 size, UInt8* buffer) {
if (offset > node->dataLength) return 0;
if ((offset + size) > node->dataLength) size = node->dataLength - offset;
memcpy(buffer, (char*)node->implementationData + offset, size);
MemoryCopy(buffer, (char*)node->implementationData + offset, size);
return size;
}
@@ -59,11 +59,11 @@ FSVNode* FSCPIOMount(void* baseAddress, UInt64 totalSize) {
UInt8* currentPointer = (UInt8*)baseAddress;
UInt8* endPointer = currentPointer + totalSize;
FSVNode* rootNode = (FSVNode*)malloc(sizeof(FSVNode));
FSVNode* rootNode = (FSVNode*)VMHeapAllocate(sizeof(FSVNode));
if (!rootNode) OSPanic("CPIO: Failed to allocate memory for root node");
memset(rootNode, 0, sizeof(FSVNode));
strcpy(rootNode->name, "/");
MemorySet(rootNode, 0, sizeof(FSVNode));
StringCopy(rootNode->name, "/");
rootNode->flags = kFSVNodeFlagDirectory;
rootNode->operations = &gFSCPIOOperations;
@@ -72,25 +72,25 @@ FSVNode* FSCPIOMount(void* baseAddress, UInt64 totalSize) {
while (currentPointer < endPointer) {
FSCPIOHeader* header = (FSCPIOHeader*)currentPointer;
if (strncmp(header->magic, "070701", 6) != 0) {
OSPanic("CPIO: Invalid magic detected in initramfs");
if (StringCompareWithLimit(header->magic, "070701", 6) != 0) {
OSPanic("CPIO: Invalid magic detected in StartupVolume");
}
UInt64 nameSize = sFSCPIOHexadecimalToUInt64(header->nameLength, 8);
UInt64 fileSize = sFSCPIOHexadecimalToUInt64(header->fileLength, 8);
char* fileName = (char*)(currentPointer + sizeof(FSCPIOHeader));
if (strcmp(fileName, "TRAILER!!!") == 0) break;
if (StringCompare(fileName, "TRAILER!!!") == 0) break;
UInt64 headerAndNameLength = sizeof(FSCPIOHeader) + nameSize;
UInt64 offsetToData = FSCPIO_ALIGN4(headerAndNameLength);
void* fileContent = (void*)(currentPointer + offsetToData);
FSVNode* newNode = (FSVNode*)malloc(sizeof(FSVNode));
FSVNode* newNode = (FSVNode*)VMHeapAllocate(sizeof(FSVNode));
if (!newNode) OSPanic("CPIO: Failed to allocate memory for new node");
memset(newNode, 0, sizeof(FSVNode));
strncpy(newNode->name, fileName, sizeof(newNode->name) - 1);
MemorySet(newNode, 0, sizeof(FSVNode));
StringCopyWithLimit(newNode->name, fileName, sizeof(newNode->name) - 1);
newNode->dataLength = fileSize;
newNode->inodeIdentifier = sFSCPIOHexadecimalToUInt64(header->inode, 8);
+2 -2
View File
@@ -23,7 +23,7 @@ FSVNode* FSVirtualFileSystemOpenPath(const char* path) {
return nullptr;
}
if (strcmp(path, "/") == 0) {
if (StringCompare(path, "/") == 0) {
return gFSVirtualFileSystemRoot;
}
@@ -34,7 +34,7 @@ FSVNode* FSVirtualFileSystemOpenPath(const char* path) {
FSVNode* nodeIterator = gFSVirtualFileSystemRoot->childNode;
while (nodeIterator != nullptr) {
if (strcmp(nodeIterator->name, searchName) == 0) {
if (StringCompare(nodeIterator->name, searchName) == 0) {
if (nodeIterator->operations && nodeIterator->operations->open) {
nodeIterator->operations->open(nodeIterator);
}

Some files were not shown because too many files have changed in this diff Show More