Pridana verze v0.1

This commit is contained in:
2026-07-12 05:44:42 +02:00
commit 1266a65b82
40 changed files with 6126 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
*.sh text eol=lf
setup text eol=lf
+11
View File
@@ -0,0 +1,11 @@
build/
tools/
asterfs.img
clean.sh
CONTRIBUTING.md
DOCS.md
README.md
ROADMAP.md
setup
setup.sh
setup-runfromdisk.sh
+84
View File
@@ -0,0 +1,84 @@
# AsterOS build systém
ARCH := x86_64
# Prefer dedicated cross toolchain, fallback to host toolchain when unavailable.
CROSS ?= $(shell if command -v x86_64-elf-gcc >/dev/null 2>&1; then echo x86_64-elf-; else echo; fi)
CC := $(CROSS)gcc
LD := $(CROSS)ld
OBJCOPY := $(CROSS)objcopy
AS := nasm
CFLAGS := -std=gnu11 -ffreestanding -fno-stack-protector -fno-pic -m64 -Wall -Wextra -Iinclude
LDFLAGS := -nostdlib -T linker.ld
BUILD := build
IMG := $(BUILD)/aster.img
DATA_DISK := asterfs.img
BRIDGE_IF ?= br0
KERNEL_OBJS := \
$(BUILD)/arch/x86_64/entry.o \
$(BUILD)/arch/x86_64/gdt.o \
$(BUILD)/arch/x86_64/idt.o \
$(BUILD)/arch/x86_64/interrupts.o \
$(BUILD)/arch/x86_64/cpu.o \
$(BUILD)/kernel/main.o \
$(BUILD)/kernel/panic.o \
$(BUILD)/kernel/printk.o \
$(BUILD)/kernel/memory.o \
$(BUILD)/kernel/process.o \
$(BUILD)/kernel/scheduler.o \
$(BUILD)/kernel/syscall.o \
$(BUILD)/kernel/aster_api.o \
$(BUILD)/kernel/string.o \
$(BUILD)/drivers/display.o \
$(BUILD)/drivers/keyboard.o \
$(BUILD)/drivers/timer.o \
$(BUILD)/drivers/storage.o
all: $(IMG)
$(BUILD):
mkdir -p $(BUILD)/boot $(BUILD)/kernel $(BUILD)/arch/x86_64 $(BUILD)/drivers
$(BUILD)/boot/boot.bin: boot/boot.asm | $(BUILD)
$(AS) -f bin $< -o $@
$(BUILD)/boot/stage2.bin: boot/stage2.asm boot/disk.asm | $(BUILD)
$(AS) -I boot/ -f bin $< -o $@
$(BUILD)/arch/x86_64/%.o: arch/x86_64/%.asm | $(BUILD)
$(AS) -f elf64 $< -o $@
$(BUILD)/arch/x86_64/%.o: arch/x86_64/%.c | $(BUILD)
$(CC) $(CFLAGS) -c $< -o $@
$(BUILD)/kernel/%.o: kernel/%.c | $(BUILD)
$(CC) $(CFLAGS) -c $< -o $@
$(BUILD)/drivers/%.o: drivers/%.c | $(BUILD)
$(CC) $(CFLAGS) -c $< -o $@
$(BUILD)/kernel.elf: $(KERNEL_OBJS) linker.ld
$(LD) $(LDFLAGS) -o $@ $(KERNEL_OBJS)
$(BUILD)/kernel.bin: $(BUILD)/kernel.elf
$(OBJCOPY) -O binary $< $@
$(IMG): $(BUILD)/boot/boot.bin $(BUILD)/boot/stage2.bin $(BUILD)/kernel.bin
dd if=/dev/zero of=$(IMG) bs=512 count=2880
dd if=$(BUILD)/boot/boot.bin of=$(IMG) conv=notrunc
dd if=$(BUILD)/boot/stage2.bin of=$(IMG) bs=512 seek=1 conv=notrunc
dd if=$(BUILD)/kernel.bin of=$(IMG) bs=512 seek=17 conv=notrunc
$(DATA_DISK):
if [ -f $(BUILD)/asterfs.img ] && [ ! -f $(DATA_DISK) ]; then cp $(BUILD)/asterfs.img $(DATA_DISK); fi
test -f $(DATA_DISK) || dd if=/dev/zero of=$(DATA_DISK) bs=512 count=8192
run: $(IMG) $(DATA_DISK)
qemu-system-x86_64 -no-reboot -no-shutdown -drive format=raw,file=$(IMG),if=ide,index=0 -drive format=raw,file=$(DATA_DISK),if=ide,index=1
clean:
rm -rf $(BUILD)
.PHONY: all run clean
+71
View File
@@ -0,0 +1,71 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalas
* Rok: 2026
*
*/
/*
* Ukazkova C aplikace nad Aster API. Aplikace predvadi jednoduchou
* kalkulacku a muze slouzit jako sablona pro dalsi user-space programy.
*/
#include "aster_api.h"
static void append_number(char *out, int value) {
char tmp[16];
int i = 0;
int j;
int neg = 0;
if (value == 0) {
out[0] = '0';
out[1] = '\0';
return;
}
if (value < 0) {
neg = 1;
value = -value;
}
while (value > 0 && i < 15) {
tmp[i++] = (char)('0' + (value % 10));
value /= 10;
}
j = 0;
if (neg) {
out[j++] = '-';
}
while (i > 0) {
out[j++] = tmp[--i];
}
out[j] = '\0';
}
void app_calc_main(void) {
char n1[16];
char n2[16];
char nr[16];
char line[80];
int a = 24;
int b = 18;
int r = a + b;
append_number(n1, a);
append_number(n2, b);
append_number(nr, r);
line[0] = '\0';
aster_api_print("[calc_app] start\n");
aster_api_print("[calc_app] ");
aster_api_print(n1);
aster_api_print(" + ");
aster_api_print(n2);
aster_api_print(" = ");
aster_api_print(nr);
aster_api_print("\n");
}
+161
View File
@@ -0,0 +1,161 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento architekturalni modul inicializuje GDT, IDT a remapuje PIC.
* Obsahuje centralni vstup pro obsluhu vyjimek, hardwarovych preruseni
* i syscall vektoru, vcetne predani rizeni scheduleru pri timer IRQ.
*/
#include "cpu.h"
#include "panic.h"
#include "printk.h"
#include "scheduler.h"
#include "syscall.h"
#include "timer.h"
#include "types.h"
extern void arch_load_gdt(void *ptr);
extern void arch_reload_segments(void);
extern void arch_load_idt(void *ptr);
extern void *isr_stub_table[];
#define IDT_ENTRIES 256
static inline void outb(u16 port, u8 value) {
__asm__ volatile ("outb %0, %1" : : "a"(value), "Nd"(port));
}
static inline void io_wait(void) {
__asm__ volatile ("outb %%al, $0x80" : : "a"(0));
}
struct __attribute__((packed)) gdt_ptr {
u16 limit;
u64 base;
};
struct __attribute__((packed)) idt_entry {
u16 offset_low;
u16 selector;
u8 ist;
u8 type_attr;
u16 offset_mid;
u32 offset_high;
u32 zero;
};
struct __attribute__((packed)) idt_ptr {
u16 limit;
u64 base;
};
static u64 gdt_table[3];
static struct idt_entry idt[IDT_ENTRIES];
static void set_idt_gate(u8 vec, void *isr, u8 flags) {
u64 addr = (u64)isr;
idt[vec].offset_low = (u16)(addr & 0xFFFF);
idt[vec].selector = 0x08;
idt[vec].ist = 0;
idt[vec].type_attr = flags;
idt[vec].offset_mid = (u16)((addr >> 16) & 0xFFFF);
idt[vec].offset_high = (u32)((addr >> 32) & 0xFFFFFFFF);
idt[vec].zero = 0;
}
static void pic_remap(void) {
outb(0x20, 0x11);
io_wait();
outb(0xA0, 0x11);
io_wait();
outb(0x21, 0x20);
io_wait();
outb(0xA1, 0x28);
io_wait();
outb(0x21, 0x04);
io_wait();
outb(0xA1, 0x02);
io_wait();
outb(0x21, 0x01);
io_wait();
outb(0xA1, 0x01);
io_wait();
outb(0x21, 0x00);
outb(0xA1, 0x00);
}
void cpu_init(void) {
struct gdt_ptr gp;
gdt_table[0] = 0x0000000000000000ULL;
gdt_table[1] = 0x00AF9A000000FFFFULL;
gdt_table[2] = 0x00CF92000000FFFFULL;
gp.limit = sizeof(gdt_table) - 1;
gp.base = (u64)&gdt_table[0];
arch_load_gdt(&gp);
arch_reload_segments();
}
void interrupts_init(void) {
struct idt_ptr ip;
u32 i;
for (i = 0; i < IDT_ENTRIES; ++i) {
set_idt_gate((u8)i, isr_stub_table[0], 0x8E);
}
for (i = 0; i < 34; ++i) {
set_idt_gate((u8)i, isr_stub_table[i], 0x8E);
}
set_idt_gate(128, isr_stub_table[34], 0xEE);
ip.limit = sizeof(idt) - 1;
ip.base = (u64)&idt[0];
arch_load_idt(&ip);
pic_remap();
__asm__ volatile ("sti");
}
void interrupt_dispatch(interrupt_frame_t *frame) {
if (frame->vector < 32) {
printk("[EXC] vector=%d error=%x\n", (int)frame->vector, (u32)frame->error);
panic("CPU exception");
}
if (frame->vector == 32) {
scheduler_tick();
outb(0x20, 0x20);
return;
}
if (frame->vector == 33) {
outb(0x20, 0x20);
return;
}
if (frame->vector == 128) {
frame->rax = syscall_dispatch(frame->rax, frame->rbx, frame->rcx, frame->rdx, frame->rsi);
return;
}
}
void cpu_halt(void) {
__asm__ volatile ("cli");
for (;;) {
__asm__ volatile ("hlt");
}
}
+29
View File
@@ -0,0 +1,29 @@
; /*
; * AsterOS Kernel
; * Autor: Pavel Kalaš
; * Rok: 2026
; *
; * Vytvořeno jen tak z nudy a z chuti zkoušet nové věci.
; */
[bits 64]
section .text.boot
global _start
extern kmain
_start:
cli
mov word [0xB800A], 0x0F4B
mov rsp, stack_top
call kmain
.halt:
hlt
jmp .halt
section .bss
align 16
stack_bottom:
resb 16384
stack_top:
+31
View File
@@ -0,0 +1,31 @@
; /*
; * AsterOS Kernel
; * Autor: Pavel Kalaš
; * Rok: 2026
; *
; * Vytvořeno jen tak z nudy a z chuti zkoušet nové věci.
; */
[bits 64]
section .text
global arch_load_gdt
global arch_reload_segments
arch_load_gdt:
lgdt [rdi]
ret
arch_reload_segments:
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
push qword 0x08
lea rax, [rel .flush]
push rax
retfq
.flush:
ret
+15
View File
@@ -0,0 +1,15 @@
; /*
; * AsterOS Kernel
; * Autor: Pavel Kalaš
; * Rok: 2026
; *
; * Vytvořeno jen tak z nudy a z chuti zkoušet nové věci.
; */
[bits 64]
section .text
global arch_load_idt
arch_load_idt:
lidt [rdi]
ret
+143
View File
@@ -0,0 +1,143 @@
; /*
; * AsterOS Kernel
; * Autor: Pavel Kalaš
; * Rok: 2026
; *
; * Vytvořeno jen tak z nudy a z chuti zkoušet nové věci.
; */
[bits 64]
section .text
extern interrupt_dispatch
global isr_stub_table
%macro ISR_NOERR 1
global isr_%1
isr_%1:
push qword 0
push qword %1
jmp isr_common
%endmacro
%macro ISR_ERR 1
global isr_%1
isr_%1:
push qword %1
jmp isr_common
%endmacro
ISR_NOERR 0
ISR_NOERR 1
ISR_NOERR 2
ISR_NOERR 3
ISR_NOERR 4
ISR_NOERR 5
ISR_NOERR 6
ISR_NOERR 7
ISR_ERR 8
ISR_NOERR 9
ISR_ERR 10
ISR_ERR 11
ISR_ERR 12
ISR_ERR 13
ISR_ERR 14
ISR_NOERR 15
ISR_NOERR 16
ISR_ERR 17
ISR_NOERR 18
ISR_NOERR 19
ISR_NOERR 20
ISR_ERR 21
ISR_NOERR 22
ISR_NOERR 23
ISR_NOERR 24
ISR_NOERR 25
ISR_NOERR 26
ISR_NOERR 27
ISR_NOERR 28
ISR_NOERR 29
ISR_ERR 30
ISR_NOERR 31
ISR_NOERR 32
ISR_NOERR 33
ISR_NOERR 128
isr_common:
cld
push rax
push rbx
push rcx
push rdx
push rbp
push rdi
push rsi
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
mov rdi, rsp
call interrupt_dispatch
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rsi
pop rdi
pop rbp
pop rdx
pop rcx
pop rbx
pop rax
add rsp, 16
iretq
section .rodata
isr_stub_table:
dq isr_0
dq isr_1
dq isr_2
dq isr_3
dq isr_4
dq isr_5
dq isr_6
dq isr_7
dq isr_8
dq isr_9
dq isr_10
dq isr_11
dq isr_12
dq isr_13
dq isr_14
dq isr_15
dq isr_16
dq isr_17
dq isr_18
dq isr_19
dq isr_20
dq isr_21
dq isr_22
dq isr_23
dq isr_24
dq isr_25
dq isr_26
dq isr_27
dq isr_28
dq isr_29
dq isr_30
dq isr_31
dq isr_32
dq isr_33
dq isr_128
+74
View File
@@ -0,0 +1,74 @@
; /*
; * AsterOS Kernel
; * Autor: Pavel Kalaš
; * Rok: 2026
; *
; */
[org 0x7C00]
[bits 16]
STAGE2_SECTORS equ 16
STAGE2_LBA equ 1
start:
cli
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7C00
sti
mov [boot_drive], dl
mov si, boot_msg
call print_string
mov word [dap + 2], STAGE2_SECTORS
mov word [dap + 4], 0x8000
mov word [dap + 6], 0x0000
mov dword [dap + 8], STAGE2_LBA
mov dword [dap + 12], 0
mov si, dap
mov ah, 0x42
mov dl, [boot_drive]
int 0x13
jc disk_error
jmp 0x0000:0x8000
disk_error:
mov si, disk_msg
call print_string
jmp $
print_string:
lodsb
test al, al
jz .done
mov ah, 0x0E
mov bh, 0x00
mov bl, 0x0F
int 0x10
jmp print_string
.done:
ret
boot_drive: db 0
boot_msg: db "Aster Bootloader stage1", 13, 10, 0
disk_msg: db "Disk read error", 13, 10, 0
align 8
dap:
db 0x10
db 0
dw 0
dw 0
dw 0
dd 0
dd 0
times 510 - ($ - $$) db 0
dw 0xAA55
+18
View File
@@ -0,0 +1,18 @@
; /*
; * AsterOS Kernel
; * Autor: Pavel Kalaš
; * Rok: 2026
; *
; */
[bits 16]
global disk_read_lba
; DS:SI -> adresa DAP struktury, DL -> číslo disku
disk_read_lba:
push ax
mov ah, 0x42
int 0x13
pop ax
ret
+245
View File
@@ -0,0 +1,245 @@
; /*
; * AsterOS Kernel
; * Autor: Pavel Kalaš
; * Rok: 2026
; *
; */
[org 0x8000]
[bits 16]
jmp start2
%include "disk.asm"
KERNEL_SECTORS equ 256
KERNEL_START_LBA equ 17
KERNEL_LOAD_SEG equ 0x1000
PML4_ADDR equ 0x00070000
PDPT_ADDR equ 0x00071000
PD_ADDR equ 0x00072000
start2:
cli
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x9000
sti
mov [boot_drive], dl
mov si, msg_stage2
call print_string
call enable_a20
call load_kernel
jc load_error
mov si, msg_kernel_loaded
call print_string
cli
lgdt [gdt_descriptor]
mov eax, cr0
or eax, 0x1
mov cr0, eax
jmp 0x08:protected_entry
load_error:
mov si, msg_load_error
call print_string
jmp $
enable_a20:
in al, 0x92
or al, 0x02
out 0x92, al
ret
load_kernel:
mov word [remaining_sectors], KERNEL_SECTORS
mov word [current_seg], KERNEL_LOAD_SEG
mov dword [current_lba], KERNEL_START_LBA
.next_chunk:
mov ax, [remaining_sectors]
test ax, ax
jz .done
cmp ax, 127
jbe .use_rest
mov ax, 127
.use_rest:
mov [chunk_sectors], ax
mov word [dap + 2], ax
mov word [dap + 4], 0x0000
mov ax, [current_seg]
mov word [dap + 6], ax
mov eax, [current_lba]
mov dword [dap + 8], eax
mov dword [dap + 12], 0
mov dl, [boot_drive]
mov si, dap
call disk_read_lba
jc .error
mov ax, [chunk_sectors]
shl ax, 5
add [current_seg], ax
mov eax, [current_lba]
movzx ebx, word [chunk_sectors]
add eax, ebx
mov [current_lba], eax
mov ax, [remaining_sectors]
sub ax, [chunk_sectors]
mov [remaining_sectors], ax
jmp .next_chunk
.error:
stc
ret
.done:
clc
ret
print_string:
lodsb
test al, al
jz .done
mov ah, 0x0E
mov bh, 0x00
mov bl, 0x0F
int 0x10
jmp print_string
.done:
ret
boot_drive: db 0
msg_stage2: db "Aster Bootloader stage2", 13, 10, 0
msg_kernel_loaded: db "Kernel read OK", 13, 10, 0
msg_load_error: db "Kernel load error", 13, 10, 0
align 8
dap:
db 0x10
db 0x00
dw 0
dw 0
dw 0
dd 0
remaining_sectors: dw 0
chunk_sectors: dw 0
current_seg: dw 0
current_lba: dd 0
dd 0
align 8
gdt_start:
dq 0x0000000000000000
dq 0x00CF9A000000FFFF
dq 0x00CF92000000FFFF
dq 0x00AF9A000000FFFF
dq 0x00CF92000000FFFF
gdt_end:
gdt_descriptor:
dw gdt_end - gdt_start - 1
dd gdt_start
[bits 32]
protected_entry:
mov word [0xB8000], 0x0F50
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov esp, 0x9FC00
mov esi, 0x00010000
mov edi, 0x00100000
mov ecx, (KERNEL_SECTORS * 512) / 4
rep movsd
call setup_paging
mov word [0xB8002], 0x0F47
mov eax, cr4
or eax, (1 << 5)
mov cr4, eax
mov ecx, 0xC0000080
rdmsr
or eax, (1 << 8)
wrmsr
mov eax, PML4_ADDR
mov cr3, eax
mov eax, cr0
or eax, 0x80000001
mov cr0, eax
mov word [0xB8004], 0x0F4C
jmp 0x18:long_mode_entry
setup_paging:
mov edi, PML4_ADDR
mov ecx, (4096 * 3) / 4
xor eax, eax
rep stosd
mov dword [PML4_ADDR], PDPT_ADDR | 0x03
mov dword [PML4_ADDR + 4], 0
mov dword [PDPT_ADDR], PD_ADDR | 0x03
mov dword [PDPT_ADDR + 4], 0
mov edi, PD_ADDR
xor ebx, ebx
mov ecx, 512
.map_pd:
mov eax, ebx
or eax, 0x83
mov dword [edi], eax
mov dword [edi + 4], 0
add ebx, 0x200000
add edi, 8
loop .map_pd
ret
[bits 64]
long_mode_entry:
mov word [0xB8006], 0x0F4D
mov ax, 0x20
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov rsp, 0x200000
mov word [0xB8008], 0x0F4A
mov rax, 0x00100000
jmp rax
halt64:
hlt
jmp halt64
+190
View File
@@ -0,0 +1,190 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento ovladac realizuje textovou konzoli nad VGA pameti na adrese 0xB8000.
* Ridi pozici kurzoru, barvy znaku, zpracovani ridicich znaku
* a automaticky scroll, kdyz vystup presahne posledni radek obrazovky.
*/
#include "display.h"
#define VGA_WIDTH 80
#define VGA_HEIGHT 25
#define VGA_CONTENT_HEIGHT (VGA_HEIGHT - 1)
static volatile u16 *const vga = (u16 *)0xB8000;
static u8 color = 0x0F;
static usize row = 0;
static usize col = 0;
static inline void outb(u16 port, u8 value) {
__asm__ volatile ("outb %0, %1" : : "a"(value), "Nd"(port));
}
static void update_hw_cursor(void) {
u16 pos = (u16)(row * VGA_WIDTH + col);
outb(0x3D4, 0x0F);
outb(0x3D5, (u8)(pos & 0xFF));
outb(0x3D4, 0x0E);
outb(0x3D5, (u8)((pos >> 8) & 0xFF));
}
static inline u16 vga_entry(char c, u8 clr) {
return (u16)c | ((u16)clr << 8);
}
static void scroll_if_needed(void) {
usize r;
usize c;
if (row < VGA_CONTENT_HEIGHT) {
return;
}
for (r = 1; r < VGA_CONTENT_HEIGHT; ++r) {
for (c = 0; c < VGA_WIDTH; ++c) {
vga[(r - 1) * VGA_WIDTH + c] = vga[r * VGA_WIDTH + c];
}
}
for (c = 0; c < VGA_WIDTH; ++c) {
vga[(VGA_CONTENT_HEIGHT - 1) * VGA_WIDTH + c] = vga_entry(' ', color);
}
row = VGA_CONTENT_HEIGHT - 1;
}
void display_set_color(u8 fg, u8 bg) {
color = (u8)((bg << 4) | (fg & 0x0F));
}
void display_clear(void) {
usize i;
for (i = 0; i < VGA_WIDTH * VGA_HEIGHT; ++i) {
vga[i] = vga_entry(' ', color);
}
row = 0;
col = 0;
update_hw_cursor();
}
void display_init(void) {
display_set_color(0x0F, 0x00);
display_clear();
}
void display_putc(char c) {
if (c == '\n') {
col = 0;
++row;
scroll_if_needed();
update_hw_cursor();
return;
}
if (c == '\r') {
col = 0;
update_hw_cursor();
return;
}
if (c == '\b') {
if (col > 0) {
--col;
} else if (row > 0) {
--row;
col = VGA_WIDTH - 1;
}
vga[row * VGA_WIDTH + col] = vga_entry(' ', color);
update_hw_cursor();
return;
}
if (c == '\t') {
col = (col + 4) & ~3ULL;
if (col >= VGA_WIDTH) {
col = 0;
++row;
scroll_if_needed();
}
update_hw_cursor();
return;
}
vga[row * VGA_WIDTH + col] = vga_entry(c, color);
++col;
if (col >= VGA_WIDTH) {
col = 0;
++row;
scroll_if_needed();
}
update_hw_cursor();
}
void display_write(const char *text) {
while (*text) {
display_putc(*text++);
}
}
void display_get_cursor(usize *out_row, usize *out_col) {
if (out_row) {
*out_row = row;
}
if (out_col) {
*out_col = col;
}
}
void display_set_cursor(usize new_row, usize new_col) {
if (new_row >= VGA_HEIGHT) {
new_row = VGA_HEIGHT - 1;
}
if (new_col >= VGA_WIDTH) {
new_col = VGA_WIDTH - 1;
}
row = new_row;
col = new_col;
update_hw_cursor();
}
void display_fill_row(usize target_row, char ch, u8 fg, u8 bg) {
usize c;
u8 clr;
if (target_row >= VGA_HEIGHT) {
return;
}
clr = (u8)((bg << 4) | (fg & 0x0F));
for (c = 0; c < VGA_WIDTH; ++c) {
vga[target_row * VGA_WIDTH + c] = vga_entry(ch, clr);
}
}
void display_write_at(usize target_row, usize target_col, const char *text, u8 fg, u8 bg) {
usize c = target_col;
u8 clr;
if (!text || target_row >= VGA_HEIGHT || target_col >= VGA_WIDTH) {
return;
}
clr = (u8)((bg << 4) | (fg & 0x0F));
while (*text && c < VGA_WIDTH) {
vga[target_row * VGA_WIDTH + c] = vga_entry(*text++, clr);
++c;
}
}
+275
View File
@@ -0,0 +1,275 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento soubor implementuje zakladni klavesnicovy vstup pres PS/2 porty.
* Preklada scancode na ASCII znaky a poskytuje funkci pro nacitani radku,
* kterou pouziva shell pro prijem prikazu od uzivatele.
*/
#include "display.h"
#include "drivers.h"
#define KBD_HISTORY_MAX 32
#define KBD_HISTORY_LINE_MAX 128
static char g_history[KBD_HISTORY_MAX][KBD_HISTORY_LINE_MAX];
static int g_history_count = 0;
static int g_history_head = 0;
static int g_ctrl_down = 0;
static inline unsigned char inb(unsigned short port) {
unsigned char ret;
__asm__ volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port));
return ret;
}
static const char keymap[128] = {
0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', '\t',
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 0, 'a', 's',
'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0, '\\', 'z', 'x', 'c', 'v',
'b', 'n', 'm', ',', '.', '/', 0, '*', 0, ' ',
};
void keyboard_init(void) {
}
int keyboard_try_read_key(void) {
unsigned char sc;
int out = -1;
if ((inb(0x64) & 1) == 0) {
return -1;
}
sc = inb(0x60);
if (sc == 0xE0) {
unsigned char ext;
if ((inb(0x64) & 1) == 0) {
return -1;
}
ext = inb(0x60);
if (ext == 0x1D) {
g_ctrl_down = 1;
return -1;
}
if (ext == 0x9D) {
g_ctrl_down = 0;
return -1;
}
if (ext & 0x80) {
return -1;
}
if (ext == 0x48) {
out = ASTER_KEY_UP;
return out;
}
if (ext == 0x50) {
out = ASTER_KEY_DOWN;
return out;
}
if (ext == 0x4B) {
out = ASTER_KEY_LEFT;
return out;
}
if (ext == 0x4D) {
out = ASTER_KEY_RIGHT;
return out;
}
return -1;
}
if (sc == 0x1D) {
g_ctrl_down = 1;
return -1;
}
if (sc == 0x9D) {
g_ctrl_down = 0;
return -1;
}
if (sc & 0x80) {
return -1;
}
if (sc == 0x3B) {
out = ASTER_KEY_F1;
return out;
}
if (sc == 0x3C) {
out = ASTER_KEY_F2;
return out;
}
if (sc == 0x1F && g_ctrl_down) {
out = 19; /* Ctrl+S */
return out;
}
if (sc < 128 && keymap[sc]) {
out = keymap[sc];
return out;
}
return -1;
}
int keyboard_read_key(void) {
for (;;) {
int k = keyboard_try_read_key();
if (k != -1) {
return k;
}
__asm__ volatile ("pause");
}
}
static void clear_current_line(int len) {
int j;
for (j = 0; j < len; ++j) {
display_putc('\b');
}
}
static void set_line_from_history(char *buffer, int *len, int max_len, const char *src) {
int j = 0;
int limit = max_len - 1;
clear_current_line(*len);
while (src[j] && j < limit) {
buffer[j] = src[j];
display_putc(src[j]);
++j;
}
buffer[j] = '\0';
*len = j;
}
static void history_push(const char *line) {
int i;
int slot;
if (!line || !line[0]) {
return;
}
if (g_history_count > 0) {
int last = (g_history_head + KBD_HISTORY_MAX - 1) % KBD_HISTORY_MAX;
if (g_history[last][0] != '\0') {
i = 0;
while (line[i] && g_history[last][i] && line[i] == g_history[last][i]) {
++i;
}
if (line[i] == '\0' && g_history[last][i] == '\0') {
return;
}
}
}
slot = g_history_head;
for (i = 0; i < KBD_HISTORY_LINE_MAX - 1 && line[i]; ++i) {
g_history[slot][i] = line[i];
}
g_history[slot][i] = '\0';
g_history_head = (g_history_head + 1) % KBD_HISTORY_MAX;
if (g_history_count < KBD_HISTORY_MAX) {
++g_history_count;
}
}
int keyboard_readline(char *buffer, int max_len) {
int i = 0;
int history_nav = -1;
if (max_len <= 1) {
return 0;
}
for (;;) {
int c = keyboard_read_key();
if (c == ASTER_KEY_F1 || c == ASTER_KEY_F2) {
continue;
}
if (c == ASTER_KEY_UP) {
if (g_history_count == 0) {
continue;
}
if (history_nav < g_history_count - 1) {
++history_nav;
}
{
int idx = (g_history_head + KBD_HISTORY_MAX - 1 - history_nav) % KBD_HISTORY_MAX;
set_line_from_history(buffer, &i, max_len, g_history[idx]);
}
continue;
}
if (c == ASTER_KEY_DOWN) {
if (g_history_count == 0) {
continue;
}
if (history_nav > 0) {
--history_nav;
{
int idx = (g_history_head + KBD_HISTORY_MAX - 1 - history_nav) % KBD_HISTORY_MAX;
set_line_from_history(buffer, &i, max_len, g_history[idx]);
}
} else if (history_nav == 0) {
history_nav = -1;
clear_current_line(i);
i = 0;
buffer[0] = '\0';
}
continue;
}
if (c == '\n') {
display_putc('\n');
buffer[i] = '\0';
history_push(buffer);
return i;
}
if (c == '\b') {
if (i > 0) {
--i;
display_putc('\b');
}
continue;
}
if (i < max_len - 1) {
buffer[i++] = (char)c;
display_putc((char)c);
buffer[i] = '\0';
history_nav = -1;
}
}
}
+669
View File
@@ -0,0 +1,669 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalas
* Rok: 2026
*
*/
/*
* Tento modul implementuje AsterFS nad realnym ATA diskem v QEMU.
* Data se nahravaji pri startu a po kazde zmene se synchronizuji
* do sektoru na druhem IDE disku, aby pretrvala mezi restarty.
*/
#include "storage.h"
#include "string.h"
#define ATA_IO_BASE 0x1F0
#define ATA_CTRL_BASE 0x3F6
#define ATA_DRIVE_SLAVE 0xF0
#define ATA_REG_DATA 0
#define ATA_REG_SECCOUNT0 2
#define ATA_REG_LBA0 3
#define ATA_REG_LBA1 4
#define ATA_REG_LBA2 5
#define ATA_REG_HDDEVSEL 6
#define ATA_REG_COMMAND 7
#define ATA_REG_STATUS 7
#define ATA_CMD_READ_PIO 0x20
#define ATA_CMD_WRITE_PIO 0x30
#define ATA_CMD_CACHE_FLUSH 0xE7
#define ATA_SR_BSY 0x80
#define ATA_SR_DRQ 0x08
#define ATA_SR_ERR 0x01
#define ASTERFS_MAGIC "ASTERFS1"
#define ASTERFS_VERSION 1U
#define ASTERFS_NODE_BYTES (ASTERFS_NAME_LEN + 1 + 2 + 1 + ASTERFS_DATA_LEN)
#define ASTERFS_NODE_SECTORS (((ASTERFS_MAX_FILES * ASTERFS_NODE_BYTES) + 511) / 512)
#define ASTERFS_DISK_START_LBA 1U
typedef struct {
char magic[8];
u32 version;
u32 nodes_used;
u32 reserved;
u8 pad[512 - 8 - 4 - 4 - 4];
} asterfs_superblock_t;
typedef struct {
char name[ASTERFS_NAME_LEN];
u8 is_dir;
u16 size;
u8 reserved;
u8 data[ASTERFS_DATA_LEN];
} asterfs_disk_node_t;
static asterfs_node_t nodes[ASTERFS_MAX_FILES];
static int nodes_used = 0;
static int disk_ready = 0;
static u8 g_sector_buffer[512];
static u8 g_nodes_blob[ASTERFS_MAX_FILES * ASTERFS_NODE_BYTES];
static inline void outb(unsigned short port, unsigned char value) {
__asm__ volatile ("outb %0, %1" : : "a"(value), "Nd"(port));
}
static inline unsigned char inb(unsigned short port) {
unsigned char ret;
__asm__ volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port));
return ret;
}
static inline void outw(unsigned short port, unsigned short value) {
__asm__ volatile ("outw %0, %1" : : "a"(value), "Nd"(port));
}
static inline unsigned short inw(unsigned short port) {
unsigned short ret;
__asm__ volatile ("inw %1, %0" : "=a"(ret) : "Nd"(port));
return ret;
}
static void ata_delay_400ns(void) {
(void)inb(ATA_CTRL_BASE);
(void)inb(ATA_CTRL_BASE);
(void)inb(ATA_CTRL_BASE);
(void)inb(ATA_CTRL_BASE);
}
static int ata_wait_not_busy(void) {
unsigned int timeout = 200000U;
while (timeout-- > 0) {
unsigned char s = inb(ATA_IO_BASE + ATA_REG_STATUS);
if (s == 0x00 || s == 0xFF) {
return -1;
}
if ((s & ATA_SR_BSY) == 0) {
return 0;
}
}
return -1;
}
static int ata_wait_drq(void) {
unsigned int timeout = 200000U;
while (timeout-- > 0) {
unsigned char s = inb(ATA_IO_BASE + ATA_REG_STATUS);
if (s == 0x00 || s == 0xFF) {
return -1;
}
if (s & ATA_SR_ERR) {
return -1;
}
if ((s & ATA_SR_BSY) == 0 && (s & ATA_SR_DRQ) != 0) {
return 0;
}
}
return -1;
}
static int ata_select_drive_lba(u32 lba) {
if (ata_wait_not_busy() != 0) {
return -1;
}
outb(ATA_IO_BASE + ATA_REG_HDDEVSEL, (unsigned char)(ATA_DRIVE_SLAVE | ((lba >> 24) & 0x0F)));
ata_delay_400ns();
return 0;
}
static int ata_probe_slave(void) {
unsigned char s;
outb(ATA_IO_BASE + ATA_REG_HDDEVSEL, ATA_DRIVE_SLAVE);
ata_delay_400ns();
s = inb(ATA_IO_BASE + ATA_REG_STATUS);
if (s == 0x00 || s == 0xFF) {
return -1;
}
return ata_wait_not_busy();
}
static int ata_read_sector(u32 lba, u8 *buf512) {
int i;
if (!buf512) {
return -1;
}
if (ata_select_drive_lba(lba) != 0) {
return -1;
}
outb(ATA_IO_BASE + ATA_REG_SECCOUNT0, 1);
outb(ATA_IO_BASE + ATA_REG_LBA0, (unsigned char)(lba & 0xFF));
outb(ATA_IO_BASE + ATA_REG_LBA1, (unsigned char)((lba >> 8) & 0xFF));
outb(ATA_IO_BASE + ATA_REG_LBA2, (unsigned char)((lba >> 16) & 0xFF));
outb(ATA_IO_BASE + ATA_REG_COMMAND, ATA_CMD_READ_PIO);
if (ata_wait_drq() != 0) {
return -1;
}
for (i = 0; i < 256; ++i) {
unsigned short w = inw(ATA_IO_BASE + ATA_REG_DATA);
buf512[i * 2] = (u8)(w & 0xFF);
buf512[i * 2 + 1] = (u8)((w >> 8) & 0xFF);
}
return 0;
}
static int ata_write_sector(u32 lba, const u8 *buf512) {
int i;
if (!buf512) {
return -1;
}
if (ata_select_drive_lba(lba) != 0) {
return -1;
}
outb(ATA_IO_BASE + ATA_REG_SECCOUNT0, 1);
outb(ATA_IO_BASE + ATA_REG_LBA0, (unsigned char)(lba & 0xFF));
outb(ATA_IO_BASE + ATA_REG_LBA1, (unsigned char)((lba >> 8) & 0xFF));
outb(ATA_IO_BASE + ATA_REG_LBA2, (unsigned char)((lba >> 16) & 0xFF));
outb(ATA_IO_BASE + ATA_REG_COMMAND, ATA_CMD_WRITE_PIO);
if (ata_wait_drq() != 0) {
return -1;
}
for (i = 0; i < 256; ++i) {
unsigned short w = (unsigned short)buf512[i * 2] | ((unsigned short)buf512[i * 2 + 1] << 8);
outw(ATA_IO_BASE + ATA_REG_DATA, w);
}
outb(ATA_IO_BASE + ATA_REG_COMMAND, ATA_CMD_CACHE_FLUSH);
if (ata_wait_not_busy() != 0) {
return -1;
}
return 0;
}
static void fs_reset_memory(void) {
int i;
for (i = 0; i < ASTERFS_MAX_FILES; ++i) {
nodes[i].name[0] = '\0';
nodes[i].is_dir = 0;
nodes[i].size = 0;
}
nodes_used = 0;
}
static void fs_encode_nodes(u8 *out) {
int i;
for (i = 0; i < ASTERFS_MAX_FILES; ++i) {
asterfs_disk_node_t d;
usize off = (usize)i * ASTERFS_NODE_BYTES;
aster_memset(&d, 0, sizeof(d));
aster_memcpy(d.name, nodes[i].name, ASTERFS_NAME_LEN);
d.is_dir = nodes[i].is_dir;
d.size = nodes[i].size;
aster_memcpy(d.data, nodes[i].data, ASTERFS_DATA_LEN);
aster_memcpy(out + off, &d, ASTERFS_NODE_BYTES);
}
}
static void fs_decode_nodes(const u8 *in) {
int i;
for (i = 0; i < ASTERFS_MAX_FILES; ++i) {
asterfs_disk_node_t d;
usize off = (usize)i * ASTERFS_NODE_BYTES;
aster_memcpy(&d, in + off, ASTERFS_NODE_BYTES);
aster_memset(nodes[i].name, 0, ASTERFS_NAME_LEN);
aster_memcpy(nodes[i].name, d.name, ASTERFS_NAME_LEN);
nodes[i].is_dir = d.is_dir;
nodes[i].size = d.size;
if (nodes[i].size > ASTERFS_DATA_LEN) {
nodes[i].size = ASTERFS_DATA_LEN;
}
aster_memcpy(nodes[i].data, d.data, ASTERFS_DATA_LEN);
}
}
static int fs_flush_disk(void) {
asterfs_superblock_t super;
unsigned int sector;
if (!disk_ready) {
return 0;
}
aster_memset(&super, 0, sizeof(super));
aster_memcpy(super.magic, ASTERFS_MAGIC, 8);
super.version = ASTERFS_VERSION;
super.nodes_used = (u32)nodes_used;
aster_memset(g_sector_buffer, 0, sizeof(g_sector_buffer));
aster_memcpy(g_sector_buffer, &super, sizeof(super));
if (ata_write_sector(ASTERFS_DISK_START_LBA, g_sector_buffer) != 0) {
return -1;
}
fs_encode_nodes(g_nodes_blob);
for (sector = 0; sector < ASTERFS_NODE_SECTORS; ++sector) {
usize off = (usize)sector * 512;
aster_memset(g_sector_buffer, 0, sizeof(g_sector_buffer));
if (off < sizeof(g_nodes_blob)) {
usize left = sizeof(g_nodes_blob) - off;
usize chunk = left < 512 ? left : 512;
aster_memcpy(g_sector_buffer, g_nodes_blob + off, chunk);
}
if (ata_write_sector(ASTERFS_DISK_START_LBA + 1U + sector, g_sector_buffer) != 0) {
return -1;
}
}
return 0;
}
static int fs_load_disk(void) {
asterfs_superblock_t super;
unsigned int sector;
if (!disk_ready) {
return -1;
}
if (ata_read_sector(ASTERFS_DISK_START_LBA, g_sector_buffer) != 0) {
return -1;
}
aster_memcpy(&super, g_sector_buffer, sizeof(super));
if (aster_strncmp(super.magic, ASTERFS_MAGIC, 8) != 0 || super.version != ASTERFS_VERSION) {
fs_reset_memory();
return fs_flush_disk();
}
for (sector = 0; sector < ASTERFS_NODE_SECTORS; ++sector) {
usize off = (usize)sector * 512;
if (ata_read_sector(ASTERFS_DISK_START_LBA + 1U + sector, g_sector_buffer) != 0) {
return -1;
}
if (off < sizeof(g_nodes_blob)) {
usize left = sizeof(g_nodes_blob) - off;
usize chunk = left < 512 ? left : 512;
aster_memcpy(g_nodes_blob + off, g_sector_buffer, chunk);
}
}
fs_decode_nodes(g_nodes_blob);
if (super.nodes_used > ASTERFS_MAX_FILES) {
nodes_used = ASTERFS_MAX_FILES;
} else {
nodes_used = (int)super.nodes_used;
}
return 0;
}
static int is_root(const char *path) {
return path && path[0] == '/' && path[1] == '\0';
}
static int path_parent_exists(const char *path) {
int i;
int last = -1;
char parent[ASTERFS_NAME_LEN];
if (!path || path[0] != '/') {
return 0;
}
for (i = 0; path[i] != '\0'; ++i) {
if (path[i] == '/') {
last = i;
}
}
if (last <= 0) {
return 1;
}
if ((usize)last >= ASTERFS_NAME_LEN) {
return 0;
}
aster_memcpy(parent, path, (usize)last);
parent[last] = '\0';
for (i = 0; i < nodes_used; ++i) {
if (nodes[i].is_dir && aster_strcmp(nodes[i].name, parent) == 0) {
return 1;
}
}
return 0;
}
static int path_is_child(const char *parent, const char *path, const char **leaf_start) {
usize parent_len;
const char *rest;
const char *p;
if (!parent || !path || path[0] != '/') {
return 0;
}
if (is_root(parent)) {
if (path[0] != '/' || path[1] == '\0') {
return 0;
}
rest = path + 1;
p = rest;
while (*p && *p != '/') {
++p;
}
if (*p != '\0') {
return 0;
}
*leaf_start = rest;
return 1;
}
parent_len = aster_strlen(parent);
if (aster_strncmp(path, parent, parent_len) != 0) {
return 0;
}
if (path[parent_len] != '/') {
return 0;
}
rest = path + parent_len + 1;
if (*rest == '\0') {
return 0;
}
p = rest;
while (*p && *p != '/') {
++p;
}
if (*p != '\0') {
return 0;
}
*leaf_start = rest;
return 1;
}
void storage_init(void) {
asterfs_init();
}
void asterfs_init(void) {
fs_reset_memory();
disk_ready = (ata_probe_slave() == 0);
if (!disk_ready) {
return;
}
if (fs_load_disk() != 0) {
fs_reset_memory();
(void)fs_flush_disk();
}
}
static int find_node(const char *name) {
int i;
for (i = 0; i < nodes_used; ++i) {
if (aster_strcmp(nodes[i].name, name) == 0) {
return i;
}
}
return -1;
}
int asterfs_create_file(const char *name) {
usize len;
if (!name || name[0] != '/' || nodes_used >= ASTERFS_MAX_FILES) {
return -1;
}
if (!path_parent_exists(name)) {
return -1;
}
if (find_node(name) >= 0) {
return 0;
}
len = aster_strlen(name);
if (len >= ASTERFS_NAME_LEN) {
return -1;
}
aster_memset(nodes[nodes_used].name, 0, ASTERFS_NAME_LEN);
aster_memcpy(nodes[nodes_used].name, name, len);
nodes[nodes_used].size = 0;
nodes[nodes_used].is_dir = 0;
++nodes_used;
(void)fs_flush_disk();
return 0;
}
int asterfs_create_dir(const char *name) {
usize len;
if (!name || name[0] != '/' || is_root(name) || nodes_used >= ASTERFS_MAX_FILES) {
return -1;
}
if (!path_parent_exists(name)) {
return -1;
}
if (find_node(name) >= 0) {
return 0;
}
len = aster_strlen(name);
if (len >= ASTERFS_NAME_LEN) {
return -1;
}
aster_memset(nodes[nodes_used].name, 0, ASTERFS_NAME_LEN);
aster_memcpy(nodes[nodes_used].name, name, len);
nodes[nodes_used].size = 0;
nodes[nodes_used].is_dir = 1;
++nodes_used;
(void)fs_flush_disk();
return 0;
}
int asterfs_remove_file(const char *name) {
int idx;
int i;
idx = find_node(name);
if (idx < 0 || nodes[idx].is_dir) {
return -1;
}
for (i = idx; i < nodes_used - 1; ++i) {
nodes[i] = nodes[i + 1];
}
--nodes_used;
(void)fs_flush_disk();
return 0;
}
int asterfs_remove_dir(const char *name) {
int idx;
int i;
const char *leaf;
if (is_root(name)) {
return -1;
}
idx = find_node(name);
if (idx < 0 || !nodes[idx].is_dir) {
return -1;
}
for (i = 0; i < nodes_used; ++i) {
if (i == idx) {
continue;
}
if (path_is_child(name, nodes[i].name, &leaf)) {
return -1;
}
}
for (i = idx; i < nodes_used - 1; ++i) {
nodes[i] = nodes[i + 1];
}
--nodes_used;
(void)fs_flush_disk();
return 0;
}
int asterfs_write_file(const char *name, const u8 *data, u16 len) {
int idx;
if (!name || !data || name[0] != '/') {
return -1;
}
idx = find_node(name);
if (idx < 0) {
if (asterfs_create_file(name) != 0) {
return -1;
}
idx = find_node(name);
}
if (idx < 0 || nodes[idx].is_dir) {
return -1;
}
if (len > ASTERFS_DATA_LEN) {
len = ASTERFS_DATA_LEN;
}
aster_memset(nodes[idx].data, 0, ASTERFS_DATA_LEN);
aster_memcpy(nodes[idx].data, data, len);
nodes[idx].size = len;
(void)fs_flush_disk();
return len;
}
int asterfs_read_file(const char *name, u8 *out, u16 max_len) {
int idx;
u16 len;
if (!name || !out || name[0] != '/') {
return -1;
}
idx = find_node(name);
if (idx < 0 || nodes[idx].is_dir) {
return -1;
}
len = nodes[idx].size;
if (len > max_len) {
len = max_len;
}
aster_memcpy(out, nodes[idx].data, len);
return len;
}
void asterfs_list(void (*cb)(const char *name, u8 is_dir, u16 size)) {
int i;
for (i = 0; i < nodes_used; ++i) {
cb(nodes[i].name, nodes[i].is_dir, nodes[i].size);
}
}
int asterfs_get_type(const char *name) {
int idx;
if (is_root(name)) {
return 1;
}
idx = find_node(name);
if (idx < 0) {
return -1;
}
return nodes[idx].is_dir ? 1 : 0;
}
void asterfs_list_dir(const char *path, void (*cb)(const char *name, u8 is_dir, u16 size)) {
int i;
const char *leaf = 0;
char temp[ASTERFS_NAME_LEN];
usize n;
for (i = 0; i < nodes_used; ++i) {
if (!path_is_child(path, nodes[i].name, &leaf)) {
continue;
}
n = aster_strlen(leaf);
if (n >= ASTERFS_NAME_LEN) {
n = ASTERFS_NAME_LEN - 1;
}
aster_memcpy(temp, leaf, n);
temp[n] = '\0';
cb(temp, nodes[i].is_dir, nodes[i].size);
}
}
+83
View File
@@ -0,0 +1,83 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento soubor implementuje ovladac PIT casovace.
* Nastavuje frekvenci hardwaroveho casovace, drzi globalni citac tiku
* a poskytuje blokujici uspani jadra na zadany pocet milisekund.
*/
#include "timer.h"
static volatile unsigned long g_ticks = 0;
static inline unsigned long long read_tsc(void) {
unsigned int lo;
unsigned int hi;
__asm__ volatile ("rdtsc" : "=a"(lo), "=d"(hi));
return ((unsigned long long)hi << 32) | (unsigned long long)lo;
}
static int interrupts_enabled(void) {
unsigned long long rflags;
__asm__ volatile ("pushfq; popq %0" : "=r"(rflags));
return (rflags & (1ULL << 9)) != 0;
}
static void busy_delay_ms(unsigned long ms) {
unsigned long long start = read_tsc();
unsigned long long wait_cycles = (unsigned long long)ms * 1000000ULL;
unsigned long long end = start + wait_cycles;
while (read_tsc() < end) {
__asm__ volatile ("pause");
}
}
static inline void outb(unsigned short port, unsigned char value) {
__asm__ volatile ("outb %0, %1" : : "a"(value), "Nd"(port));
}
void timer_init(unsigned int hz) {
unsigned int divisor;
if (hz == 0) {
hz = 100;
}
divisor = 1193180U / hz;
outb(0x43, 0x36);
outb(0x40, (unsigned char)(divisor & 0xFF));
outb(0x40, (unsigned char)((divisor >> 8) & 0xFF));
}
unsigned long timer_ticks(void) {
return g_ticks;
}
void timer_tick_advance(void) {
++g_ticks;
}
void timer_sleep_ms(unsigned long ms) {
if (!interrupts_enabled()) {
busy_delay_ms(ms);
return;
}
unsigned long start = timer_ticks();
unsigned long wait_ticks = (ms + 9UL) / 10UL;
if (wait_ticks == 0) {
wait_ticks = 1;
}
while ((timer_ticks() - start) < wait_ticks) {
__asm__ volatile ("hlt");
}
}
+35
View File
@@ -0,0 +1,35 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalas
* Rok: 2026
*
*/
/*
* Tento header definuje experimentalni API vrstvu pro C aplikace.
* API je navrzene pro budouci user-space runtime, ale lze ho uz ted
* pouzit pro jednotne volani kernel sluzeb v internich aplikacich.
*/
#ifndef ASTER_API_H
#define ASTER_API_H
#include "types.h"
#define ASTER_APP_API_VERSION 1
typedef struct {
u32 api_version;
u32 reserved;
} aster_app_context_t;
int aster_api_print(const char *text);
int aster_api_clear(void);
int aster_api_ticks(u64 *out_ticks);
void *aster_api_alloc(usize size);
int aster_api_file_create(const char *path);
int aster_api_file_read(const char *path, u8 *out, u16 max_len);
int aster_api_file_write(const char *path, const u8 *data, u16 len);
int aster_api_process_spawn(void (*entry)(void), const char *name, u8 priority);
#endif
+49
View File
@@ -0,0 +1,49 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento header definuje datovy tvar CPU kontextu ulozeneho pri preruseni.
* Obsahuje strukturu interrupt_frame_t a rozhrani pro inicializaci CPU,
* nastaveni tabulek preruseni a centralni dispatch obsluhy preruseni.
*/
#ifndef ASTER_CPU_H
#define ASTER_CPU_H
#include "types.h"
typedef struct {
u64 r15;
u64 r14;
u64 r13;
u64 r12;
u64 r11;
u64 r10;
u64 r9;
u64 r8;
u64 rsi;
u64 rdi;
u64 rbp;
u64 rdx;
u64 rcx;
u64 rbx;
u64 rax;
u64 vector;
u64 error;
u64 rip;
u64 cs;
u64 rflags;
u64 rsp;
u64 ss;
} interrupt_frame_t;
void cpu_init(void);
void interrupts_init(void);
void interrupt_dispatch(interrupt_frame_t *frame);
void cpu_halt(void);
#endif
+29
View File
@@ -0,0 +1,29 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento header vystavuje jednotne API pro textovy vystup v VGA rezimu.
* Definuje operace pro inicializaci, cisteni obrazovky, zapis znaku,
* zapis retezce a zmenu barevne palety textove konzole.
*/
#ifndef ASTER_DISPLAY_H
#define ASTER_DISPLAY_H
#include "types.h"
void display_init(void);
void display_clear(void);
void display_putc(char c);
void display_write(const char *text);
void display_set_color(u8 fg, u8 bg);
void display_get_cursor(usize *out_row, usize *out_col);
void display_set_cursor(usize new_row, usize new_col);
void display_fill_row(usize target_row, char ch, u8 fg, u8 bg);
void display_write_at(usize target_row, usize target_col, const char *text, u8 fg, u8 bg);
#endif
+34
View File
@@ -0,0 +1,34 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento soubor slouzi jako centralni rozcestnik pro verejne ovladace jadra.
* Drzi pohromade deklarace klavesnice, casovace a storage vrstvy,
* aby je kernel mohl jednoduse inicializovat z jednoho mista.
*/
#ifndef ASTER_DRIVERS_H
#define ASTER_DRIVERS_H
#define ASTER_KEY_F1 0x101
#define ASTER_KEY_F2 0x102
#define ASTER_KEY_UP 0x103
#define ASTER_KEY_DOWN 0x104
#define ASTER_KEY_LEFT 0x105
#define ASTER_KEY_RIGHT 0x106
void keyboard_init(void);
int keyboard_read_key(void);
int keyboard_try_read_key(void);
int keyboard_readline(char *buffer, int max_len);
void timer_init(unsigned int hz);
unsigned long timer_ticks(void);
void storage_init(void);
#endif
+29
View File
@@ -0,0 +1,29 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento header definuje rozhrani pametoveho subsystému jadra.
* Obsahuje API pro allocator fyzickych stranek, jednoduche heap alokace
* a funkce pro cteni zakladnich statistik o celkove a volne pameti.
*/
#ifndef ASTER_MEMORY_H
#define ASTER_MEMORY_H
#include "types.h"
#define PAGE_SIZE 4096
void memory_init(void);
void *page_alloc(void);
void page_free(void *page);
void *kmalloc(usize size);
void kfree(void *ptr);
usize memory_total_pages(void);
usize memory_free_pages(void);
#endif
+19
View File
@@ -0,0 +1,19 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento header deklaruje fatalni panic cestu jadra.
* Funkce panic je urcena pro situace, kdy nelze bezpecne pokracovat,
* proto vypise duvod chyby a prevede system do zastaveneho stavu.
*/
#ifndef ASTER_PANIC_H
#define ASTER_PANIC_H
void panic(const char *reason);
#endif
+20
View File
@@ -0,0 +1,20 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento soubor definuje rozhrani pro kernelovy diagnosticky vystup.
* Poskytuje jednoduche API pro vypis retezce i formatovany log,
* ktery slouzi pro ladeni bootu, preruseni i behu kernel sluzeb.
*/
#ifndef ASTER_PRINTK_H
#define ASTER_PRINTK_H
void aster_print(const char *text);
void printk(const char *fmt, ...);
#endif
+57
View File
@@ -0,0 +1,57 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento header popisuje procesovy model jadra.
* Obsahuje stavy procesu, kontext CPU registru a strukturu process_t,
* plus API pro vytvareni procesu, ukonceni a pristup k procesove tabulce.
*/
#ifndef ASTER_PROCESS_H
#define ASTER_PROCESS_H
#include "types.h"
#define ASTER_MAX_PROCESSES 16
typedef enum {
PROCESS_UNUSED = 0,
PROCESS_READY,
PROCESS_RUNNING,
PROCESS_BLOCKED,
PROCESS_EXITED
} process_state_t;
typedef struct {
u64 r15;
u64 r14;
u64 r13;
u64 r12;
u64 rbx;
u64 rbp;
u64 rip;
} context_t;
typedef struct {
u32 pid;
process_state_t state;
u8 priority;
u8 *stack_base;
u64 stack_top;
context_t context;
const char *name;
} process_t;
void process_init(void);
process_t *process_create(const char *name, void (*entry)(void), u8 priority);
void process_exit(void);
process_t *process_current(void);
void process_set_current(process_t *p);
process_t *process_table(void);
usize process_count(void);
#endif
+25
View File
@@ -0,0 +1,25 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento soubor deklaruje planovac, ktery rozhoduje o prideleni CPU casu.
* Popisuje vstupni body pro inicializaci, periodicky tick a prepnuti,
* a funkce pro vyber dalsiho kandidata k vykonu.
*/
#ifndef ASTER_SCHEDULER_H
#define ASTER_SCHEDULER_H
#include "process.h"
void scheduler_init(void);
void scheduler_tick(void);
void scheduler_run_once(void);
void scheduler_yield(void);
process_t *scheduler_pick_next(void);
#endif
+41
View File
@@ -0,0 +1,41 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento header definuje verejne rozhrani jednoducheho AsterFS.
* Popisuje format uzlu souboru nebo adresare a deklaruje operace
* pro inicializaci, vytvareni, cteni, zapis a vypis obsahu.
*/
#ifndef ASTER_STORAGE_H
#define ASTER_STORAGE_H
#include "types.h"
#define ASTERFS_MAX_FILES 64
#define ASTERFS_NAME_LEN 64
#define ASTERFS_DATA_LEN 512
typedef struct {
char name[ASTERFS_NAME_LEN];
u8 is_dir;
u16 size;
u8 data[ASTERFS_DATA_LEN];
} asterfs_node_t;
void asterfs_init(void);
int asterfs_create_file(const char *name);
int asterfs_create_dir(const char *name);
int asterfs_remove_file(const char *name);
int asterfs_remove_dir(const char *name);
int asterfs_write_file(const char *name, const u8 *data, u16 len);
int asterfs_read_file(const char *name, u8 *out, u16 max_len);
int asterfs_get_type(const char *name);
void asterfs_list(void (*cb)(const char *name, u8 is_dir, u16 size));
void asterfs_list_dir(const char *path, void (*cb)(const char *name, u8 is_dir, u16 size));
#endif
+25
View File
@@ -0,0 +1,25 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento soubor deklaruje minimalisticke utility bez zavislosti na libc.
* Obsahuje zakladni operace nad retezci a pameti, ktere kernel potrebuje
* uz v ranych fazich bootu, kdy standardni knihovny nejsou dostupne.
*/
#ifndef ASTER_STRING_H
#define ASTER_STRING_H
#include "types.h"
usize aster_strlen(const char *s);
int aster_strcmp(const char *a, const char *b);
int aster_strncmp(const char *a, const char *b, usize n);
void *aster_memcpy(void *dst, const void *src, usize n);
void *aster_memset(void *dst, int v, usize n);
#endif
+30
View File
@@ -0,0 +1,30 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento header popisuje syscall ABI mezi user casti a jadrem.
* Definuje cisla volani, centralni dispatcher a obalove funkce,
* ktere mapuji uzivatelske pozadavky na kernelove sluzby.
*/
#ifndef ASTER_SYSCALL_H
#define ASTER_SYSCALL_H
#include "types.h"
#define SYSCALL_WRITE 0
#define SYSCALL_ALLOC 1
#define SYSCALL_PROCESS_CREATE 2
void syscall_init(void);
u64 syscall_dispatch(u64 id, u64 a1, u64 a2, u64 a3, u64 a4);
u64 aster_write(const char *text);
void *aster_alloc(usize size);
i64 aster_process_create(void (*entry)(void), const char *name, u8 priority);
#endif
+22
View File
@@ -0,0 +1,22 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento soubor deklaruje casovaci vrstvu nad PIT hardwarem.
* Zahrnuje inicializaci frekvence, cteni tiku, inkrement z ISR
* a blokujici uspani jadra na zadany pocet milisekund.
*/
#ifndef ASTER_TIMER_H
#define ASTER_TIMER_H
void timer_init(unsigned int hz);
unsigned long timer_ticks(void);
void timer_tick_advance(void);
void timer_sleep_ms(unsigned long ms);
#endif
+28
View File
@@ -0,0 +1,28 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento header sjednocuje zakladni celoctiselne typy jadra.
* Cilem je mit stabilni velikosti typu nezavisle na kompilatoru
* a pouzivat je konzistentne ve vsech kernel subsystémech.
*/
#ifndef ASTER_TYPES_H
#define ASTER_TYPES_H
typedef unsigned long long u64;
typedef signed long long i64;
typedef unsigned int u32;
typedef signed int i32;
typedef unsigned short u16;
typedef signed short i16;
typedef unsigned char u8;
typedef signed char i8;
typedef unsigned long usize;
typedef long isize;
#endif
+56
View File
@@ -0,0 +1,56 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalas
* Rok: 2026
*
*/
/*
* Tento soubor implementuje bridge mezi API pro aplikace a jadrem.
* Dnes funguje jako tenka vrstva nad kernel sluzbami a syscall API,
* aby bylo mozne na stejnem rozhrani pozdeji stavet user-space runtime.
*/
#include "aster_api.h"
#include "display.h"
#include "storage.h"
#include "syscall.h"
#include "timer.h"
int aster_api_print(const char *text) {
return (int)aster_write(text);
}
int aster_api_clear(void) {
display_clear();
return 0;
}
int aster_api_ticks(u64 *out_ticks) {
if (!out_ticks) {
return -1;
}
*out_ticks = (u64)timer_ticks();
return 0;
}
void *aster_api_alloc(usize size) {
return aster_alloc(size);
}
int aster_api_file_create(const char *path) {
return asterfs_create_file(path);
}
int aster_api_file_read(const char *path, u8 *out, u16 max_len) {
return asterfs_read_file(path, out, max_len);
}
int aster_api_file_write(const char *path, const u8 *data, u16 len) {
return asterfs_write_file(path, data, len);
}
int aster_api_process_spawn(void (*entry)(void), const char *name, u8 priority) {
return (int)aster_process_create(entry, name, priority);
}
+2959
View File
File diff suppressed because it is too large Load Diff
+106
View File
@@ -0,0 +1,106 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento modul realizuje dve vrstvy spravy pameti jadra.
* Prvni cast je bitmap allocator fyzickych stranek pro page_alloc/page_free,
* druha cast je jednoducha linearni heap alokace pro kernelove objekty.
*/
#include "memory.h"
#include "string.h"
#define PMM_MAX_MEMORY (64ULL * 1024ULL * 1024ULL)
#define PMM_MAX_PAGES (PMM_MAX_MEMORY / PAGE_SIZE)
#define PMM_BITMAP_SIZE (PMM_MAX_PAGES / 8)
static u8 page_bitmap[PMM_BITMAP_SIZE];
static usize free_pages = PMM_MAX_PAGES;
#define KHEAP_SIZE (1024 * 1024)
static u8 kernel_heap[KHEAP_SIZE];
static usize heap_offset = 0;
static void bitmap_set(usize idx) {
page_bitmap[idx / 8] |= (u8)(1u << (idx % 8));
}
static void bitmap_clear(usize idx) {
page_bitmap[idx / 8] &= (u8)~(1u << (idx % 8));
}
static int bitmap_test(usize idx) {
return (page_bitmap[idx / 8] & (u8)(1u << (idx % 8))) != 0;
}
void memory_init(void) {
aster_memset(page_bitmap, 0, PMM_BITMAP_SIZE);
free_pages = PMM_MAX_PAGES;
heap_offset = 0;
for (usize i = 0; i < 256; ++i) {
bitmap_set(i);
--free_pages;
}
}
void *page_alloc(void) {
usize i;
for (i = 0; i < PMM_MAX_PAGES; ++i) {
if (!bitmap_test(i)) {
bitmap_set(i);
--free_pages;
return (void *)(i * PAGE_SIZE);
}
}
return 0;
}
void page_free(void *page) {
usize idx;
if (!page) {
return;
}
idx = ((usize)page) / PAGE_SIZE;
if (idx < PMM_MAX_PAGES && bitmap_test(idx)) {
bitmap_clear(idx);
++free_pages;
}
}
void *kmalloc(usize size) {
usize aligned;
if (size == 0) {
return 0;
}
aligned = (size + 15) & ~((usize)15);
if (heap_offset + aligned > KHEAP_SIZE) {
return 0;
}
void *ptr = &kernel_heap[heap_offset];
heap_offset += aligned;
return ptr;
}
void kfree(void *ptr) {
(void)ptr;
}
usize memory_total_pages(void) {
return PMM_MAX_PAGES;
}
usize memory_free_pages(void) {
return free_pages;
}
+23
View File
@@ -0,0 +1,23 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento soubor drzi nouzovou cestu pro neobnovitelne chyby jadra.
* Pri volani panic prepne vizualni styl vystupu, vypise duvod selhani
* a bezpecne zastavi CPU, aby se predeslo dalsimu poskozeni stavu.
*/
#include "cpu.h"
#include "display.h"
#include "panic.h"
#include "printk.h"
void panic(const char *reason) {
display_set_color(0x0F, 0x04);
printk("\n[KERNEL PANIC] %s\n", reason ? reason : "unknown");
cpu_halt();
}
+106
View File
@@ -0,0 +1,106 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento modul implementuje tiskovou vrstvu kernelu nad VGA vystupem.
* Obsahuje podporu zakladnich formatovacich specifikatoru pro ladeni
* a jednotne API, ktere pouzivaji ostatni casti jadra pri logovani.
*/
#include <stdarg.h>
#include "display.h"
#include "printk.h"
static void print_u64(unsigned long long value, unsigned int base) {
char buf[32];
const char *digits = "0123456789abcdef";
int i = 0;
if (value == 0) {
display_putc('0');
return;
}
while (value > 0 && i < (int)sizeof(buf)) {
buf[i++] = digits[value % base];
value /= base;
}
while (i > 0) {
display_putc(buf[--i]);
}
}
void aster_print(const char *text) {
display_write(text);
}
void printk(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
while (*fmt) {
if (*fmt != '%') {
display_putc(*fmt++);
continue;
}
++fmt;
switch (*fmt) {
case '%':
display_putc('%');
break;
case 'c': {
int c = va_arg(args, int);
display_putc((char)c);
break;
}
case 's': {
const char *s = va_arg(args, const char *);
if (!s) {
s = "(null)";
}
display_write(s);
break;
}
case 'd': {
long v = va_arg(args, int);
if (v < 0) {
display_putc('-');
print_u64((unsigned long long)(-v), 10);
} else {
print_u64((unsigned long long)v, 10);
}
break;
}
case 'u': {
unsigned int v = va_arg(args, unsigned int);
print_u64(v, 10);
break;
}
case 'x': {
unsigned int v = va_arg(args, unsigned int);
print_u64(v, 16);
break;
}
case 'p': {
unsigned long long v = (unsigned long long)va_arg(args, void *);
display_write("0x");
print_u64(v, 16);
break;
}
default:
display_putc('?');
break;
}
++fmt;
}
va_end(args);
}
+91
View File
@@ -0,0 +1,91 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento soubor spravuje zivotni cyklus kernel procesu.
* Implementuje statickou procesovou tabulku, prirazovani PID,
* pripravu stacku a zakladni operace pro vytvoreni a ukonceni procesu.
*/
#include "memory.h"
#include "process.h"
#include "string.h"
#define PROCESS_STACK_SIZE (16 * 1024)
static process_t g_processes[ASTER_MAX_PROCESSES];
static usize g_process_count = 0;
static u32 g_next_pid = 1;
static process_t *g_current = 0;
void process_init(void) {
usize i;
for (i = 0; i < ASTER_MAX_PROCESSES; ++i) {
g_processes[i].pid = 0;
g_processes[i].state = PROCESS_UNUSED;
g_processes[i].priority = 0;
g_processes[i].stack_base = 0;
g_processes[i].stack_top = 0;
g_processes[i].name = 0;
g_processes[i].context.rip = 0;
}
g_process_count = 0;
g_current = 0;
}
process_t *process_create(const char *name, void (*entry)(void), u8 priority) {
process_t *p;
void *stack;
if (g_process_count >= ASTER_MAX_PROCESSES || !entry) {
return 0;
}
p = &g_processes[g_process_count];
stack = kmalloc(PROCESS_STACK_SIZE);
if (!stack) {
return 0;
}
p->pid = g_next_pid++;
p->state = PROCESS_READY;
p->priority = priority;
p->stack_base = (u8 *)stack;
p->stack_top = (u64)(p->stack_base + PROCESS_STACK_SIZE - 16);
p->name = name;
aster_memset(&p->context, 0, sizeof(context_t));
p->context.rip = (u64)entry;
p->context.rbp = p->stack_top;
++g_process_count;
return p;
}
void process_exit(void) {
if (g_current) {
g_current->state = PROCESS_EXITED;
}
}
process_t *process_current(void) {
return g_current;
}
void process_set_current(process_t *p) {
g_current = p;
}
process_t *process_table(void) {
return &g_processes[0];
}
usize process_count(void) {
return g_process_count;
}
+81
View File
@@ -0,0 +1,81 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento modul implementuje jednoduchy planovac typu round-robin.
* Reaguje na tiky casovace, vybira dalsi bezici proces
* a ridi prepinani mezi stavy READY, RUNNING a EXITED.
*/
#include "process.h"
#include "scheduler.h"
#include "timer.h"
static usize g_current_index = 0;
static unsigned long g_quantum_ticks = 0;
void scheduler_init(void) {
g_current_index = 0;
g_quantum_ticks = 0;
}
process_t *scheduler_pick_next(void) {
process_t *table = process_table();
usize count = process_count();
usize i;
if (count == 0) {
return 0;
}
for (i = 0; i < count; ++i) {
usize idx = (g_current_index + i + 1) % count;
if (table[idx].state == PROCESS_READY || table[idx].state == PROCESS_RUNNING) {
g_current_index = idx;
return &table[idx];
}
}
return 0;
}
void scheduler_run_once(void) {
process_t *next = scheduler_pick_next();
if (!next) {
return;
}
process_set_current(next);
if (next->state == PROCESS_READY) {
void (*entry)(void) = (void (*)(void))next->context.rip;
next->state = PROCESS_RUNNING;
entry();
if (next->state == PROCESS_RUNNING) {
next->state = PROCESS_EXITED;
}
}
}
void scheduler_yield(void) {
process_t *current = process_current();
if (current && current->state == PROCESS_RUNNING) {
current->state = PROCESS_READY;
}
scheduler_run_once();
}
void scheduler_tick(void) {
timer_tick_advance();
++g_quantum_ticks;
if ((g_quantum_ticks % 5) == 0) {
scheduler_run_once();
}
}
+65
View File
@@ -0,0 +1,65 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento soubor obsahuje vlastni implementace zakladnich utility funkci.
* Kernel je pouziva misto standardni knihovny pro strlen, strcmp,
* memcpy a memset, aby zustal freestanding a plne pod kontrolou jadra.
*/
#include "string.h"
usize aster_strlen(const char *s) {
usize n = 0;
while (s && s[n]) {
++n;
}
return n;
}
int aster_strcmp(const char *a, const char *b) {
while (*a && (*a == *b)) {
++a;
++b;
}
return (unsigned char)*a - (unsigned char)*b;
}
int aster_strncmp(const char *a, const char *b, usize n) {
usize i;
for (i = 0; i < n; ++i) {
if (a[i] != b[i] || a[i] == '\0' || b[i] == '\0') {
return (unsigned char)a[i] - (unsigned char)b[i];
}
}
return 0;
}
void *aster_memcpy(void *dst, const void *src, usize n) {
usize i;
u8 *d = (u8 *)dst;
const u8 *s = (const u8 *)src;
for (i = 0; i < n; ++i) {
d[i] = s[i];
}
return dst;
}
void *aster_memset(void *dst, int v, usize n) {
usize i;
u8 *d = (u8 *)dst;
for (i = 0; i < n; ++i) {
d[i] = (u8)v;
}
return dst;
}
+58
View File
@@ -0,0 +1,58 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento modul je vstupni brana pro systemova volani.
* Obsahuje dispatcher, ktery podle ID vola konkretni kernelovou sluzbu,
* a implementuje zakladni syscall operace pro zapis, alokaci a procesy.
*/
#include "memory.h"
#include "printk.h"
#include "process.h"
#include "syscall.h"
void syscall_init(void) {
}
u64 syscall_dispatch(u64 id, u64 a1, u64 a2, u64 a3, u64 a4) {
(void)a3;
(void)a4;
switch (id) {
case SYSCALL_WRITE:
return aster_write((const char *)a1);
case SYSCALL_ALLOC:
return (u64)aster_alloc((usize)a1);
case SYSCALL_PROCESS_CREATE:
return (u64)aster_process_create((void (*)(void))a1, (const char *)a2, (u8)a3);
default:
return (u64)-1;
}
}
u64 aster_write(const char *text) {
if (!text) {
return (u64)-1;
}
printk("%s", text);
return 0;
}
void *aster_alloc(usize size) {
return kmalloc(size);
}
i64 aster_process_create(void (*entry)(void), const char *name, u8 priority) {
process_t *p = process_create(name, entry, priority);
if (!p) {
return -1;
}
return p->pid;
}
+37
View File
@@ -0,0 +1,37 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
* Vytvořeno jen tak z nudy a z chuti zkoušet nové věci.
*/
OUTPUT_FORMAT(elf64-x86-64)
ENTRY(_start)
SECTIONS
{
. = 0x00100000;
.text :
{
*(.text.boot)
*(.text*)
}
.rodata :
{
*(.rodata*)
}
.data :
{
*(.data*)
}
.bss :
{
*(COMMON)
*(.bss*)
}
}