Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 21270a3cc8 | |||
| 7d32444da2 |
+3
-1
@@ -2,4 +2,6 @@
|
||||
build*
|
||||
.venv
|
||||
initrd/image.cpio
|
||||
initramfs/*
|
||||
initramfs/*
|
||||
|
||||
target
|
||||
+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
|
||||
DEPENDS ${INIT_FILES} init_elf
|
||||
VERBATIM
|
||||
COMMENT "Packing initramfs to cpio..."
|
||||
)
|
||||
|
||||
@@ -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;
|
||||
@@ -2,5 +2,7 @@
|
||||
// Copyright (c) 2026 0xKarinyash
|
||||
|
||||
#pragma once
|
||||
#include <types.h>
|
||||
#include <core/scheduler.h>
|
||||
|
||||
void jump_to_userspace(void* entry, void* user_stack_top);
|
||||
u64 load_hot(process* proc, u8* data);
|
||||
@@ -4,6 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <types.h>
|
||||
#include <core/scheduler.h>
|
||||
|
||||
bool exec_init(const char* path);
|
||||
bool exec_init(process* p, const char* path);
|
||||
void init_task_entry();
|
||||
@@ -3,15 +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;
|
||||
u64 kernel_stack_top;
|
||||
process* proc;
|
||||
} task;
|
||||
|
||||
void sched_init();
|
||||
task* 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);
|
||||
@@ -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);
|
||||
@@ -11,4 +11,5 @@ void print_regs();
|
||||
void cmd_sleep();
|
||||
void cmd_debug();
|
||||
void cmd_rand();
|
||||
void cmd_ver();
|
||||
void cmd_ver();
|
||||
void cmd_userspace();
|
||||
@@ -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;
|
||||
}
|
||||
+26
-61
@@ -1,14 +1,17 @@
|
||||
// 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/userspace.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>
|
||||
@@ -16,67 +19,29 @@
|
||||
#include <drivers/console.h>
|
||||
#include <types.h>
|
||||
|
||||
extern u64* pml4_kernel;
|
||||
extern task* curr_task;
|
||||
|
||||
bool exec_init(const char* path) {
|
||||
kprintf("[Loader] loading %s...\n", path);
|
||||
fs_node* file = vfs_open(path);
|
||||
if (!file) {
|
||||
kprintf("[Loader] Error: %s not found in initramfs!\n", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
u64 virt_code = 0x400000;
|
||||
u64 virt_stack = 0x800000;
|
||||
u64 stack_size = 8192;
|
||||
|
||||
u64 bytes_left = file->len;
|
||||
u64 offset = 0;
|
||||
u64 page_idx = 0;
|
||||
|
||||
while (bytes_left > 0) {
|
||||
void* phys = pmm_alloc_page();
|
||||
if (!phys) {
|
||||
kprintf("Loader: OOM!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
vmm_map_page(pml4_kernel, (u64)phys, virt_code + (page_idx * 4096), PTE_PRESENT | PTE_RW | PTE_USER);
|
||||
|
||||
void* k_ptr = (void*)(HHDM_OFFSET + (u64)phys);
|
||||
memset(k_ptr, 0, 4096);
|
||||
|
||||
u64 chunk = (bytes_left > 4096) ? 4096 : bytes_left;
|
||||
vfs_read(file, offset, chunk, (u8*)k_ptr);
|
||||
|
||||
bytes_left -= chunk;
|
||||
offset += chunk;
|
||||
page_idx++;
|
||||
}
|
||||
|
||||
for (u64 i = 0; i < (stack_size / 4096); i++) {
|
||||
void* phys = pmm_alloc_page();
|
||||
vmm_map_page(pml4_kernel, (u64)phys, virt_stack + (i * 4096), PTE_PRESENT | PTE_RW | PTE_USER);
|
||||
memset((void*)(HHDM_OFFSET + (u64)phys), 0, 4096);
|
||||
}
|
||||
|
||||
__asm__ volatile(
|
||||
"mov %%cr3, %%rax\n\t"
|
||||
"mov %%rax, %%cr3\n\t"
|
||||
::: "rax", "memory"
|
||||
);
|
||||
|
||||
kprintf("[Loader] Transferring control to userspace...\n");
|
||||
jump_to_userspace((void*)virt_code, (void*)(virt_stack + stack_size));
|
||||
|
||||
return true; // unreachable
|
||||
}
|
||||
#define USER_STACK_TOP 0x70000000
|
||||
|
||||
void init_task_entry() {
|
||||
if (!exec_init("/init")) {
|
||||
kprintf("FATAL: Could not load /init\n");
|
||||
sched_spawn(ksh);
|
||||
|
||||
while(1) __asm__("hlt");
|
||||
}
|
||||
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"); }
|
||||
}
|
||||
@@ -3,7 +3,9 @@
|
||||
|
||||
#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>
|
||||
|
||||
@@ -11,30 +13,46 @@ 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* kt = (task*)malloc(sizeof(task));
|
||||
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* sched_spawn(void(*entry)()) {
|
||||
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
|
||||
@@ -43,6 +61,7 @@ task* 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;
|
||||
@@ -67,6 +86,8 @@ u64 sched_next(u64 curr_rsp) {
|
||||
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;
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Copyright (c) 2026 0xKarinyash
|
||||
|
||||
#include <core/userspace.h>
|
||||
#include <types.h>
|
||||
|
||||
#define USER_DS (0x18 | 3)
|
||||
#define USER_CS (0x20 | 3)
|
||||
#define RFLAGS_IF 0x202
|
||||
|
||||
void jump_to_userspace(void* entry, void* user_stack_top) {
|
||||
__asm__ volatile (
|
||||
"mov %0, %%ds\n"
|
||||
"mov %0, %%es\n"
|
||||
"mov %0, %%fs\n"
|
||||
:: "r" ((u64)USER_DS) : "memory"
|
||||
);
|
||||
|
||||
__asm__ volatile (
|
||||
"pushq %0\n" // SS (User Data Selector)
|
||||
"pushq %1\n" // RSP (User Stack Pointer)
|
||||
"pushq %2\n" // RFLAGS
|
||||
"pushq %3\n" // CS (User Code Selector)
|
||||
"pushq %4\n" // RIP (Entry Point)
|
||||
"iretq\n"
|
||||
:
|
||||
: "r" ((u64)USER_DS),
|
||||
"r" ((u64)user_stack_top),
|
||||
"r" ((u64)RFLAGS_IF),
|
||||
"r" ((u64)USER_CS),
|
||||
"r" ((u64)entry)
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
+2
-2
@@ -101,8 +101,8 @@ void kmain(Bootinfo* info) {
|
||||
c = console_getc();
|
||||
if (c != '\n') staying_in_ksh = true;
|
||||
|
||||
if (staying_in_ksh) sched_spawn(ksh);
|
||||
else sched_spawn(init_task_entry);
|
||||
if (staying_in_ksh) sched_spawn(ksh, nullptr, false, 0);
|
||||
else sched_spawn(init_task_entry, nullptr, false, 0);
|
||||
|
||||
__asm__ volatile("sti");
|
||||
|
||||
|
||||
+56
-13
@@ -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;
|
||||
@@ -89,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;
|
||||
@@ -126,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,19 @@
|
||||
#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"
|
||||
|
||||
extern task* curr_task;
|
||||
|
||||
const char* ascii_logo[] = {
|
||||
" /\\___/\\ ",
|
||||
" | > < | ",
|
||||
@@ -48,7 +57,6 @@ void cmd_meow() {
|
||||
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");
|
||||
@@ -58,6 +66,7 @@ void cmd_help() {
|
||||
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");
|
||||
@@ -112,4 +121,8 @@ 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);
|
||||
}
|
||||
@@ -33,6 +33,7 @@ typedef enum {
|
||||
TOKEN_PANIC,
|
||||
TOKEN_PANIC_UD2,
|
||||
TOKEN_PANIC_PF,
|
||||
TOKEN_USERSPACE,
|
||||
|
||||
TOKEN_CLEAR,
|
||||
TOKEN_BLINKING,
|
||||
@@ -61,6 +62,7 @@ static const ksh_command_map token_map[] = {
|
||||
{"panic", TOKEN_PANIC},
|
||||
{"ud2", TOKEN_PANIC_UD2},
|
||||
{"pf", TOKEN_PANIC_PF},
|
||||
{"userspace", TOKEN_USERSPACE},
|
||||
|
||||
// fun
|
||||
{"meow", TOKEN_MEOW},
|
||||
@@ -84,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];
|
||||
@@ -103,7 +105,8 @@ void ksh() {
|
||||
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;
|
||||
|
||||
Generated
+88
@@ -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"
|
||||
@@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "elf2hot"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
goblin = "0.10.4"
|
||||
@@ -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(())
|
||||
}
|
||||
@@ -1,32 +1,33 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(termOSinit LANGUAGES C ASM_NASM)
|
||||
project(termOSinit LANGUAGES C)
|
||||
|
||||
set(CMAKE_C_STANDARD 23)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_C_EXTENSIONS OFF)
|
||||
|
||||
message(STATUS "Building termOS's init")
|
||||
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 CMAKE_CONFIGURE_DEPENDS
|
||||
"src/*.asm"
|
||||
"src/*.c"
|
||||
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
|
||||
)
|
||||
|
||||
add_executable(init ${INIT_SOURCES})
|
||||
set_target_properties(init PROPERTIES
|
||||
SUFFIX ""
|
||||
LINKER_LANGUAGE C
|
||||
)
|
||||
|
||||
target_link_options(init PRIVATE
|
||||
target_link_options(init_elf PRIVATE
|
||||
-nostdlib
|
||||
-static
|
||||
-Wl,--oformat=binary
|
||||
-Wl,-Ttext=0x400000
|
||||
-Wl,-e,start
|
||||
-T "${CMAKE_CURRENT_SOURCE_DIR}/linker.ld"
|
||||
)
|
||||
|
||||
add_custom_command(TARGET init POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:init> ${CMAKE_SOURCE_DIR}/initramfs/init
|
||||
COMMENT "Installing init binary to initramfs"
|
||||
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
|
||||
)
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
[bits 64]
|
||||
|
||||
section .text
|
||||
global start
|
||||
extern main
|
||||
|
||||
start:
|
||||
call main
|
||||
.hang:
|
||||
jmp .hang
|
||||
@@ -1,17 +0,0 @@
|
||||
[BITS 64]
|
||||
|
||||
start:
|
||||
mov rax, 2 ; SYS_WRITE
|
||||
mov rdi, msg_hello ; Адрес строки
|
||||
syscall
|
||||
|
||||
mov rax, 1 ; SYS_EXEC
|
||||
syscall
|
||||
|
||||
mov rax, 0 ; SYS_EXIT
|
||||
mov rdi, 1337
|
||||
syscall
|
||||
|
||||
jmp $
|
||||
|
||||
msg_hello: db "Hello from init!", 0xA, 0
|
||||
@@ -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");
|
||||
}
|
||||
Reference in New Issue
Block a user