v0.5.3-pre: refactor syscall handlers and introduce libterm

Moved handlers to syscalls/, implemented libterm (malloc, stdio)
This commit is contained in:
Karina
2026-01-30 04:58:43 +04:00
parent 9c103218d0
commit 888bc5abdd
41 changed files with 818 additions and 103 deletions
+1 -1
View File
@@ -42,7 +42,7 @@ if(MCOPY_EXE AND MKFS_EXE AND CPIO_EXE)
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR} 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}\"" COMMAND sh -c "find . -mindepth 1 ! -name '*.cpio' -print0 | ${CPIO_EXE} --null -ov -H newc > \"${INITRAMFS_CPIO_FILE}\""
WORKING_DIRECTORY ${INITRAMFS_SRC_DIR} WORKING_DIRECTORY ${INITRAMFS_SRC_DIR}
DEPENDS ${INIT_FILES} init_elf DEPENDS ${INIT_FILES} init debug
VERBATIM VERBATIM
COMMENT "Packing initramfs to cpio..." COMMENT "Packing initramfs to cpio..."
) )
+1
View File
@@ -23,6 +23,7 @@ file(GLOB_RECURSE KERNEL_SOURCES CMAKE_CONFIGURE_DEPENDS
"src/mm/*.c" "src/mm/*.c"
"src/shell/*.c" "src/shell/*.c"
"src/fs/*.c" "src/fs/*.c"
"src/syscalls/*.c"
"data/*.c" "data/*.c"
) )
+3 -1
View File
@@ -13,8 +13,10 @@
typedef enum { typedef enum {
SYS_EXIT, SYS_EXIT,
SYS_EXEC, SYS_SPAWN,
SYS_MEM,
SYS_WRITE, SYS_WRITE,
SYS_READ,
} syscalls; } syscalls;
void syscall_init(); void syscall_init();
+1 -2
View File
@@ -4,7 +4,6 @@
#pragma once #pragma once
#include <types.h> #include <types.h>
#include <core/scheduler.h>
bool exec_init(process* p, const char* path); i32 process_spawn(const char* path, const char* name);
void init_task_entry(); void init_task_entry();
+3
View File
@@ -15,6 +15,8 @@ typedef struct process {
u64 pml4_phys; u64 pml4_phys;
struct process* parent; struct process* parent;
char name[32]; char name[32];
u64 heap_start;
u64 heap_cur;
} process; } process;
typedef struct task { typedef struct task {
@@ -22,6 +24,7 @@ typedef struct task {
struct task* next; struct task* next;
u32 id; u32 id;
u32 sleep_ticks; u32 sleep_ticks;
process_state task_state; // reusing process_state cuz wn
u64 kernel_stack_top; u64 kernel_stack_top;
process* proc; process* proc;
} task; } task;
+1
View File
@@ -13,6 +13,7 @@ void console_set_color(u32 color);
void console_set_default_color(u32 color); void console_set_default_color(u32 color);
void console_set_cursor_pos(SG_Point *p); void console_set_cursor_pos(SG_Point *p);
char console_getc(); char console_getc();
void console_putc(char c);
void kprint(const char *str); void kprint(const char *str);
void kprintf(const char *fmt, ...); void kprintf(const char *fmt, ...);
void kgets(char* buff, u32 lim); void kgets(char* buff, u32 lim);
+8
View File
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <types.h>
u64 sys_write(u64 fd, u64 buff, u64 len);
u64 sys_read(u64 fd, u64 buff, u64 count);
+7
View File
@@ -0,0 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <types.h>
u64 sys_mem(u64 size);
+9
View File
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <types.h>
u64 sys_exit(i32 code);
u64 sys_spawn(const char* path);
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash // Copyright (c) 2026 0xKarinyash
#include "types.h" #include <types.h>
#include <cpuinfo.h> #include <cpuinfo.h>
#define MSR_GS_BASE 0xC0000101 #define MSR_GS_BASE 0xC0000101
-1
View File
@@ -60,7 +60,6 @@ syscall_entry:
pop r11 ; rflags pop r11 ; rflags
add rsp, 8 ; skip rsp add rsp, 8 ; skip rsp
mov [gs:8], rsp
mov rsp, [gs:0] mov rsp, [gs:0]
swapgs swapgs
+11 -13
View File
@@ -8,6 +8,10 @@
#include <mm/pmm.h> #include <mm/pmm.h>
#include <mm/vmm.h> #include <mm/vmm.h>
#include <syscalls/proc.h>
#include <syscalls/mem.h>
#include <syscalls/io.h>
static inline void wrmsr(u32 msr, u64 val) { static inline void wrmsr(u32 msr, u64 val) {
u32 low = (u32)val; u32 low = (u32)val;
u32 high = (u32)(val >> 32); u32 high = (u32)(val >> 32);
@@ -47,20 +51,14 @@ void syscall_init() {
} }
u64 syscall_dispatch(u64 id, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5) { u64 syscall_dispatch(u64 id, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5) {
__asm__ volatile("cli");
switch (id) { switch (id) {
case SYS_EXIT: { case SYS_EXIT: return sys_exit(arg1);
kprintf("\n[Dewar] process exited with code %d", arg1); case SYS_SPAWN: return sys_spawn((const char*)arg1);
while(1) __asm__ ("hlt"); // stub case SYS_MEM: return sys_mem(arg1);
return 0; case SYS_WRITE: return sys_write(arg1, arg2, arg3);
} case SYS_READ: return sys_read(arg1, arg2, arg3);
case SYS_EXEC: {
kprintf("\n[Dewar] process called exec syscall");
return 0; // stub as well
}
case SYS_WRITE: {
kprintf("%s", (char*)arg1);
return 0;
}
default: kprintf("[Dewar] Unknown syscall %d\n", id); return -1; default: kprintf("[Dewar] Unknown syscall %d\n", id); return -1;
} }
__asm__ volatile("sti");
} }
+16 -13
View File
@@ -19,27 +19,30 @@ u64 load_hot(process* proc, u8* data) {
} }
hot_segment* segments = (hot_segment*)(data + sizeof(hot_header)); hot_segment* segments = (hot_segment*)(data + sizeof(hot_header));
u64 kernel_cr3 = vmm_get_current_cr3();
for (u64 i = 0; i < header->segments_count; i++) { for (u64 i = 0; i < header->segments_count; i++) {
hot_segment* seg = &segments[i]; hot_segment* seg = &segments[i];
if (seg->memsz == 0) continue; if (seg->memsz == 0) continue;
u64 start = seg->vaddr & ~(0xFFF); u64 start = seg->vaddr & ~(0xFFFULL);
u64 end = (seg->vaddr + seg->memsz + 0xFFF) & ~(0xFFF); u64 end = (seg->vaddr + seg->memsz + 0xFFF) & ~(0xFFFULL);
for (u64 addr = start; addr < end; addr += PAGE_SIZE) { for (u64 addr = start; addr < end; addr += PAGE_SIZE) {
void* phys = pmm_alloc_page(); void* phys = pmm_alloc_page();
vmm_map_page((u64*)proc->pml4_phys, (u64)phys, addr, PTE_USER | PTE_RW | PTE_PRESENT); vmm_map_page((u64*)proc->pml4_phys, (u64)phys, addr, PTE_USER | PTE_RW | PTE_PRESENT);
} void* kernel_virt = (void*)((u64)phys + HHDM_OFFSET);
memset(kernel_virt, 0, PAGE_SIZE);
u64 page_overleap_start = (addr > seg->vaddr) ? addr : seg->vaddr;
u64 page_overleap_end = (addr + PAGE_SIZE < seg->vaddr + seg->filesz)
? (addr + PAGE_SIZE)
: (seg->vaddr + seg->filesz);
if (page_overleap_start < page_overleap_end) {
u64 copy_size = page_overleap_end - page_overleap_start;
u64 src_offset = seg->offset + (page_overleap_start - seg->vaddr);
u64 dst_offset = page_overleap_start - addr;
load_cr3(proc->pml4_phys); memcpy((u8*)kernel_virt + dst_offset, data + src_offset, copy_size);
if (seg->filesz > 0) memcpy((void*)seg->vaddr, data + seg->offset, seg->filesz); }
if (seg->memsz > seg->filesz) {
u64 bss_start = seg->vaddr + seg->filesz;
u64 bss_len = seg->memsz - seg->filesz;
memset((void*)bss_start, 0, bss_len);
} }
load_cr3(kernel_cr3);
} }
return header->entry_point; return header->entry_point;
+35 -15
View File
@@ -20,28 +20,48 @@
#include <types.h> #include <types.h>
extern task* curr_task; extern task* curr_task;
extern u32 next_pid;
#define USER_STACK_TOP 0x70000000 #define USER_STACK_TOP 0x70000000
#define HEAP_START 0x40000000
void init_task_entry() { i32 process_spawn(const char* path, const char* name) {
process* init_proc = (process*)malloc(sizeof(process)); fs_node* file = vfs_open(path);
init_proc->pid = 1; if (!file) return -1;
init_proc->state = RUNNING;
init_proc->pml4_phys = vmm_create_address_space();
strcpy(init_proc->name, "init");
fs_node* file = vfs_open("/init"); process* new_proc = (process*)malloc(sizeof(process));
if (!file) panic("FATAL: /init not found!"); if (!new_proc) return -2;
memset(new_proc, 0, sizeof(process));
new_proc->pid = next_pid++;
new_proc->state = RUNNING;
new_proc->pml4_phys = vmm_create_address_space();
new_proc->heap_start = HEAP_START;
new_proc->heap_cur = HEAP_START;
strncpy(new_proc->name, name, 31);
u8* file_buffer = (u8*)malloc(file->len); u8* file_buffer = (u8*)malloc(file->len);
if (!file_buffer) {
free(new_proc);
return -3;
}
vfs_read(file, 0, file->len, file_buffer); vfs_read(file, 0, file->len, file_buffer);
u64 entry = load_hot(init_proc, file_buffer); u64 entry = load_hot(new_proc, file_buffer);
if (!entry) panic("Invalid HOT executable"); if (!entry) return -4;
free(file_buffer);
vmm_setup_user_stack((u64*)init_proc->pml4_phys);
sched_spawn((void(*)())entry, init_proc, true, USER_STACK_TOP);
while(1) { __asm__("sti; hlt"); } free(file_buffer);
vmm_setup_user_stack((u64*)new_proc->pml4_phys);
sched_spawn((void(*)())entry, new_proc, true, USER_STACK_TOP);
return new_proc->pid;
}
void init_task_entry() {
i32 pid = process_spawn("/init", "init");
if (pid < 0) {
panic("FATAL: Failed to spawn /init");
}
while (1) { __asm__("sti; hlt"); }
} }
-1
View File
@@ -32,7 +32,6 @@ const char* fun_messages[] = {
"Code have been eaten by Aliens", "Code have been eaten by Aliens",
"That's all, folks!", "That's all, folks!",
"Raiden, answer me, Raiden, respond! Raiden?! RAIDEEEEEEEEEN!", "Raiden, answer me, Raiden, respond! Raiden?! RAIDEEEEEEEEEN!",
"Fatal error has been occurred.\n\t\t\t\t Your device will be terminated in 30 seconds.",
"I'll be back", "I'll be back",
"Hastla la vista, baby", "Hastla la vista, baby",
"Ti chego mne tut nagovoril...", "Ti chego mne tut nagovoril...",
+17
View File
@@ -6,6 +6,7 @@
#include <core/string.h> #include <core/string.h>
#include <mm/heap.h> #include <mm/heap.h>
#include <mm/vmm.h> #include <mm/vmm.h>
#include <mm/memory.h>
#include <cpuinfo.h> #include <cpuinfo.h>
#include <gdt.h> #include <gdt.h>
@@ -17,6 +18,12 @@ extern u64 pml4_kernel_phys;
static process kernel_process; static process kernel_process;
void idle_task() {
while (1) {
__asm__ volatile ("hlt");
}
}
void sched_init() { void sched_init() {
kernel_process.pid = 0; kernel_process.pid = 0;
kernel_process.state = RUNNING; kernel_process.state = RUNNING;
@@ -24,12 +31,15 @@ void sched_init() {
strcpy(kernel_process.name, "kernel"); strcpy(kernel_process.name, "kernel");
task* kt = (task*)malloc(sizeof(task)); task* kt = (task*)malloc(sizeof(task));
memset(kt, 0, sizeof(task));
kt->id = 0; kt->id = 0;
kt->proc = &kernel_process; kt->proc = &kernel_process;
kt->sleep_ticks = 0; kt->sleep_ticks = 0;
kt->next = kt; kt->next = kt;
kt->task_state = RUNNING;
curr_task = kt; curr_task = kt;
sched_spawn(idle_task, &kernel_process, false, 0);
} }
task* sched_spawn(void(*entry)(), process* owner, bool is_user, u64 fixed_user_stack) { task* sched_spawn(void(*entry)(), process* owner, bool is_user, u64 fixed_user_stack) {
@@ -66,6 +76,7 @@ task* sched_spawn(void(*entry)(), process* owner, bool is_user, u64 fixed_user_s
t->sleep_ticks = 0; t->sleep_ticks = 0;
t->next = curr_task->next; t->next = curr_task->next;
t->kernel_stack_top = (u64)stack_base + stack_size; t->kernel_stack_top = (u64)stack_base + stack_size;
t->task_state = RUNNING;
curr_task->next = t; curr_task->next = t;
return t; return t;
} }
@@ -84,6 +95,12 @@ u64 sched_next(u64 curr_rsp) {
if (curr_task->sleep_ticks > 0) curr_task->sleep_ticks--; if (curr_task->sleep_ticks > 0) curr_task->sleep_ticks--;
task* next = curr_task->next; task* next = curr_task->next;
while (next->task_state == DEAD) {
// TODO: add gc here;
next = next->next;
if (next == curr_task) panic("no alive tasks");
}
while (next != curr_task && next->sleep_ticks > 0) next = next->next; // what the fuck i just wrote while (next != curr_task && next->sleep_ticks > 0) next = next->next; // what the fuck i just wrote
if (next->proc->pml4_phys != curr_task->proc->pml4_phys) load_cr3(next->proc->pml4_phys); if (next->proc->pml4_phys != curr_task->proc->pml4_phys) load_cr3(next->proc->pml4_phys);
+1 -1
View File
@@ -80,7 +80,7 @@ void console_set_cursor_pos(SG_Point *p) {
s_cursor_pos.y = p->y; s_cursor_pos.y = p->y;
} }
static void console_putc(char c) { void console_putc(char c) {
serial_writec(c); serial_writec(c);
if (!ctx_ptr) return; if (!ctx_ptr) return;
if (c == '\n') { if (c == '\n') {
+27
View File
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#include <syscalls/io.h>
#include <drivers/console.h>
u64 sys_write(u64 fd, u64 buff, u64 len) {
if (fd == 1 || fd == 2) {
char* str = (char*)buff;
for (u64 i = 0; i < len; i++) {
console_putc(str[i]);
}
return len;
}
return 0;
}
u64 sys_read(u64 fd, u64 buff, u64 count) {
char* buf = (char*)buff;
if (fd == 0) {
for (u64 i = 0; i < count; i++) {
buf[i] = console_getc();
}
return count;
}
return 0;
}
+32
View File
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#include <syscalls/mem.h>
#include <core/scheduler.h>
#include <mm/pmm.h>
#include <mm/vmm.h>
#include <mm/memory.h>
extern task* curr_task;
u64 sys_mem(u64 size) {
if (size == 0) return 0;
process* proc = curr_task->proc;
u64 addr_to_ret = proc->heap_cur;
u64 pages_needed = (size + (PAGE_SIZE-1)) / PAGE_SIZE;
for (u64 i = 0; i < pages_needed; i++) {
void* phys = pmm_alloc_page();
if (!phys) return 0;
vmm_map_page((u64*)proc->pml4_phys, (u64)phys, proc->heap_cur, PTE_PRESENT | PTE_RW | PTE_USER);
memset((void*)PHYS_TO_HHDM((u64)phys), 0, PAGE_SIZE);
proc->heap_cur += 4096;
}
return addr_to_ret;
}
+22
View File
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#include <syscalls/proc.h>
#include <core/scheduler.h>
#include <drivers/console.h>
#include <core/loader.h>
extern task* curr_task;
u64 sys_exit(i32 code) {
kprintf("\n[Dewar] process %s exited with code %d", curr_task->proc->name, code);
curr_task->task_state = DEAD;
sched_next(curr_task->rsp);
while (1) { __asm__ ("hlt"); }
}
u64 sys_spawn(const char* path) {
return process_spawn(path, path);
}
+3 -1
View File
@@ -7,4 +7,6 @@ set(CMAKE_C_EXTENSIONS OFF)
message(STATUS "Building termOS's userspace") message(STATUS "Building termOS's userspace")
add_subdirectory(init) add_subdirectory(libterm)
add_subdirectory(init)
add_subdirectory(debug)
+6
View File
@@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 3.20)
project(termOSdbg LANGUAGES C)
file(GLOB_RECURSE debug_SOURCES "src/*.c")
add_termos_executable(debug "${debug_SOURCES}")
+85
View File
@@ -0,0 +1,85 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#include <stdio.h>
#include <malloc.h>
#define VECTOR_BUFFER_SIZE 8
typedef struct {
i32* data;
u64 size;
u64 capacity;
} Vector;
void vector_init(Vector* vec) {
vec->data = nullptr;
vec->size = 0;
vec->capacity = 0;
}
u8 vector_append(Vector* vec, const i32 num) {
if (vec->size >= vec->capacity) {
u64 new_cap = (vec->capacity == 0) ? VECTOR_BUFFER_SIZE : vec->capacity * 2;
i32* new_data = realloc(vec->data, new_cap * sizeof(i32));
if (!new_data) return 2; // Out of memory
vec->data = new_data;
vec->capacity = new_cap;
}
vec->data[vec->size] = num;
vec->size++;
return 0;
}
void vector_reset(Vector* vec) {
vec->size = 0;
}
u8 vector_reserve(Vector* vec, u64 new_cap) {
if (new_cap <= vec->capacity) return 0;
i32* new_data = realloc(vec->data, new_cap * sizeof(i32));
if (!new_data) return 2;
vec->data = new_data;
vec->capacity = new_cap;
return 0;
}
void vector_free(Vector* vec) {
free(vec->data);
vec->data = nullptr;
vec->size = vec->capacity = 0;
}
void render_list(Vector* numbers) {
printf("\nNumbers [%d/%d]: [", numbers->size, numbers->capacity);
if (numbers->size == 0) printf("]");
for (u64 i = 0; i < numbers->size; i++) {
printf("%d", numbers->data[i]);
if (i + 1 >= numbers->size) {
printf("]");
break;
}
printf(", ");
}
}
int main() {
Vector nums;
vector_init(&nums);
printf("Heap test\n");
printf("press any key to add 1 number press 'q' to exit\n");
char c = 'd';
u64 i = 0;
while (c != 'q') {
render_list(&nums);
vector_append(&nums, i);
i++;
c = getchar();
}
vector_free(&nums);
}
+2 -29
View File
@@ -1,33 +1,6 @@
cmake_minimum_required(VERSION 3.20) cmake_minimum_required(VERSION 3.20)
project(termOSinit LANGUAGES C) project(termOSinit LANGUAGES C)
set(CMAKE_C_STANDARD 23) file(GLOB_RECURSE INIT_SOURCES "src/*.c")
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
get_filename_component(TOOLS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../tools/elf2hot" ABSOLUTE) add_termos_executable(init "${INIT_SOURCES}")
set(FINAL_INIT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../initramfs/init")
file(GLOB_RECURSE INIT_SOURCES "src/*.asm" "src/*.c")
add_executable(init_elf ${INIT_SOURCES})
set_target_properties(init_elf PROPERTIES
OUTPUT_NAME "init"
LINKER_LANGUAGE C
)
target_link_options(init_elf PRIVATE
-nostdlib
-static
-T "${CMAKE_CURRENT_SOURCE_DIR}/linker.ld"
)
add_custom_command(TARGET init_elf POST_BUILD
COMMAND cargo run --release --quiet -- $<TARGET_FILE:init_elf> ${FINAL_INIT_PATH}
WORKING_DIRECTORY ${TOOLS_DIR}
COMMENT "Cargo is converting ELF to HOT! format..."
VERBATIM
)
-10
View File
@@ -1,10 +0,0 @@
[bits 64]
section .text
global start
extern main
start:
call main
.hang:
jmp .hang
+9 -13
View File
@@ -1,16 +1,12 @@
static inline void sys_write(const char* str) { // SPDX-License-Identifier: GPL-3.0-or-later
__asm__ volatile ( // Copyright (c) 2026 0xKarinyash
"mov $2, %%rax\n\t"
"mov %0, %%rdi\n\t" #include <process.h>
"syscall" #include <stdio.h>
: #include <malloc.h>
: "r"(str)
: "rax", "rdi", "rcx", "r11", "memory"
);
}
int main() { int main() {
sys_write("Meowww!!!\n"); printf("Launching debug\n");
sys_write("Nyaaaaa"); spawn("debug");
for (int i = 0; i < 100; i++) sys_write("a"); while (1) {}
} }
+63
View File
@@ -0,0 +1,63 @@
cmake_minimum_required(VERSION 3.16)
project(libterm LANGUAGES C ASM_NASM)
set(USER_C_FLAGS
-ffreestanding
-nostdlib
-nostdinc
-fno-stack-protector
-fno-pic
-fno-pie
-m64
-mno-red-zone
-mcmodel=small
-Wall
-Wextra
-Werror
-O2
)
set(CMAKE_ASM_NASM_FLAGS "-f 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
)
add_library(term STATIC ${LIBTERM_SOURCES})
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}>)
function(add_termos_executable NAME SOURCES)
add_executable(${NAME} ${SOURCES})
target_sources(${NAME} PRIVATE $<TARGET_OBJECTS:crt0_obj>)
target_compile_options(${NAME} PRIVATE $<$<COMPILE_LANGUAGE:C>:${USER_C_FLAGS}>)
target_link_libraries(${NAME} PRIVATE term)
target_link_options(${NAME} PRIVATE
-T ${libterm_SOURCE_DIR}/linker.ld
-nostdlib
-static
)
set(ELF2HOT_DIR "${CMAKE_SOURCE_DIR}/tools/elf2hot")
set(FINAL_HOT_PATH "${CMAKE_SOURCE_DIR}/initramfs/${NAME}")
add_custom_command(TARGET ${NAME} POST_BUILD
COMMAND cargo run --release --quiet -- $<TARGET_FILE:${NAME}> ${FINAL_HOT_PATH}
WORKING_DIRECTORY ${ELF2HOT_DIR}
COMMENT "elf2hot: Converting ${NAME} to HOT! format..."
VERBATIM
)
endfunction()
+19
View File
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <types.h>
#define HEADER_MAGIC 0x1CE1CE
typedef struct block_header {
u64 magic;
struct block_header* next;
struct block_header* prev;
u64 size;
bool is_free;
} block_header;
void* malloc(u64 size);
void free(void* ptr);
void* realloc(void* ptr, u64 new_size);
+7
View File
@@ -0,0 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <types.h>
u64 spawn(const char* path);
+8
View File
@@ -0,0 +1,8 @@
#pragma once
typedef __builtin_va_list va_list;
#define va_start(v, l) __builtin_va_start(v, l)
#define va_end(v) __builtin_va_end(v)
#define va_arg(v, l) __builtin_va_arg(v, l)
#define va_copy(d, s) __builtin_va_copy(d, s)
+10
View File
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <types.h>
void printf(const char *fmt, ...);
int getchar();
char* gets(char* str);
char* gets_s(char* str, u64 size);
+13
View File
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <types.h>
void *memset(void *ptr, int value, usize num);
void* memcpy(void* dest, const void* src, u64 n);
i32 strcmp(const char *s1, const char *s2);
i32 strncmp(const char* s1, const char* s2, u64 n);
char* strcpy(char* dest, const char* src);
char* strncpy(char* dest, const char* src, u64 n);
u64 strlen(const char* str);
+23
View File
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2025 0xKarinyash
#pragma once
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef signed char i8;
typedef signed short i16;
typedef signed int i32;
typedef signed long long i64;
typedef u64 usize;
typedef u64 uintptr_t;
#ifndef __cplusplus
#define bool _Bool
#define true 1
#define false 0
#endif
@@ -1,4 +1,4 @@
ENTRY(start) ENTRY(_start)
SECTIONS SECTIONS
{ {
+14
View File
@@ -0,0 +1,14 @@
; SPDX-License-Identifier: GPL-3.0-or-later
; Copyright (c) 2026 0xKarinyash
[bits 64]
section .text
global _start
extern main
extern sys_exit
_start:
call main
mov rdi, rax
call sys_exit
View File
+103
View File
@@ -0,0 +1,103 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
// brutally copypasting from kernel/mm/heap.c
#include <malloc.h>
#include <string.h>
static block_header* heap_list_head = nullptr;
extern u64 sys_mem(u64 size);
void combine_forward(block_header* curr) {
if (!curr->next || !curr->next->is_free) return;
curr->size += sizeof(block_header) + curr->next->size;
curr->next = curr->next->next;
if (curr->next) curr->next->prev = curr; // what the fuck
}
void* malloc(u64 size) {
if (size == 0) return nullptr;
u64 aligned_size = (size + 15) & ~15;
block_header* curr = heap_list_head;
block_header* last = nullptr;
while (curr) {
if (curr->is_free && curr->size >= aligned_size) {
if (curr->size > aligned_size + sizeof(block_header) + 16) {
block_header* new_block = (block_header*)((u64)curr + sizeof(block_header) + aligned_size);
new_block->size = curr->size - aligned_size - sizeof(block_header);
new_block->is_free = true;
new_block->next = curr->next;
new_block->prev = curr;
new_block->magic = HEADER_MAGIC;
if (curr->next) curr->next->prev = new_block;
curr->next = new_block;
curr->size = aligned_size;
}
curr->is_free = false;
return (void*)((u64)curr + sizeof(block_header));
}
last = curr;
curr = curr->next;
}
u64 need_to_alloc = aligned_size + sizeof(block_header);
u64 page_aligned_size = (need_to_alloc + 4095) & ~4095;
u64 new_mem_addr = sys_mem(page_aligned_size);
if (new_mem_addr == 0) return nullptr;
block_header* new_block = (block_header*)new_mem_addr;
new_block->size = page_aligned_size - sizeof(block_header);
new_block->is_free = true;
new_block->magic = HEADER_MAGIC;
new_block->next = nullptr;
new_block->prev = last;
if (last) {
last->next = new_block;
} else {
heap_list_head = new_block;
}
return malloc(size);
}
void free(void* ptr) {
if (!ptr) return;
block_header* curr = (block_header*)((u64)ptr - sizeof(block_header));
if (curr->magic != HEADER_MAGIC) return;
curr->is_free = true;
if (curr->next && curr->next->is_free) combine_forward(curr);
if (curr->prev && curr->prev->is_free) combine_forward(curr->prev);
}
void* realloc(void* ptr, u64 new_size) {
if (!ptr) return malloc(new_size);
if (new_size == 0) {
free(ptr);
return nullptr;
}
block_header* curr = (block_header*)((u64)ptr - sizeof(block_header));
if (curr->size >= new_size) return ptr;
if (curr->next &&
curr->next->is_free &&
(curr->size + sizeof(block_header) + curr->next->size) >= new_size) { // why ts so fucking unreadable
combine_forward(curr);
return ptr;
}
void* new_ptr = malloc(new_size);
if (!new_ptr) return nullptr;
memcpy(new_ptr, ptr, curr->size);
free(ptr);
return new_ptr;
}
+10
View File
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#include <process.h>
extern u64 sys_spawn(const char* path);
u64 spawn(const char* path) {
return sys_spawn(path);
}
+132
View File
@@ -0,0 +1,132 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#include <stdio.h>
#include <stdarg.h>
#include <types.h>
#include <string.h>
#define EOF (-1)
extern u64 sys_read(u64 fd, void* buf, u64 len);
extern u64 sys_write(u64 fd, const void* buf, u64 len);
static void putchar(char c) {
sys_write(1, &c, 1);
}
static void print_str(const char* str) {
if (!str) str = "(null)";
sys_write(1, str, strlen(str));
}
static void print_dec(long long n) {
if (n < 0) {
putchar('-');
n = -n;
}
unsigned long long u = (unsigned long long)n;
char buffer[32];
int i = 0;
do {
buffer[i++] = (u % 10) + '0';
u /= 10;
} while (u > 0);
while (--i >= 0) putchar(buffer[i]);
}
static void print_hex(unsigned long long u, int padding) {
char buffer[16];
int i = 0;
const char* hex_chars = "0123456789ABCDEF";
do {
buffer[i++] = hex_chars[u % 16];
u /= 16;
} while (u > 0);
while (i < padding) buffer[i++] = '0';
print_str("0x");
while (--i >= 0) putchar(buffer[i]);
}
void printf(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
for (int i = 0; fmt[i] != '\0'; i++) {
if (fmt[i] == '%') {
i++;
switch (fmt[i]) {
case 's': print_str(va_arg(args, const char*)); break;
case 'c': putchar((char)va_arg(args, int)); break;
case 'd': print_dec(va_arg(args, int)); break;
case 'x': print_hex(va_arg(args, unsigned long long), 0); break;
case 'X': print_hex(va_arg(args, unsigned long long), 16); break;
case '%': putchar('%'); break;
default: putchar(fmt[i]); break;
}
}
else {
putchar(fmt[i]);
}
}
va_end(args);
}
int getchar() {
char c;
unsigned long long res = sys_read(0, &c, 1);
if (res <= 0) return EOF;
return (int)(unsigned char)c;
}
char* gets(char* str) {
int i = 0;
int c;
while (1) {
c = getchar();
if (c == EOF || c == '\n' || c == '\r') {
break;
}
str[i++] = (char)c;
char ch = (char)c;
sys_write(1, &ch, 1);
}
str[i] = '\0';
char nl = '\n';
sys_write(1, &nl, 1);
return str;
}
char* gets_s(char* str, u64 size) {
if (size == 0) return str;
u64 i = 0;
int c;
while (i < size - 1) {
c = getchar();
if (c == EOF || c == '\n' || c == '\r') break;
str[i++] = (char)c;
char ch = (char)c;
sys_write(1, &ch, 1);
}
str[i] = '\0';
char nl = '\n';
sys_write(1, &nl, 1);
return str;
}
+77
View File
@@ -0,0 +1,77 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#include <string.h>
void *memset(void *ptr, int value, usize num) {
u8 *p = (u8 *)ptr;
while (num--) {
*p++ = (u8)value;
}
return ptr;
}
void* memcpy(void* dest, const void* src, u64 n) {
u8* d = (u8*)dest;
const u8* s = (const u8*)src;
while (n >= 8) {
*(u64*)d = *(const u64*)s;
d += 8;
s += 8;
n -= 8;
}
while (n > 0) {
*d++ = *s++;
n--;
}
return dest;
}
i32 strcmp(const char *s1, const char *s2) {
while (*s1 && (*s1 == *s2)) {
s1++;
s2++;
}
return *(const unsigned char*)s1 - *(const unsigned char*)s2;
}
i32 strncmp(const char* s1, const char* s2, u64 n) {
while (n > 0) {
if (*s1 != *s2) return *(unsigned char*)s1 - *(unsigned char*)s2;
if (*s1 == '\0') return 0;
s1++;
s2++;
n--;
}
return 0;
}
char* strcpy(char* dest, const char* src) {
char* saved = dest;
while (*src) *dest++ = *src++;
*dest = 0;
return saved;
}
char* strncpy(char* dest, const char* src, u64 n) {
char* saved = dest;
while (*src && n > 0) {
*dest++ = *src++;
n--;
}
while (n > 0) {
*dest++ = 0;
n--;
}
return saved;
}
u64 strlen(const char* str) {
u64 res = 0;
for (res = 0; str[res]; res++);
return res;
}
+37
View File
@@ -0,0 +1,37 @@
; SPDX-License-Identifier: GPL-3.0-or-later
; Copyright (c) 2026 0xKarinyash
bits 64
section .text
global sys_exit
global sys_spawn
global sys_mem
global sys_write
global sys_read
sys_exit:
mov rax, 0
syscall
ret
sys_spawn:
mov rax, 1
syscall
ret
sys_mem:
mov rax, 2
syscall
ret
sys_write:
mov rax, 3
syscall
ret
sys_read:
mov rax, 4
syscall
ret