7 Commits

Author SHA1 Message Date
Karina 21270a3cc8 feat: introduce HOT! executable format and Ring 3 process isolation (v0.5.2)
- Implement custom 'HOT!' binary format and Rust-based elf2hot converter.
- Upgrade kernel loader with segment-based loading and BSS zeroing.
- Refactor scheduler for Ring 3 IRET frames and fix CS/SS selector swap.
- Add user stack allocation (0x70000000) and linker scripts for binary cleanup.
2026-01-30 00:12:11 +04:00
Karina 7d32444da2 feat(core): v0.5.1 - process isolation and syscalls
- Implemented CR3 switching in scheduler for process isolation

- Added 'process' structure and PML4 cloning (vmm_create_address_space)

- Added NASM crt0 and C entry point for userspace apps
2026-01-29 22:28:41 +04:00
Karina 55ea8fc533 feat(userspace): userspace support
build: updated CMakeLists to build and copy to initramfs

wip(syscalls): initial syscalls

chore(ksh/kfetch): minor changes

chore(gitignore): added initramfs/*
2026-01-29 21:25:45 +04:00
Karina 3f3a026432 build: officially naming the kernel "Dewar" and updating kfetch 2026-01-29 05:29:39 +04:00
Karina 8a6994ebd8 build(cmake): added TERMOS_VERSION defenition
fix(kfetch): added correct versioning in kfetch
2026-01-29 05:03:46 +04:00
Karina 3525c81d9e fix(linker): _start is now always first in binary
feat(rand): real random using rdrand/xorshift

chore(panic): added 2 more fun_messages

feat(ksh): removed rectest and added rand command

wip(ksh/kfetch): now it shows vendor string instead of stub
2026-01-29 04:44:25 +04:00
Karina d01a91c993 feat: jumping to userspace (currently only in dbg command with infinit jmp to self loop 2026-01-29 01:10:14 +04:00
42 changed files with 999 additions and 181 deletions
+4 -1
View File
@@ -1,4 +1,7 @@
.cache
build*
.venv
initrd/image.cpio
initrd/image.cpio
initramfs/*
target
+2 -1
View File
@@ -5,4 +5,5 @@ kernel/data
*.md
tools/
bootloader/
bootloader/src/uefi
bootloader/src/uefi
initramfs/
+20 -4
View File
@@ -6,15 +6,30 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
add_subdirectory(bootloader)
add_subdirectory(kernel)
find_program(MCOPY_EXE mcopy)
find_program(MKFS_EXE mkfs.fat)
find_program(CPIO_EXE cpio)
find_program(QEMU_EXE qemu-system-x86_64)
set(OVMF_PATH "/usr/share/edk2/ovmf/OVMF_CODE.fd" CACHE FILEPATH "Path to OVMF bios")
execute_process(
COMMAND git describe --tags --always --dirty
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE KERNEL_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(NOT KERNEL_VERSION)
set(KERNEL_VERSION "unknown-version")
endif()
message(STATUS "Building termOS version: ${KERNEL_VERSION}")
add_compile_definitions(TERMOS_VERSION=\"${KERNEL_VERSION}\")
add_subdirectory(bootloader)
add_subdirectory(kernel)
add_subdirectory(userspace)
if(MCOPY_EXE AND MKFS_EXE AND CPIO_EXE)
set(IMG_FILE "${CMAKE_BINARY_DIR}/termOS.img")
@@ -27,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}
DEPENDS ${INIT_FILES} init_elf
VERBATIM
COMMENT "Packing initramfs to cpio..."
)
@@ -58,6 +73,7 @@ if(QEMU_EXE)
-net none
-serial stdio
-m 512M
-s
DEPENDS image
)
endif()
+1
View File
@@ -4,6 +4,7 @@ set(UEFI_COMPILE_OPTIONS
-std=c23
-target x86_64-unknown-windows-msvc
-Wall -Wextra
-fno-builtin
$<$<CONFIG:Release>:-Werror>
)
+23
View File
@@ -0,0 +1,23 @@
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
#define HOT_MAGIC 0x21544F48
typedef struct hot_segment {
u64 type; // 1 = rx 2 = rw
u64 vaddr;
u64 offset;
u64 filesz;
u64 memsz;
} hot_segment;
typedef struct hot_header {
u32 magic; // "HOT!"
u8 version; // 1
u8 reserved_pad[3];
u64 entry_point;
u64 segments_count;
u64 reserved;
} hot_header;
-1
View File
@@ -1 +0,0 @@
Meow!!
-1
View File
@@ -1 +0,0 @@
Nyaaa
+2 -2
View File
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.20)
project(termOS_krn LANGUAGES C ASM_NASM)
project(dewar LANGUAGES C ASM_NASM)
set(CMAKE_C_STANDARD 23)
set(CMAKE_C_STANDARD_REQUIRED ON)
@@ -9,7 +9,7 @@ if (NOT DEFINED ARCH)
set(ARCH "x86_64")
endif()
message(STATUS "TermOS Kernel: Building for architecture '${ARCH}'")
message(STATUS "Dewar kernel: Building for architecture '${ARCH}'")
file(GLOB_RECURSE KERNEL_SOURCES CMAKE_CONFIGURE_DEPENDS
+40
View File
@@ -0,0 +1,40 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <types.h>
#define CPU_FEAT_FPU (1ULL << 0)
#define CPU_FEAT_TSC (1ULL << 1)
#define CPU_FEAT_MSR (1ULL << 2)
#define CPU_FEAT_APIC (1ULL << 3)
#define CPU_FEAT_MTRR (1ULL << 4)
#define CPU_FEAT_PAE (1ULL << 5)
#define CPU_FEAT_SSE (1ULL << 10)
#define CPU_FEAT_SSE2 (1ULL << 11)
#define CPU_FEAT_SSE3 (1ULL << 12)
#define CPU_FEAT_SSSE3 (1ULL << 13)
#define CPU_FEAT_SSE4_1 (1ULL << 14)
#define CPU_FEAT_SSE4_2 (1ULL << 15)
#define CPU_FEAT_AVX (1ULL << 20)
#define CPU_FEAT_F16C (1ULL << 21)
#define CPU_FEAT_RDRAND (1ULL << 22)
#define CPU_FEAT_HYPERVISOR (1ULL << 30)
typedef struct {
u64 user_rsp;
u64 kernel_rsp;
u64 self;
u64 features;
char vendor[13];
u32 family;
u32 model;
} cpu_info;
extern cpu_info g_cpu;
void cpuinfo_init(u64 kernel_stack_top);
bool cpu_has(u64 feature);
+2
View File
@@ -37,4 +37,6 @@ typedef struct {
u16 iomap_base;
} __attribute__((packed)) TSS;
extern TSS tss;
void gdt_init();
+20
View File
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#pragma once
#define MSR_EFER 0xC0000080
#define MSR_STAR 0xC0000081
#define MSR_LSTAR 0xC0000082
#define MSR_FMASK 0xC0000084
#define MSR_KERNEL_GS_BASE 0xC0000102
#define EFER_SCE 0x01 // System Call Enable
typedef enum {
SYS_EXIT,
SYS_EXEC,
SYS_WRITE,
} syscalls;
void syscall_init();
+8
View File
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <types.h>
#include <core/scheduler.h>
u64 load_hot(process* proc, u8* data);
+10
View File
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <types.h>
#include <core/scheduler.h>
bool exec_init(process* p, const char* path);
void init_task_entry();
+2 -1
View File
@@ -4,4 +4,5 @@
#pragma once
#include <types.h>
u64 shitrand();
void rng_init();
u64 krand();
+18 -2
View File
@@ -3,14 +3,30 @@
#pragma once
#include <types.h>
typedef enum process_state {
DEAD,
RUNNING,
} process_state;
typedef struct process {
u64 pid;
process_state state;
u64 pml4_phys;
struct process* parent;
char name[32];
} process;
typedef struct task {
u64 rsp;
struct task* next;
u32 id;
u32 sleep_ticks;
} task_t;
u64 kernel_stack_top;
process* proc;
} task;
void sched_init();
task_t* sched_spawn(void(*entry)());
task* sched_spawn(void(*entry)(), process* owner, bool is_user, u64 fixed_user_stack);
u64 sched_next(u64 curr_rsp);
void yield(u64 ticks);
+1 -9
View File
@@ -26,16 +26,8 @@ typedef struct {
const unsigned char* base;
} SG_Font;
typedef struct {
SG_Context *ctx;
SG_Point pos;
const char *title;
} SG_Window;
void sg_init(SG_Context *ctx);
u32 sg_get_pixel(SG_Context *ctx, SG_Point *p);
void sg_put_img(SG_Context *ctx, SG_Point *p, SG_Image *img);
void sg_draw_rect(SG_Context *ctx, SG_Point *p, u32 w, u32 h, u32 color);
void sg_draw_char_bitmap(SG_Context *ctx, SG_Point *p, char c, u32 color, SG_Font *font);
SG_Window* create_window(const char *title, SG_Point* size, SG_Point* position);
void composer_task();
void sg_draw_char_bitmap(SG_Context *ctx, SG_Point *p, char c, u32 color, SG_Font *font);
+4
View File
@@ -37,3 +37,7 @@
void vmm_init(Bootinfo* info);
u64* vmm_map_page(u64* pml4, u64 phys, u64 virt, u64 flags);
u64 vmm_create_address_space();
u64 vmm_get_current_cr3();
void load_cr3(u64 pml4_addr);
void vmm_setup_user_stack(u64* pml4_phys);
+3 -1
View File
@@ -10,4 +10,6 @@ void cmd_regs();
void print_regs();
void cmd_sleep();
void cmd_debug();
int rectest(int a);
void cmd_rand();
void cmd_ver();
void cmd_userspace();
+72
View File
@@ -0,0 +1,72 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#include "types.h"
#include <cpuinfo.h>
#define MSR_GS_BASE 0xC0000101
#define MSR_KERNEL_GS_BASE 0xC0000102
cpu_info g_cpu = {0};
static inline void cpuid(u32 leaf, u32 subleaf, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx) {
__asm__ volatile("cpuid"
: "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx)
: "a"(leaf), "c"(subleaf)
);
}
static inline void wrmsr(u32 msr, u64 val) {
u32 low = (u32)val;
u32 high = (u32)(val >> 32);
__asm__ volatile("wrmsr" :: "a"(low), "d"(high), "c"(msr));
}
void cpuinfo_init(u64 kernel_stack_top) {
g_cpu.kernel_rsp = kernel_stack_top;
g_cpu.self = (u64)&g_cpu;
wrmsr(MSR_KERNEL_GS_BASE, (u64)&g_cpu);
u32 eax, ebx, ecx, edx;
cpuid(0, 0, &eax, &ebx, &ecx, &edx);
u32* vendor_ptr = (u32*)g_cpu.vendor;
vendor_ptr[0] = ebx;
vendor_ptr[1] = edx;
vendor_ptr[2] = ecx;
g_cpu.vendor[12] = '\0';
cpuid(1, 0, &eax, &ebx, &ecx, &edx);
g_cpu.family = (eax >> 8) & 0xF;
g_cpu.model = (eax >> 4) & 0xF;
if (g_cpu.family == 6 || g_cpu.family == 15) {
g_cpu.model += ((eax >> 16) & 0xF) << 4;
}
if (edx & (1 << 0)) g_cpu.features |= CPU_FEAT_FPU;
if (edx & (1 << 4)) g_cpu.features |= CPU_FEAT_TSC;
if (edx & (1 << 5)) g_cpu.features |= CPU_FEAT_MSR;
if (edx & (1 << 6)) g_cpu.features |= CPU_FEAT_PAE;
if (edx & (1 << 9)) g_cpu.features |= CPU_FEAT_APIC;
if (edx & (1 << 12)) g_cpu.features |= CPU_FEAT_MTRR;
if (edx & (1 << 25)) g_cpu.features |= CPU_FEAT_SSE;
if (edx & (1 << 26)) g_cpu.features |= CPU_FEAT_SSE2;
if (ecx & (1 << 0)) g_cpu.features |= CPU_FEAT_SSE3;
if (ecx & (1 << 9)) g_cpu.features |= CPU_FEAT_SSSE3;
if (ecx & (1 << 19)) g_cpu.features |= CPU_FEAT_SSE4_1;
if (ecx & (1 << 20)) g_cpu.features |= CPU_FEAT_SSE4_2;
if (ecx & (1 << 28)) g_cpu.features |= CPU_FEAT_AVX;
if (ecx & (1 << 29)) g_cpu.features |= CPU_FEAT_F16C;
if (ecx & (1 << 30)) g_cpu.features |= CPU_FEAT_RDRAND;
if (ecx & (1 << 31)) g_cpu.features |= CPU_FEAT_HYPERVISOR;
}
bool cpu_has(u64 feature) {
return (g_cpu.features & feature) != 0;
}
+2 -1
View File
@@ -27,9 +27,10 @@ stack_guard:
global stack_bottom
stack_bottom:
resb 16384
global stack_top
stack_top:
section .text
section .text.entry
global _start
global gdt_flush
extern kmain
+16 -7
View File
@@ -4,8 +4,9 @@
// just fucking kill me already
#include <gdt.h>
#define GDT_ENTIRES 7
GDTDescriptor gdt[5];
GDTDescriptor gdt[GDT_ENTIRES];
GDTPtr gdt_ptr;
TSS tss;
u8 double_fault_stack[4096] = {0};
@@ -40,7 +41,7 @@ void write_tss(int num) {
extern void gdt_flush(u64 gdt_ptr_addr); // entry.asm
void gdt_init() {
gdt_ptr.limit = (sizeof(GDTDescriptor) * 5) - 1;
gdt_ptr.limit = (sizeof(GDTDescriptor) * GDT_ENTIRES) - 1;
gdt_ptr.base = (u64)&gdt;
// 0: Null
@@ -53,17 +54,25 @@ void gdt_init() {
// 0x20 = 0010 0000 bit 5 is "Long mode"
// 2: Kernel Data (Ring 0)
// Access: 0x92 (Present, Ring0, Read/Write)
gdt_set_gate(2, 0, 0, 0x92, 0); // 0x92 can't exec
gdt_set_gate(2, 0, 0, 0x92, 0); // 0x92 = 1 00 1 0 0 1
for (u64 i = 0; i < sizeof(TSS); i++) ((u8*)&tss)[i] = 0; // hack. zeroifying tss struct
// 3: User Data (Ring 3)
// Access: 0xF2 (Present, Ring3, Read/Write)
gdt_set_gate(3, 0, 0, 0xF2, 0); // 0xF2 = 1 11 1 0 0 1
// 4: User Code (Ring 3)
// Access: 0xFA (Present, Ring3, RWX)
gdt_set_gate(4, 0, 0, 0xFA, 0x20); // 0xFA = 1 11 1 1 0 1
for (u64 i = 0; i < sizeof(TSS); i++) ((u8*)&tss)[i] = 0; // zeroifying tss struct
tss.iomap_base = sizeof(TSS);
tss.ist1 = (u64)double_fault_stack + sizeof(double_fault_stack);
write_tss(3);
write_tss(5);
gdt_flush((u64)&gdt_ptr);
// telling cpu that TSS info located at gdt[3]; offset = 3 * 8 = 24 = 0x18
__asm__ volatile ("ltr %%ax" :: "a" (0x18));
// telling cpu that TSS info located at gdt[5]; offset = 5 * 8 = 40 = 0x28
__asm__ volatile ("ltr %%ax" :: "a" (0x28));
}
+70
View File
@@ -0,0 +1,70 @@
; SPDX-License-Identifier: GPL-3.0-or-later
; Copyright (c) 2026 0xKarinyash
bits 64
extern syscall_dispatch
global syscall_entry
section .text
syscall_entry:
swapgs
mov [gs:0], rsp ; saving users rsp in g_cpu.user_rsp
mov rsp, [gs:8] ; load kernel rsp from g_cpu.kernel_rsp
push qword [gs:0]
push r11 ; rflags
push rcx ; rip
push rbp
push rbx
push rdi
push rsi
push rdx
push r10
push r8
push r9
push r12
push r13
push r14
push r15
; preparing c code
; c waits rdi, rsi, rdx, rcx, r8, r9
; user sent rax, rdi, rsi, rdx, r10, r8 (rax=id)
mov r9, r8 ; 6th arg
mov r8, r10 ; 5th arg
mov rcx, rdx ; 4th arg
mov rdx, rsi ; 3rd arg
mov rsi, rdi ; 2nd arg
mov rdi, rax ; 1st arg (id)
call syscall_dispatch
; restoring context except RAX (result there)
pop r15
pop r14
pop r13
pop r12
pop r9
pop r8
pop r10
pop rdx
pop rsi
pop rdi
pop rbx
pop rbp
pop rcx ; rip
pop r11 ; rflags
add rsp, 8 ; skip rsp
mov [gs:8], rsp
mov rsp, [gs:0]
swapgs
o64 sysret
+66
View File
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#include <cpuinfo.h>
#include <syscall.h>
#include <types.h>
#include <drivers/console.h>
#include <mm/pmm.h>
#include <mm/vmm.h>
static inline void wrmsr(u32 msr, u64 val) {
u32 low = (u32)val;
u32 high = (u32)(val >> 32);
__asm__ volatile("wrmsr" :: "a"(low), "d"(high), "c"(msr));
}
static inline u64 rdmsr(u32 msr) {
u32 low, high;
__asm__ volatile("rdmsr" : "=a"(low), "=d"(high) : "c"(msr));
return ((u64)high << 32) | low;
}
extern void syscall_entry();
void syscall_init() {
u64 efer = rdmsr(MSR_EFER);
wrmsr(MSR_EFER, efer | 1); // Enabling SCE in EFER. Just enabling 0 bit
// setting up STAR
// 32:47 kernel selector (0x08)
// 48:64 user selector (0x01 cuz sysret adds +16 for CS and +8 for SS)
u64 star = (0x13ULL << 48) | (0x08ULL << 32);
wrmsr(MSR_STAR, star);
wrmsr(MSR_LSTAR, (u64)syscall_entry); // setting handler adress
// masking flags (IA32_FMASK)
// 9 bit for finterrupts in syscall (IF) and few more necessary flags
wrmsr(MSR_FMASK, 0x200); // masking only IF
if (g_cpu.kernel_rsp == 0) {
void* stack_phys = pmm_alloc_page();
g_cpu.kernel_rsp = (u64)stack_phys + HHDM_OFFSET + 4096;
}
wrmsr(MSR_KERNEL_GS_BASE, (u64)&g_cpu);
}
u64 syscall_dispatch(u64 id, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5) {
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;
}
default: kprintf("[Dewar] Unknown syscall %d\n", id); return -1;
}
}
+46
View File
@@ -0,0 +1,46 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#include <core/hot.h>
#include <core/scheduler.h>
#include <core/string.h>
#include <mm/pmm.h>
#include <mm/vmm.h>
#include <mm/heap.h>
#include <mm/memory.h>
#include "../../common/hot_header.h"
u64 load_hot(process* proc, u8* data) {
hot_header* header = (hot_header*)data;
if (header->magic != HOT_MAGIC) {
return -1;
}
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);
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);
}
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);
}
load_cr3(kernel_cr3);
}
return header->entry_point;
}
+47
View File
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#include <core/panic.h>
#include <core/hot.h>
#include <core/loader.h>
#include <core/scheduler.h>
#include <core/string.h>
#include <shell/ksh.h>
#include <mm/pmm.h>
#include <mm/vmm.h>
#include <mm/heap.h>
#include <mm/memory.h>
#include <fs/vfs.h>
#include <drivers/console.h>
#include <types.h>
extern task* curr_task;
#define USER_STACK_TOP 0x70000000
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");
fs_node* file = vfs_open("/init");
if (!file) panic("FATAL: /init not found!");
u8* file_buffer = (u8*)malloc(file->len);
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);
while(1) { __asm__("sti; hlt"); }
}
+5 -3
View File
@@ -51,7 +51,9 @@ const char* fun_messages[] = {
"Attaboy, Jack. He's good. Really good.",
"Zhenih priehal",
"YOUR PC WAS BLOCKED BY FBI FOR WATCHING PORNOGRAPHY SEND 20 US DOLLARS",
"fuck off"
"fuck off",
"Your GPU is now mining Ethereum for me. Thanks.",
"Your PC is locked!\n\t\t\t\tPay a fee of 0.019082006 bitcoins to a wallet 1KtoProchitalTotSosal to get decryption key!",
};
@@ -102,7 +104,7 @@ void draw_panic_bg() {
console_set_default_color(0xFFFFFF);
u64 msg_count = sizeof(fun_messages) / sizeof(fun_messages[0]);
u8 rand_num = shitrand() % msg_count;
u8 rand_num = krand() % msg_count;
kprintf("\n\n");
kprintf("\t\t\t\t^bKERNEL PANIC^! :( \n");
@@ -133,7 +135,7 @@ __attribute__((noreturn)) void panic_exception(Registers *regs) {
u64 user = (regs->err_code & (1 << 2)) != 0;
u64 reserved = (regs->err_code & (1 << 3)) != 0;
u64 instruction = (regs->err_code & (1 << 4)) != 0;
kprintf("\t\t\t[^bP^!] ^yReason^! %s\n", present ? "Page Protection violation" : "Non-present page");
kprintf("\t\t\t[^bP^!] ^yReason^!: %s\n", present ? "Page Protection violation" : "Non-present page");
kprintf("\t\t\t[^bW^!] ^yCaused by^! %s\n", write ? "WRITE" : "READ");
kprintf("\t\t\t[^bU^!] ^yRing^! %s\n", user ? "3" : "0");
if (reserved) kprintf("\t\t\t[^bR^!] CPU Wrote 1 to a reserved field in page table entry. ^rCorrupt page table?^!\n");
+34 -4
View File
@@ -1,15 +1,45 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2025 0xKarinyash
#include "bootinfo.h"
#include <core/rand.h>
#include <cpuinfo.h>
#include <types.h>
// really shiity rand lol.
// not shitty.. basic.
static u64 prng_state = 0;
u64 shitrand() {
int lo, hi;
static inline u64 rdtsc() {
u32 lo, hi;
__asm__ volatile ("rdtsc" : "=a" (lo), "=d" (hi));
return ((u64)hi << 32) | lo;
}
void rng_init() {
prng_state = rdtsc();
if (prng_state == 0) prng_state = BOOTINFO_MAGIC; // why not reuse "termOS"?
}
static u64 xorshift_rand() {
u64 x = prng_state;
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
return prng_state = x;
}
static bool hw_rand(u64 *val) {
u8 ok;
__asm__ volatile ("rdrand %0; setc %1"
: "=r" (*val), "=qm" (ok));
return ok != 0;
}
u64 krand() {
u64 res;
if (cpu_has(CPU_FEAT_RDRAND)) {
if (hw_rand(&res)) return res;
}
return xorshift_rand();
}
+37 -12
View File
@@ -3,36 +3,56 @@
#include <core/panic.h>
#include <core/scheduler.h>
#include <core/string.h>
#include <mm/heap.h>
#include <mm/vmm.h>
#include <cpuinfo.h>
#include <gdt.h>
task_t* curr_task = nullptr;
task* curr_task = nullptr;
u32 next_pid = 1;
extern void irq0_handler();
extern u64 pml4_kernel_phys;
static process kernel_process;
void sched_init() {
task_t* kt = (task_t*)malloc(sizeof(task_t));
kernel_process.pid = 0;
kernel_process.state = RUNNING;
kernel_process.pml4_phys = pml4_kernel_phys;
strcpy(kernel_process.name, "kernel");
task* kt = (task*)malloc(sizeof(task));
kt->id = 0;
kt->proc = &kernel_process;
kt->sleep_ticks = 0;
kt->next = kt;
curr_task = kt;
}
task_t* sched_spawn(void(*entry)()) {
task_t* t = (task_t*)malloc(sizeof(task_t));
task* sched_spawn(void(*entry)(), process* owner, bool is_user, u64 fixed_user_stack) {
task* t = (task*)malloc(sizeof(task));
if (!t) return nullptr;
if (!owner) owner = &kernel_process;
u64 stack_size = 16384;
u8* stack_base = (u8*)malloc(stack_size);
if (!stack_base) panic("OOM for task stack");
u64* rsp = (u64*)(stack_base + stack_size);
*--rsp = 0x10; // SS -- Kernel data
*--rsp = (u64)stack_base + stack_size; // rsp
*--rsp = 0x202; // RFLAGS -- Interrupts Enabled | Reserved bit;
*--rsp = 0x08; // CS -- Kernel Code;
u64 cs = is_user ? 0x23 : 0x08;
u64 ss = is_user ? 0x1b : 0x10;
u64 rflags = 0x202;
u64 target_rsp = 0;
if (is_user) target_rsp = fixed_user_stack;
else target_rsp = (u64)stack_base + stack_size;
*--rsp = ss; // SS -- Kernel data
*--rsp = target_rsp; // rsp
*--rsp = rflags; // RFLAGS -- Interrupts Enabled | Reserved bit;
*--rsp = cs; // CS -- Kernel Code;
*--rsp = (u64)entry; // RIP
*--rsp = 0; // int no
@@ -41,11 +61,12 @@ task_t* sched_spawn(void(*entry)()) {
for (u8 i = 0; i < 15; i++) *--rsp = 0; // R15 .. RAX
t->rsp = (u64)rsp;
t->proc = owner;
t->id = next_pid++;
t->sleep_ticks = 0;
t->next = curr_task->next;
t->kernel_stack_top = (u64)stack_base + stack_size;
curr_task->next = t;
return t;
}
@@ -53,7 +74,7 @@ u64 sched_next(u64 curr_rsp) {
if (!curr_task) return curr_rsp;
curr_task->rsp = curr_rsp;
task_t* it = curr_task->next;
task* it = curr_task->next;
do {
if (it->sleep_ticks > 0) it->sleep_ticks--;
@@ -62,10 +83,14 @@ u64 sched_next(u64 curr_rsp) {
if (curr_task->sleep_ticks > 0) curr_task->sleep_ticks--;
task_t* next = curr_task->next;
task* next = curr_task->next;
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);
curr_task = next;
tss.rsp0 = curr_task->kernel_stack_top;
g_cpu.kernel_rsp = curr_task->kernel_stack_top;
return curr_task->rsp;
}
-63
View File
@@ -8,11 +8,8 @@
#include <mm/memory.h>
#define SHITGUI_TRANSPARENCY_KEY 0xFF00FF
#define SHITGUI_MAX_WINDOWS_AMOUNT 64
SG_Context* main_context;
SG_Window* windows[SHITGUI_MAX_WINDOWS_AMOUNT]; // нет блять линукс
u64 windows_amount = 0;
void sg_init(SG_Context *ctx) {
main_context = ctx;
@@ -85,64 +82,4 @@ void sg_draw_char_bitmap(SG_Context *ctx, SG_Point *p, char c, u32 color, SG_Fon
}
}
}
}
SG_Window* create_window(const char *title, SG_Point* size, SG_Point* position) {
if (windows_amount >= SHITGUI_MAX_WINDOWS_AMOUNT) return nullptr;
SG_Context* ctx = nullptr;
u32* fb = nullptr;
SG_Window* window = nullptr;
ctx = (SG_Context*)malloc(sizeof(SG_Context));
if (!ctx) goto fail; // goto is GOOD for cleaning up in C stfu.
// Mainline linux kernel contains 100k gotos
fb = malloc(size->x * size->y * sizeof(u32));
if (!fb) goto fail;
memset(fb, 0, size->x * size->y * sizeof(u32));
window = (SG_Window*)malloc(sizeof(SG_Window));
if (!window) goto fail;
ctx->fb = fb;
ctx->height = size->y;
ctx->width = size->x;
ctx->pitch = size->x;
window->ctx = ctx;
window->title = title;
window->pos.x = position->x;
window->pos.y = position->y;
windows[windows_amount] = window;
windows_amount++;
return window;
fail:
if (ctx) free(ctx);
if (fb) free(fb);
if (window) free(window);
return nullptr;
}
void render_window(SG_Context *ctx, SG_Window *window) {
SG_Image img = {0};
img.buffer = window->ctx->fb;
if (!img.buffer) panic("No img buffer found");
img.height = window->ctx->height;
img.width = window->ctx->width;
sg_put_img(ctx, &window->pos, &img);
}
void composer_task() {
while (true) {
for (u64 i = 0; i < windows_amount; i++) {
render_window(main_context, windows[i]);
}
yield(1);
}
}
+27 -5
View File
@@ -2,6 +2,7 @@
// Copyright (c) 2025 0xKarinyash
#include "bootinfo.h"
#include <shell/ksh.h>
#include <types.h>
@@ -14,10 +15,14 @@
#include <core/panic.h>
#include <core/scheduler.h>
#include <core/splash.h>
#include <core/rand.h>
#include <core/loader.h>
#include <gdt.h>
#include <idt.h>
#include <pic.h>
#include <cpuinfo.h>
#include <syscall.h>
#include <mm/pmm.h>
#include <mm/vmm.h>
@@ -30,6 +35,7 @@
#define BG_COLOR 0x111111
extern u64 _kernel_end;
extern void* stack_top;
static SG_Context sg_ctx;
void kmain(Bootinfo* info) {
@@ -40,6 +46,10 @@ void kmain(Bootinfo* info) {
if (info->magic != BOOTINFO_MAGIC) panic("Corrupt bootinfo!");
cpuinfo_init((u64)&stack_top);
kprintf("Got CPUINFO\n");
rng_init();
kprintf("RNG initialized\n");
gdt_init();
kprintf("GDT initialized\n");
idt_init();
@@ -58,15 +68,16 @@ void kmain(Bootinfo* info) {
kprintf("Scheduler initialized\n");
sg_init(&sg_ctx);
kprintf("Shitgui initialized\n");
syscall_init();
info = (Bootinfo*)PHYS_TO_HHDM((u64)info);
fs_node* root = cpio_mount(PHYS_TO_HHDM(info->initramfs.addr), info->initramfs.size);
vfs_init(root);
kprintf("VFS initialized");
kprintf("VFS initialized\n");
u32 *fb = (u32*)info->framebuffer.base;
if (!fb) return serial_write("No framebuffer found!!");
if (!fb) return kprintf("No framebuffer found!!");
sg_ctx.fb = fb;
sg_ctx.height = info->framebuffer.height;
@@ -79,9 +90,20 @@ void kmain(Bootinfo* info) {
show_splash(&sg_ctx);
sched_spawn(composer_task);
sched_spawn(ksh);
if (!info->initramfs.addr) kprintf("^rWARNING^!: Failed to load ^yinitramfs^!, VFS is empty.\n\n");
bool staying_in_ksh = false;
if (!info->initramfs.addr) {
kprintf("^rWARNING^!: Failed to load ^yinitramfs^!! Staying in kernel rescue shell!\n\n");
staying_in_ksh = true;
}
kprintf("Press any key to stay in ^gksh^!. \nPress ^yenter^! to continue booting in ring 3\n");
char c = '\n';
c = console_getc();
if (c != '\n') staying_in_ksh = true;
if (staying_in_ksh) sched_spawn(ksh, nullptr, false, 0);
else sched_spawn(init_task_entry, nullptr, false, 0);
__asm__ volatile("sti");
while (true) __asm__ volatile("hlt");
+67 -17
View File
@@ -4,13 +4,19 @@
#include <mm/pmm.h>
#include <mm/memory.h>
#include <core/panic.h>
#include <gdt.h>
#include <idt.h>
#include <types.h>
#include "bootinfo.h"
#define USER_STACK_TOP 0x70000000
#define USER_STACK_SIZE 0x4000
u64* pml4_kernel = nullptr;
u64 pml4_kernel_phys = 0;
static bool is_initialized = false;
extern u64 _kernel_start;
@@ -18,7 +24,6 @@ extern u64 _kernel_end;
extern u8* bitmap;
extern u64 bitmap_size_g;
extern GDTDescriptor gdt[];
extern TSS tss[];
extern IDTEntry idt[];
extern u8 double_fault_stack[];
extern u8 stack_guard;
@@ -37,12 +42,16 @@ u64* vmm_map_page(u64* pml4, u64 phys, u64 virt, u64 flags) {
u64* pml4_virt = pml4;
if (is_initialized) pml4_virt = (u64*)PHYS_TO_HHDM((u64)pml4);
u64 table_flags = PTE_PRESENT | PTE_RW | (flags & PTE_USER);
if (!(pml4_virt[pml4_idx] & PTE_PRESENT)) {
u64* addr = pmm_alloc_page();
if (!addr) return nullptr;
u64* addr_virt = get_table_virt((u64)addr);
memset(addr_virt, 0, PAGE_SIZE);
pml4_virt[pml4_idx] = (u64)addr | PTE_PRESENT | PTE_RW;
pml4_virt[pml4_idx] = (u64)addr | table_flags;
} else {
pml4_virt[pml4_idx] |= (flags & PTE_USER);
}
u64* pdpt = (u64*)PTE_GET_ADDR(pml4_virt[pml4_idx]);
@@ -53,7 +62,9 @@ u64* vmm_map_page(u64* pml4, u64 phys, u64 virt, u64 flags) {
if (!addr) return nullptr;
u64* addr_virt = get_table_virt((u64)addr);
memset(addr_virt, 0, PAGE_SIZE);
pdpt_virt[pdpt_idx] = (u64)addr | PTE_PRESENT | PTE_RW;
pdpt_virt[pdpt_idx] = (u64)addr | table_flags;
} else {
pdpt_virt[pdpt_idx] |= (flags & PTE_USER);
}
u64* pd = (u64*)PTE_GET_ADDR(pdpt_virt[pdpt_idx]);
@@ -64,7 +75,9 @@ u64* vmm_map_page(u64* pml4, u64 phys, u64 virt, u64 flags) {
if (!addr) return nullptr;
u64* addr_virt = get_table_virt((u64)addr);
memset(addr_virt, 0, PAGE_SIZE);
pd_virt[pd_idx] = (u64)addr | PTE_PRESENT | PTE_RW;
pd_virt[pd_idx] = (u64)addr | table_flags;
} else {
pd_virt[pd_idx] |= (flags & PTE_USER);
}
u64* pt = (u64*)PTE_GET_ADDR(pd_virt[pd_idx]);
@@ -82,26 +95,30 @@ void vmm_unmap_page(u64* pml4, u64 virt) {
u64 pdpt_idx = VMM_PDPT_INDEX(virt);
u64 pml4_idx = VMM_PML4_INDEX(virt);
if (!(pml4[pml4_idx] & PTE_PRESENT)) return;
u64* pdpt = get_table_virt(PTE_GET_ADDR(pml4[pml4_idx]));
if (!(pdpt[pdpt_idx] & PTE_PRESENT)) return;
u64* pd = get_table_virt(PTE_GET_ADDR(pdpt[pdpt_idx]));
if (!(pd[pd_idx] & PTE_PRESENT)) return;
u64* pt = get_table_virt(PTE_GET_ADDR(pd[pd_idx]));
u64* pml4_virt = pml4;
if (is_initialized) pml4_virt = (u64*)PHYS_TO_HHDM((u64)pml4);
pt[pt_idx] = 0;
if (!(pml4_virt[pml4_idx] & PTE_PRESENT)) return;
u64* pdpt_virt = get_table_virt(PTE_GET_ADDR(pml4_virt[pml4_idx]));
if (!(pdpt_virt[pdpt_idx] & PTE_PRESENT)) return;
u64* pd_virt = get_table_virt(PTE_GET_ADDR(pdpt_virt[pdpt_idx]));
if (!(pd_virt[pd_idx] & PTE_PRESENT)) return;
u64* pt_virt = get_table_virt(PTE_GET_ADDR(pd_virt[pd_idx]));
pt_virt[pt_idx] = 0;
__asm__ volatile("invlpg (%0)" :: "r" (virt) : "memory");
}
static inline void load_cr3(u64 pml4_addr) {
void load_cr3(u64 pml4_addr) {
__asm__ volatile ("mov %0, %%cr3" :: "r"(pml4_addr) : "memory");
}
void vmm_init(Bootinfo* info) {
pml4_kernel = pmm_alloc_page();
pml4_kernel_phys = (u64)pmm_alloc_page();
pml4_kernel = (u64*)pml4_kernel_phys;
memset(pml4_kernel, 0, PAGE_SIZE);
u64 k_virt_start = (u64)&_kernel_start;
@@ -119,6 +136,39 @@ void vmm_init(Bootinfo* info) {
bitmap = (u8*)PHYS_TO_HHDM((u64)bitmap);
info->framebuffer.base = (u32*)FB_VIRT_BASE;
load_cr3((u64)pml4_kernel);
load_cr3(pml4_kernel_phys);
is_initialized = true;
}
}
u64 vmm_create_address_space() {
u64 phys = (u64)pmm_alloc_page();
if (!phys) return 0;
u64* virt = (u64*)PHYS_TO_HHDM(phys);
memset(virt, 0, PAGE_SIZE);
u64* kernel_pml4_virt = get_table_virt((u64)pml4_kernel);
for (u32 i = 256; i < 512; i++) {
virt[i] = kernel_pml4_virt[i];
}
return phys;
}
u64 vmm_get_current_cr3() {
u64 cr3;
__asm__ volatile("mov %%cr3, %0" : "=r"(cr3));
return cr3;
}
void vmm_setup_user_stack(u64* pml4_phys) {
u64 stack_bottom = USER_STACK_TOP - USER_STACK_SIZE;
for (u64 addr = stack_bottom; addr < USER_STACK_TOP; addr += 4096) {
void* phys = pmm_alloc_page();
if (!phys) panic("OOM in user stack setup");
memset((void*)PHYS_TO_HHDM((u64)phys), 0, 4096);
vmm_map_page((u64*)pml4_phys, (u64)phys, addr, PTE_PRESENT | PTE_RW | PTE_USER);
}
}
+39 -18
View File
@@ -1,14 +1,26 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2025 0xKarinyash
#include <drivers/console.h>
#include <core/rand.h>
#include <drivers/timer.h>
#include <types.h>
#include <cpuinfo.h>
#include <drivers/console.h>
#include <drivers/timer.h>
#include <core/rand.h>
#include <core/loader.h>
#include <core/scheduler.h>
#include <core/string.h>
#include <mm/vmm.h>
#include <mm/heap.h>
#include <shell/dbgcmd.h>
#include "../data/cats.h"
#include "shell/dbgcmd.h"
extern task* curr_task;
const char* ascii_logo[] = {
" /\\___/\\ ",
@@ -21,47 +33,40 @@ const char* ascii_logo[] = {
" |_______| "
};
int rectest(int a) {
volatile int b = a + 1;
kprintf("%d", b);
return rectest(b * 2);
}
void cmd_kfetch() {
u64 uptime_s = get_uptime() / 1000;
kprintf("\n\n");
kprintf("^p %s ^!\t\t^g kernel^!@^gtermos\n^0", ascii_logo[0]);
kprintf("^p %s ^!\t\t^!-------------\n^!", ascii_logo[1]);
kprintf("^p %s ^!\t\t^gOS^!: termOS 0.0.1\n^!", ascii_logo[2]);
kprintf("^p %s ^!\t\t^gKernel^!: sucks\n^!", ascii_logo[3]);
kprintf("^p %s ^!\t\t^!-------------\n^!", ascii_logo[1]);
kprintf("^p %s ^!\t\t^gOS^!: termOS %s\n^!", ascii_logo[2], TERMOS_VERSION);
kprintf("^p %s ^!\t\t^gKernel^!: Dewar (x86_64), build: %s %s\n^!", ascii_logo[3], __DATE__, __TIME__);
kprintf("^p %s ^!\t\t^gUptime^!: %d seconds\n^!", ascii_logo[4], uptime_s);
kprintf("^p %s ^!\t\t^gShell^!: ksh\n^!", ascii_logo[5]);
kprintf("^p %s ^p\t\t^gDE^!: shitgui\n^!", ascii_logo[6]);
kprintf("^p %s ^p\t\t^gCPU^!: %s\n^!", ascii_logo[7], "cool one");
kprintf("^p %s ^!\t\t^gDE^!: shitgui\n^!", ascii_logo[6]);
kprintf("^p %s ^!\t\t^gCPU^!: %s (^yFamily^!: %d; ^yModel^!: %d)\n^!", ascii_logo[7], g_cpu.vendor, g_cpu.family, g_cpu.model);
kprintf("\n\n");
}
void cmd_meow() {
u64 cats_count = sizeof(cats) / sizeof(cats[0]);
u8 rand_num = shitrand() % cats_count;
u8 rand_num = krand() % cats_count;
kprintf("Nyaaa!!\n\n%s\n\n", cats[rand_num]);
}
void cmd_help() {
kprintf("Welcome to ^ptermOS^!'s ^gk^!ernel ^gsh^!ell!\n");
kprintf("It loads when userspace is failed to load and acts as a basic rescue environment\n");
kprintf("At this moment i dont have userspace so it loads always\n");
kprintf("Available commands:\n");
kprintf("\t^rDebug^!:\n");
kprintf("\t\t^ysleep^! \t\tSleep for 3seconds\n");
kprintf("\t\t^ydbg^! \t\tTest new stuff\n");
kprintf("\t\t^yregs^! \t\tPrint current regs\n");
kprintf("\t\t^yrectest^! \t\tTSS test\n");
kprintf("\t\t^ypanic^! \t\tPanics (lol)\n");
kprintf("\t\t^yud2^! \t\tPanics with #UD\n");
kprintf("\t\t^ypf^! \t\tPanics with #PF\n");
kprintf("\t\t^yuserspace^! \t\tAttempt to jump in ring 3\n");
kprintf("\t^pFun^!:\n");
kprintf("\t\t^ysplash^! \t\tShows splash (works kinda unstable)\n");
@@ -74,6 +79,8 @@ void cmd_help() {
kprintf("\t^bMisc^!:\n");
kprintf("\t\t^yclear^! \t\tClear console\n");
kprintf("\t\t^yhelp^! \t\tShow this menu\n");
kprintf("\t\t^yrand^! \t\tGet a random number\n");
kprintf("\t\t^yver^! \t\tDisplays termOS's version\n");
}
void cmd_regs() {
@@ -100,8 +107,22 @@ void cmd_sleep() {
sleep(3000);
}
void cmd_rand() {
kprintf("Your rand number (0..100) is ... ^y%d^!!\n", krand() % 100);
}
void cmd_debug() {
u64 status = debug();
kprintf("\nDebug ended with code %d\n", status);
return;
}
void cmd_ver() {
kprintf("termOS version %s\n", TERMOS_VERSION);
kprintf("Dewar Kernel (x86_64), build: %s %s\n", __DATE__, __TIME__);
kprintf("License: GPL-3.0-or-later\n");
}
void cmd_userspace() {
sched_spawn(init_task_entry, nullptr, false, 0);
}
+2 -24
View File
@@ -1,31 +1,9 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2025 0xKarinyash
// contents of this file will be changed CONSTANTLY
// im just testing new stuff here
// Copyright (c) 2026 0xKarinyash
#include <drivers/console.h>
#include <shell/dbgcmd.h>
#include <fs/vfs.h>
#include <mm/memory.h>
#include <drivers/console.h>
u64 debug() {
kprintf("Debug: Trying to open /test1.txt...\n");
fs_node* file = vfs_open("/test1.txt");
if (file == nullptr) {
kprintf("Error: File not found! Check initrd or filename.\n");
return 1;
}
kprintf("Success!\n");
kprintf("\tFilename: %s\n", file->name);
kprintf("\tSize: %d bytes\n", file->len);
char buf[64];
memset(buf, 0, 64);
vfs_read(file, 0, 63, (u8*)buf);
kprintf("\tContent: %s\n", buf);
return 0;
}
+12 -4
View File
@@ -33,9 +33,12 @@ typedef enum {
TOKEN_PANIC,
TOKEN_PANIC_UD2,
TOKEN_PANIC_PF,
TOKEN_USERSPACE,
TOKEN_CLEAR,
TOKEN_BLINKING,
TOKEN_RAND,
TOKEN_VER,
TOKEN_BACK,
TOKEN_FORWARD,
@@ -56,10 +59,10 @@ static const ksh_command_map token_map[] = {
{"sleep", TOKEN_SLEEP},
{"dbg", TOKEN_DEBUG},
{"regs", TOKEN_REGS},
{"rectest", TOKEN_RECTEST},
{"panic", TOKEN_PANIC},
{"ud2", TOKEN_PANIC_UD2},
{"pf", TOKEN_PANIC_PF},
{"userspace", TOKEN_USERSPACE},
// fun
{"meow", TOKEN_MEOW},
@@ -69,6 +72,9 @@ static const ksh_command_map token_map[] = {
// misc
{"help", TOKEN_HELP},
{"clear", TOKEN_CLEAR},
{"rand", TOKEN_RAND},
{"ver", TOKEN_VER},
{nullptr, TOKEN_NULL}
};
@@ -80,7 +86,7 @@ ksh_token char2token(char* token) {
}
void ksh() {
sched_spawn(cursor_blinker_sched_task);
sched_spawn(cursor_blinker_sched_task, nullptr, false, 0);
while (true) {
kprintf("ksh_> ");
char cmdbuff[256];
@@ -90,15 +96,17 @@ void ksh() {
case TOKEN_CLEAR: console_clear((u32) console_get_colors() & 0xFFFFFFFF); break;
case TOKEN_BLINKING: console_toggle_cursor_blink(); break;
case TOKEN_RAND: cmd_rand(); break;
case TOKEN_VER: cmd_ver(); break;
case TOKEN_SLEEP: cmd_sleep(); break;
case TOKEN_DEBUG: cmd_debug(); break;
case TOKEN_REGS: cmd_regs(); break;
case TOKEN_RECTEST: rectest(0); break;
case TOKEN_PANIC: panic("Manually initiated panic");
case TOKEN_PANIC_UD2: __asm__ volatile ("ud2");
case TOKEN_PANIC_PF: u64* bad_ptr = (u64*)0xDEADBEEF; *bad_ptr = 666;
case TOKEN_USERSPACE: cmd_userspace(); break;
case TOKEN_SPLASH: show_splash(console_get_context()); break;
case TOKEN_KFETCH: cmd_kfetch(); break;
case TOKEN_MEOW: cmd_meow(); break;
+88
View File
@@ -0,0 +1,88 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "elf2hot"
version = "0.1.0"
dependencies = [
"goblin",
]
[[package]]
name = "goblin"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4db6758c546e6f81f265638c980e5e84dfbda80cfd8e89e02f83454c8e8124bd"
dependencies = [
"log",
"plain",
"scroll",
]
[[package]]
name = "log"
version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
name = "plain"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
[[package]]
name = "proc-macro2"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4"
dependencies = [
"proc-macro2",
]
[[package]]
name = "scroll"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1257cd4248b4132760d6524d6dda4e053bc648c9070b960929bf50cfb1e7add"
dependencies = [
"scroll_derive",
]
[[package]]
name = "scroll_derive"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed76efe62313ab6610570951494bdaa81568026e0318eaa55f167de70eeea67d"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "2.0.114"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
+7
View File
@@ -0,0 +1,7 @@
[package]
name = "elf2hot"
version = "0.1.0"
edition = "2024"
[dependencies]
goblin = "0.10.4"
+98
View File
@@ -0,0 +1,98 @@
use goblin::elf::program_header::PT_LOAD;
use std::env;
use std::fs::File;
use std::io::{Read, Write};
#[repr(C, packed)]
#[derive(Default, Debug)]
struct HotHeader {
magic: u32,
version: u8,
reserved_pad: [u8; 3],
entry_point: u64,
segments_count: u64,
reserved: u64,
}
#[repr(C, packed)]
#[derive(Default, Debug, Clone, Copy)]
struct HotSegment {
stype: u64,
vaddr: u64,
offset: u64,
filesz: u64,
memsz: u64,
}
const HOT_MAGIC: u32 = 0x21544F48; // "HOT!"
fn main() -> Result<(), Box<dyn std::error::Error>> {
let args: Vec<String> = env::args().collect();
if args.len() < 3 {
println!("Usage: elf2hot <input_elf> <output_hot>");
return Ok(());
}
let input_path = &args[1];
let output_path = &args[2];
let mut f = File::open(input_path)?;
let mut buffer = Vec::new();
f.read_to_end(&mut buffer)?;
let elf = goblin::elf::Elf::parse(&buffer)?;
let mut hot_segments = Vec::new();
let mut segment_data = Vec::new();
let mut current_offset = std::mem::size_of::<HotHeader>() as u64;
let load_segments: Vec<_> = elf.program_headers.iter()
.filter(|ph| ph.p_type == PT_LOAD)
.collect();
current_offset += (load_segments.len() * std::mem::size_of::<HotSegment>()) as u64;
for ph in load_segments {
let is_code = ph.is_executable();
let data = &buffer[ph.p_offset as usize..(ph.p_offset + ph.p_filesz) as usize];
segment_data.push(data);
hot_segments.push(HotSegment {
stype: if is_code { 1 } else { 2 },
vaddr: ph.p_vaddr,
offset: current_offset,
filesz: ph.p_filesz,
memsz: ph.p_memsz,
});
current_offset += ph.p_filesz;
}
let header = HotHeader {
magic: HOT_MAGIC,
version: 1,
entry_point: elf.entry,
segments_count: hot_segments.len() as u64,
..Default::default()
};
let mut out = File::create(output_path)?;
let header_bytes: [u8; std::mem::size_of::<HotHeader>()] = unsafe { std::mem::transmute(header) };
out.write_all(&header_bytes)?;
for seg in hot_segments {
let seg_bytes: [u8; std::mem::size_of::<HotSegment>()] = unsafe { std::mem::transmute(seg) };
out.write_all(&seg_bytes)?;
}
for data in segment_data {
out.write_all(data)?;
}
println!("Successfully converted {} to {}!", input_path, output_path);
println!("Entry point: 0x{:X}", elf.entry);
Ok(())
}
+10
View File
@@ -0,0 +1,10 @@
cmake_minimum_required(VERSION 3.20)
project(termOSuserspace LANGUAGES C ASM_NASM)
set(CMAKE_C_STANDARD 23)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
message(STATUS "Building termOS's userspace")
add_subdirectory(init)
+33
View File
@@ -0,0 +1,33 @@
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)
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
)
+35
View File
@@ -0,0 +1,35 @@
ENTRY(start)
SECTIONS
{
. = 0x400000;
.text : {
*(.text)
}
.rodata : {
*(.rodata)
}
.data : {
*(.data)
}
.bss : {
*(.bss)
*(COMMON)
}
/DISCARD/ : {
*(.note.gnu.build-id)
*(.note.GNU-stack)
*(.note.gnu.property)
*(.comment)
*(.interp)
*(.dynsym)
*(.dynstr)
*(.hash)
*(.gnu.hash)
}
}
+10
View File
@@ -0,0 +1,10 @@
[bits 64]
section .text
global start
extern main
start:
call main
.hang:
jmp .hang
+16
View File
@@ -0,0 +1,16 @@
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"
);
}
int main() {
sys_write("Meowww!!!\n");
sys_write("Nyaaaaa");
for (int i = 0; i < 100; i++) sys_write("a");
}