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 ${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..."
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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();
|
||||||
@@ -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();
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
// 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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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"); }
|
||||||
}
|
}
|
||||||
@@ -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...",
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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') {
|
||||||
|
|||||||
@@ -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")
|
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)
|
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
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -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) {
|
// 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) {}
|
||||||
}
|
}
|
||||||
@@ -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
|
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