v0.5.3-pre: refactor syscall handlers and introduce libterm
Moved handlers to syscalls/, implemented libterm (malloc, stdio)
This commit is contained in:
+1
-1
@@ -42,7 +42,7 @@ if(MCOPY_EXE AND MKFS_EXE AND CPIO_EXE)
|
||||
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_elf
|
||||
DEPENDS ${INIT_FILES} init debug
|
||||
VERBATIM
|
||||
COMMENT "Packing initramfs to cpio..."
|
||||
)
|
||||
|
||||
@@ -23,6 +23,7 @@ file(GLOB_RECURSE KERNEL_SOURCES CMAKE_CONFIGURE_DEPENDS
|
||||
"src/mm/*.c"
|
||||
"src/shell/*.c"
|
||||
"src/fs/*.c"
|
||||
"src/syscalls/*.c"
|
||||
|
||||
"data/*.c"
|
||||
)
|
||||
|
||||
@@ -13,8 +13,10 @@
|
||||
|
||||
typedef enum {
|
||||
SYS_EXIT,
|
||||
SYS_EXEC,
|
||||
SYS_SPAWN,
|
||||
SYS_MEM,
|
||||
SYS_WRITE,
|
||||
SYS_READ,
|
||||
} syscalls;
|
||||
|
||||
void syscall_init();
|
||||
@@ -4,7 +4,6 @@
|
||||
#pragma once
|
||||
|
||||
#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();
|
||||
@@ -15,6 +15,8 @@ typedef struct process {
|
||||
u64 pml4_phys;
|
||||
struct process* parent;
|
||||
char name[32];
|
||||
u64 heap_start;
|
||||
u64 heap_cur;
|
||||
} process;
|
||||
|
||||
typedef struct task {
|
||||
@@ -22,6 +24,7 @@ typedef struct task {
|
||||
struct task* next;
|
||||
u32 id;
|
||||
u32 sleep_ticks;
|
||||
process_state task_state; // reusing process_state cuz wn
|
||||
u64 kernel_stack_top;
|
||||
process* proc;
|
||||
} task;
|
||||
|
||||
@@ -13,6 +13,7 @@ void console_set_color(u32 color);
|
||||
void console_set_default_color(u32 color);
|
||||
void console_set_cursor_pos(SG_Point *p);
|
||||
char console_getc();
|
||||
void console_putc(char c);
|
||||
void kprint(const char *str);
|
||||
void kprintf(const char *fmt, ...);
|
||||
void kgets(char* buff, u32 lim);
|
||||
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Copyright (c) 2026 0xKarinyash
|
||||
|
||||
#include "types.h"
|
||||
#include <types.h>
|
||||
#include <cpuinfo.h>
|
||||
|
||||
#define MSR_GS_BASE 0xC0000101
|
||||
|
||||
@@ -60,7 +60,6 @@ syscall_entry:
|
||||
pop r11 ; rflags
|
||||
add rsp, 8 ; skip rsp
|
||||
|
||||
mov [gs:8], rsp
|
||||
mov rsp, [gs:0]
|
||||
swapgs
|
||||
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
#include <mm/pmm.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) {
|
||||
u32 low = (u32)val;
|
||||
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) {
|
||||
__asm__ volatile("cli");
|
||||
switch (id) {
|
||||
case SYS_EXIT: {
|
||||
kprintf("\n[Dewar] process exited with code %d", arg1);
|
||||
while(1) __asm__ ("hlt"); // stub
|
||||
return 0;
|
||||
}
|
||||
case SYS_EXEC: {
|
||||
kprintf("\n[Dewar] process called exec syscall");
|
||||
return 0; // stub as well
|
||||
}
|
||||
case SYS_WRITE: {
|
||||
kprintf("%s", (char*)arg1);
|
||||
return 0;
|
||||
}
|
||||
case SYS_EXIT: return sys_exit(arg1);
|
||||
case SYS_SPAWN: return sys_spawn((const char*)arg1);
|
||||
case SYS_MEM: return sys_mem(arg1);
|
||||
case SYS_WRITE: return sys_write(arg1, arg2, arg3);
|
||||
case SYS_READ: return sys_read(arg1, arg2, arg3);
|
||||
default: kprintf("[Dewar] Unknown syscall %d\n", id); return -1;
|
||||
}
|
||||
__asm__ volatile("sti");
|
||||
}
|
||||
+16
-13
@@ -19,27 +19,30 @@ u64 load_hot(process* proc, u8* data) {
|
||||
}
|
||||
|
||||
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++) {
|
||||
hot_segment* seg = &segments[i];
|
||||
if (seg->memsz == 0) continue;
|
||||
|
||||
u64 start = seg->vaddr & ~(0xFFF);
|
||||
u64 end = (seg->vaddr + seg->memsz + 0xFFF) & ~(0xFFF);
|
||||
u64 start = seg->vaddr & ~(0xFFFULL);
|
||||
u64 end = (seg->vaddr + seg->memsz + 0xFFF) & ~(0xFFFULL);
|
||||
|
||||
for (u64 addr = start; addr < end; addr += PAGE_SIZE) {
|
||||
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);
|
||||
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);
|
||||
memcpy((u8*)kernel_virt + dst_offset, data + src_offset, copy_size);
|
||||
}
|
||||
}
|
||||
|
||||
load_cr3(kernel_cr3);
|
||||
}
|
||||
|
||||
return header->entry_point;
|
||||
|
||||
+35
-15
@@ -20,28 +20,48 @@
|
||||
#include <types.h>
|
||||
|
||||
extern task* curr_task;
|
||||
extern u32 next_pid;
|
||||
|
||||
#define USER_STACK_TOP 0x70000000
|
||||
#define HEAP_START 0x40000000
|
||||
|
||||
void init_task_entry() {
|
||||
process* init_proc = (process*)malloc(sizeof(process));
|
||||
init_proc->pid = 1;
|
||||
init_proc->state = RUNNING;
|
||||
init_proc->pml4_phys = vmm_create_address_space();
|
||||
strcpy(init_proc->name, "init");
|
||||
i32 process_spawn(const char* path, const char* name) {
|
||||
fs_node* file = vfs_open(path);
|
||||
if (!file) return -1;
|
||||
|
||||
fs_node* file = vfs_open("/init");
|
||||
if (!file) panic("FATAL: /init not found!");
|
||||
process* new_proc = (process*)malloc(sizeof(process));
|
||||
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);
|
||||
if (!file_buffer) {
|
||||
free(new_proc);
|
||||
return -3;
|
||||
}
|
||||
vfs_read(file, 0, file->len, file_buffer);
|
||||
|
||||
u64 entry = load_hot(init_proc, file_buffer);
|
||||
if (!entry) panic("Invalid HOT executable");
|
||||
|
||||
free(file_buffer);
|
||||
vmm_setup_user_stack((u64*)init_proc->pml4_phys);
|
||||
sched_spawn((void(*)())entry, init_proc, true, USER_STACK_TOP);
|
||||
u64 entry = load_hot(new_proc, file_buffer);
|
||||
if (!entry) return -4;
|
||||
|
||||
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"); }
|
||||
}
|
||||
@@ -32,7 +32,6 @@ const char* fun_messages[] = {
|
||||
"Code have been eaten by Aliens",
|
||||
"That's all, folks!",
|
||||
"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",
|
||||
"Hastla la vista, baby",
|
||||
"Ti chego mne tut nagovoril...",
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <core/string.h>
|
||||
#include <mm/heap.h>
|
||||
#include <mm/vmm.h>
|
||||
#include <mm/memory.h>
|
||||
#include <cpuinfo.h>
|
||||
#include <gdt.h>
|
||||
|
||||
@@ -17,6 +18,12 @@ extern u64 pml4_kernel_phys;
|
||||
|
||||
static process kernel_process;
|
||||
|
||||
void idle_task() {
|
||||
while (1) {
|
||||
__asm__ volatile ("hlt");
|
||||
}
|
||||
}
|
||||
|
||||
void sched_init() {
|
||||
kernel_process.pid = 0;
|
||||
kernel_process.state = RUNNING;
|
||||
@@ -24,12 +31,15 @@ void sched_init() {
|
||||
strcpy(kernel_process.name, "kernel");
|
||||
|
||||
task* kt = (task*)malloc(sizeof(task));
|
||||
memset(kt, 0, sizeof(task));
|
||||
kt->id = 0;
|
||||
kt->proc = &kernel_process;
|
||||
kt->sleep_ticks = 0;
|
||||
kt->next = kt;
|
||||
kt->task_state = RUNNING;
|
||||
|
||||
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) {
|
||||
@@ -66,6 +76,7 @@ task* sched_spawn(void(*entry)(), process* owner, bool is_user, u64 fixed_user_s
|
||||
t->sleep_ticks = 0;
|
||||
t->next = curr_task->next;
|
||||
t->kernel_stack_top = (u64)stack_base + stack_size;
|
||||
t->task_state = RUNNING;
|
||||
curr_task->next = t;
|
||||
return t;
|
||||
}
|
||||
@@ -84,6 +95,12 @@ u64 sched_next(u64 curr_rsp) {
|
||||
if (curr_task->sleep_ticks > 0) curr_task->sleep_ticks--;
|
||||
|
||||
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
|
||||
|
||||
if (next->proc->pml4_phys != curr_task->proc->pml4_phys) load_cr3(next->proc->pml4_phys);
|
||||
|
||||
@@ -80,7 +80,7 @@ void console_set_cursor_pos(SG_Point *p) {
|
||||
s_cursor_pos.y = p->y;
|
||||
}
|
||||
|
||||
static void console_putc(char c) {
|
||||
void console_putc(char c) {
|
||||
serial_writec(c);
|
||||
if (!ctx_ptr) return;
|
||||
if (c == '\n') {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -7,4 +7,6 @@ set(CMAKE_C_EXTENSIONS OFF)
|
||||
|
||||
message(STATUS "Building termOS's userspace")
|
||||
|
||||
add_subdirectory(init)
|
||||
add_subdirectory(libterm)
|
||||
add_subdirectory(init)
|
||||
add_subdirectory(debug)
|
||||
@@ -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}")
|
||||
@@ -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);
|
||||
}
|
||||
@@ -1,33 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(termOSinit LANGUAGES C)
|
||||
|
||||
set(CMAKE_C_STANDARD 23)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_C_EXTENSIONS OFF)
|
||||
file(GLOB_RECURSE INIT_SOURCES "src/*.c")
|
||||
|
||||
get_filename_component(TOOLS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../tools/elf2hot" ABSOLUTE)
|
||||
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
|
||||
)
|
||||
add_termos_executable(init "${INIT_SOURCES}")
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
[bits 64]
|
||||
|
||||
section .text
|
||||
global start
|
||||
extern main
|
||||
|
||||
start:
|
||||
call main
|
||||
.hang:
|
||||
jmp .hang
|
||||
@@ -1,16 +1,12 @@
|
||||
static inline void sys_write(const char* str) {
|
||||
__asm__ volatile (
|
||||
"mov $2, %%rax\n\t"
|
||||
"mov %0, %%rdi\n\t"
|
||||
"syscall"
|
||||
:
|
||||
: "r"(str)
|
||||
: "rax", "rdi", "rcx", "r11", "memory"
|
||||
);
|
||||
}
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Copyright (c) 2026 0xKarinyash
|
||||
|
||||
#include <process.h>
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
|
||||
int main() {
|
||||
sys_write("Meowww!!!\n");
|
||||
sys_write("Nyaaaaa");
|
||||
for (int i = 0; i < 100; i++) sys_write("a");
|
||||
printf("Launching debug\n");
|
||||
spawn("debug");
|
||||
while (1) {}
|
||||
}
|
||||
@@ -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()
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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)
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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
|
||||
{
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user