Initial commit: SUB-OS 64-Bit Production Monolithic Operating System with LazyBox userland suite

This commit is contained in:
subhobhai943 committed 2026-08-16 21:23:52 +05:30
commit cd9c786d14
88 files changed
+7132

No files matched your search

+10
View File
@@ -0,0 +1,10 @@
build/
*.bin
*.img
*.elf
*.o
*.iso
*.log
*.tmp
.DS_Store
.system_generated/
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 subhobhai943
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+114
View File
@@ -0,0 +1,114 @@
# =============================================================================
# SUB-OS Master Makefile - Modular Monolithic Linux-Like Kernel Build System
# =============================================================================
# Cross Compiler & Toolchain Detection
CROSS_COMPILE ?= x86_64-elf-
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
OBJCOPY = $(CROSS_COMPILE)objcopy
ASM = nasm
# Build Directories
BUILD_DIR = build
BOOT_DIR = boot
# Target Architecture Flags
CFLAGS = -ffreestanding \
-mno-red-zone \
-mno-mmx \
-mno-sse \
-mno-sse2 \
-mcmodel=kernel \
-Wall \
-Wextra \
-Wno-unused-function \
-Wno-unused-parameter \
-O2 \
-Iinclude
ASMFLAGS_ELF = -f elf64
ASMFLAGS_BOOT = -f bin -I$(BOOT_DIR)/
LDFLAGS = -nostdlib -T linker.ld
# Source Files Discovery
ARCH_C_SRCS = $(shell find arch -name '*.c' 2>/dev/null)
ARCH_ASM_SRCS = $(shell find arch -name '*.asm' 2>/dev/null)
KERNEL_C_SRCS = $(shell find kernel -name '*.c' 2>/dev/null)
MM_C_SRCS = $(shell find mm -name '*.c' 2>/dev/null)
DRIVERS_C_SRCS = $(shell find drivers -name '*.c' 2>/dev/null)
FS_C_SRCS = $(shell find fs -name '*.c' 2>/dev/null)
NET_C_SRCS = $(shell find net -name '*.c' 2>/dev/null)
CRYPTO_C_SRCS = $(shell find crypto -name '*.c' 2>/dev/null)
LIB_C_SRCS = $(shell find lib -name '*.c' 2>/dev/null)
USERLAND_C_SRCS = $(shell find userland -name '*.c' 2>/dev/null)
ALL_C_SRCS = $(ARCH_C_SRCS) $(KERNEL_C_SRCS) $(MM_C_SRCS) $(DRIVERS_C_SRCS) \
$(FS_C_SRCS) $(NET_C_SRCS) $(CRYPTO_C_SRCS) $(LIB_C_SRCS) $(USERLAND_C_SRCS)
# Object Files Mapping
C_OBJS = $(patsubst %.c, $(BUILD_DIR)/%.o, $(ALL_C_SRCS))
ASM_OBJS = $(patsubst %.asm, $(BUILD_DIR)/%.o, $(ARCH_ASM_SRCS))
# Put entry.o first in linker sequence
ENTRY_OBJ = $(BUILD_DIR)/arch/x86_64/boot/entry.o
OTHER_OBJS = $(filter-out $(ENTRY_OBJ), $(ASM_OBJS) $(C_OBJS))
IMAGE = SUB-OS.img
.PHONY: all clean run debug info
all: $(IMAGE)
# Assemble 16-bit Bootloader Stage 1
$(BUILD_DIR)/boot/boot.bin: $(BOOT_DIR)/boot.asm | $(BUILD_DIR)/boot
$(ASM) $(ASMFLAGS_BOOT) $< -o $@
# Assemble 16/32/64-bit Bootloader Stage 2
$(BUILD_DIR)/boot/stage2.bin: $(BOOT_DIR)/stage2.asm $(BOOT_DIR)/gdt.asm | $(BUILD_DIR)/boot
$(ASM) $(ASMFLAGS_BOOT) $< -o $@
# Compile 64-bit C source files
$(BUILD_DIR)/%.o: %.c
@mkdir -p $(dir $@)
$(CC) $(CFLAGS) -c $< -o $@
# Assemble 64-bit ASM source files
$(BUILD_DIR)/%.o: %.asm
@mkdir -p $(dir $@)
$(ASM) $(ASMFLAGS_ELF) $< -o $@
# Link Kernel ELF
$(BUILD_DIR)/kernel.elf: $(ENTRY_OBJ) $(OTHER_OBJS) linker.ld
$(LD) $(LDFLAGS) -o $@ $(ENTRY_OBJ) $(OTHER_OBJS)
# Convert ELF to Flat Binary
$(BUILD_DIR)/kernel.bin: $(BUILD_DIR)/kernel.elf
$(OBJCOPY) -O binary $< $@
# Create Bootable Floppy / HDD Raw Disk Image
$(IMAGE): $(BUILD_DIR)/boot/boot.bin $(BUILD_DIR)/boot/stage2.bin $(BUILD_DIR)/kernel.bin
dd if=/dev/zero of=$@ bs=512 count=2880 status=none
dd if=$(BUILD_DIR)/boot/boot.bin of=$@ bs=512 conv=notrunc status=none
dd if=$(BUILD_DIR)/boot/stage2.bin of=$@ bs=512 seek=1 conv=notrunc status=none
dd if=$(BUILD_DIR)/kernel.bin of=$@ bs=512 seek=16 conv=notrunc status=none
@echo "=== [SUB-OS Disk Image Built Successfully: $@ (Size: $$(du -h $@ | cut -f1))] ==="
$(BUILD_DIR)/boot:
mkdir -p $(BUILD_DIR)/boot
run: $(IMAGE)
qemu-system-x86_64 -drive format=raw,file=$(IMAGE) -nic model=e1000 -serial stdio
debug: $(IMAGE)
qemu-system-x86_64 -drive format=raw,file=$(IMAGE) -nic model=e1000 -serial stdio -s -S
info:
@echo "C Sources: $(words $(ALL_C_SRCS)) files"
@echo "ASM Sources: $(words $(ARCH_ASM_SRCS)) files"
@echo "Target: $(IMAGE)"
clean:
rm -rf $(BUILD_DIR) $(IMAGE)
+140
View File
@@ -0,0 +1,140 @@
# SUB-OS 64-Bit Production Monolithic Operating System
[![Build](https://img.shields.io/badge/build-passing-brightgreen.svg)]()
[![Architecture](https://img.shields.io/badge/arch-x86__64%20Long%20Mode-blue.svg)]()
[![Userland](https://img.shields.io/badge/userland-LazyBox%20v2.0.0--pro-orange.svg)]()
[![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
**SUB-OS** is a modular monolithic 64-bit x86_64 operating system designed and engineered from scratch following modern Linux kernel architectural patterns and incorporating the **LazyBox** multi-call userland binary suite.
---
## 🌟 Key Features
- **64-Bit Long Mode Bare-Metal Core**: Custom two-stage MBR bootloader with BIOS E820 memory mapping and 4GB 4-level PML4 identity paging.
- **Modular Monolithic Linux Layout**: Clean directory structure (`arch/`, `kernel/`, `mm/`, `drivers/`, `fs/`, `net/`, `crypto/`, `lib/`, `userland/`).
- **Preemptive Multitasking Scheduler**: Round-Robin scheduling driven by 8254 PIT (100 Hz, 10ms resolution) with atomic spinlocks & semaphores.
- **Physical & Dynamic Memory Management**: 64-bit Page Frame Allocator (4 KB bitmap) and Kernel Dynamic Heap (4 MB pool) with boundary tag splitting and coalescing.
- **Virtual File System (VFS)**: Path resolver (`vfs_namei`), file descriptors (64 max), in-memory RAMFS, synthetic `/dev` device filesystem, and `/proc` dynamic system metrics filesystem.
- **Hardware Drivers**:
- **Char**: VGA Text Mode, Virtual Terminals TTY1-4 with ANSI escape parsing, 16550 UART Serial (COM1), PS/2 Keyboard with circular buffer.
- **Block**: ATA / IDE Hard Disk PIO driver (28-bit LBA).
- **PCI**: PCI Bus Enumeration & MMIO BAR configuration.
- **Network**: Intel 82540EM/82545EM Gigabit Ethernet NIC with circular DMA RX/TX rings.
- **Sound**: PC Speaker square-wave tone generator.
- **Network Protocol Stack**: Ethernet encapsulation, ARP resolution table, IPv4 routing/checksums, and ICMP Echo client/server (`ping`).
- **Kernel Cryptographic Engine**: FIPS 180-4 SHA-256, RFC 1321 MD5, IEEE 802.3 CRC32, and Xorshift128+ CSPRNG.
- **LazyBox Multi-Call Userland Suite**: 42 built-in applets with history, arrow-key line editing, and ANSI color support.
---
## 📁 Source Tree
```
├── arch/x86_64/ # Hardware-specific CPU, paging, and entry code
│ ├── boot/ # 64-bit kernel entry point (entry.asm)
│ ├── cpu/ # GDT/TSS, IDT (256 gates), Dual 8259A PIC, 8254 PIT, CPUID
│ └── mm/ # 4-Level PML4 Paging & TLB management
├── boot/ # Custom two-stage MBR bootloader
│ ├── boot.asm # Stage 1: 512-byte MBR loader (INT 13h LBA/CHS)
│ └── stage2.asm # Stage 2: A20, E820 Memory Map, 4GB Identity Paging, Long Mode switch
├── kernel/ # Core Monolithic Kernel Engine
│ ├── main.c # 11-step master initialization sequence
│ ├── printk.c # ANSI loglevel printk with 64KB dmesg ringbuffer & COM1 serial port output
│ ├── panic.c # Kernel panic screen with 64-bit register dump
│ ├── task.c # Task Control Blocks (PCB) & Process Management
│ ├── sched.c # Preemptive Round-Robin Multi-Tasking Scheduler
│ └── sync.c # Atomic spinlocks and semaphores
├── mm/ # Memory Management Subsystem
│ ├── pmm.c # 64-bit Physical Page Frame Allocator (4 KB bitmap)
│ └── kmalloc.c # Kernel Dynamic Heap Allocator (4 MB initial pool)
├── drivers/ # Device Driver Tree
│ ├── char/ # VGA text driver, Virtual Terminals TTY1-4, 16550 UART COM1, PS/2 Keyboard
│ ├── block/ # ATA / IDE Hard Disk PIO driver (28-bit LBA)
│ ├── pci/ # PCI Bus Enumerator & BAR mapping
│ ├── net/ # Intel 82540EM/82545EM Gigabit Ethernet NIC Driver (Circular DMA Rings)
│ └── sound/ # PC Speaker tone generator & PIT Channel 2
├── fs/ # Virtual File System (VFS)
│ ├── vfs.c # VFS core, path resolver (vfs_namei), file descriptor table (64 max)
│ ├── ramfs.c # In-memory RAM filesystem
│ ├── devfs.c # Synthetic Device Filesystem (/dev/null, /dev/zero, /dev/random, /dev/tty)
│ └── procfs.c # Dynamic Information Filesystem (/proc/version, /proc/meminfo, /proc/cpuinfo)
├── crypto/ # Kernel Cryptographic Engine
│ ├── sha256.c # FIPS 180-4 Standard SHA-256 Digest
│ ├── md5.c # RFC 1321 MD5 Message-Digest
│ ├── crc32.c # IEEE 802.3 32-bit Cyclic Redundancy Check
│ └── prng.c # Xorshift128+ High-Performance CSPRNG
├── net/core/ # Network Protocol Stack
│ └── net.c # Ethernet encapsulation, ARP Table, IPv4 routing, ICMP Echo ping client/server
├── lib/ # Standard Kernel Runtime Library
│ ├── string.c # String & memory manipulation
│ ├── vsprintf.c # vsnprintf with width, alignment, and formatting
│ └── bitmap.c # Bit manipulation utilities
└── userland/lazybox/ # Userland Shell & Multi-Call Suite
├── lazybox.c # Multi-call binary dispatcher with 42 applets
└── shell.c # Interactive terminal shell (history, tab-completion, ANSI color)
```
---
## ⚡ 11-Step Master Boot Pipeline
1. **[1/11] GDT & TSS**: 64-bit flat segment selectors + Task State Segment with dedicated 64KB kernel stack.
2. **[2/11] IDT & ISRs**: 256-entry Interrupt Gate Table with CPU exception and hardware IRQ handlers.
3. **[3/11] Dual 8259A PIC**: Remapped hardware IRQs 0-15 to vectors 32-47 with cascade handling.
4. **[4/11] 8254 PIT Timer**: Configured for 100 Hz (10ms resolution) driving preemptive multitasking.
5. **[5/11] PS/2 Keyboard**: Full scancode translation table with Shift, CapsLock, and circular buffer.
6. **[6/11] Physical Memory Manager**: 64-bit frame allocator tracking 128 MB RAM (31,712 free pages).
7. **[7/11] Kernel Dynamic Heap**: 4 MB initial pool with boundary tag headers, coalescing, and reallocation.
8. **[8/11] ATA / IDE Hard Disk**: 28-bit LBA PIO controller supporting read/write operations.
9. **[9/11] PCI & Intel E1000 NIC**: Intel Gigabit Ethernet controller (`52:54:00:12:34:56`), DMA RX/TX rings.
10. **[10/11] Virtual File System**: Root RAMFS, `/dev` synthetic device filesystem, `/proc` dynamic info filesystem.
11. **[11/11] LazyBox & Scheduler**: Preemptive scheduler initialization and interactive multi-call binary userland.
---
## 🛠️ Build and Run
### Prerequisites
- `nasm` (>= 2.15)
- `x86_64-elf-gcc` (>= 13.0) & `x86_64-elf-ld`
- `qemu-system-x86_64`
- `make`
### Commands
```bash
# Build the 1.5MB bootable disk image
make
# Launch in QEMU with Intel E1000 Gigabit NIC
make run
# Clean build artifacts
make clean
```
---
## 💻 LazyBox Applet Reference
```
[Filesystem]
ls cat touch mkdir wc
[Crypto]
md5sum sha256sum crc32
[Network]
ifconfig ping arp
[Storage]
hdparm
[System]
uname free uptime dmesg sleep
[Terminal]
clear
[Core]
lazybox echo neofetch
```
---
## 📄 License
This project is open-source software licensed under the [MIT License](LICENSE).
+37
View File
@@ -0,0 +1,37 @@
[BITS 64]
extern kernel_main
extern __bss_start
extern __bss_end
extern stack_top
global kernel_entry
section .text
kernel_entry:
; 1. Set up high-performance dedicated 64 KB kernel stack
mov rsp, stack_top
; 2. Preserve bootloader arguments safely in callee-saved registers R12 & R13
mov r12, rdi ; memory_map pointer
mov r13, rsi ; memory_map count
; 3. Zero out the entire BSS section (.bss)
mov rdi, __bss_start
mov rcx, __bss_end
sub rcx, rdi
xor al, al
cld
rep stosb
; 4. Restore bootloader arguments into RDI and RSI per AMD64 System V ABI
mov rdi, r12
mov rsi, r13
; 5. Call kernel_main(memory_map, memory_map_count)
call kernel_main
.hang:
cli
hlt
jmp .hang
+65
View File
@@ -0,0 +1,65 @@
#include <arch/x86_64/cpuid.h>
#include <lib/string.h>
static cpu_info_t global_cpu_info;
static bool cpu_detected = false;
static inline void cpuid(uint32_t code, uint32_t* a, uint32_t* b, uint32_t* c, uint32_t* d) {
__asm__ volatile("cpuid"
: "=a"(*a), "=b"(*b), "=c"(*c), "=d"(*d)
: "a"(code));
}
void cpuid_detect(cpu_info_t* info) {
uint32_t eax, ebx, ecx, edx;
memset(info, 0, sizeof(cpu_info_t));
// 1. Get Vendor String
cpuid(0, &eax, &ebx, &ecx, &edx);
((uint32_t*)info->vendor)[0] = ebx;
((uint32_t*)info->vendor)[1] = edx;
((uint32_t*)info->vendor)[2] = ecx;
info->vendor[12] = '\0';
// 2. Get Features & Model Info
cpuid(1, &eax, &ebx, &ecx, &edx);
info->stepping = eax & 0x0F;
info->model_id = (eax >> 4) & 0x0F;
info->family = (eax >> 8) & 0x0F;
info->has_fpu = (edx & (1 << 0)) != 0;
info->has_tsc = (edx & (1 << 4)) != 0;
info->has_msr = (edx & (1 << 5)) != 0;
info->has_pae = (edx & (1 << 6)) != 0;
info->has_apic = (edx & (1 << 9)) != 0;
info->has_sse = (edx & (1 << 25)) != 0;
info->has_sse2 = (edx & (1 << 26)) != 0;
info->has_sse3 = (ecx & (1 << 0)) != 0;
info->has_sse4_1= (ecx & (1 << 19)) != 0;
info->has_sse4_2= (ecx & (1 << 20)) != 0;
info->has_avx = (ecx & (1 << 28)) != 0;
info->has_rdrand= (ecx & (1 << 30)) != 0;
// 3. Get Brand String (Extended Functions)
cpuid(0x80000000, &eax, &ebx, &ecx, &edx);
if (eax >= 0x80000004) {
uint32_t* brand = (uint32_t*)info->model;
cpuid(0x80000002, &brand[0], &brand[1], &brand[2], &brand[3]);
cpuid(0x80000003, &brand[4], &brand[5], &brand[6], &brand[7]);
cpuid(0x80000004, &brand[8], &brand[9], &brand[10], &brand[11]);
info->model[48] = '\0';
} else {
strcpy(info->model, "x86_64 Compatible Processor");
}
global_cpu_info = *info;
cpu_detected = true;
}
const cpu_info_t* cpuid_get_info(void) {
if (!cpu_detected) {
cpuid_detect(&global_cpu_info);
}
return &global_cpu_info;
}
+65
View File
@@ -0,0 +1,65 @@
#include <arch/x86_64/gdt.h>
#include <lib/string.h>
extern void gdt_flush(uint64_t gdt_ptr);
extern void tss_flush(void);
static gdt_entry_t gdt_entries[7];
static gdt_ptr_t gdt_ptr;
static tss_entry_t tss_entry;
static void gdt_set_gate(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran) {
gdt_entries[num].base_low = (base & 0xFFFF);
gdt_entries[num].base_middle = (base >> 16) & 0xFF;
gdt_entries[num].base_high = (base >> 24) & 0xFF;
gdt_entries[num].limit_low = (limit & 0xFFFF);
gdt_entries[num].granularity = (limit >> 16) & 0x0F;
gdt_entries[num].granularity |= gran & 0xF0;
gdt_entries[num].access = access;
}
static void write_tss(int num, uint64_t base, uint32_t limit) {
gdt_set_gate(num, (uint32_t)base, limit, 0x89, 0x00);
// TSS descriptor takes 16 bytes in 64-bit mode (2 entries)
uint32_t* high_part = (uint32_t*)&gdt_entries[num + 1];
high_part[0] = (uint32_t)(base >> 32);
high_part[1] = 0;
}
void gdt_init(void) {
gdt_ptr.limit = sizeof(gdt_entries) - 1;
gdt_ptr.base = (uint64_t)&gdt_entries;
// 0x00: Null Descriptor
gdt_set_gate(0, 0, 0, 0, 0);
// 0x08: Kernel 64-bit Code Segment (Access=0x9A, Gran=0x20 for Long Mode)
gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0x20);
// 0x10: Kernel 64-bit Data Segment (Access=0x92, Gran=0x00)
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0x00);
// 0x18: User 64-bit Code Segment (Access=0xFA, Gran=0x20)
gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0x20);
// 0x20: User 64-bit Data Segment (Access=0xF2, Gran=0x00)
gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0x00);
// 0x28: TSS (Task State Segment) - takes slots 5 & 6
extern char stack_top[];
memset(&tss_entry, 0, sizeof(tss_entry_t));
tss_entry.rsp0 = (uint64_t)stack_top;
tss_entry.ist1 = (uint64_t)stack_top;
tss_entry.iomap_base = sizeof(tss_entry_t);
write_tss(5, (uint64_t)&tss_entry, sizeof(tss_entry_t) - 1);
gdt_flush((uint64_t)&gdt_ptr);
tss_flush();
}
void gdt_set_kernel_stack(uint64_t stack) {
tss_entry.rsp0 = stack;
}
+29
View File
@@ -0,0 +1,29 @@
[BITS 64]
global gdt_flush
global tss_flush
section .text
gdt_flush:
lgdt [rdi]
; Reload data segments
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
; Reload CS via far return
push 0x08
lea rax, [rel .reload_cs]
push rax
retfq
.reload_cs:
ret
tss_flush:
mov ax, 0x28
ltr ax
ret
+34
View File
@@ -0,0 +1,34 @@
#include <arch/x86_64/idt.h>
#include <lib/string.h>
extern void idt_flush(uint64_t idt_ptr);
static idt_entry_t idt_entries[IDT_ENTRIES];
static idt_ptr_t idt_ptr;
void idt_set_gate(uint8_t vector, void* isr, uint8_t flags) {
uint64_t addr = (uint64_t)isr;
idt_entries[vector].isr_low = (uint16_t)(addr & 0xFFFF);
idt_entries[vector].kernel_cs = 0x08;
idt_entries[vector].ist = 0;
idt_entries[vector].attributes = flags;
idt_entries[vector].isr_mid = (uint16_t)((addr >> 16) & 0xFFFF);
idt_entries[vector].isr_high = (uint32_t)((addr >> 32) & 0xFFFFFFFF);
idt_entries[vector].reserved = 0;
}
void idt_enable_gate(uint8_t vector) {
idt_entries[vector].attributes |= 0x80;
}
void idt_disable_gate(uint8_t vector) {
idt_entries[vector].attributes &= ~0x80;
}
void idt_init(void) {
idt_ptr.limit = sizeof(idt_entries) - 1;
idt_ptr.base = (uint64_t)&idt_entries;
memset(&idt_entries, 0, sizeof(idt_entries));
idt_flush((uint64_t)&idt_ptr);
}
+8
View File
@@ -0,0 +1,8 @@
[BITS 64]
global idt_flush
section .text
idt_flush:
lidt [rdi]
ret
+87
View File
@@ -0,0 +1,87 @@
#include <arch/x86_64/isr.h>
#include <arch/x86_64/idt.h>
#include <arch/x86_64/pic.h>
#include <kernel/printk.h>
#include <kernel/panic.h>
#include <lib/string.h>
extern void* isr_stub_table[48];
static isr_handler_t interrupt_handlers[256];
static const char* exception_messages[32] = {
"Division By Zero",
"Debug",
"Non-Maskable Interrupt",
"Breakpoint",
"Into Detected Overflow",
"Out of Bounds",
"Invalid Opcode",
"No Coprocessor",
"Double Fault",
"Coprocessor Segment Overrun",
"Bad TSS",
"Segment Not Present",
"Stack Fault",
"General Protection Fault",
"Page Fault",
"Unknown Interrupt",
"Coprocessor Fault",
"Alignment Check",
"Machine Check",
"SIMD Floating-Point Exception",
"Virtualization Exception",
"Control Protection Exception",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Hypervisor Injection Exception",
"VMM Communication Exception",
"Security Exception",
"Reserved"
};
void isr_register_handler(uint8_t int_no, isr_handler_t handler) {
interrupt_handlers[int_no] = handler;
}
void isr_unregister_handler(uint8_t int_no) {
interrupt_handlers[int_no] = NULL;
}
void isr_handler_common(registers_t* regs) {
if (regs->int_no < 32) {
// CPU Exception Fault
printk(KERN_EMERG "\n[EXCEPTION] Vector %llu: %s (Error code: 0x%llx)\n",
regs->int_no, exception_messages[regs->int_no], regs->error_code);
panic_with_regs(exception_messages[regs->int_no], regs);
}
if (interrupt_handlers[regs->int_no] != NULL) {
interrupt_handlers[regs->int_no](regs);
}
// Acknowledge Hardware PIC Interrupts (IRQs 32-47)
if (regs->int_no >= 32 && regs->int_no < 48) {
pic_send_eoi((uint8_t)(regs->int_no - 32));
}
}
extern void* isr_stub_default;
void isr_init(void) {
memset(interrupt_handlers, 0, sizeof(interrupt_handlers));
// 1. Initialize all 256 gates to isr_stub_default
for (int i = 0; i < 256; i++) {
idt_set_gate(i, isr_stub_default, 0x8E);
}
// 2. Install dedicated CPU exception gates (0-31) and hardware IRQ gates (32-47)
for (uint8_t i = 0; i < 48; i++) {
idt_set_gate(i, isr_stub_table[i], 0x8E);
}
}
+133
View File
@@ -0,0 +1,133 @@
[BITS 64]
extern isr_handler_common
global isr_stub_table
global isr_stub_default
%macro ISR_NOERRCODE 1
isr_stub_%1:
push qword 0 ; Dummy error code
push qword %1 ; Interrupt vector number
jmp isr_common_stub
%endmacro
%macro ISR_ERRCODE 1
isr_stub_%1:
push qword %1 ; Interrupt vector number (error code already on stack)
jmp isr_common_stub
%endmacro
section .text
; CPU Exceptions 0-31
ISR_NOERRCODE 0
ISR_NOERRCODE 1
ISR_NOERRCODE 2
ISR_NOERRCODE 3
ISR_NOERRCODE 4
ISR_NOERRCODE 5
ISR_NOERRCODE 6
ISR_NOERRCODE 7
ISR_ERRCODE 8
ISR_NOERRCODE 9
ISR_ERRCODE 10
ISR_ERRCODE 11
ISR_ERRCODE 12
ISR_ERRCODE 13
ISR_ERRCODE 14
ISR_NOERRCODE 15
ISR_NOERRCODE 16
ISR_ERRCODE 17
ISR_NOERRCODE 18
ISR_NOERRCODE 19
ISR_NOERRCODE 20
ISR_NOERRCODE 21
ISR_NOERRCODE 22
ISR_NOERRCODE 23
ISR_NOERRCODE 24
ISR_NOERRCODE 25
ISR_NOERRCODE 26
ISR_NOERRCODE 27
ISR_NOERRCODE 28
ISR_NOERRCODE 29
ISR_ERRCODE 30
ISR_NOERRCODE 31
; Hardware IRQs 32-47
ISR_NOERRCODE 32
ISR_NOERRCODE 33
ISR_NOERRCODE 34
ISR_NOERRCODE 35
ISR_NOERRCODE 36
ISR_NOERRCODE 37
ISR_NOERRCODE 38
ISR_NOERRCODE 39
ISR_NOERRCODE 40
ISR_NOERRCODE 41
ISR_NOERRCODE 42
ISR_NOERRCODE 43
ISR_NOERRCODE 44
ISR_NOERRCODE 45
ISR_NOERRCODE 46
ISR_NOERRCODE 47
isr_stub_default:
push qword 0
push qword 255
jmp isr_common_stub
isr_common_stub:
push rax
push rbx
push rcx
push rdx
push rsi
push rdi
push rbp
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
mov rdi, rsp
cld
call isr_handler_common
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rbp
pop rdi
pop rsi
pop rdx
pop rcx
pop rbx
pop rax
add rsp, 16
iretq
section .data
align 8
isr_stub_table:
dq isr_stub_0, isr_stub_1, isr_stub_2, isr_stub_3
dq isr_stub_4, isr_stub_5, isr_stub_6, isr_stub_7
dq isr_stub_8, isr_stub_9, isr_stub_10, isr_stub_11
dq isr_stub_12, isr_stub_13, isr_stub_14, isr_stub_15
dq isr_stub_16, isr_stub_17, isr_stub_18, isr_stub_19
dq isr_stub_20, isr_stub_21, isr_stub_22, isr_stub_23
dq isr_stub_24, isr_stub_25, isr_stub_26, isr_stub_27
dq isr_stub_28, isr_stub_29, isr_stub_30, isr_stub_31
dq isr_stub_32, isr_stub_33, isr_stub_34, isr_stub_35
dq isr_stub_36, isr_stub_37, isr_stub_38, isr_stub_39
dq isr_stub_40, isr_stub_41, isr_stub_42, isr_stub_43
dq isr_stub_44, isr_stub_45, isr_stub_46, isr_stub_47
+78
View File
@@ -0,0 +1,78 @@
#include <arch/x86_64/pic.h>
#include <arch/x86_64/io.h>
#define PIC1_COMMAND 0x20
#define PIC1_DATA 0x21
#define PIC2_COMMAND 0xA0
#define PIC2_DATA 0xA1
#define PIC_EOI 0x20
#define ICW1_INIT 0x10
#define ICW1_ICW4 0x01
#define ICW4_8086 0x01
void pic_send_eoi(uint8_t irq) {
if (irq >= 8) {
outb(PIC2_COMMAND, PIC_EOI);
}
outb(PIC1_COMMAND, PIC_EOI);
}
void pic_init(void) {
outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4);
io_wait();
outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4);
io_wait();
// Remap Master PIC to 0x20 (32), Slave PIC to 0x28 (40)
outb(PIC1_DATA, 0x20);
io_wait();
outb(PIC2_DATA, 0x28);
io_wait();
outb(PIC1_DATA, 4); // Tell Master that Slave is at IRQ2
io_wait();
outb(PIC2_DATA, 2); // Tell Slave its cascade identity
io_wait();
outb(PIC1_DATA, ICW4_8086);
io_wait();
outb(PIC2_DATA, ICW4_8086);
io_wait();
// Mask all interrupts initially except Cascade (IRQ2)
outb(PIC1_DATA, 0xFB);
outb(PIC2_DATA, 0xFF);
}
void pic_set_mask(uint8_t irq) {
uint16_t port;
if (irq < 8) {
port = PIC1_DATA;
} else {
port = PIC2_DATA;
irq -= 8;
}
uint8_t value = inb(port) | (1 << irq);
outb(port, value);
}
void pic_clear_mask(uint8_t irq) {
uint16_t port;
if (irq < 8) {
port = PIC1_DATA;
} else {
port = PIC2_DATA;
irq -= 8;
uint8_t master_val = inb(PIC1_DATA) & ~(1 << 2);
outb(PIC1_DATA, master_val);
}
uint8_t value = inb(port) & ~(1 << irq);
outb(port, value);
}
void pic_disable(void) {
outb(PIC1_DATA, 0xFF);
outb(PIC2_DATA, 0xFF);
}
+49
View File
@@ -0,0 +1,49 @@
#include <arch/x86_64/pit.h>
#include <arch/x86_64/isr.h>
#include <arch/x86_64/pic.h>
#include <arch/x86_64/io.h>
#include <kernel/sched.h>
#define PIT_COMMAND_PORT 0x43
#define PIT_CHANNEL0_PORT 0x40
#define PIT_BASE_FREQUENCY 1193182
static volatile uint64_t pit_ticks = 0;
static uint32_t pit_freq = 100;
static void pit_handler(registers_t* regs) {
(void)regs;
pit_ticks++;
// Notify preemptive scheduler
sched_tick();
}
void pit_init(uint32_t frequency) {
pit_freq = frequency;
uint32_t divisor = PIT_BASE_FREQUENCY / frequency;
// Channel 0, lobyte/hibyte, Rate generator (Mode 2)
outb(PIT_COMMAND_PORT, 0x36);
outb(PIT_CHANNEL0_PORT, (uint8_t)(divisor & 0xFF));
outb(PIT_CHANNEL0_PORT, (uint8_t)((divisor >> 8) & 0xFF));
// Register IRQ0 handler
isr_register_handler(32, pit_handler);
pic_clear_mask(0);
}
uint64_t pit_get_ticks(void) {
return pit_ticks;
}
uint64_t pit_get_uptime_ms(void) {
return (pit_ticks * 1000) / pit_freq;
}
void pit_sleep(uint32_t milliseconds) {
uint64_t target = pit_ticks + (milliseconds * pit_freq) / 1000;
while (pit_ticks < target) {
hlt();
}
}
+92
View File
@@ -0,0 +1,92 @@
#include <arch/x86_64/paging.h>
#include <mm/pmm.h>
#include <lib/string.h>
static pml4e_t* kernel_pml4 = (pml4e_t*)0x1000;
void paging_flush_tlb_single(uint64_t virt) {
__asm__ volatile("invlpg (%0)" : : "r"(virt) : "memory");
}
void paging_init(void) {
// PML4 is already loaded at 0x1000 by Stage 2 bootloader with 4GB mapped
kernel_pml4 = (pml4e_t*)0x1000;
}
void paging_map_page(uint64_t virt, uint64_t phys, uint64_t flags) {
size_t pml4_idx = (virt >> 39) & 0x1FF;
size_t pdpt_idx = (virt >> 30) & 0x1FF;
size_t pd_idx = (virt >> 21) & 0x1FF;
size_t pt_idx = (virt >> 12) & 0x1FF;
if (!(kernel_pml4[pml4_idx] & PAGE_PRESENT)) {
void* new_pdpt = pmm_alloc_page();
if (!new_pdpt) return;
memset(new_pdpt, 0, PAGE_SIZE);
kernel_pml4[pml4_idx] = (uint64_t)new_pdpt | PAGE_PRESENT | PAGE_WRITABLE | (flags & PAGE_USER);
}
pdpte_t* pdpt = (pdpte_t*)(kernel_pml4[pml4_idx] & ~0xFFFULL);
if (!(pdpt[pdpt_idx] & PAGE_PRESENT)) {
void* new_pd = pmm_alloc_page();
if (!new_pd) return;
memset(new_pd, 0, PAGE_SIZE);
pdpt[pdpt_idx] = (uint64_t)new_pd | PAGE_PRESENT | PAGE_WRITABLE | (flags & PAGE_USER);
}
pde_t* pd = (pde_t*)(pdpt[pdpt_idx] & ~0xFFFULL);
if (!(pd[pd_idx] & PAGE_PRESENT)) {
void* new_pt = pmm_alloc_page();
if (!new_pt) return;
memset(new_pt, 0, PAGE_SIZE);
pd[pd_idx] = (uint64_t)new_pt | PAGE_PRESENT | PAGE_WRITABLE | (flags & PAGE_USER);
}
pte_t* pt = (pte_t*)(pd[pd_idx] & ~0xFFFULL);
pt[pt_idx] = (phys & ~0xFFFULL) | flags | PAGE_PRESENT;
paging_flush_tlb_single(virt);
}
void paging_unmap_page(uint64_t virt) {
size_t pml4_idx = (virt >> 39) & 0x1FF;
size_t pdpt_idx = (virt >> 30) & 0x1FF;
size_t pd_idx = (virt >> 21) & 0x1FF;
size_t pt_idx = (virt >> 12) & 0x1FF;
if (!(kernel_pml4[pml4_idx] & PAGE_PRESENT)) return;
pdpte_t* pdpt = (pdpte_t*)(kernel_pml4[pml4_idx] & ~0xFFFULL);
if (!(pdpt[pdpt_idx] & PAGE_PRESENT)) return;
pde_t* pd = (pde_t*)(pdpt[pdpt_idx] & ~0xFFFULL);
if (!(pd[pd_idx] & PAGE_PRESENT)) return;
pte_t* pt = (pte_t*)(pd[pd_idx] & ~0xFFFULL);
pt[pt_idx] = 0;
paging_flush_tlb_single(virt);
}
uint64_t paging_get_phys(uint64_t virt) {
size_t pml4_idx = (virt >> 39) & 0x1FF;
size_t pdpt_idx = (virt >> 30) & 0x1FF;
size_t pd_idx = (virt >> 21) & 0x1FF;
size_t pt_idx = (virt >> 12) & 0x1FF;
if (!(kernel_pml4[pml4_idx] & PAGE_PRESENT)) return 0;
pdpte_t* pdpt = (pdpte_t*)(kernel_pml4[pml4_idx] & ~0xFFFULL);
if (!(pdpt[pdpt_idx] & PAGE_PRESENT)) return 0;
pde_t* pd = (pde_t*)(pdpt[pdpt_idx] & ~0xFFFULL);
// Check for 2MB huge page
if (pd[pd_idx] & PAGE_HUGE) {
return (pd[pd_idx] & ~0x1FFFFFULL) | (virt & 0x1FFFFF);
}
if (!(pd[pd_idx] & PAGE_PRESENT)) return 0;
pte_t* pt = (pte_t*)(pd[pd_idx] & ~0xFFFULL);
if (!(pt[pt_idx] & PAGE_PRESENT)) return 0;
return (pt[pt_idx] & ~0xFFFULL) | (virt & 0xFFF);
}
+98
View File
@@ -0,0 +1,98 @@
BITS 16
ORG 0x7C00
start:
; Set up segments and stack
cli
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7C00
sti
; Save boot drive number from BIOS (DL)
mov [BOOT_DRIVE], dl
; Print greeting
mov si, MSG_BOOT
call print_string
; Check for LBA extensions (INT 13h, AH=41h)
mov ah, 0x41
mov bx, 0x55AA
mov dl, [BOOT_DRIVE]
int 0x13
jc load_chs
cmp bx, 0xAA55
jne load_chs
load_lba:
; Load stage 2 using LBA (INT 13h, AH=42h)
; Read 15 sectors starting from LBA 1 to 0x0000:0x7E00
mov ah, 0x42
mov dl, [BOOT_DRIVE]
mov si, dap
int 0x13
jc disk_error
jmp jump_stage2
load_chs:
; Fallback: Load stage 2 using CHS (INT 13h, AH=02h)
mov ah, 0x02
mov al, 15 ; 15 sectors (sectors 2-16)
mov ch, 0 ; Cylinder 0
mov dh, 0 ; Head 0
mov cl, 2 ; Sector 2
xor bx, bx
mov es, bx
mov bx, 0x7E00 ; ES:BX = 0x0000:0x7E00
mov dl, [BOOT_DRIVE]
int 0x13
jc disk_error
jump_stage2:
; Pass boot drive in DL to Stage 2
mov dl, [BOOT_DRIVE]
jmp 0x0000:0x7E00
disk_error:
mov si, MSG_DISK_ERR
call print_string
.halt:
cli
hlt
jmp .halt
; BIOS Teletype string print (SI = null-terminated string)
print_string:
pusha
mov ah, 0x0E
.loop:
lodsb
test al, al
jz .done
int 0x10
jmp .loop
.done:
popa
ret
; Data
BOOT_DRIVE db 0
MSG_BOOT db "SUB-OS Bootloader...", 13, 10, 0
MSG_DISK_ERR db "Boot Disk Error!", 13, 10, 0
; Disk Address Packet for LBA
align 4
dap:
db 0x10 ; DAP size (16 bytes)
db 0 ; Reserved
dw 15 ; Read 15 sectors
dw 0x7E00 ; Offset
dw 0x0000 ; Segment
dq 1 ; Starting LBA (Sector 1)
; Boot Sector Signature
times 510 - ($ - $$) db 0
dw 0xAA55
+43
View File
@@ -0,0 +1,43 @@
; Global Descriptor Table Definition
align 16
gdt_start:
; Null descriptor (0x00)
dq 0
; 32-bit Code Segment (0x08)
dw 0xFFFF ; Limit (low 16 bits)
dw 0x0000 ; Base (low 16 bits)
db 0x00 ; Base (next 8 bits)
db 10011010b ; Access byte (Present, Ring 0, Code/Data, Executable, Read/Write)
db 11001111b ; Flags (32-bit, 4KB granularity) and Limit (high 4 bits)
db 0x00 ; Base (high 8 bits)
; 32-bit Data Segment (0x10)
dw 0xFFFF ; Limit
dw 0x0000 ; Base
db 0x00 ; Base
db 10010010b ; Access byte (Present, Ring 0, Code/Data, Read/Write)
db 11001111b ; Flags and Limit
db 0x00 ; Base
; 64-bit Code Segment (0x18)
dw 0x0000 ; Limit (ignored)
dw 0x0000 ; Base
db 0x00 ; Base
db 10011010b ; Access byte (Present, Ring 0, Code/Data, Executable, Read/Write)
db 00100000b ; Flags (64-bit code segment, Long Mode) and Limit
db 0x00 ; Base
; 64-bit Data Segment (0x20)
dw 0x0000 ; Limit (ignored)
dw 0x0000 ; Base
db 0x00 ; Base
db 10010010b ; Access byte (Present, Ring 0, Code/Data, Read/Write)
db 00000000b ; Flags and Limit
db 0x00 ; Base
gdt_end:
gdt_descriptor:
dw gdt_end - gdt_start - 1 ; Size of GDT minus 1
dd gdt_start ; Base address of GDT
+272
View File
@@ -0,0 +1,272 @@
BITS 16
ORG 0x7E00
start2:
cli
; Ensure segment registers are zero
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7C00
sti
; Save boot drive number passed from stage 1 in DL
mov [boot_drive], dl
; Print Stage 2 startup message
mov si, msg_stage2_start
call print_string_16
; -------------------------------------------------------------
; Step 1: Enable A20 Line
; -------------------------------------------------------------
mov si, msg_a20
call print_string_16
in al, 0x92
test al, 2
jnz .a20_done
or al, 2
and al, 0xFE
out 0x92, al
.a20_done:
; -------------------------------------------------------------
; Step 2: Detect Memory via INT 15h, EAX=0xE820
; Destination: 0x9000 (count at 0x9000, entries at 0x9008)
; -------------------------------------------------------------
mov si, msg_mmap
call print_string_16
; Zero out count at 0x9000
mov dword [0x9000], 0
mov dword [0x9004], 0
mov di, 0x9008 ; Memory map entries destination
xor ebx, ebx ; Continuation value
xor bp, bp ; Entry counter
mov edx, 0x534D4150 ; 'SMAP' signature
mov eax, 0xE820
mov ecx, 24 ; Buffer size
int 0x15
jc .mmap_error
.mmap_loop:
inc bp
add di, 24
test ebx, ebx
jz .mmap_finished
mov edx, 0x534D4150
mov eax, 0xE820
mov ecx, 24
int 0x15
jc .mmap_finished
jmp .mmap_loop
.mmap_error:
; If E820 failed, create 1 fallback entry (128MB usable)
mov dword [0x9000], 1
mov dword [0x9004], 0
mov dword [0x9008], 0x100000 ; base = 1MB
mov dword [0x900C], 0
mov dword [0x9010], 0x07F00000 ; length = 127MB
mov dword [0x9014], 0
mov dword [0x9018], 1 ; type = 1 (USABLE)
mov dword [0x901C], 1
jmp .mmap_store_done
.mmap_finished:
mov word [0x9000], bp
mov word [0x9002], 0
mov dword [0x9004], 0
.mmap_store_done:
; -------------------------------------------------------------
; Step 3: Load Kernel from Disk to 0x10000 (Conventional RAM)
; 4 chunks x 64 sectors = 256 sectors (128 KB)
; -------------------------------------------------------------
mov si, msg_kernel_load
call print_string_16
mov word [kernel_dap_off], 0x0000
mov word [kernel_dap_seg], 0x1000
mov dword [kernel_dap_lba], 16
mov dword [kernel_dap_lba + 4], 0
mov cx, 4 ; 4 chunks * 64 sectors = 256 sectors (128 KB)
.kernel_chunk_loop:
push cx
mov ah, 0x42
mov dl, [boot_drive]
mov si, kernel_dap
int 0x13
jc .kernel_disk_error
; Advance LBA by 64 sectors
add dword [kernel_dap_lba], 64
; Advance Segment by 0x800 (64 sectors * 512 bytes = 32768 bytes = 0x800 paragraphs)
add word [kernel_dap_seg], 0x0800
pop cx
loop .kernel_chunk_loop
.kernel_loaded_ok:
; -------------------------------------------------------------
; Step 4: Set up Identity Paging for Long Mode (All 4 GB)
; -------------------------------------------------------------
; Clear 24 KB for 6 page tables (0x1000 - 0x6FFF)
mov ax, 0x0000
mov es, ax
mov di, 0x1000
mov cx, 6144
xor eax, eax
rep stosd
; PML4[0] -> PDPT at 0x2000
mov dword [0x1000], 0x2003
mov dword [0x1004], 0
; PDPT -> 4 PDs
mov dword [0x2000], 0x3003
mov dword [0x2004], 0
mov dword [0x2008], 0x4003
mov dword [0x200C], 0
mov dword [0x2010], 0x5003
mov dword [0x2014], 0
mov dword [0x2018], 0x6003
mov dword [0x201C], 0
; Map 4GB (2048 x 2MB pages)
mov di, 0x3000
mov eax, 0x00000083
mov cx, 2048
.map_4gb_loop:
mov [di], eax
mov dword [di + 4], 0
add eax, 0x200000
add di, 8
loop .map_4gb_loop
; -------------------------------------------------------------
; Step 5: Switch to 32-bit Protected Mode
; -------------------------------------------------------------
mov si, msg_entering_pm
call print_string_16
cli
lgdt [gdt_descriptor]
mov eax, cr0
or eax, 1
mov cr0, eax
jmp 0x08:pm_entry
.kernel_disk_error:
mov si, msg_kernel_err
call print_string_16
.halt16:
cli
hlt
jmp .halt16
print_string_16:
pusha
mov ah, 0x0E
.p_loop:
lodsb
test al, al
jz .p_done
int 0x10
jmp .p_loop
.p_done:
popa
ret
; -----------------------------------------------------------------
; 32-Bit Protected Mode Entry Point
; -----------------------------------------------------------------
BITS 32
pm_entry:
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov esp, 0x7C00
; Copy kernel from 0x10000 to 0x100000 (1MB mark) - 256 KB (512 sectors)
mov esi, 0x10000
mov edi, 0x100000
mov ecx, (512 * 512) / 4
rep movsd
; Enable PAE in CR4
mov eax, cr4
or eax, (1 << 5)
mov cr4, eax
; Load CR3
mov eax, 0x1000
mov cr3, eax
; Enable Long Mode in EFER MSR
mov ecx, 0xC0000080
rdmsr
or eax, (1 << 8)
wrmsr
; Enable Paging and Protected Mode
mov eax, cr0
or eax, (1 << 31) | (1 << 0)
mov cr0, eax
jmp 0x18:lm_entry
; -----------------------------------------------------------------
; 64-Bit Long Mode Entry Point
; -----------------------------------------------------------------
BITS 64
lm_entry:
mov ax, 0x20
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
; Arguments: RDI = 0x9008 (entries), RSI = count at 0x9000
mov rdi, 0x9008
mov rsi, [0x9000]
mov rax, 0x100000
jmp rax
; -----------------------------------------------------------------
; Data Section
; -----------------------------------------------------------------
BITS 16
align 4
boot_drive: db 0
msg_stage2_start: db "Stage 2: Loaded", 13, 10, 0
msg_a20: db "Stage 2: A20 enabled", 13, 10, 0
msg_mmap: db "Stage 2: Memory map detected", 13, 10, 0
msg_kernel_load: db "Stage 2: Loading kernel...", 13, 10, 0
msg_entering_pm: db "Stage 2: Jumping to 64-bit mode...", 13, 10, 0
msg_kernel_err: db "Stage 2: Kernel Disk Read Error!", 13, 10, 0
align 4
kernel_dap:
db 0x10
db 0
dw 64 ; 64 sectors per chunk (32 KB)
kernel_dap_off:
dw 0x0000
kernel_dap_seg:
dw 0x1000
kernel_dap_lba:
dq 16
%include "gdt.asm"
+35
View File
@@ -0,0 +1,35 @@
#include <crypto/crypto.h>
static uint32_t crc32_table[256];
static bool table_computed = false;
static void make_crc32_table(void) {
uint32_t c;
for (uint32_t n = 0; n < 256; n++) {
c = n;
for (int k = 0; k < 8; k++) {
if (c & 1) {
c = 0xEDB88320L ^ (c >> 1);
} else {
c = c >> 1;
}
}
crc32_table[n] = c;
}
table_computed = true;
}
uint32_t crc32(uint32_t crc, const void* buf, size_t size) {
if (!table_computed) {
make_crc32_table();
}
const uint8_t* p = (const uint8_t*)buf;
crc = crc ^ 0xFFFFFFFF;
while (size--) {
crc = crc32_table[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
}
return crc ^ 0xFFFFFFFF;
}
+186
View File
@@ -0,0 +1,186 @@
#include <crypto/crypto.h>
#include <lib/string.h>
#include <lib/printf.h>
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
#define FF(a, b, c, d, x, s, ac) { \
(a) += F((b), (c), (d)) + (x) + (uint32_t)(ac); \
(a) = ROTATE_LEFT((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G((b), (c), (d)) + (x) + (uint32_t)(ac); \
(a) = ROTATE_LEFT((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H((b), (c), (d)) + (x) + (uint32_t)(ac); \
(a) = ROTATE_LEFT((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I((b), (c), (d)) + (x) + (uint32_t)(ac); \
(a) = ROTATE_LEFT((a), (s)); \
(a) += (b); \
}
static void md5_transform(uint32_t state[4], const uint8_t block[64]) {
uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
for (int i = 0, j = 0; j < 64; i++, j += 4) {
x[i] = ((uint32_t)block[j]) | (((uint32_t)block[j + 1]) << 8) |
(((uint32_t)block[j + 2]) << 16) | (((uint32_t)block[j + 3]) << 24);
}
// Round 1
FF(a, b, c, d, x[0], 7, 0xd76aa478);
FF(d, a, b, c, x[1], 12, 0xe8c7b756);
FF(c, d, a, b, x[2], 17, 0x242070db);
FF(b, c, d, a, x[3], 22, 0xc1bdceee);
FF(a, b, c, d, x[4], 7, 0xf57c0faf);
FF(d, a, b, c, x[5], 12, 0x4787c62a);
FF(c, d, a, b, x[6], 17, 0xa8304613);
FF(b, c, d, a, x[7], 22, 0xfd469501);
FF(a, b, c, d, x[8], 7, 0x698098d8);
FF(d, a, b, c, x[9], 12, 0x8b44f7af);
FF(c, d, a, b, x[10], 17, 0xffff5bb1);
FF(b, c, d, a, x[11], 22, 0x895cd7be);
FF(a, b, c, d, x[12], 7, 0x6b901122);
FF(d, a, b, c, x[13], 12, 0xfd987193);
FF(c, d, a, b, x[14], 17, 0xa679438e);
FF(b, c, d, a, x[15], 22, 0x49b40821);
// Round 2
GG(a, b, c, d, x[1], 5, 0xf61e2562);
GG(d, a, b, c, x[6], 9, 0xc040b340);
GG(c, d, a, b, x[11], 14, 0x265e5a51);
GG(b, c, d, a, x[0], 20, 0xe9b6c7aa);
GG(a, b, c, d, x[5], 5, 0xd62f105d);
GG(d, a, b, c, x[10], 9, 0x02441453);
GG(c, d, a, b, x[15], 14, 0xd8a1e681);
GG(b, c, d, a, x[4], 20, 0xe7d3fbc8);
GG(a, b, c, d, x[9], 5, 0x21e1cde6);
GG(d, a, b, c, x[14], 9, 0xc33707d6);
GG(c, d, a, b, x[3], 14, 0xf4d50d87);
GG(b, c, d, a, x[8], 20, 0x455a14ed);
GG(a, b, c, d, x[13], 5, 0xa9e3e905);
GG(d, a, b, c, x[2], 9, 0xfcefa3f8);
GG(c, d, a, b, x[7], 14, 0x676f02d9);
GG(b, c, d, a, x[12], 20, 0x8d2a4c8a);
// Round 3
HH(a, b, c, d, x[5], 4, 0xfffa3942);
HH(d, a, b, c, x[8], 11, 0x8771f681);
HH(c, d, a, b, x[11], 16, 0x6d9d6122);
HH(b, c, d, a, x[14], 23, 0xfde5380c);
HH(a, b, c, d, x[1], 4, 0xa4beea44);
HH(d, a, b, c, x[4], 11, 0x4bdecfa9);
HH(c, d, a, b, x[7], 16, 0xf6bb4b60);
HH(b, c, d, a, x[10], 23, 0xbebfbc70);
HH(a, b, c, d, x[13], 4, 0x289b7ec6);
HH(d, a, b, c, x[0], 11, 0xeaa127fa);
HH(c, d, a, b, x[3], 16, 0xd4ef3085);
HH(b, c, d, a, x[6], 23, 0x04881d05);
HH(a, b, c, d, x[9], 4, 0xd9d4d039);
HH(d, a, b, c, x[12], 11, 0xe6db99e5);
HH(c, d, a, b, x[15], 16, 0x1fa27cf8);
HH(b, c, d, a, x[2], 23, 0xc4ac5665);
// Round 4
II(a, b, c, d, x[0], 6, 0xf4292244);
II(d, a, b, c, x[7], 10, 0x432aff97);
II(c, d, a, b, x[14], 15, 0xab9423a7);
II(b, c, d, a, x[5], 21, 0xfc93a039);
II(a, b, c, d, x[12], 6, 0x655b59c3);
II(d, a, b, c, x[3], 10, 0x8f0ccc92);
II(c, d, a, b, x[10], 15, 0xffeff47d);
II(b, c, d, a, x[1], 21, 0x85845dd1);
II(a, b, c, d, x[8], 6, 0x6fa87e4f);
II(d, a, b, c, x[15], 10, 0xfe2ce6e0);
II(c, d, a, b, x[6], 15, 0xa3014314);
II(b, c, d, a, x[13], 21, 0x4e0811a1);
II(a, b, c, d, x[4], 6, 0xf7537e82);
II(d, a, b, c, x[11], 10, 0xbd3af235);
II(c, d, a, b, x[2], 15, 0x2ad7d2bb);
II(b, c, d, a, x[9], 21, 0xeb86d391);
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
}
void md5_init(md5_ctx_t* ctx) {
ctx->count[0] = ctx->count[1] = 0;
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xefcdab89;
ctx->state[2] = 0x98badcfe;
ctx->state[3] = 0x10325476;
}
void md5_update(md5_ctx_t* ctx, const void* input, size_t input_len) {
uint32_t i, index, part_len;
const uint8_t* buf = (const uint8_t*)input;
index = (uint32_t)((ctx->count[0] >> 3) & 0x3F);
if ((ctx->count[0] += ((uint32_t)input_len << 3)) < ((uint32_t)input_len << 3)) {
ctx->count[1]++;
}
ctx->count[1] += ((uint32_t)input_len >> 29);
part_len = 64 - index;
if (input_len >= part_len) {
memcpy(&ctx->buffer[index], buf, part_len);
md5_transform(ctx->state, ctx->buffer);
for (i = part_len; i + 63 < input_len; i += 64) {
md5_transform(ctx->state, &buf[i]);
}
index = 0;
} else {
i = 0;
}
memcpy(&ctx->buffer[index], &buf[i], input_len - i);
}
void md5_final(uint8_t digest[16], md5_ctx_t* ctx) {
static const uint8_t PADDING[64] = { 0x80 };
uint8_t bits[8];
uint32_t index, pad_len;
for (int i = 0; i < 4; i++) {
bits[i] = (uint8_t)((ctx->count[0] >> (i * 8)) & 0xFF);
bits[i + 4] = (uint8_t)((ctx->count[1] >> (i * 8)) & 0xFF);
}
index = (uint32_t)((ctx->count[0] >> 3) & 0x3F);
pad_len = (index < 56) ? (56 - index) : (120 - index);
md5_update(ctx, PADDING, pad_len);
md5_update(ctx, bits, 8);
for (int i = 0; i < 4; i++) {
digest[i] = (uint8_t)((ctx->state[0] >> (i * 8)) & 0xFF);
digest[i + 4] = (uint8_t)((ctx->state[1] >> (i * 8)) & 0xFF);
digest[i + 8] = (uint8_t)((ctx->state[2] >> (i * 8)) & 0xFF);
digest[i + 12] = (uint8_t)((ctx->state[3] >> (i * 8)) & 0xFF);
}
}
void md5_string(const char* str, char output[33]) {
md5_ctx_t ctx;
uint8_t digest[16];
md5_init(&ctx);
md5_update(&ctx, str, strlen(str));
md5_final(digest, &ctx);
for (int i = 0; i < 16; i++) {
sprintf(output + i * 2, "%02x", digest[i]);
}
output[32] = '\0';
}
+43
View File
@@ -0,0 +1,43 @@
#include <crypto/crypto.h>
#include <arch/x86_64/pit.h>
static uint64_t prng_s[2] = { 0x8a5cd789635d2dffULL, 0x121fd2155c472f96ULL };
void prng_seed(uint64_t seed1, uint64_t seed2) {
if (seed1 == 0 && seed2 == 0) {
seed1 = 0x8a5cd789635d2dffULL ^ pit_get_ticks();
seed2 = 0x121fd2155c472f96ULL ^ (pit_get_ticks() << 32);
}
prng_s[0] = seed1;
prng_s[1] = seed2;
}
uint64_t prng_rand64(void) {
uint64_t s1 = prng_s[0];
const uint64_t s0 = prng_s[1];
prng_s[0] = s0;
s1 ^= s1 << 23;
prng_s[1] = s1 ^ s0 ^ (s1 >> 17) ^ (s0 >> 26);
return prng_s[1] + s0;
}
uint32_t prng_rand32(void) {
return (uint32_t)(prng_rand64() & 0xFFFFFFFF);
}
void prng_get_bytes(void* buf, size_t len) {
uint8_t* p = (uint8_t*)buf;
while (len >= 8) {
uint64_t r = prng_rand64();
*(uint64_t*)p = r;
p += 8;
len -= 8;
}
if (len > 0) {
uint64_t r = prng_rand64();
uint8_t* r_bytes = (uint8_t*)&r;
for (size_t i = 0; i < len; i++) {
p[i] = r_bytes[i];
}
}
}
+141
View File
@@ -0,0 +1,141 @@
#include <crypto/crypto.h>
#include <lib/string.h>
#include <lib/printf.h>
#define DBL_INT_ADD(a, b, c) if ((a) > 0xFFFFFFFF - (c)) ++(b); (a) += (c);
#define ROTRIGHT(a, b) (((a) >> (b)) | ((a) << (32 - (b))))
#define CH(x, y, z) (((x) & (y)) ^ (~(x) & (z)))
#define MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
#define EP0(x) (ROTRIGHT(x, 2) ^ ROTRIGHT(x, 13) ^ ROTRIGHT(x, 22))
#define EP1(x) (ROTRIGHT(x, 6) ^ ROTRIGHT(x, 11) ^ ROTRIGHT(x, 25))
#define SIG0(x) (ROTRIGHT(x, 7) ^ ROTRIGHT(x, 18) ^ ((x) >> 3))
#define SIG1(x) (ROTRIGHT(x, 17) ^ ROTRIGHT(x, 19) ^ ((x) >> 10))
static const uint32_t k[64] = {
0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
};
static void sha256_transform(sha256_ctx_t* ctx, const uint8_t data[]) {
uint32_t a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
for (i = 0, j = 0; i < 16; ++i, j += 4)
m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]);
for (; i < 64; ++i)
m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
a = ctx->state[0];
b = ctx->state[1];
c = ctx->state[2];
d = ctx->state[3];
e = ctx->state[4];
f = ctx->state[5];
g = ctx->state[6];
h = ctx->state[7];
for (i = 0; i < 64; ++i) {
t1 = h + EP1(e) + CH(e, f, g) + k[i] + m[i];
t2 = EP0(a) + MAJ(a, b, c);
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
}
ctx->state[0] += a;
ctx->state[1] += b;
ctx->state[2] += c;
ctx->state[3] += d;
ctx->state[4] += e;
ctx->state[5] += f;
ctx->state[6] += g;
ctx->state[7] += h;
}
void sha256_init(sha256_ctx_t* ctx) {
ctx->datalen = 0;
ctx->bitlen = 0;
ctx->state[0] = 0x6a09e667;
ctx->state[1] = 0xbb67ae85;
ctx->state[2] = 0x3c6ef372;
ctx->state[3] = 0xa54ff53a;
ctx->state[4] = 0x510e527f;
ctx->state[5] = 0x9b05688c;
ctx->state[6] = 0x1f83d9ab;
ctx->state[7] = 0x5be0cd19;
}
void sha256_update(sha256_ctx_t* ctx, const void* data, size_t len) {
const uint8_t* p = (const uint8_t*)data;
for (size_t i = 0; i < len; ++i) {
ctx->buffer[ctx->datalen] = p[i];
ctx->datalen++;
if (ctx->datalen == 64) {
sha256_transform(ctx, ctx->buffer);
ctx->bitlen += 512;
ctx->datalen = 0;
}
}
}
void sha256_final(uint8_t hash[32], sha256_ctx_t* ctx) {
size_t i = ctx->datalen;
if (ctx->datalen < 56) {
ctx->buffer[i++] = 0x80;
while (i < 56)
ctx->buffer[i++] = 0x00;
} else {
ctx->buffer[i++] = 0x80;
while (i < 64)
ctx->buffer[i++] = 0x00;
sha256_transform(ctx, ctx->buffer);
memset(ctx->buffer, 0, 56);
}
ctx->bitlen += ctx->datalen * 8;
ctx->buffer[63] = (uint8_t)(ctx->bitlen);
ctx->buffer[62] = (uint8_t)(ctx->bitlen >> 8);
ctx->buffer[61] = (uint8_t)(ctx->bitlen >> 16);
ctx->buffer[60] = (uint8_t)(ctx->bitlen >> 24);
ctx->buffer[59] = (uint8_t)(ctx->bitlen >> 32);
ctx->buffer[58] = (uint8_t)(ctx->bitlen >> 40);
ctx->buffer[57] = (uint8_t)(ctx->bitlen >> 48);
ctx->buffer[56] = (uint8_t)(ctx->bitlen >> 56);
sha256_transform(ctx, ctx->buffer);
for (i = 0; i < 4; ++i) {
hash[i] = (uint8_t)((ctx->state[0] >> (24 - i * 8)) & 0x000000ff);
hash[i + 4] = (uint8_t)((ctx->state[1] >> (24 - i * 8)) & 0x000000ff);
hash[i + 8] = (uint8_t)((ctx->state[2] >> (24 - i * 8)) & 0x000000ff);
hash[i + 12] = (uint8_t)((ctx->state[3] >> (24 - i * 8)) & 0x000000ff);
hash[i + 16] = (uint8_t)((ctx->state[4] >> (24 - i * 8)) & 0x000000ff);
hash[i + 20] = (uint8_t)((ctx->state[5] >> (24 - i * 8)) & 0x000000ff);
hash[i + 24] = (uint8_t)((ctx->state[6] >> (24 - i * 8)) & 0x000000ff);
hash[i + 28] = (uint8_t)((ctx->state[7] >> (24 - i * 8)) & 0x000000ff);
}
}
void sha256_string(const char* str, char output[65]) {
sha256_ctx_t ctx;
uint8_t hash[32];
sha256_init(&ctx);
sha256_update(&ctx, str, strlen(str));
sha256_final(hash, &ctx);
for (int i = 0; i < 32; i++) {
sprintf(output + i * 2, "%02x", hash[i]);
}
output[64] = '\0';
}
+135
View File
@@ -0,0 +1,135 @@
#include <drivers/ata.h>
#include <arch/x86_64/io.h>
#include <kernel/printk.h>
#include <lib/string.h>
static ata_device_t primary_master;
static void ata_wait_ready(uint16_t io_base) {
// 400ns delay
inb(io_base + 7);
inb(io_base + 7);
inb(io_base + 7);
inb(io_base + 7);
while (inb(io_base + 7) & 0x80); // Wait while BSY (Busy) bit is set
}
static void ata_wait_drq(uint16_t io_base) {
while (!(inb(io_base + 7) & 0x08)); // Wait while DRQ (Data Request) bit is clear
}
bool ata_init(void) {
memset(&primary_master, 0, sizeof(ata_device_t));
// Select Primary Master (Drive 0, LBA mode)
outb(ATA_PRIMARY_IO + 6, 0xA0);
outb(ATA_PRIMARY_IO + 2, 0);
outb(ATA_PRIMARY_IO + 3, 0);
outb(ATA_PRIMARY_IO + 4, 0);
outb(ATA_PRIMARY_IO + 5, 0);
outb(ATA_PRIMARY_IO + 7, 0xEC); // IDENTIFY Command
uint8_t status = inb(ATA_PRIMARY_IO + 7);
if (status == 0 || status == 0xFF) {
return false; // No drive
}
ata_wait_ready(ATA_PRIMARY_IO);
uint8_t mid = inb(ATA_PRIMARY_IO + 4);
uint8_t hi = inb(ATA_PRIMARY_IO + 5);
if (mid != 0 || hi != 0) {
return false; // ATAPI or not ATA
}
ata_wait_drq(ATA_PRIMARY_IO);
uint16_t identify_data[256];
for (int i = 0; i < 256; i++) {
identify_data[i] = inw(ATA_PRIMARY_IO);
}
primary_master.present = true;
primary_master.is_master = true;
primary_master.sector_count = (uint32_t)identify_data[60] | ((uint32_t)identify_data[61] << 16);
// Model String (Words 27-46, byte-swapped)
char* model_ptr = (char*)&identify_data[27];
for (int i = 0; i < 40; i += 2) {
primary_master.model[i] = model_ptr[i + 1];
primary_master.model[i + 1] = model_ptr[i];
}
primary_master.model[40] = '\0';
// Trim trailing spaces in model
for (int i = 39; i >= 0 && primary_master.model[i] == ' '; i--) {
primary_master.model[i] = '\0';
}
printk(KERN_INFO "ATA: Primary Master Disk: %s (%llu MB, %u sectors)\n",
primary_master.model,
((uint64_t)primary_master.sector_count * 512) / (1024 * 1024),
primary_master.sector_count);
return true;
}
bool ata_read_sectors(uint32_t lba, uint8_t count, void* buffer) {
if (!primary_master.present || !buffer || count == 0) return false;
ata_wait_ready(ATA_PRIMARY_IO);
outb(ATA_PRIMARY_IO + 6, 0xE0 | ((lba >> 24) & 0x0F)); // Master, LBA mode
outb(ATA_PRIMARY_IO + 2, count);
outb(ATA_PRIMARY_IO + 3, (uint8_t)lba);
outb(ATA_PRIMARY_IO + 4, (uint8_t)(lba >> 8));
outb(ATA_PRIMARY_IO + 5, (uint8_t)(lba >> 16));
outb(ATA_PRIMARY_IO + 7, 0x20); // READ SECTORS command
uint16_t* ptr = (uint16_t*)buffer;
for (uint8_t s = 0; s < count; s++) {
ata_wait_ready(ATA_PRIMARY_IO);
ata_wait_drq(ATA_PRIMARY_IO);
for (int i = 0; i < 256; i++) {
*ptr++ = inw(ATA_PRIMARY_IO);
}
}
return true;
}
bool ata_write_sectors(uint32_t lba, uint8_t count, const void* buffer) {
if (!primary_master.present || !buffer || count == 0) return false;
ata_wait_ready(ATA_PRIMARY_IO);
outb(ATA_PRIMARY_IO + 6, 0xE0 | ((lba >> 24) & 0x0F));
outb(ATA_PRIMARY_IO + 2, count);
outb(ATA_PRIMARY_IO + 3, (uint8_t)lba);
outb(ATA_PRIMARY_IO + 4, (uint8_t)(lba >> 8));
outb(ATA_PRIMARY_IO + 5, (uint8_t)(lba >> 16));
outb(ATA_PRIMARY_IO + 7, 0x30); // WRITE SECTORS command
const uint16_t* ptr = (const uint16_t*)buffer;
for (uint8_t s = 0; s < count; s++) {
ata_wait_ready(ATA_PRIMARY_IO);
ata_wait_drq(ATA_PRIMARY_IO);
for (int i = 0; i < 256; i++) {
outw(ATA_PRIMARY_IO, *ptr++);
}
}
// Flush Cache
outb(ATA_PRIMARY_IO + 7, 0xE7);
ata_wait_ready(ATA_PRIMARY_IO);
return true;
}
const ata_device_t* ata_get_primary_master(void) {
return &primary_master;
}
+139
View File
@@ -0,0 +1,139 @@
#include <drivers/keyboard.h>
#include <drivers/tty.h>
#include <arch/x86_64/isr.h>
#include <arch/x86_64/pic.h>
#include <arch/x86_64/io.h>
#define KEYBOARD_DATA_PORT 0x60
#define KEYBOARD_STATUS_PORT 0x64
#define KEYBOARD_BUFFER_SIZE 128
static volatile uint16_t key_buffer[KEYBOARD_BUFFER_SIZE];
static volatile int buffer_head = 0;
static volatile int buffer_tail = 0;
static bool shift_pressed = false;
static bool ctrl_pressed = false;
static bool alt_pressed = false;
static bool capslock = false;
static bool extended_code = false;
static const char scancode_ascii[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, ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static const char scancode_ascii_shift[128] = {
0, 27, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\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, ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static void buffer_enqueue(uint16_t key) {
int next = (buffer_head + 1) % KEYBOARD_BUFFER_SIZE;
if (next != buffer_tail) {
key_buffer[buffer_head] = key;
buffer_head = next;
}
}
static void keyboard_interrupt_handler(registers_t* regs) {
(void)regs;
uint8_t scancode = inb(KEYBOARD_DATA_PORT);
if (scancode == 0xE0) {
extended_code = true;
return;
}
if (scancode & 0x80) { // Key Release
uint8_t released = scancode & 0x7F;
if (released == 0x2A || released == 0x36) shift_pressed = false;
else if (released == 0x1D) ctrl_pressed = false;
else if (released == 0x38) alt_pressed = false;
extended_code = false;
return;
}
// Key Press
if (scancode == 0x2A || scancode == 0x36) { shift_pressed = true; return; }
if (scancode == 0x1D) { ctrl_pressed = true; return; }
if (scancode == 0x38) { alt_pressed = true; return; }
if (scancode == 0x3A) { capslock = !capslock; return; }
// Alt + F1..F4 -> Switch Virtual Consoles
if (alt_pressed) {
if (scancode >= 0x3B && scancode <= 0x3E) { // F1 - F4
tty_switch(scancode - 0x3B);
return;
}
}
if (extended_code) {
extended_code = false;
switch (scancode) {
case 0x48: buffer_enqueue(KEY_UP); return;
case 0x50: buffer_enqueue(KEY_DOWN); return;
case 0x4B: buffer_enqueue(KEY_LEFT); return;
case 0x4D: buffer_enqueue(KEY_RIGHT); return;
case 0x47: buffer_enqueue(KEY_HOME); return;
case 0x4F: buffer_enqueue(KEY_END); return;
case 0x49: buffer_enqueue(KEY_PAGE_UP); return;
case 0x51: buffer_enqueue(KEY_PAGE_DOWN); return;
case 0x52: buffer_enqueue(KEY_INSERT); return;
case 0x53: buffer_enqueue(KEY_DELETE); return;
}
}
// Function Keys F1-F12
if (scancode >= 0x3B && scancode <= 0x44) {
buffer_enqueue(KEY_F1 + (scancode - 0x3B));
return;
}
if (ctrl_pressed) {
if (scancode == 0x2E) { buffer_enqueue(0x03); return; } // Ctrl+C
if (scancode == 0x26) { buffer_enqueue(0x0C); return; } // Ctrl+L
if (scancode == 0x20) { buffer_enqueue(0x04); return; } // Ctrl+D
}
bool use_shift = shift_pressed ^ capslock;
char c = use_shift ? scancode_ascii_shift[scancode] : scancode_ascii[scancode];
if (c) {
buffer_enqueue((uint16_t)c);
}
}
void keyboard_init(void) {
buffer_head = 0;
buffer_tail = 0;
isr_register_handler(33, keyboard_interrupt_handler); // IRQ1
pic_clear_mask(1);
}
bool keyboard_has_key(void) {
return buffer_head != buffer_tail;
}
uint16_t keyboard_get_key(void) {
while (!keyboard_has_key()) {
hlt();
}
uint16_t key = key_buffer[buffer_tail];
buffer_tail = (buffer_tail + 1) % KEYBOARD_BUFFER_SIZE;
return key;
}
char keyboard_get_char(void) {
uint16_t key = keyboard_get_key();
if (key & KEY_SPECIAL_FLAG) return 0;
return (char)(key & 0xFF);
}
+39
View File
@@ -0,0 +1,39 @@
#include <drivers/serial.h>
#include <arch/x86_64/io.h>
void serial_init(void) {
outb(COM1_PORT + 1, 0x00); // Disable all interrupts
outb(COM1_PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
outb(COM1_PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud
outb(COM1_PORT + 1, 0x00); // (hi byte)
outb(COM1_PORT + 3, 0x03); // 8 bits, no parity, one stop bit
outb(COM1_PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
outb(COM1_PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
}
static bool serial_is_transmit_empty(void) {
return (inb(COM1_PORT + 5) & 0x20) != 0;
}
void serial_write_char(char c) {
while (!serial_is_transmit_empty());
outb(COM1_PORT, c);
}
void serial_write_string(const char* str) {
while (*str) {
if (*str == '\n') {
serial_write_char('\r');
}
serial_write_char(*str++);
}
}
bool serial_received(void) {
return (inb(COM1_PORT + 5) & 1) != 0;
}
char serial_read_char(void) {
while (!serial_received());
return inb(COM1_PORT);
}
+166
View File
@@ -0,0 +1,166 @@
#include <drivers/tty.h>
#include <drivers/vga.h>
#include <lib/string.h>
typedef struct {
uint16_t buffer[TTY_HEIGHT][TTY_WIDTH];
int cursor_row;
int cursor_col;
uint8_t current_color;
} tty_t;
static tty_t ttys[MAX_TTYS];
static int current_tty = 0;
static volatile uint16_t* const VGA_MEM = (uint16_t*)VGA_MEMORY;
static void tty_render_current(void) {
tty_t* t = &ttys[current_tty];
for (int y = 0; y < TTY_HEIGHT; y++) {
for (int x = 0; x < TTY_WIDTH; x++) {
VGA_MEM[y * TTY_WIDTH + x] = t->buffer[y][x];
}
}
vga_set_cursor(t->cursor_row, t->cursor_col);
}
void tty_switch(int index) {
if (index < 0 || index >= MAX_TTYS) return;
current_tty = index;
tty_render_current();
}
int tty_get_current(void) {
return current_tty;
}
static void tty_scroll(tty_t* t) {
for (int y = 0; y < TTY_HEIGHT - 1; y++) {
for (int x = 0; x < TTY_WIDTH; x++) {
t->buffer[y][x] = t->buffer[y + 1][x];
}
}
for (int x = 0; x < TTY_WIDTH; x++) {
t->buffer[TTY_HEIGHT - 1][x] = vga_entry(' ', t->current_color);
}
t->cursor_row = TTY_HEIGHT - 1;
}
void tty_clear(void) {
tty_t* t = &ttys[current_tty];
for (int y = 0; y < TTY_HEIGHT; y++) {
for (int x = 0; x < TTY_WIDTH; x++) {
t->buffer[y][x] = vga_entry(' ', t->current_color);
}
}
t->cursor_row = 0;
t->cursor_col = 0;
tty_render_current();
}
void tty_set_cursor(int row, int col) {
tty_t* t = &ttys[current_tty];
t->cursor_row = row;
t->cursor_col = col;
vga_set_cursor(row, col);
}
void tty_write(const char* data, size_t size) {
tty_t* t = &ttys[current_tty];
for (size_t i = 0; i < size; i++) {
char c = data[i];
// Basic ANSI escape sequence parser (e.g. \033[31m)
if (c == '\033' && i + 1 < size && data[i + 1] == '[') {
i += 2;
int code = 0;
while (i < size && data[i] >= '0' && data[i] <= '9') {
code = code * 10 + (data[i] - '0');
i++;
}
if (i < size && data[i] == 'm') {
if (code == 0) t->current_color = 0x07; // Reset
else if (code == 31) t->current_color = 0x04; // Red
else if (code == 32) t->current_color = 0x02; // Green
else if (code == 33) t->current_color = 0x06; // Brown/Yellow
else if (code == 34) t->current_color = 0x01; // Blue
else if (code == 35) t->current_color = 0x05; // Magenta
else if (code == 36) t->current_color = 0x03; // Cyan
else if (code == 37) t->current_color = 0x07; // White
else if (code == 90) t->current_color = 0x08; // Bright Black (Dark Grey)
else if (code == 91) t->current_color = 0x0C; // Bright Red
else if (code == 92) t->current_color = 0x0A; // Bright Green
else if (code == 93) t->current_color = 0x0E; // Bright Yellow
else if (code == 94) t->current_color = 0x09; // Bright Blue
else if (code == 95) t->current_color = 0x0D; // Bright Magenta
else if (code == 96) t->current_color = 0x0B; // Bright Cyan
else if (code == 97) t->current_color = 0x0F; // Bright White
} else if (i < size && data[i] == 'K') {
// Clear from cursor to end of line
for (int x = t->cursor_col; x < TTY_WIDTH; x++) {
t->buffer[t->cursor_row][x] = vga_entry(' ', t->current_color);
}
} else if (i < size && data[i] == 'D') {
// Move cursor left
if (t->cursor_col > 0) t->cursor_col--;
} else if (i < size && data[i] == 'C') {
// Move cursor right
if (t->cursor_col < TTY_WIDTH - 1) t->cursor_col++;
}
continue;
}
if (c == '\n') {
t->cursor_col = 0;
if (++t->cursor_row >= TTY_HEIGHT) {
tty_scroll(t);
}
} else if (c == '\r') {
t->cursor_col = 0;
} else if (c == '\t') {
t->cursor_col = (t->cursor_col + 8) & ~7;
if (t->cursor_col >= TTY_WIDTH) {
t->cursor_col = 0;
if (++t->cursor_row >= TTY_HEIGHT) {
tty_scroll(t);
}
}
} else if (c == '\b') {
if (t->cursor_col > 0) {
t->cursor_col--;
t->buffer[t->cursor_row][t->cursor_col] = vga_entry(' ', t->current_color);
}
} else {
t->buffer[t->cursor_row][t->cursor_col] = vga_entry(c, t->current_color);
if (++t->cursor_col >= TTY_WIDTH) {
t->cursor_col = 0;
if (++t->cursor_row >= TTY_HEIGHT) {
tty_scroll(t);
}
}
}
}
tty_render_current();
}
void tty_write_string(const char* data) {
tty_write(data, strlen(data));
}
void tty_init(void) {
vga_init();
for (int i = 0; i < MAX_TTYS; i++) {
ttys[i].cursor_row = 0;
ttys[i].cursor_col = 0;
ttys[i].current_color = 0x07;
for (int y = 0; y < TTY_HEIGHT; y++) {
for (int x = 0; x < TTY_WIDTH; x++) {
ttys[i].buffer[y][x] = vga_entry(' ', 0x07);
}
}
}
current_tty = 0;
tty_render_current();
}
+106
View File
@@ -0,0 +1,106 @@
#include <drivers/vga.h>
#include <arch/x86_64/io.h>
#include <lib/string.h>
static volatile uint16_t* const VGA_BUFFER = (uint16_t*)VGA_MEMORY;
static uint8_t vga_color = 0x07;
static int vga_row = 0;
static int vga_col = 0;
void vga_set_cursor(int row, int col) {
vga_row = row;
vga_col = col;
uint16_t pos = row * VGA_WIDTH + col;
outb(0x3D4, 0x0F);
outb(0x3D5, (uint8_t)(pos & 0xFF));
outb(0x3D4, 0x0E);
outb(0x3D5, (uint8_t)((pos >> 8) & 0xFF));
}
void vga_get_cursor(int* row, int* col) {
if (row) *row = vga_row;
if (col) *col = vga_col;
}
void vga_enable_cursor(uint8_t cursor_start, uint8_t cursor_end) {
outb(0x3D4, 0x0A);
outb(0x3D5, (inb(0x3D5) & 0xC0) | cursor_start);
outb(0x3D4, 0x0B);
outb(0x3D5, (inb(0x3D5) & 0xE0) | cursor_end);
}
void vga_disable_cursor(void) {
outb(0x3D4, 0x0A);
outb(0x3D5, 0x20);
}
void vga_set_color(enum vga_color fg, enum vga_color bg) {
vga_color = vga_entry_color(fg, bg);
}
void vga_clear(void) {
for (int y = 0; y < VGA_HEIGHT; y++) {
for (int x = 0; x < VGA_WIDTH; x++) {
VGA_BUFFER[y * VGA_WIDTH + x] = vga_entry(' ', vga_color);
}
}
vga_set_cursor(0, 0);
}
static void vga_scroll(void) {
for (int y = 0; y < VGA_HEIGHT - 1; y++) {
for (int x = 0; x < VGA_WIDTH; x++) {
VGA_BUFFER[y * VGA_WIDTH + x] = VGA_BUFFER[(y + 1) * VGA_WIDTH + x];
}
}
for (int x = 0; x < VGA_WIDTH; x++) {
VGA_BUFFER[(VGA_HEIGHT - 1) * VGA_WIDTH + x] = vga_entry(' ', vga_color);
}
vga_row = VGA_HEIGHT - 1;
}
void vga_putc(char c) {
if (c == '\n') {
vga_col = 0;
if (++vga_row >= VGA_HEIGHT) {
vga_scroll();
}
} else if (c == '\r') {
vga_col = 0;
} else if (c == '\t') {
vga_col = (vga_col + 8) & ~7;
if (vga_col >= VGA_WIDTH) {
vga_col = 0;
if (++vga_row >= VGA_HEIGHT) {
vga_scroll();
}
}
} else if (c == '\b') {
if (vga_col > 0) {
vga_col--;
VGA_BUFFER[vga_row * VGA_WIDTH + vga_col] = vga_entry(' ', vga_color);
}
} else {
VGA_BUFFER[vga_row * VGA_WIDTH + vga_col] = vga_entry(c, vga_color);
if (++vga_col >= VGA_WIDTH) {
vga_col = 0;
if (++vga_row >= VGA_HEIGHT) {
vga_scroll();
}
}
}
vga_set_cursor(vga_row, vga_col);
}
void vga_write(const char* str) {
while (*str) {
vga_putc(*str++);
}
}
void vga_init(void) {
vga_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK);
vga_clear();
vga_enable_cursor(14, 15);
}
+252
View File
@@ -0,0 +1,252 @@
#include <drivers/e1000.h>
#include <drivers/pci.h>
#include <net/net.h>
#include <mm/kmalloc.h>
#include <mm/pmm.h>
#include <arch/x86_64/isr.h>
#include <arch/x86_64/pic.h>
#include <arch/x86_64/io.h>
#include <lib/string.h>
#include <kernel/printk.h>
#define REG_CTRL 0x0000
#define REG_STATUS 0x0008
#define REG_EEPROM 0x0014
#define REG_ICR 0x00C0
#define REG_IMS 0x00D0
#define REG_IMC 0x00D8
#define REG_RCTL 0x0100
#define REG_RDBAL 0x2800
#define REG_RDBAH 0x2804
#define REG_RDLEN 0x2808
#define REG_RDH 0x2810
#define REG_RDT 0x2818
#define REG_TCTL 0x0400
#define REG_TDBAL 0x3800
#define REG_TDBAH 0x3804
#define REG_TDLEN 0x3808
#define REG_TDH 0x3810
#define REG_TDT 0x3818
#define NUM_RX_DESCRIPTORS 32
#define NUM_TX_DESCRIPTORS 16
#define RX_BUFFER_SIZE 2048
typedef struct {
uint64_t buffer_addr;
uint16_t length;
uint16_t checksum;
uint8_t status;
uint8_t errors;
uint16_t special;
} __attribute__((packed)) e1000_rx_desc_t;
typedef struct {
uint64_t buffer_addr;
uint16_t length;
uint8_t cso;
uint8_t cmd;
uint8_t status;
uint8_t css;
uint16_t special;
} __attribute__((packed)) e1000_tx_desc_t;
static pci_device_t* e1000_pci_dev = NULL;
static uint64_t mmio_base = 0;
static uint16_t io_base = 0;
static bool use_mmio = true;
static uint8_t mac_addr[6] = {0x52, 0x54, 0x00, 0x12, 0x34, 0x56};
static e1000_rx_desc_t* rx_descriptors = NULL;
static uint8_t* rx_buffers[NUM_RX_DESCRIPTORS];
static uint16_t rx_cur = 0;
static e1000_tx_desc_t* tx_descriptors = NULL;
static uint8_t* tx_buffers[NUM_TX_DESCRIPTORS];
static uint16_t tx_cur = 0;
static uint64_t stats_rx_packets = 0;
static uint64_t stats_tx_packets = 0;
static uint64_t stats_rx_bytes = 0;
static uint64_t stats_tx_bytes = 0;
static inline void e1000_write32(uint32_t reg, uint32_t val) {
if (use_mmio && mmio_base) {
*((volatile uint32_t*)(mmio_base + reg)) = val;
} else if (io_base) {
outl(io_base, reg);
outl(io_base + 4, val);
}
}
static inline uint32_t e1000_read32(uint32_t reg) {
if (use_mmio && mmio_base) {
return *((volatile uint32_t*)(mmio_base + reg));
} else if (io_base) {
outl(io_base, reg);
return inl(io_base + 4);
}
return 0;
}
static void e1000_read_mac(void) {
uint32_t ral = e1000_read32(0x5400);
uint32_t rah = e1000_read32(0x5404);
if (ral != 0 || (rah & 0xFFFF) != 0) {
mac_addr[0] = ral & 0xFF;
mac_addr[1] = (ral >> 8) & 0xFF;
mac_addr[2] = (ral >> 16) & 0xFF;
mac_addr[3] = (ral >> 24) & 0xFF;
mac_addr[4] = rah & 0xFF;
mac_addr[5] = (rah >> 8) & 0xFF;
}
}
static void e1000_handle_receive(void) {
while (rx_descriptors[rx_cur].status & 0x01) {
uint16_t len = rx_descriptors[rx_cur].length;
uint8_t* buf = rx_buffers[rx_cur];
stats_rx_packets++;
stats_rx_bytes += len;
// Forward to network stack
net_receive(buf, len);
rx_descriptors[rx_cur].status = 0;
uint16_t old_cur = rx_cur;
rx_cur = (rx_cur + 1) % NUM_RX_DESCRIPTORS;
e1000_write32(REG_RDT, old_cur);
}
}
static void e1000_interrupt_handler(registers_t* regs) {
(void)regs;
uint32_t icr = e1000_read32(REG_ICR);
if (icr & 0x80) {
e1000_handle_receive();
}
if (icr & 0x04) {
printk(KERN_INFO "[E1000] Link status changed: %s\n", e1000_is_link_up() ? "UP" : "DOWN");
}
}
static void e1000_init_rx(void) {
rx_descriptors = (e1000_rx_desc_t*)kzalloc(sizeof(e1000_rx_desc_t) * NUM_RX_DESCRIPTORS + 16);
rx_descriptors = (e1000_rx_desc_t*)(((uint64_t)rx_descriptors + 15) & ~15);
for (int i = 0; i < NUM_RX_DESCRIPTORS; i++) {
rx_buffers[i] = (uint8_t*)kmalloc(RX_BUFFER_SIZE + 16);
rx_descriptors[i].buffer_addr = (uint64_t)rx_buffers[i];
rx_descriptors[i].status = 0;
}
uint64_t rx_desc_phys = (uint64_t)rx_descriptors;
e1000_write32(REG_RDBAL, (uint32_t)(rx_desc_phys & 0xFFFFFFFF));
e1000_write32(REG_RDBAH, (uint32_t)(rx_desc_phys >> 32));
e1000_write32(REG_RDLEN, NUM_RX_DESCRIPTORS * sizeof(e1000_rx_desc_t));
e1000_write32(REG_RDH, 0);
e1000_write32(REG_RDT, NUM_RX_DESCRIPTORS - 1);
rx_cur = 0;
// RCTL: Enable, Broadcast, Strip CRC, Multicast
e1000_write32(REG_RCTL, (1 << 1) | (1 << 15) | (1 << 26) | (1 << 4));
}
static void e1000_init_tx(void) {
tx_descriptors = (e1000_tx_desc_t*)kzalloc(sizeof(e1000_tx_desc_t) * NUM_TX_DESCRIPTORS + 16);
tx_descriptors = (e1000_tx_desc_t*)(((uint64_t)tx_descriptors + 15) & ~15);
for (int i = 0; i < NUM_TX_DESCRIPTORS; i++) {
tx_buffers[i] = (uint8_t*)kmalloc(RX_BUFFER_SIZE + 16);
tx_descriptors[i].buffer_addr = (uint64_t)tx_buffers[i];
tx_descriptors[i].status = 1;
tx_descriptors[i].cmd = 0;
}
uint64_t tx_desc_phys = (uint64_t)tx_descriptors;
e1000_write32(REG_TDBAL, (uint32_t)(tx_desc_phys & 0xFFFFFFFF));
e1000_write32(REG_TDBAH, (uint32_t)(tx_desc_phys >> 32));
e1000_write32(REG_TDLEN, NUM_TX_DESCRIPTORS * sizeof(e1000_tx_desc_t));
e1000_write32(REG_TDH, 0);
e1000_write32(REG_TDT, 0);
tx_cur = 0;
// TCTL: Enable, Pad Short Packets, Collisions
e1000_write32(REG_TCTL, (1 << 1) | (1 << 3) | (0x0F << 4) | (0x40 << 12));
}
bool e1000_init(void) {
e1000_pci_dev = pci_find_device(E1000_VENDOR_ID, E1000_DEV_82540EM);
if (!e1000_pci_dev) e1000_pci_dev = pci_find_device(E1000_VENDOR_ID, E1000_DEV_82545EM);
if (!e1000_pci_dev) e1000_pci_dev = pci_find_class(PCI_CLASS_NETWORK, PCI_SUBCLASS_ETHERNET);
if (!e1000_pci_dev) {
return false;
}
pci_enable_bus_mastering(e1000_pci_dev);
if (e1000_pci_dev->bar_type[0] == 0 && e1000_pci_dev->bar[0] != 0) {
mmio_base = e1000_pci_dev->bar[0] & ~0xF;
use_mmio = true;
} else {
io_base = (uint16_t)(e1000_pci_dev->bar[1] & ~0x3);
use_mmio = false;
}
e1000_read_mac();
uint8_t irq = e1000_pci_dev->irq;
if (irq > 0 && irq <= 15) {
isr_register_handler(32 + irq, e1000_interrupt_handler);
pic_clear_mask(irq);
}
e1000_init_rx();
e1000_init_tx();
e1000_write32(REG_IMS, (1 << 7) | (1 << 4) | (1 << 6) | (1 << 2));
e1000_read32(REG_ICR);
printk(KERN_INFO "[E1000] Initialized. MAC: %02x:%02x:%02x:%02x:%02x:%02x (IRQ %d)\n",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5], irq);
return true;
}
void e1000_send(const void* data, uint16_t len) {
if (!data || len == 0) return;
while (!(tx_descriptors[tx_cur].status & 0x01)) {
io_wait();
}
memcpy(tx_buffers[tx_cur], data, len);
tx_descriptors[tx_cur].length = len;
tx_descriptors[tx_cur].cmd = (1 << 0) | (1 << 1) | (1 << 3); // EOP, RS, IFCS
tx_descriptors[tx_cur].status = 0;
tx_cur = (tx_cur + 1) % NUM_TX_DESCRIPTORS;
stats_tx_packets++;
stats_tx_bytes += len;
e1000_write32(REG_TDT, tx_cur);
}
void e1000_get_mac(uint8_t* mac_out) {
if (mac_out) {
memcpy(mac_out, mac_addr, 6);
}
}
bool e1000_is_link_up(void) {
uint32_t status = e1000_read32(REG_STATUS);
return (status & (1 << 1)) != 0;
}
uint64_t e1000_get_rx_packets(void) { return stats_rx_packets; }
uint64_t e1000_get_tx_packets(void) { return stats_tx_packets; }
uint64_t e1000_get_rx_bytes(void) { return stats_rx_bytes; }
uint64_t e1000_get_tx_bytes(void) { return stats_tx_bytes; }
+138
View File
@@ -0,0 +1,138 @@
#include <drivers/pci.h>
#include <arch/x86_64/io.h>
#include <mm/kmalloc.h>
#include <kernel/printk.h>
#include <lib/string.h>
static pci_device_t* pci_device_list = NULL;
uint32_t pci_config_read32(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) {
uint32_t address = (uint32_t)((1U << 31) |
((uint32_t)bus << 16) |
((uint32_t)slot << 11) |
((uint32_t)func << 8) |
(offset & 0xFC));
outl(PCI_CONFIG_ADDRESS, address);
return inl(PCI_CONFIG_DATA);
}
uint16_t pci_config_read16(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) {
uint32_t val = pci_config_read32(bus, slot, func, offset);
return (uint16_t)((val >> ((offset & 2) * 8)) & 0xFFFF);
}
uint8_t pci_config_read8(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) {
uint32_t val = pci_config_read32(bus, slot, func, offset);
return (uint8_t)((val >> ((offset & 3) * 8)) & 0xFF);
}
void pci_config_write32(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint32_t val) {
uint32_t address = (uint32_t)((1U << 31) |
((uint32_t)bus << 16) |
((uint32_t)slot << 11) |
((uint32_t)func << 8) |
(offset & 0xFC));
outl(PCI_CONFIG_ADDRESS, address);
outl(PCI_CONFIG_DATA, val);
}
void pci_config_write16(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint16_t val) {
uint32_t old = pci_config_read32(bus, slot, func, offset);
uint32_t shift = (offset & 2) * 8;
uint32_t mask = 0xFFFF << shift;
uint32_t new_val = (old & ~mask) | ((uint32_t)val << shift);
pci_config_write32(bus, slot, func, offset, new_val);
}
void pci_enable_bus_mastering(pci_device_t* dev) {
if (!dev) return;
uint16_t cmd = pci_config_read16(dev->bus, dev->slot, dev->function, 0x04);
cmd |= (1 << 2) | (1 << 0) | (1 << 1); // Bus Master, I/O Space, Memory Space
pci_config_write16(dev->bus, dev->slot, dev->function, 0x04, cmd);
}
static void pci_check_function(uint8_t bus, uint8_t slot, uint8_t func) {
uint16_t vendor = pci_config_read16(bus, slot, func, 0x00);
if (vendor == 0xFFFF || vendor == 0x0000) return;
uint16_t device = pci_config_read16(bus, slot, func, 0x02);
uint8_t class_id = pci_config_read8(bus, slot, func, 0x0B);
uint8_t subclass_id = pci_config_read8(bus, slot, func, 0x0A);
uint8_t prog_if = pci_config_read8(bus, slot, func, 0x09);
uint8_t revision = pci_config_read8(bus, slot, func, 0x08);
uint8_t irq = pci_config_read8(bus, slot, func, 0x3C);
pci_device_t* dev = (pci_device_t*)kmalloc(sizeof(pci_device_t));
if (!dev) return;
dev->bus = bus;
dev->slot = slot;
dev->function = func;
dev->vendor_id = vendor;
dev->device_id = device;
dev->class_id = class_id;
dev->subclass_id = subclass_id;
dev->prog_if = prog_if;
dev->revision = revision;
dev->irq = irq;
// Read BARs 0-5
for (int b = 0; b < 6; b++) {
uint32_t bar = pci_config_read32(bus, slot, func, 0x10 + b * 4);
dev->bar[b] = bar;
dev->bar_type[b] = (bar & 1); // 0 = Memory, 1 = I/O
}
dev->next = pci_device_list;
pci_device_list = dev;
printk(KERN_INFO "PCI: %02x:%02x.%d [%04x:%04x] Class %02x.%02x (IRQ %d)\n",
bus, slot, func, vendor, device, class_id, subclass_id, irq);
}
void pci_init(void) {
pci_device_list = NULL;
for (uint16_t bus = 0; bus < 256; bus++) {
for (uint8_t slot = 0; slot < 32; slot++) {
uint16_t vendor = pci_config_read16((uint8_t)bus, slot, 0, 0x00);
if (vendor == 0xFFFF) continue;
pci_check_function((uint8_t)bus, slot, 0);
uint8_t header_type = pci_config_read8((uint8_t)bus, slot, 0, 0x0E);
if (header_type & 0x80) {
// Multi-function device
for (uint8_t func = 1; func < 8; func++) {
pci_check_function((uint8_t)bus, slot, func);
}
}
}
}
}
pci_device_t* pci_get_devices(void) {
return pci_device_list;
}
pci_device_t* pci_find_device(uint16_t vendor_id, uint16_t device_id) {
pci_device_t* curr = pci_device_list;
while (curr) {
if (curr->vendor_id == vendor_id && curr->device_id == device_id) {
return curr;
}
curr = curr->next;
}
return NULL;
}
pci_device_t* pci_find_class(uint8_t class_id, uint8_t subclass_id) {
pci_device_t* curr = pci_device_list;
while (curr) {
if (curr->class_id == class_id && curr->subclass_id == subclass_id) {
return curr;
}
curr = curr->next;
}
return NULL;
}
+30
View File
@@ -0,0 +1,30 @@
#include <drivers/speaker.h>
#include <arch/x86_64/pit.h>
#include <arch/x86_64/io.h>
void speaker_on(uint32_t frequency) {
if (frequency == 0) return;
uint32_t divisor = 1193180 / frequency;
// Set PIT Channel 2
outb(0x43, 0xB6);
outb(0x42, (uint8_t)(divisor & 0xFF));
outb(0x42, (uint8_t)((divisor >> 8) & 0xFF));
// Enable speaker via Port 0x61
uint8_t tmp = inb(0x61);
if (tmp != (tmp | 3)) {
outb(0x61, tmp | 3);
}
}
void speaker_off(void) {
uint8_t tmp = inb(0x61) & 0xFC;
outb(0x61, tmp);
}
void speaker_beep(uint32_t frequency, uint32_t duration_ms) {
speaker_on(frequency);
pit_sleep(duration_ms);
speaker_off();
}
+79
View File
@@ -0,0 +1,79 @@
#include <fs/devfs.h>
#include <fs/ramfs.h>
#include <drivers/tty.h>
#include <crypto/crypto.h>
#include <lib/string.h>
#include <mm/kmalloc.h>
static vfs_node_t* devfs_root = NULL;
static ssize_t dev_null_write(vfs_node_t* node, off_t offset, size_t size, const uint8_t* buffer) {
(void)node; (void)offset; (void)buffer;
return (ssize_t)size; // Discard everything
}
static ssize_t dev_null_read(vfs_node_t* node, off_t offset, size_t size, uint8_t* buffer) {
(void)node; (void)offset; (void)size; (void)buffer;
return 0; // EOF immediately
}
static ssize_t dev_zero_read(vfs_node_t* node, off_t offset, size_t size, uint8_t* buffer) {
(void)node; (void)offset;
memset(buffer, 0, size);
return (ssize_t)size;
}
static ssize_t dev_random_read(vfs_node_t* node, off_t offset, size_t size, uint8_t* buffer) {
(void)node; (void)offset;
prng_get_bytes(buffer, size);
return (ssize_t)size;
}
static ssize_t dev_tty_write(vfs_node_t* node, off_t offset, size_t size, const uint8_t* buffer) {
(void)node; (void)offset;
tty_write((const char*)buffer, size);
return (ssize_t)size;
}
void devfs_init(void) {
devfs_root = ramfs_add_dir(NULL, "dev");
// 1. /dev/null
vfs_node_t* null_dev = ramfs_add_file(devfs_root, "null", NULL, 0);
if (null_dev) {
null_dev->flags = FS_CHARDEVICE;
null_dev->read = dev_null_read;
null_dev->write = dev_null_write;
}
// 2. /dev/zero
vfs_node_t* zero_dev = ramfs_add_file(devfs_root, "zero", NULL, 0);
if (zero_dev) {
zero_dev->flags = FS_CHARDEVICE;
zero_dev->read = dev_zero_read;
zero_dev->write = dev_null_write;
}
// 3. /dev/random & /dev/urandom
vfs_node_t* rand_dev = ramfs_add_file(devfs_root, "random", NULL, 0);
if (rand_dev) {
rand_dev->flags = FS_CHARDEVICE;
rand_dev->read = dev_random_read;
}
vfs_node_t* urand_dev = ramfs_add_file(devfs_root, "urandom", NULL, 0);
if (urand_dev) {
urand_dev->flags = FS_CHARDEVICE;
urand_dev->read = dev_random_read;
}
// 4. /dev/tty
vfs_node_t* tty_dev = ramfs_add_file(devfs_root, "tty", NULL, 0);
if (tty_dev) {
tty_dev->flags = FS_CHARDEVICE;
tty_dev->write = dev_tty_write;
}
}
vfs_node_t* devfs_get_root(void) {
return devfs_root;
}
+142
View File
@@ -0,0 +1,142 @@
#include <fs/procfs.h>
#include <fs/ramfs.h>
#include <arch/x86_64/cpuid.h>
#include <arch/x86_64/pit.h>
#include <mm/pmm.h>
#include <mm/kmalloc.h>
#include <drivers/e1000.h>
#include <lib/printf.h>
#include <lib/string.h>
static vfs_node_t* procfs_root = NULL;
static ssize_t proc_version_read(vfs_node_t* node, off_t offset, size_t size, uint8_t* buffer) {
(void)node;
char text[256];
int len = sprintf(text, "SUB-OS version 0.2.0-lts (subhobhai@sub-os) (x86_64-elf-gcc 13.3.0) #1 SMP PREEMPT Sun Aug 16 2026\n");
if (offset >= len) return 0;
if (offset + size > (size_t)len) size = len - offset;
memcpy(buffer, text + offset, size);
return (ssize_t)size;
}
static ssize_t proc_uptime_read(vfs_node_t* node, off_t offset, size_t size, uint8_t* buffer) {
(void)node;
uint64_t ticks = pit_get_ticks();
uint64_t secs = ticks / 100;
uint64_t frac = (ticks % 100);
char text[64];
int len = sprintf(text, "%llu.%02llu %llu.%02llu\n", secs, frac, secs, frac);
if (offset >= len) return 0;
if (offset + size > (size_t)len) size = len - offset;
memcpy(buffer, text + offset, size);
return (ssize_t)size;
}
static ssize_t proc_meminfo_read(vfs_node_t* node, off_t offset, size_t size, uint8_t* buffer) {
(void)node;
uint64_t total_kb = (pmm_get_total_pages() * 4096) / 1024;
uint64_t free_kb = (pmm_get_free_pages() * 4096) / 1024;
uint64_t used_kb = (pmm_get_used_pages() * 4096) / 1024;
char text[512];
int len = sprintf(text,
"MemTotal: %8llu kB\n"
"MemFree: %8llu kB\n"
"MemAvailable: %8llu kB\n"
"Buffers: 0 kB\n"
"Cached: %8llu kB\n"
"HeapTotal: %8llu kB\n"
"HeapUsed: %8llu kB\n"
"HeapFree: %8llu kB\n",
total_kb, free_kb, free_kb,
(heap_get_used_bytes() / 1024),
heap_get_total_bytes() / 1024,
heap_get_used_bytes() / 1024,
heap_get_free_bytes() / 1024);
if (offset >= len) return 0;
if (offset + size > (size_t)len) size = len - offset;
memcpy(buffer, text + offset, size);
return (ssize_t)size;
}
static ssize_t proc_cpuinfo_read(vfs_node_t* node, off_t offset, size_t size, uint8_t* buffer) {
(void)node;
const cpu_info_t* cpu = cpuid_get_info();
char text[1024];
int len = sprintf(text,
"processor\t: 0\n"
"vendor_id\t: %s\n"
"cpu family\t: %u\n"
"model\t\t: %u\n"
"model name\t: %s\n"
"stepping\t: %u\n"
"flags\t\t: %s%s%s%s%s%s%s%s%s\n"
"bogomips\t: 4800.00\n"
"clflush size\t: 64\n",
cpu->vendor,
cpu->family,
cpu->model_id,
cpu->model,
cpu->stepping,
cpu->has_fpu ? "fpu " : "",
cpu->has_tsc ? "tsc " : "",
cpu->has_pae ? "pae " : "",
cpu->has_apic ? "apic " : "",
cpu->has_sse ? "sse " : "",
cpu->has_sse2 ? "sse2 " : "",
cpu->has_sse3 ? "sse3 " : "",
cpu->has_sse4_1 ? "sse4_1 " : "",
cpu->has_avx ? "avx " : "");
if (offset >= len) return 0;
if (offset + size > (size_t)len) size = len - offset;
memcpy(buffer, text + offset, size);
return (ssize_t)size;
}
static ssize_t proc_net_dev_read(vfs_node_t* node, off_t offset, size_t size, uint8_t* buffer) {
(void)node;
char text[512];
int len = sprintf(text,
"Inter-| Receive | Transmit\n"
" face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed\n"
" lo: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
" eth0: %7llu %7llu 0 0 0 0 0 0 %7llu %7llu 0 0 0 0 0 0\n",
e1000_get_rx_bytes(), e1000_get_rx_packets(),
e1000_get_tx_bytes(), e1000_get_tx_packets());
if (offset >= len) return 0;
if (offset + size > (size_t)len) size = len - offset;
memcpy(buffer, text + offset, size);
return (ssize_t)size;
}
void procfs_init(void) {
procfs_root = ramfs_add_dir(NULL, "proc");
vfs_node_t* ver = ramfs_add_file(procfs_root, "version", NULL, 0);
if (ver) { ver->flags = FS_FILE; ver->read = proc_version_read; }
vfs_node_t* uptime = ramfs_add_file(procfs_root, "uptime", NULL, 0);
if (uptime) { uptime->flags = FS_FILE; uptime->read = proc_uptime_read; }
vfs_node_t* mem = ramfs_add_file(procfs_root, "meminfo", NULL, 0);
if (mem) { mem->flags = FS_FILE; mem->read = proc_meminfo_read; }
vfs_node_t* cpu = ramfs_add_file(procfs_root, "cpuinfo", NULL, 0);
if (cpu) { cpu->flags = FS_FILE; cpu->read = proc_cpuinfo_read; }
vfs_node_t* net_dir = ramfs_add_dir(procfs_root, "net");
if (net_dir) {
vfs_node_t* net_dev = ramfs_add_file(net_dir, "dev", NULL, 0);
if (net_dev) { net_dev->flags = FS_FILE; net_dev->read = proc_net_dev_read; }
}
}
vfs_node_t* procfs_get_root(void) {
return procfs_root;
}
+195
View File
@@ -0,0 +1,195 @@
#include <fs/ramfs.h>
#include <mm/kmalloc.h>
#include <lib/string.h>
#define MAX_CHILDREN 32
typedef struct ramfs_entry {
vfs_node_t node;
uint8_t* data;
size_t capacity;
struct ramfs_entry* children[MAX_CHILDREN];
uint32_t child_count;
} ramfs_entry_t;
static vfs_dirent_t shared_dirent;
static int ramfs_mkdir_impl(vfs_node_t* parent, const char* name, mode_t mode);
static int ramfs_create_impl(vfs_node_t* parent, const char* name, mode_t mode);
static struct vfs_dirent* ramfs_readdir(vfs_node_t* node, uint32_t index);
static struct vfs_node* ramfs_finddir(vfs_node_t* node, const char* name);
static ssize_t ramfs_read(vfs_node_t* node, off_t offset, size_t size, uint8_t* buffer) {
ramfs_entry_t* entry = (ramfs_entry_t*)node;
if (!entry || !entry->data || (size_t)offset >= node->length) return 0;
if (offset + size > node->length) {
size = node->length - offset;
}
memcpy(buffer, entry->data + offset, size);
return (ssize_t)size;
}
static ssize_t ramfs_write(vfs_node_t* node, off_t offset, size_t size, const uint8_t* buffer) {
ramfs_entry_t* entry = (ramfs_entry_t*)node;
if (!entry) return -1;
if (offset + size > entry->capacity) {
size_t new_cap = (offset + size + 256) & ~255;
uint8_t* new_data = (uint8_t*)kmalloc(new_cap);
if (!new_data) return -1;
if (entry->data) {
memcpy(new_data, entry->data, node->length);
kfree(entry->data);
}
entry->data = new_data;
entry->capacity = new_cap;
}
memcpy(entry->data + offset, buffer, size);
if (offset + size > node->length) {
node->length = offset + size;
}
return (ssize_t)size;
}
static struct vfs_dirent* ramfs_readdir(vfs_node_t* node, uint32_t index) {
ramfs_entry_t* entry = (ramfs_entry_t*)node;
if (!entry || index >= entry->child_count) return NULL;
strncpy(shared_dirent.name, entry->children[index]->node.name, sizeof(shared_dirent.name) - 1);
shared_dirent.inode = entry->children[index]->node.inode;
shared_dirent.type = entry->children[index]->node.flags;
return &shared_dirent;
}
static struct vfs_node* ramfs_finddir(vfs_node_t* node, const char* name) {
ramfs_entry_t* entry = (ramfs_entry_t*)node;
if (!entry) return NULL;
for (uint32_t i = 0; i < entry->child_count; i++) {
if (strcmp(entry->children[i]->node.name, name) == 0) {
return &entry->children[i]->node;
}
}
return NULL;
}
static int ramfs_mkdir_impl(vfs_node_t* parent, const char* name, mode_t mode) {
ramfs_entry_t* p = (ramfs_entry_t*)parent;
if (!p || p->child_count >= MAX_CHILDREN) return -1;
ramfs_entry_t* child = (ramfs_entry_t*)kzalloc(sizeof(ramfs_entry_t));
if (!child) return -1;
strncpy(child->node.name, name, sizeof(child->node.name) - 1);
child->node.flags = FS_DIRECTORY;
child->node.mode = mode;
child->node.readdir = ramfs_readdir;
child->node.finddir = ramfs_finddir;
child->node.mkdir = ramfs_mkdir_impl;
child->node.create = ramfs_create_impl;
p->children[p->child_count++] = child;
return 0;
}
static int ramfs_create_impl(vfs_node_t* parent, const char* name, mode_t mode) {
ramfs_entry_t* p = (ramfs_entry_t*)parent;
if (!p || p->child_count >= MAX_CHILDREN) return -1;
ramfs_entry_t* child = (ramfs_entry_t*)kzalloc(sizeof(ramfs_entry_t));
if (!child) return -1;
strncpy(child->node.name, name, sizeof(child->node.name) - 1);
child->node.flags = FS_FILE;
child->node.mode = mode;
child->node.read = ramfs_read;
child->node.write = ramfs_write;
p->children[p->child_count++] = child;
return 0;
}
vfs_node_t* ramfs_add_file(vfs_node_t* parent, const char* name, const void* content, size_t size) {
ramfs_entry_t* p = (ramfs_entry_t*)parent;
if (!p || p->child_count >= MAX_CHILDREN) return NULL;
ramfs_entry_t* child = (ramfs_entry_t*)kzalloc(sizeof(ramfs_entry_t));
if (!child) return NULL;
strncpy(child->node.name, name, sizeof(child->node.name) - 1);
child->node.flags = FS_FILE;
child->node.mode = 0644;
child->node.length = size;
child->node.read = ramfs_read;
child->node.write = ramfs_write;
if (size > 0 && content) {
child->capacity = size;
child->data = (uint8_t*)kmalloc(size);
if (child->data) {
memcpy(child->data, content, size);
}
}
p->children[p->child_count++] = child;
return &child->node;
}
vfs_node_t* ramfs_add_dir(vfs_node_t* parent, const char* name) {
ramfs_entry_t* child = (ramfs_entry_t*)kzalloc(sizeof(ramfs_entry_t));
if (!child) return NULL;
strncpy(child->node.name, name, sizeof(child->node.name) - 1);
child->node.flags = FS_DIRECTORY;
child->node.mode = 0755;
child->node.readdir = ramfs_readdir;
child->node.finddir = ramfs_finddir;
child->node.mkdir = ramfs_mkdir_impl;
child->node.create = ramfs_create_impl;
if (parent) {
ramfs_entry_t* p = (ramfs_entry_t*)parent;
if (p->child_count < MAX_CHILDREN) {
p->children[p->child_count++] = child;
}
}
return &child->node;
}
vfs_node_t* ramfs_create_root(void) {
ramfs_entry_t* root = (ramfs_entry_t*)kzalloc(sizeof(ramfs_entry_t));
if (!root) return NULL;
strcpy(root->node.name, "/");
root->node.flags = FS_DIRECTORY;
root->node.mode = 0755;
root->node.readdir = ramfs_readdir;
root->node.finddir = ramfs_finddir;
root->node.mkdir = ramfs_mkdir_impl;
root->node.create = ramfs_create_impl;
// Seed default file system structure
vfs_node_t* etc = ramfs_add_dir(&root->node, "etc");
ramfs_add_dir(&root->node, "bin");
ramfs_add_dir(&root->node, "dev");
ramfs_add_dir(&root->node, "proc");
ramfs_add_dir(&root->node, "home");
ramfs_add_dir(&root->node, "tmp");
if (etc) {
ramfs_add_file(etc, "hostname", "sub-os\n", 7);
ramfs_add_file(etc, "os-release", "NAME=\"SUB-OS\"\nVERSION=\"0.2.0-lts\"\nARCH=\"x86_64\"\n", 48);
ramfs_add_file(etc, "resolv.conf", "nameserver 10.0.2.3\nsearch localdomain\n", 39);
ramfs_add_file(etc, "motd", "====================================================\n Welcome to SUB-OS Modular Monolithic Linux Core!\n====================================================\n", 137);
}
const char* readme = "SUB-OS Production-Level Modular Operating System\nArchitecture: x86_64 Long Mode\nSubsystems: PMM, Heap, VFS, PCI, E1000, Net, Crypto, LazyBox\n";
ramfs_add_file(&root->node, "readme.txt", readme, strlen(readme));
return &root->node;
}
+242
View File
@@ -0,0 +1,242 @@
#include <fs/vfs.h>
#include <fs/ramfs.h>
#include <fs/devfs.h>
#include <fs/procfs.h>
#include <mm/kmalloc.h>
#include <lib/string.h>
#include <kernel/printk.h>
#define MAX_OPEN_FILES 64
static vfs_node_t* vfs_root = NULL;
static file_descriptor_t file_descriptors[MAX_OPEN_FILES];
void vfs_init(void) {
memset(file_descriptors, 0, sizeof(file_descriptors));
// 1. Create root RAM filesystem
vfs_root = ramfs_create_root();
// 2. Initialize and mount /dev
devfs_init();
vfs_mount("/dev", devfs_get_root());
// 3. Initialize and mount /proc
procfs_init();
vfs_mount("/proc", procfs_get_root());
printk(KERN_INFO "VFS: Mounted root ramfs, /dev synthetic devfs, and /proc procfs\n");
}
vfs_node_t* vfs_get_root(void) {
return vfs_root;
}
vfs_node_t* vfs_namei(const char* path) {
if (!path || !vfs_root) return NULL;
if (strcmp(path, "/") == 0) return vfs_root;
if (*path == '/') path++; // Skip leading slash
char buffer[256];
strncpy(buffer, path, sizeof(buffer) - 1);
buffer[sizeof(buffer) - 1] = '\0';
vfs_node_t* current = vfs_root;
char* token = buffer;
while (*token) {
char* next_slash = strchr(token, '/');
if (next_slash) {
*next_slash = '\0';
}
if (current->finddir) {
current = current->finddir(current, token);
if (!current) return NULL;
// Follow mountpoints
if (current->ptr && (current->flags & FS_MOUNTPOINT)) {
current = current->ptr;
}
} else {
return NULL;
}
if (next_slash) {
token = next_slash + 1;
} else {
break;
}
}
return current;
}
int vfs_open(const char* path, uint32_t flags) {
vfs_node_t* node = vfs_namei(path);
if (!node) {
if (flags & O_CREAT) {
// Find parent and create
char parent_path[256];
strncpy(parent_path, path, sizeof(parent_path) - 1);
char* last_slash = strrchr(parent_path, '/');
if (last_slash) {
*last_slash = '\0';
const char* filename = last_slash + 1;
vfs_node_t* parent = vfs_namei(parent_path[0] ? parent_path : "/");
if (parent && parent->create) {
parent->create(parent, filename, 0644);
node = vfs_namei(path);
}
}
}
if (!node) return -1;
}
if (node->open) {
if (node->open(node, flags) != 0) return -1;
}
// Find free file descriptor
for (int fd = 3; fd < MAX_OPEN_FILES; fd++) {
if (!file_descriptors[fd].node) {
file_descriptors[fd].node = node;
file_descriptors[fd].offset = 0;
file_descriptors[fd].flags = flags;
return fd;
}
}
return -1; // Out of file descriptors
}
ssize_t vfs_read(int fd, void* buffer, size_t size) {
if (fd < 0 || fd >= MAX_OPEN_FILES || !file_descriptors[fd].node) return -1;
file_descriptor_t* desc = &file_descriptors[fd];
if (desc->node->read) {
ssize_t bytes_read = desc->node->read(desc->node, desc->offset, size, (uint8_t*)buffer);
if (bytes_read > 0) {
desc->offset += bytes_read;
}
return bytes_read;
}
return -1;
}
ssize_t vfs_write(int fd, const void* buffer, size_t size) {
if (fd < 0 || fd >= MAX_OPEN_FILES || !file_descriptors[fd].node) return -1;
file_descriptor_t* desc = &file_descriptors[fd];
if (desc->node->write) {
ssize_t bytes_written = desc->node->write(desc->node, desc->offset, size, (const uint8_t*)buffer);
if (bytes_written > 0) {
desc->offset += bytes_written;
}
return bytes_written;
}
return -1;
}
off_t vfs_lseek(int fd, off_t offset, int whence) {
if (fd < 0 || fd >= MAX_OPEN_FILES || !file_descriptors[fd].node) return -1;
file_descriptor_t* desc = &file_descriptors[fd];
if (whence == SEEK_SET) desc->offset = offset;
else if (whence == SEEK_CUR) desc->offset += offset;
else if (whence == SEEK_END) desc->offset = desc->node->length + offset;
return desc->offset;
}
int vfs_close(int fd) {
if (fd < 0 || fd >= MAX_OPEN_FILES || !file_descriptors[fd].node) return -1;
if (file_descriptors[fd].node->close) {
file_descriptors[fd].node->close(file_descriptors[fd].node);
}
file_descriptors[fd].node = NULL;
file_descriptors[fd].offset = 0;
return 0;
}
int vfs_mkdir(const char* path, mode_t mode) {
if (!path || !*path) return -1;
char parent_path[256];
strncpy(parent_path, path, sizeof(parent_path) - 1);
parent_path[sizeof(parent_path) - 1] = '\0';
char* last_slash = strrchr(parent_path, '/');
const char* dirname = path;
vfs_node_t* parent = vfs_get_root();
if (last_slash) {
if (last_slash == parent_path) {
parent = vfs_namei("/");
dirname = last_slash + 1;
} else {
*last_slash = '\0';
dirname = last_slash + 1;
parent = vfs_namei(parent_path);
}
}
if (parent && parent->mkdir) {
return parent->mkdir(parent, dirname, mode);
}
return -1;
}
int vfs_create(const char* path, mode_t mode) {
if (!path || !*path) return -1;
char parent_path[256];
strncpy(parent_path, path, sizeof(parent_path) - 1);
parent_path[sizeof(parent_path) - 1] = '\0';
char* last_slash = strrchr(parent_path, '/');
const char* filename = path;
vfs_node_t* parent = vfs_get_root();
if (last_slash) {
if (last_slash == parent_path) {
parent = vfs_namei("/");
filename = last_slash + 1;
} else {
*last_slash = '\0';
filename = last_slash + 1;
parent = vfs_namei(parent_path);
}
}
if (parent && parent->create) {
return parent->create(parent, filename, mode);
}
return -1;
}
int vfs_mount(const char* path, vfs_node_t* fs_root) {
if (!path || !fs_root) return -1;
vfs_node_t* mount_node = vfs_namei(path);
if (!mount_node) {
// Create directory node for mount point
char parent_path[256];
strncpy(parent_path, path, sizeof(parent_path) - 1);
char* last_slash = strrchr(parent_path, '/');
if (last_slash) {
*last_slash = '\0';
const char* dirname = last_slash + 1;
vfs_node_t* parent = vfs_namei(parent_path[0] ? parent_path : "/");
if (parent && parent->mkdir) {
parent->mkdir(parent, dirname, 0755);
mount_node = vfs_namei(path);
}
}
}
if (mount_node) {
mount_node->flags |= FS_MOUNTPOINT;
mount_node->ptr = fs_root;
return 0;
}
return -1;
}
+30
View File
@@ -0,0 +1,30 @@
#ifndef _ARCH_X86_64_CPUID_H
#define _ARCH_X86_64_CPUID_H
#include <stdint.h>
#include <stdbool.h>
typedef struct {
char vendor[13];
char model[49];
uint32_t family;
uint32_t model_id;
uint32_t stepping;
bool has_fpu;
bool has_tsc;
bool has_msr;
bool has_pae;
bool has_apic;
bool has_sse;
bool has_sse2;
bool has_sse3;
bool has_sse4_1;
bool has_sse4_2;
bool has_avx;
bool has_rdrand;
} cpu_info_t;
void cpuid_detect(cpu_info_t* info);
const cpu_info_t* cpuid_get_info(void);
#endif // _ARCH_X86_64_CPUID_H
+47
View File
@@ -0,0 +1,47 @@
#ifndef _ARCH_X86_64_GDT_H
#define _ARCH_X86_64_GDT_H
#include <stdint.h>
#define GDT_KERNEL_CODE 0x08
#define GDT_KERNEL_DATA 0x10
#define GDT_USER_CODE 0x18
#define GDT_USER_DATA 0x20
#define GDT_TSS 0x28
typedef struct {
uint16_t limit_low;
uint16_t base_low;
uint8_t base_middle;
uint8_t access;
uint8_t granularity;
uint8_t base_high;
} __attribute__((packed)) gdt_entry_t;
typedef struct {
uint16_t limit;
uint64_t base;
} __attribute__((packed)) gdt_ptr_t;
typedef struct {
uint32_t reserved0;
uint64_t rsp0;
uint64_t rsp1;
uint64_t rsp2;
uint64_t reserved1;
uint64_t ist1;
uint64_t ist2;
uint64_t ist3;
uint64_t ist4;
uint64_t ist5;
uint64_t ist6;
uint64_t ist7;
uint64_t reserved2;
uint16_t reserved3;
uint16_t iomap_base;
} __attribute__((packed)) tss_entry_t;
void gdt_init(void);
void gdt_set_kernel_stack(uint64_t stack);
#endif // _ARCH_X86_64_GDT_H
+28
View File
@@ -0,0 +1,28 @@
#ifndef _ARCH_X86_64_IDT_H
#define _ARCH_X86_64_IDT_H
#include <stdint.h>
#define IDT_ENTRIES 256
typedef struct {
uint16_t isr_low;
uint16_t kernel_cs;
uint8_t ist;
uint8_t attributes;
uint16_t isr_mid;
uint32_t isr_high;
uint32_t reserved;
} __attribute__((packed)) idt_entry_t;
typedef struct {
uint16_t limit;
uint64_t base;
} __attribute__((packed)) idt_ptr_t;
void idt_init(void);
void idt_set_gate(uint8_t vector, void* isr, uint8_t flags);
void idt_enable_gate(uint8_t vector);
void idt_disable_gate(uint8_t vector);
#endif // _ARCH_X86_64_IDT_H
+52
View File
@@ -0,0 +1,52 @@
#ifndef _ARCH_X86_64_IO_H
#define _ARCH_X86_64_IO_H
#include <stdint.h>
static inline void outb(uint16_t port, uint8_t val) {
__asm__ volatile ("outb %0, %1" : : "a"(val), "Nd"(port));
}
static inline uint8_t inb(uint16_t port) {
uint8_t ret;
__asm__ volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port));
return ret;
}
static inline void outw(uint16_t port, uint16_t val) {
__asm__ volatile ("outw %0, %1" : : "a"(val), "Nd"(port));
}
static inline uint16_t inw(uint16_t port) {
uint16_t ret;
__asm__ volatile ("inw %1, %0" : "=a"(ret) : "Nd"(port));
return ret;
}
static inline void outl(uint16_t port, uint32_t val) {
__asm__ volatile ("outl %0, %1" : : "a"(val), "Nd"(port));
}
static inline uint32_t inl(uint16_t port) {
uint32_t ret;
__asm__ volatile ("inl %1, %0" : "=a"(ret) : "Nd"(port));
return ret;
}
static inline void io_wait(void) {
outb(0x80, 0);
}
static inline void cli(void) {
__asm__ volatile ("cli");
}
static inline void sti(void) {
__asm__ volatile ("sti");
}
static inline void hlt(void) {
__asm__ volatile ("hlt");
}
#endif // _ARCH_X86_64_IO_H
+19
View File
@@ -0,0 +1,19 @@
#ifndef _ARCH_X86_64_ISR_H
#define _ARCH_X86_64_ISR_H
#include <stdint.h>
typedef struct {
uint64_t r15, r14, r13, r12, r11, r10, r9, r8;
uint64_t rbp, rdi, rsi, rdx, rcx, rbx, rax;
uint64_t int_no, error_code;
uint64_t rip, cs, rflags, rsp, ss;
} __attribute__((packed)) registers_t;
typedef void (*isr_handler_t)(registers_t*);
void isr_init(void);
void isr_register_handler(uint8_t int_no, isr_handler_t handler);
void isr_unregister_handler(uint8_t int_no);
#endif // _ARCH_X86_64_ISR_H
+25
View File
@@ -0,0 +1,25 @@
#ifndef _ARCH_X86_64_PAGING_H
#define _ARCH_X86_64_PAGING_H
#include <stdint.h>
#include <stdbool.h>
#define PAGE_SIZE 4096
#define PAGE_PRESENT (1ULL << 0)
#define PAGE_WRITABLE (1ULL << 1)
#define PAGE_USER (1ULL << 2)
#define PAGE_HUGE (1ULL << 7)
#define PAGE_NX (1ULL << 63)
typedef uint64_t pml4e_t;
typedef uint64_t pdpte_t;
typedef uint64_t pde_t;
typedef uint64_t pte_t;
void paging_init(void);
void paging_map_page(uint64_t virt, uint64_t phys, uint64_t flags);
void paging_unmap_page(uint64_t virt);
uint64_t paging_get_phys(uint64_t virt);
void paging_flush_tlb_single(uint64_t virt);
#endif // _ARCH_X86_64_PAGING_H
+12
View File
@@ -0,0 +1,12 @@
#ifndef _ARCH_X86_64_PIC_H
#define _ARCH_X86_64_PIC_H
#include <stdint.h>
void pic_init(void);
void pic_send_eoi(uint8_t irq);
void pic_set_mask(uint8_t irq);
void pic_clear_mask(uint8_t irq);
void pic_disable(void);
#endif // _ARCH_X86_64_PIC_H
+11
View File
@@ -0,0 +1,11 @@
#ifndef _ARCH_X86_64_PIT_H
#define _ARCH_X86_64_PIT_H
#include <stdint.h>
void pit_init(uint32_t frequency);
uint64_t pit_get_ticks(void);
uint64_t pit_get_uptime_ms(void);
void pit_sleep(uint32_t milliseconds);
#endif // _ARCH_X86_64_PIT_H
+42
View File
@@ -0,0 +1,42 @@
#ifndef _CRYPTO_CRYPTO_H
#define _CRYPTO_CRYPTO_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
// CRC32 API
uint32_t crc32(uint32_t crc, const void* buf, size_t size);
// MD5 API
typedef struct {
uint32_t state[4];
uint32_t count[2];
uint8_t buffer[64];
} md5_ctx_t;
void md5_init(md5_ctx_t* ctx);
void md5_update(md5_ctx_t* ctx, const void* input, size_t input_len);
void md5_final(uint8_t digest[16], md5_ctx_t* ctx);
void md5_string(const char* str, char output[33]);
// SHA-256 API
typedef struct {
uint32_t state[8];
uint64_t bitlen;
uint8_t buffer[64];
size_t datalen;
} sha256_ctx_t;
void sha256_init(sha256_ctx_t* ctx);
void sha256_update(sha256_ctx_t* ctx, const void* data, size_t len);
void sha256_final(uint8_t hash[32], sha256_ctx_t* ctx);
void sha256_string(const char* str, char output[65]);
// PRNG (Cryptographic Pseudo-Random Number Generator)
void prng_seed(uint64_t seed1, uint64_t seed2);
uint64_t prng_rand64(void);
uint32_t prng_rand32(void);
void prng_get_bytes(void* buf, size_t len);
#endif // _CRYPTO_CRYPTO_H
+28
View File
@@ -0,0 +1,28 @@
#ifndef _DRIVERS_ATA_H
#define _DRIVERS_ATA_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#define ATA_SECTOR_SIZE 512
#define ATA_PRIMARY_IO 0x1F0
#define ATA_PRIMARY_CTRL 0x3F6
#define ATA_SECONDARY_IO 0x170
#define ATA_SECONDARY_CTRL 0x376
typedef struct {
bool present;
bool is_master;
uint32_t sector_count;
char model[41];
char serial[21];
} ata_device_t;
bool ata_init(void);
bool ata_read_sectors(uint32_t lba, uint8_t count, void* buffer);
bool ata_write_sectors(uint32_t lba, uint8_t count, const void* buffer);
const ata_device_t* ata_get_primary_master(void);
#endif // _DRIVERS_ATA_H
+22
View File
@@ -0,0 +1,22 @@
#ifndef _DRIVERS_E1000_H
#define _DRIVERS_E1000_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#define E1000_VENDOR_ID 0x8086
#define E1000_DEV_82540EM 0x100E
#define E1000_DEV_82545EM 0x100F
bool e1000_init(void);
void e1000_send(const void* data, uint16_t len);
void e1000_get_mac(uint8_t* mac_out);
bool e1000_is_link_up(void);
uint64_t e1000_get_rx_packets(void);
uint64_t e1000_get_tx_packets(void);
uint64_t e1000_get_rx_bytes(void);
uint64_t e1000_get_tx_bytes(void);
#endif // _DRIVERS_E1000_H
+39
View File
@@ -0,0 +1,39 @@
#ifndef _DRIVERS_KEYBOARD_H
#define _DRIVERS_KEYBOARD_H
#include <stdint.h>
#include <stdbool.h>
#define KEY_SPECIAL_FLAG 0x0100
enum special_keys {
KEY_UP = KEY_SPECIAL_FLAG | 0x01,
KEY_DOWN = KEY_SPECIAL_FLAG | 0x02,
KEY_LEFT = KEY_SPECIAL_FLAG | 0x03,
KEY_RIGHT = KEY_SPECIAL_FLAG | 0x04,
KEY_HOME = KEY_SPECIAL_FLAG | 0x05,
KEY_END = KEY_SPECIAL_FLAG | 0x06,
KEY_PAGE_UP = KEY_SPECIAL_FLAG | 0x07,
KEY_PAGE_DOWN= KEY_SPECIAL_FLAG | 0x08,
KEY_INSERT = KEY_SPECIAL_FLAG | 0x09,
KEY_DELETE = KEY_SPECIAL_FLAG | 0x0A,
KEY_F1 = KEY_SPECIAL_FLAG | 0x11,
KEY_F2 = KEY_SPECIAL_FLAG | 0x12,
KEY_F3 = KEY_SPECIAL_FLAG | 0x13,
KEY_F4 = KEY_SPECIAL_FLAG | 0x14,
KEY_F5 = KEY_SPECIAL_FLAG | 0x15,
KEY_F6 = KEY_SPECIAL_FLAG | 0x16,
KEY_F7 = KEY_SPECIAL_FLAG | 0x17,
KEY_F8 = KEY_SPECIAL_FLAG | 0x18,
KEY_F9 = KEY_SPECIAL_FLAG | 0x19,
KEY_F10 = KEY_SPECIAL_FLAG | 0x1A,
KEY_F11 = KEY_SPECIAL_FLAG | 0x1B,
KEY_F12 = KEY_SPECIAL_FLAG | 0x1C,
};
void keyboard_init(void);
uint16_t keyboard_get_key(void);
bool keyboard_has_key(void);
char keyboard_get_char(void);
#endif // _DRIVERS_KEYBOARD_H
+46
View File
@@ -0,0 +1,46 @@
#ifndef _DRIVERS_PCI_H
#define _DRIVERS_PCI_H
#include <stdint.h>
#include <stdbool.h>
#define PCI_CONFIG_ADDRESS 0xCF8
#define PCI_CONFIG_DATA 0xCFC
#define PCI_CLASS_NETWORK 0x02
#define PCI_CLASS_DISPLAY 0x03
#define PCI_CLASS_STORAGE 0x01
#define PCI_SUBCLASS_ETHERNET 0x00
#define PCI_SUBCLASS_IDE 0x01
#define PCI_SUBCLASS_SATA 0x06
typedef struct pci_device {
uint8_t bus;
uint8_t slot;
uint8_t function;
uint16_t vendor_id;
uint16_t device_id;
uint8_t class_id;
uint8_t subclass_id;
uint8_t prog_if;
uint8_t revision;
uint8_t irq;
uint32_t bar[6];
uint8_t bar_type[6];
struct pci_device* next;
} pci_device_t;
void pci_init(void);
pci_device_t* pci_get_devices(void);
pci_device_t* pci_find_device(uint16_t vendor_id, uint16_t device_id);
pci_device_t* pci_find_class(uint8_t class_id, uint8_t subclass_id);
void pci_enable_bus_mastering(pci_device_t* dev);
uint32_t pci_config_read32(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset);
uint16_t pci_config_read16(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset);
uint8_t pci_config_read8(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset);
void pci_config_write32(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint32_t val);
void pci_config_write16(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint16_t val);
#endif // _DRIVERS_PCI_H
+16
View File
@@ -0,0 +1,16 @@
#ifndef _DRIVERS_SERIAL_H
#define _DRIVERS_SERIAL_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#define COM1_PORT 0x3F8
void serial_init(void);
void serial_write_char(char c);
void serial_write_string(const char* str);
char serial_read_char(void);
bool serial_received(void);
#endif // _DRIVERS_SERIAL_H
+10
View File
@@ -0,0 +1,10 @@
#ifndef _DRIVERS_SPEAKER_H
#define _DRIVERS_SPEAKER_H
#include <stdint.h>
void speaker_on(uint32_t frequency);
void speaker_off(void);
void speaker_beep(uint32_t frequency, uint32_t duration_ms);
#endif // _DRIVERS_SPEAKER_H
+20
View File
@@ -0,0 +1,20 @@
#ifndef _DRIVERS_TTY_H
#define _DRIVERS_TTY_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#define MAX_TTYS 4
#define TTY_WIDTH 80
#define TTY_HEIGHT 25
void tty_init(void);
void tty_switch(int index);
int tty_get_current(void);
void tty_write(const char* data, size_t size);
void tty_write_string(const char* data);
void tty_clear(void);
void tty_set_cursor(int row, int col);
#endif // _DRIVERS_TTY_H
+48
View File
@@ -0,0 +1,48 @@
#ifndef _DRIVERS_VGA_H
#define _DRIVERS_VGA_H
#include <stdint.h>
#include <stddef.h>
#define VGA_WIDTH 80
#define VGA_HEIGHT 25
#define VGA_MEMORY 0xB8000
enum vga_color {
VGA_COLOR_BLACK = 0,
VGA_COLOR_BLUE = 1,
VGA_COLOR_GREEN = 2,
VGA_COLOR_CYAN = 3,
VGA_COLOR_RED = 4,
VGA_COLOR_MAGENTA = 5,
VGA_COLOR_BROWN = 6,
VGA_COLOR_LIGHT_GREY = 7,
VGA_COLOR_DARK_GREY = 8,
VGA_COLOR_LIGHT_BLUE = 9,
VGA_COLOR_LIGHT_GREEN = 10,
VGA_COLOR_LIGHT_CYAN = 11,
VGA_COLOR_LIGHT_RED = 12,
VGA_COLOR_LIGHT_MAGENTA = 13,
VGA_COLOR_LIGHT_BROWN = 14,
VGA_COLOR_WHITE = 15,
};
static inline uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg) {
return fg | (bg << 4);
}
static inline uint16_t vga_entry(unsigned char uc, uint8_t color) {
return (uint16_t)uc | ((uint16_t)color << 8);
}
void vga_init(void);
void vga_clear(void);
void vga_putc(char c);
void vga_write(const char* str);
void vga_set_color(enum vga_color fg, enum vga_color bg);
void vga_set_cursor(int row, int col);
void vga_get_cursor(int* row, int* col);
void vga_enable_cursor(uint8_t cursor_start, uint8_t cursor_end);
void vga_disable_cursor(void);
#endif // _DRIVERS_VGA_H
+10
View File
@@ -0,0 +1,10 @@
#ifndef _FS_DEVFS_H
#define _FS_DEVFS_H
#include "vfs.h"
void devfs_init(void);
vfs_node_t* devfs_get_root(void);
int devfs_register_device(const char* name, vfs_node_t* dev_node);
#endif // _FS_DEVFS_H
+9
View File
@@ -0,0 +1,9 @@
#ifndef _FS_PROCFS_H
#define _FS_PROCFS_H
#include "vfs.h"
void procfs_init(void);
vfs_node_t* procfs_get_root(void);
#endif // _FS_PROCFS_H
+10
View File
@@ -0,0 +1,10 @@
#ifndef _FS_RAMFS_H
#define _FS_RAMFS_H
#include "vfs.h"
vfs_node_t* ramfs_create_root(void);
vfs_node_t* ramfs_add_file(vfs_node_t* parent, const char* name, const void* content, size_t size);
vfs_node_t* ramfs_add_dir(vfs_node_t* parent, const char* name);
#endif // _FS_RAMFS_H
+85
View File
@@ -0,0 +1,85 @@
#ifndef _FS_VFS_H
#define _FS_VFS_H
#include <kernel/types.h>
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#define FS_FILE 0x01
#define FS_DIRECTORY 0x02
#define FS_CHARDEVICE 0x04
#define FS_BLOCKDEVICE 0x08
#define FS_PIPE 0x10
#define FS_SYMLINK 0x20
#define FS_MOUNTPOINT 0x40
#define O_RDONLY 0x0000
#define O_WRONLY 0x0001
#define O_RDWR 0x0002
#define O_CREAT 0x0040
#define O_TRUNC 0x0200
#define O_APPEND 0x0400
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
struct vfs_node;
typedef ssize_t (*vfs_read_fn_t)(struct vfs_node* node, off_t offset, size_t size, uint8_t* buffer);
typedef ssize_t (*vfs_write_fn_t)(struct vfs_node* node, off_t offset, size_t size, const uint8_t* buffer);
typedef int (*vfs_open_fn_t)(struct vfs_node* node, uint32_t flags);
typedef int (*vfs_close_fn_t)(struct vfs_node* node);
typedef struct vfs_dirent* (*vfs_readdir_fn_t)(struct vfs_node* node, uint32_t index);
typedef struct vfs_node* (*vfs_finddir_fn_t)(struct vfs_node* node, const char* name);
typedef int (*vfs_mkdir_fn_t)(struct vfs_node* node, const char* name, mode_t mode);
typedef int (*vfs_create_fn_t)(struct vfs_node* node, const char* name, mode_t mode);
typedef struct vfs_node {
char name[128];
uint32_t flags;
uint32_t mode;
uid_t uid;
gid_t gid;
size_t length;
ino_t inode;
vfs_read_fn_t read;
vfs_write_fn_t write;
vfs_open_fn_t open;
vfs_close_fn_t close;
vfs_readdir_fn_t readdir;
vfs_finddir_fn_t finddir;
vfs_mkdir_fn_t mkdir;
vfs_create_fn_t create;
struct vfs_node* ptr; // Used for mountpoints / device nodes
} vfs_node_t;
typedef struct vfs_dirent {
char name[128];
ino_t inode;
uint32_t type;
} vfs_dirent_t;
typedef struct {
vfs_node_t* node;
off_t offset;
uint32_t flags;
} file_descriptor_t;
void vfs_init(void);
vfs_node_t* vfs_namei(const char* path);
int vfs_open(const char* path, uint32_t flags);
ssize_t vfs_read(int fd, void* buffer, size_t size);
ssize_t vfs_write(int fd, const void* buffer, size_t size);
off_t vfs_lseek(int fd, off_t offset, int whence);
int vfs_close(int fd);
int vfs_mkdir(const char* path, mode_t mode);
int vfs_create(const char* path, mode_t mode);
vfs_node_t* vfs_get_root(void);
int vfs_mount(const char* path, vfs_node_t* fs_root);
#endif // _FS_VFS_H
+15
View File
@@ -0,0 +1,15 @@
#ifndef _KERNEL_MAIN_H
#define _KERNEL_MAIN_H
#include "types.h"
#include "printk.h"
#include <arch/x86_64/io.h>
#define KERNEL_NAME "SUB-OS"
#define KERNEL_VERSION "0.2.0-lts"
#define KERNEL_ARCH "x86_64"
#define KERNEL_AUTHOR "SUB-OS Development Team"
void kernel_main(void* memory_map, uint64_t memory_map_count);
#endif // _KERNEL_MAIN_H
+9
View File
@@ -0,0 +1,9 @@
#ifndef _KERNEL_PANIC_H
#define _KERNEL_PANIC_H
#include <arch/x86_64/isr.h>
void panic(const char* message);
void panic_with_regs(const char* message, const registers_t* regs);
#endif // _KERNEL_PANIC_H
+48
View File
@@ -0,0 +1,48 @@
#ifndef _KERNEL_PRINTK_H
#define _KERNEL_PRINTK_H
#include <stddef.h>
#include <stdint.h>
#include <stdarg.h>
// Linux-compatible log level prefixes
#define KERN_EMERG "\0010" /* system is unusable */
#define KERN_ALERT "\0011" /* action must be taken immediately */
#define KERN_CRIT "\0012" /* critical conditions */
#define KERN_ERR "\0013" /* error conditions */
#define KERN_WARNING "\0014" /* warning conditions */
#define KERN_NOTICE "\0015" /* normal but significant condition */
#define KERN_INFO "\0016" /* informational */
#define KERN_DEBUG "\0017" /* debug-level messages */
// ANSI Color Escape Sequences
#define ANSI_RESET "\033[0m"
#define ANSI_BOLD "\033[1m"
#define ANSI_BLACK "\033[30m"
#define ANSI_RED "\033[31m"
#define ANSI_GREEN "\033[32m"
#define ANSI_YELLOW "\033[33m"
#define ANSI_BLUE "\033[34m"
#define ANSI_MAGENTA "\033[35m"
#define ANSI_CYAN "\033[36m"
#define ANSI_WHITE "\033[37m"
#define ANSI_BRIGHT_BLACK "\033[90m"
#define ANSI_BRIGHT_RED "\033[91m"
#define ANSI_BRIGHT_GREEN "\033[92m"
#define ANSI_BRIGHT_YELLOW "\033[93m"
#define ANSI_BRIGHT_BLUE "\033[94m"
#define ANSI_BRIGHT_MAGENTA "\033[95m"
#define ANSI_BRIGHT_CYAN "\033[96m"
#define ANSI_BRIGHT_WHITE "\033[97m"
// Printk API
void printk_init(void);
int printk(const char* fmt, ...);
int vprintk(const char* fmt, va_list args);
int kprintf(const char* fmt, ...); // Alias for compatibility
// Kernel Dmesg Ring Buffer API
void dmesg_dump(void);
const char* dmesg_get_buffer(size_t* size_out);
#endif // _KERNEL_PRINTK_H
+13
View File
@@ -0,0 +1,13 @@
#ifndef _KERNEL_SCHED_H
#define _KERNEL_SCHED_H
#include "task.h"
void sched_init(void);
void sched_yield(void);
void sched_schedule(void);
void sched_tick(void);
void sched_add_task(task_t* task);
void sched_remove_task(task_t* task);
#endif // _KERNEL_SCHED_H
+36
View File
@@ -0,0 +1,36 @@
#ifndef _KERNEL_SYNC_H
#define _KERNEL_SYNC_H
#include <stdint.h>
#include <stdbool.h>
typedef struct {
volatile uint32_t lock;
} spinlock_t;
#define SPINLOCK_INIT { .lock = 0 }
static inline void spinlock_init(spinlock_t* lock) {
lock->lock = 0;
}
static inline void spin_lock(spinlock_t* lock) {
while (__atomic_test_and_set(&lock->lock, __ATOMIC_ACQUIRE)) {
__asm__ volatile ("pause");
}
}
static inline void spin_unlock(spinlock_t* lock) {
__atomic_clear(&lock->lock, __ATOMIC_RELEASE);
}
typedef struct {
spinlock_t lock;
volatile int count;
} semaphore_t;
void sem_init(semaphore_t* sem, int value);
void sem_wait(semaphore_t* sem);
void sem_post(semaphore_t* sem);
#endif // _KERNEL_SYNC_H
+36
View File
@@ -0,0 +1,36 @@
#ifndef _KERNEL_TASK_H
#define _KERNEL_TASK_H
#include "types.h"
#include <lib/list.h>
typedef enum {
TASK_STATE_READY,
TASK_STATE_RUNNING,
TASK_STATE_BLOCKED,
TASK_STATE_SLEEPING,
TASK_STATE_ZOMBIE,
TASK_STATE_DEAD
} task_state_t;
typedef struct task_struct {
pid_t pid;
char name[32];
task_state_t state;
uint64_t rsp;
uint64_t stack_base;
size_t stack_size;
uint64_t sleep_until_ticks;
int priority;
int time_slice;
struct list_head list;
} task_t;
typedef void (*task_entry_fn_t)(void* arg);
task_t* task_create(const char* name, task_entry_fn_t entry, void* arg, int priority);
void task_exit(int exit_code);
task_t* task_current(void);
pid_t task_get_pid(void);
#endif // _KERNEL_TASK_H
+30
View File
@@ -0,0 +1,30 @@
#ifndef _KERNEL_TYPES_H
#define _KERNEL_TYPES_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
typedef int32_t pid_t;
typedef int32_t tid_t;
typedef uint32_t uid_t;
typedef uint32_t gid_t;
typedef int64_t off_t;
typedef int64_t ssize_t;
typedef uint32_t mode_t;
typedef uint32_t dev_t;
typedef uint64_t ino_t;
typedef uint64_t time_t;
#ifndef NULL
#define NULL ((void*)0)
#endif
#define ALIGN_UP(addr, align) (((addr) + (align) - 1) & ~((align) - 1))
#define ALIGN_DOWN(addr, align) ((addr) & ~((align) - 1))
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif // _KERNEL_TYPES_H
+26
View File
@@ -0,0 +1,26 @@
#ifndef _LIB_BITMAP_H
#define _LIB_BITMAP_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
typedef uint64_t bitmap_word_t;
#define BITS_PER_WORD (sizeof(bitmap_word_t) * 8)
static inline void bitmap_set(bitmap_word_t* map, size_t bit) {
map[bit / BITS_PER_WORD] |= ((bitmap_word_t)1 << (bit % BITS_PER_WORD));
}
static inline void bitmap_clear(bitmap_word_t* map, size_t bit) {
map[bit / BITS_PER_WORD] &= ~((bitmap_word_t)1 << (bit % BITS_PER_WORD));
}
static inline bool bitmap_test(const bitmap_word_t* map, size_t bit) {
return (map[bit / BITS_PER_WORD] & ((bitmap_word_t)1 << (bit % BITS_PER_WORD))) != 0;
}
int64_t bitmap_find_first_free(const bitmap_word_t* map, size_t total_bits);
int64_t bitmap_find_contiguous_free(const bitmap_word_t* map, size_t total_bits, size_t count);
#endif // _LIB_BITMAP_H
+56
View File
@@ -0,0 +1,56 @@
#ifndef _LIB_LIST_H
#define _LIB_LIST_H
#include <stddef.h>
struct list_head {
struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)
static inline void INIT_LIST_HEAD(struct list_head *list) {
list->next = list;
list->prev = list;
}
static inline void __list_add(struct list_head *new_node,
struct list_head *prev,
struct list_head *next) {
next->prev = new_node;
new_node->next = next;
new_node->prev = prev;
prev->next = new_node;
}
static inline void list_add(struct list_head *new_node, struct list_head *head) {
__list_add(new_node, head, head->next);
}
static inline void list_add_tail(struct list_head *new_node, struct list_head *head) {
__list_add(new_node, head->prev, head);
}
static inline void list_del(struct list_head *entry) {
entry->next->prev = entry->prev;
entry->prev->next = entry->next;
entry->next = NULL;
entry->prev = NULL;
}
static inline int list_empty(const struct list_head *head) {
return head->next == head;
}
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr) - offsetof(type, member)))
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
#endif // _LIB_LIST_H
+12
View File
@@ -0,0 +1,12 @@
#ifndef _LIB_PRINTF_H
#define _LIB_PRINTF_H
#include <stddef.h>
#include <stdarg.h>
int sprintf(char* buf, const char* fmt, ...);
int snprintf(char* buf, size_t size, const char* fmt, ...);
int vsprintf(char* buf, const char* fmt, va_list args);
int vsnprintf(char* buf, size_t size, const char* fmt, va_list args);
#endif // _LIB_PRINTF_H
+33
View File
@@ -0,0 +1,33 @@
#ifndef _LIB_STRING_H
#define _LIB_STRING_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
// Memory functions
void* memset(void* dest, int val, size_t count);
void* memcpy(void* dest, const void* src, size_t count);
void* memmove(void* dest, const void* src, size_t count);
int memcmp(const void* ptr1, const void* ptr2, size_t num);
// String functions
size_t strlen(const char* str);
int strcmp(const char* str1, const char* str2);
int strncmp(const char* str1, const char* str2, size_t num);
char* strcpy(char* dest, const char* src);
char* strncpy(char* dest, const char* src, size_t num);
char* strcat(char* dest, const char* src);
char* strncat(char* dest, const char* src, size_t num);
char* strchr(const char* str, int c);
char* strrchr(const char* str, int c);
char* strstr(const char* haystack, const char* needle);
char* strdup(const char* s);
// Conversion functions
char* itoa(int value, char* str, int base);
char* itoa_hex(uint64_t value, char* str);
int atoi(const char* str);
long strtol(const char* str, char** endptr, int base);
#endif // _LIB_STRING_H
+18
View File
@@ -0,0 +1,18 @@
#ifndef _MM_KMALLOC_H
#define _MM_KMALLOC_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
void heap_init(void);
void* kmalloc(size_t size);
void* kzalloc(size_t size);
void* krealloc(void* ptr, size_t new_size);
void kfree(void* ptr);
size_t heap_get_used_bytes(void);
size_t heap_get_free_bytes(void);
size_t heap_get_total_bytes(void);
#endif // _MM_KMALLOC_H
+36
View File
@@ -0,0 +1,36 @@
#ifndef _MM_PMM_H
#define _MM_PMM_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#define PMM_PAGE_SIZE 4096
// E820 Memory Map entry structure
typedef struct {
uint64_t base;
uint64_t length;
uint32_t type;
uint32_t acpi_attr;
} __attribute__((packed)) e820_entry_t;
#define E820_TYPE_USABLE 1
#define E820_TYPE_RESERVED 2
#define E820_TYPE_ACPI_RECLAIM 3
#define E820_TYPE_ACPI_NVS 4
#define E820_TYPE_BAD 5
void pmm_init(void* memory_map, uint64_t memory_map_count);
void* pmm_alloc_page(void);
void* pmm_alloc_pages(size_t count);
void pmm_free_page(void* page);
void pmm_free_pages(void* page, size_t count);
uint64_t pmm_get_total_pages(void);
uint64_t pmm_get_used_pages(void);
uint64_t pmm_get_free_pages(void);
uint64_t pmm_get_total_memory(void);
uint64_t pmm_get_usable_memory(void);
#endif // _MM_PMM_H
+107
View File
@@ -0,0 +1,107 @@
#ifndef _NET_NET_H
#define _NET_NET_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#define ETHERTYPE_IPV4 0x0800
#define ETHERTYPE_ARP 0x0806
#define IP_PROTO_ICMP 1
#define IP_PROTO_TCP 6
#define IP_PROTO_UDP 17
static inline uint16_t htons(uint16_t host) {
return (uint16_t)((host << 8) | (host >> 8));
}
static inline uint16_t ntohs(uint16_t net) {
return htons(net);
}
static inline uint32_t htonl(uint32_t host) {
return (uint32_t)(((host & 0x000000FF) << 24) |
((host & 0x0000FF00) << 8) |
((host & 0x00FF0000) >> 8) |
((host & 0xFF000000) >> 24));
}
static inline uint32_t ntohl(uint32_t net) {
return htonl(net);
}
typedef struct {
uint8_t dst_mac[6];
uint8_t src_mac[6];
uint16_t ethertype;
} __attribute__((packed)) eth_header_t;
typedef struct {
uint16_t htype;
uint16_t ptype;
uint8_t hlen;
uint8_t plen;
uint16_t opcode;
uint8_t sender_mac[6];
uint32_t sender_ip;
uint8_t target_mac[6];
uint32_t target_ip;
} __attribute__((packed)) arp_header_t;
typedef struct {
uint8_t ihl_version;
uint8_t tos;
uint16_t total_length;
uint16_t id;
uint16_t flags_fragment;
uint8_t ttl;
uint8_t protocol;
uint16_t checksum;
uint32_t src_ip;
uint32_t dst_ip;
} __attribute__((packed)) ip_header_t;
typedef struct {
uint8_t type;
uint8_t code;
uint16_t checksum;
uint16_t id;
uint16_t sequence;
} __attribute__((packed)) icmp_header_t;
typedef struct {
uint16_t src_port;
uint16_t dst_port;
uint16_t length;
uint16_t checksum;
} __attribute__((packed)) udp_header_t;
typedef struct {
char name[16];
uint8_t mac[6];
uint32_t ip;
uint32_t subnet;
uint32_t gateway;
uint32_t dns;
bool is_up;
} net_if_t;
typedef struct {
uint32_t ip;
uint8_t mac[6];
bool valid;
} arp_entry_t;
void net_init(void);
void net_receive(const uint8_t* packet, uint16_t length);
void net_send_eth(const uint8_t* dst_mac, uint16_t ethertype, const void* payload, uint16_t len);
void net_send_ip(uint32_t dst_ip, uint8_t protocol, const void* payload, uint16_t len);
void net_send_arp_req(uint32_t target_ip);
int net_ping(uint32_t target_ip, uint32_t count, uint32_t timeout_ms);
net_if_t* net_get_primary_if(void);
arp_entry_t* net_get_arp_table(int* count_out);
uint32_t ip_parse(const char* ip_str);
void ip_to_str(uint32_t ip, char* buf);
void mac_to_str(const uint8_t* mac, char* buf);
#endif // _NET_NET_H
+26
View File
@@ -0,0 +1,26 @@
#ifndef _USERLAND_LAZYBOX_H
#define _USERLAND_LAZYBOX_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#define LAZYBOX_VERSION "2.0.0-pro"
typedef int (*applet_fn_t)(int argc, char** argv);
typedef struct {
const char* name;
applet_fn_t func;
const char* usage;
const char* desc;
const char* category;
} lazybox_applet_t;
void lazybox_init(void);
int lazybox_main(int argc, char** argv);
bool lazybox_has_applet(const char* name);
int lazybox_run_applet(const char* name, int argc, char** argv);
const lazybox_applet_t* lazybox_get_applets(int* count_out);
#endif // _USERLAND_LAZYBOX_H
+9
View File
@@ -0,0 +1,9 @@
#ifndef _USERLAND_SHELL_H
#define _USERLAND_SHELL_H
#define MAX_COMMAND_LENGTH 256
void shell_init(void);
void shell_run(void);
#endif // _USERLAND_SHELL_H
+112
View File
@@ -0,0 +1,112 @@
#include <kernel/kernel.h>
#include <kernel/printk.h>
#include <kernel/sched.h>
#include <kernel/task.h>
#include <arch/x86_64/gdt.h>
#include <arch/x86_64/idt.h>
#include <arch/x86_64/isr.h>
#include <arch/x86_64/pic.h>
#include <arch/x86_64/pit.h>
#include <arch/x86_64/cpuid.h>
#include <arch/x86_64/paging.h>
#include <mm/pmm.h>
#include <mm/kmalloc.h>
#include <drivers/tty.h>
#include <drivers/serial.h>
#include <drivers/keyboard.h>
#include <drivers/ata.h>
#include <drivers/pci.h>
#include <drivers/e1000.h>
#include <drivers/speaker.h>
#include <fs/vfs.h>
#include <net/net.h>
#include <crypto/crypto.h>
#include <userland/lazybox.h>
#include <userland/shell.h>
void kernel_main(void* memory_map, uint64_t memory_map_count) {
// 1. Initialize Console & Telemetry Serial Port
tty_init();
serial_init();
printk_init();
printk(ANSI_BRIGHT_CYAN "=================================================================\n" ANSI_RESET);
printk(ANSI_BRIGHT_CYAN " SUB-OS 64-Bit Production Monolithic Kernel v%s (%s)\n" ANSI_RESET, KERNEL_VERSION, KERNEL_ARCH);
printk(ANSI_BRIGHT_CYAN "=================================================================\n\n" ANSI_RESET);
// 2. CPU Architecture & Interrupt Initialization
printk(KERN_INFO "[1/11] Initializing 64-Bit Global Descriptor Table (GDT)... ");
gdt_init();
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
printk(KERN_INFO "[2/11] Initializing Interrupt Descriptor Table (IDT & ISRs)... ");
idt_init();
isr_init();
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
printk(KERN_INFO "[3/11] Remapping Dual 8259A PIC Interrupt Controller... ");
pic_init();
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
printk(KERN_INFO "[4/11] Configuring 8254 PIT Timer (100 Hz, 10ms resolution)... ");
pit_init(100);
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
printk(KERN_INFO "[5/11] Initializing PS/2 Keyboard Controller Driver... ");
keyboard_init();
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
// 3. Memory Subsystems
printk(KERN_INFO "[6/11] Initializing Physical Memory Manager (PMM)...\n");
pmm_init(memory_map, memory_map_count);
printk(KERN_INFO "[7/11] Initializing Kernel Dynamic Heap Allocator (4 MB Pool)... ");
heap_init();
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
paging_init();
// 4. Hardware Storage & Bus Enumeration
printk(KERN_INFO "[8/11] Initializing ATA / IDE Hard Disk Controller... ");
if (ata_init()) {
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
} else {
printk(ANSI_YELLOW "No ATA Drive\n" ANSI_RESET);
}
printk(KERN_INFO "[9/11] Enumerating PCI Bus & Network Device Drivers...\n");
pci_init();
if (e1000_init()) {
printk(ANSI_BRIGHT_GREEN " Intel E1000 Gigabit Ethernet Controller Active\n" ANSI_RESET);
net_init();
printk(ANSI_BRIGHT_GREEN " IPv4 / ARP / ICMP Network Protocol Stack Online\n" ANSI_RESET);
} else {
printk(ANSI_YELLOW " No PCI Ethernet Controller detected\n" ANSI_RESET);
}
// 5. Security & Cryptography Engine
prng_seed(0, 0);
// 6. Virtual File System & Task Scheduler
printk(KERN_INFO "[10/11] Mounting Virtual File System (VFS, devfs, procfs)... ");
vfs_init();
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
printk(KERN_INFO "[11/11] Initializing Preemptive Task Scheduler & LazyBox... ");
sched_init();
lazybox_init();
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
// 7. Enable Hardware Interrupts
sti();
printk(ANSI_BRIGHT_GREEN "[INIT] Hardware interrupts active. System ready for userland!\n" ANSI_RESET);
tty_clear();
// 8. Launch Interactive Userland Shell
shell_run();
while (1) {
hlt();
}
}
+33
View File
@@ -0,0 +1,33 @@
#include <kernel/panic.h>
#include <kernel/printk.h>
#include <drivers/tty.h>
#include <arch/x86_64/io.h>
void panic_with_regs(const char* message, const registers_t* regs) {
cli();
printk("\n" ANSI_BRIGHT_RED "================================================================================" ANSI_RESET "\n");
printk(ANSI_BRIGHT_RED " *** KERNEL PANIC - SYSTEM HALTED *** " ANSI_RESET "\n");
printk(ANSI_BRIGHT_RED "================================================================================" ANSI_RESET "\n\n");
printk(ANSI_BRIGHT_WHITE "Reason: " ANSI_YELLOW "%s" ANSI_RESET "\n\n", message ? message : "Unknown Fault");
if (regs) {
printk(ANSI_BRIGHT_CYAN "CPU Register State (x86_64 AMD64 ABI):" ANSI_RESET "\n");
printk(" RIP: %016llx CS: %04llx RFLAGS: %016llx\n", regs->rip, regs->cs, regs->rflags);
printk(" RSP: %016llx SS: %04llx RBP: %016llx\n", regs->rsp, regs->ss, regs->rbp);
printk(" RAX: %016llx RBX: %016llx RCX: %016llx RDX: %016llx\n", regs->rax, regs->rbx, regs->rcx, regs->rdx);
printk(" RSI: %016llx RDI: %016llx R8: %016llx R9: %016llx\n", regs->rsi, regs->rdi, regs->r8, regs->r9);
printk(" R10: %016llx R11: %016llx R12: %016llx R13: %016llx\n", regs->r10, regs->r11, regs->r12, regs->r13);
printk(" R14: %016llx R15: %016llx ERR: %016llx INT: %llu\n", regs->r14, regs->r15, regs->error_code, regs->int_no);
}
printk("\n" ANSI_BRIGHT_YELLOW "Please power off or reset your system." ANSI_RESET "\n");
while (1) {
hlt();
}
}
void panic(const char* message) {
panic_with_regs(message, NULL);
}
+91
View File
@@ -0,0 +1,91 @@
#include <kernel/printk.h>
#include <drivers/tty.h>
#include <drivers/serial.h>
#include <lib/printf.h>
#include <lib/string.h>
#include <kernel/sync.h>
#define DMESG_BUFFER_SIZE 65536 // 64 KB Ring Buffer
static char dmesg_buffer[DMESG_BUFFER_SIZE];
static size_t dmesg_head = 0;
static size_t dmesg_total = 0;
static spinlock_t printk_lock = SPINLOCK_INIT;
void printk_init(void) {
memset(dmesg_buffer, 0, sizeof(dmesg_buffer));
dmesg_head = 0;
dmesg_total = 0;
}
static void dmesg_append(const char* str, size_t len) {
for (size_t i = 0; i < len; i++) {
dmesg_buffer[dmesg_head] = str[i];
dmesg_head = (dmesg_head + 1) % DMESG_BUFFER_SIZE;
if (dmesg_total < DMESG_BUFFER_SIZE) {
dmesg_total++;
}
}
}
int vprintk(const char* fmt, va_list args) {
char buffer[1024];
int len = vsnprintf(buffer, sizeof(buffer), fmt, args);
if (len <= 0) return 0;
spin_lock(&printk_lock);
// Skip loglevel prefix if present (e.g. "\0016")
const char* display_ptr = buffer;
if (buffer[0] == '\001' && buffer[1] >= '0' && buffer[1] <= '7') {
display_ptr += 2;
len -= 2;
}
// 1. Output to active TTY console
tty_write(display_ptr, (size_t)len);
// 2. Output to COM1 serial port for host debugging
for (int i = 0; i < len; i++) {
serial_write_char(display_ptr[i]);
}
// 3. Store in kernel dmesg ring buffer
dmesg_append(display_ptr, (size_t)len);
spin_unlock(&printk_lock);
return len;
}
int printk(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
int ret = vprintk(fmt, args);
va_end(args);
return ret;
}
int kprintf(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
int ret = vprintk(fmt, args);
va_end(args);
return ret;
}
void dmesg_dump(void) {
spin_lock(&printk_lock);
if (dmesg_total < DMESG_BUFFER_SIZE) {
tty_write(dmesg_buffer, dmesg_total);
} else {
// Output from head to end, then 0 to head
tty_write(dmesg_buffer + dmesg_head, DMESG_BUFFER_SIZE - dmesg_head);
tty_write(dmesg_buffer, dmesg_head);
}
spin_unlock(&printk_lock);
}
const char* dmesg_get_buffer(size_t* size_out) {
if (size_out) *size_out = dmesg_total;
return dmesg_buffer;
}
+67
View File
@@ -0,0 +1,67 @@
#include <kernel/sched.h>
#include <kernel/sync.h>
#include <arch/x86_64/pit.h>
static struct list_head ready_queue;
static spinlock_t sched_lock = SPINLOCK_INIT;
extern void task_init_idle(void);
void sched_init(void) {
INIT_LIST_HEAD(&ready_queue);
task_init_idle();
}
void sched_add_task(task_t* task) {
if (!task) return;
spin_lock(&sched_lock);
list_add_tail(&task->list, &ready_queue);
spin_unlock(&sched_lock);
}
void sched_remove_task(task_t* task) {
if (!task) return;
spin_lock(&sched_lock);
list_del(&task->list);
spin_unlock(&sched_lock);
}
void sched_yield(void) {
// Cooperative yield
sched_schedule();
}
void sched_tick(void) {
// Timer tick scheduler hook
task_t* curr = task_current();
if (curr && curr->pid != 0) {
if (--curr->time_slice <= 0) {
curr->time_slice = 10;
sched_schedule();
}
}
}
void sched_schedule(void) {
spin_lock(&sched_lock);
if (list_empty(&ready_queue)) {
spin_unlock(&sched_lock);
return;
}
task_t* next = list_entry(ready_queue.next, task_t, list);
list_del(&next->list);
list_add_tail(&next->list, &ready_queue); // Move to back of round-robin queue
task_t* curr = task_current();
if (curr != next) {
// Context switch logic
next->state = TASK_STATE_RUNNING;
if (curr->state == TASK_STATE_RUNNING) {
curr->state = TASK_STATE_READY;
}
}
spin_unlock(&sched_lock);
}
+26
View File
@@ -0,0 +1,26 @@
#include <kernel/sync.h>
#include <kernel/sched.h>
void sem_init(semaphore_t* sem, int value) {
spinlock_init(&sem->lock);
sem->count = value;
}
void sem_wait(semaphore_t* sem) {
while (1) {
spin_lock(&sem->lock);
if (sem->count > 0) {
sem->count--;
spin_unlock(&sem->lock);
return;
}
spin_unlock(&sem->lock);
sched_yield();
}
}
void sem_post(semaphore_t* sem) {
spin_lock(&sem->lock);
sem->count++;
spin_unlock(&sem->lock);
}
+81
View File
@@ -0,0 +1,81 @@
#include <kernel/task.h>
#include <kernel/sched.h>
#include <mm/kmalloc.h>
#include <lib/string.h>
static pid_t next_pid = 1;
static task_t* current_task = NULL;
static task_t kernel_idle_task;
static void task_wrapper(task_entry_fn_t entry, void* arg) {
if (entry) {
entry(arg);
}
task_exit(0);
}
task_t* task_create(const char* name, task_entry_fn_t entry, void* arg, int priority) {
task_t* task = (task_t*)kzalloc(sizeof(task_t));
if (!task) return NULL;
task->pid = next_pid++;
strncpy(task->name, name ? name : "task", sizeof(task->name) - 1);
task->state = TASK_STATE_READY;
task->priority = priority;
task->time_slice = 10; // 10 ticks = 100ms default
// Allocate 16 KB stack for thread
task->stack_size = 16384;
task->stack_base = (uint64_t)kmalloc(task->stack_size);
if (!task->stack_base) {
kfree(task);
return NULL;
}
uint64_t* stack_top = (uint64_t*)(task->stack_base + task->stack_size);
// Set up initial stack frame for AMD64
*(--stack_top) = (uint64_t)arg; // RDI (arg)
*(--stack_top) = (uint64_t)entry; // RSI (entry function)
*(--stack_top) = (uint64_t)task_wrapper; // RIP
task->rsp = (uint64_t)stack_top;
INIT_LIST_HEAD(&task->list);
sched_add_task(task);
return task;
}
void task_exit(int exit_code) {
(void)exit_code;
if (current_task && current_task->pid != 0) {
current_task->state = TASK_STATE_DEAD;
sched_remove_task(current_task);
sched_yield();
}
while (1) {
__asm__ volatile("hlt");
}
}
task_t* task_current(void) {
return current_task;
}
pid_t task_get_pid(void) {
return current_task ? current_task->pid : 0;
}
void task_set_current(task_t* task) {
current_task = task;
}
void task_init_idle(void) {
memset(&kernel_idle_task, 0, sizeof(task_t));
kernel_idle_task.pid = 0;
strcpy(kernel_idle_task.name, "swapper/0");
kernel_idle_task.state = TASK_STATE_RUNNING;
INIT_LIST_HEAD(&kernel_idle_task.list);
current_task = &kernel_idle_task;
}
+39
View File
@@ -0,0 +1,39 @@
#include <lib/bitmap.h>
int64_t bitmap_find_first_free(const bitmap_word_t* map, size_t total_bits) {
size_t words = (total_bits + BITS_PER_WORD - 1) / BITS_PER_WORD;
for (size_t w = 0; w < words; w++) {
if (map[w] != (bitmap_word_t)~0ULL) {
for (size_t b = 0; b < BITS_PER_WORD; b++) {
size_t bit_idx = w * BITS_PER_WORD + b;
if (bit_idx >= total_bits) return -1;
if (!bitmap_test(map, bit_idx)) {
return (int64_t)bit_idx;
}
}
}
}
return -1;
}
int64_t bitmap_find_contiguous_free(const bitmap_word_t* map, size_t total_bits, size_t count) {
if (count == 0) return -1;
if (count == 1) return bitmap_find_first_free(map, total_bits);
size_t run = 0;
size_t start = 0;
for (size_t i = 0; i < total_bits; i++) {
if (!bitmap_test(map, i)) {
if (run == 0) start = i;
run++;
if (run == count) {
return (int64_t)start;
}
} else {
run = 0;
}
}
return -1;
}
+226
View File
@@ -0,0 +1,226 @@
#include <lib/string.h>
#include <mm/kmalloc.h>
void* memset(void* dest, int val, size_t count) {
uint8_t* ptr = (uint8_t*)dest;
while (count--) {
*ptr++ = (uint8_t)val;
}
return dest;
}
void* memcpy(void* dest, const void* src, size_t count) {
uint8_t* d = (uint8_t*)dest;
const uint8_t* s = (const uint8_t*)src;
while (count--) {
*d++ = *s++;
}
return dest;
}
void* memmove(void* dest, const void* src, size_t count) {
uint8_t* d = (uint8_t*)dest;
const uint8_t* s = (const uint8_t*)src;
if (d < s) {
while (count--) {
*d++ = *s++;
}
} else {
d += count;
s += count;
while (count--) {
*(--d) = *(--s);
}
}
return dest;
}
int memcmp(const void* ptr1, const void* ptr2, size_t num) {
const uint8_t* p1 = (const uint8_t*)ptr1;
const uint8_t* p2 = (const uint8_t*)ptr2;
while (num--) {
if (*p1 != *p2) {
return *p1 - *p2;
}
p1++;
p2++;
}
return 0;
}
size_t strlen(const char* str) {
size_t len = 0;
while (str && str[len]) {
len++;
}
return len;
}
int strcmp(const char* str1, const char* str2) {
if (!str1 || !str2) return (str1 == str2) ? 0 : (str1 ? 1 : -1);
while (*str1 && (*str1 == *str2)) {
str1++;
str2++;
}
return *(const unsigned char*)str1 - *(const unsigned char*)str2;
}
int strncmp(const char* str1, const char* str2, size_t num) {
if (num == 0) return 0;
while (num > 0 && *str1 && (*str1 == *str2)) {
str1++;
str2++;
num--;
}
if (num == 0) return 0;
return *(const unsigned char*)str1 - *(const unsigned char*)str2;
}
char* strcpy(char* dest, const char* src) {
char* orig_dest = dest;
while ((*dest++ = *src++)) {
}
return orig_dest;
}
char* strncpy(char* dest, const char* src, size_t num) {
size_t i;
for (i = 0; i < num && src[i] != '\0'; i++) {
dest[i] = src[i];
}
for (; i < num; i++) {
dest[i] = '\0';
}
return dest;
}
char* strcat(char* dest, const char* src) {
char* rd = dest;
while (*rd) rd++;
while ((*rd++ = *src++));
return dest;
}
char* strncat(char* dest, const char* src, size_t num) {
char* rd = dest;
while (*rd) rd++;
while (num-- && (*rd++ = *src++));
*rd = '\0';
return dest;
}
char* strchr(const char* str, int c) {
if (!str) return NULL;
while (*str) {
if (*str == (char)c) return (char*)str;
str++;
}
if ((char)c == '\0') return (char*)str;
return NULL;
}
char* strrchr(const char* str, int c) {
if (!str) return NULL;
const char* last = NULL;
while (*str) {
if (*str == (char)c) last = str;
str++;
}
if ((char)c == '\0') return (char*)str;
return (char*)last;
}
char* strstr(const char* haystack, const char* needle) {
if (!haystack || !needle) return NULL;
if (*needle == '\0') return (char*)haystack;
size_t needle_len = strlen(needle);
while (*haystack) {
if (*haystack == *needle && strncmp(haystack, needle, needle_len) == 0) {
return (char*)haystack;
}
haystack++;
}
return NULL;
}
char* strdup(const char* s) {
if (!s) return NULL;
size_t len = strlen(s);
char* copy = (char*)kmalloc(len + 1);
if (copy) {
memcpy(copy, s, len + 1);
}
return copy;
}
static void strreverse(char* begin, char* end) {
char aux;
while (end > begin) {
aux = *end;
*end-- = *begin;
*begin++ = aux;
}
}
char* itoa(int value, char* str, int base) {
if (base < 2 || base > 36) {
*str = '\0';
return str;
}
char* ptr = str, *ptr1 = str;
int tmp_value;
if (value < 0 && base == 10) {
value = -value;
}
do {
tmp_value = value;
value /= base;
*ptr++ = "0123456789abcdef"[tmp_value - value * base];
} while (value);
if (tmp_value < 0 && base == 10) {
*ptr++ = '-';
}
*ptr-- = '\0';
strreverse(ptr1, ptr);
return str;
}
char* itoa_hex(uint64_t value, char* str) {
char* ptr = str;
char* ptr1 = str;
if (value == 0) {
*ptr++ = '0';
*ptr = '\0';
return str;
}
while (value > 0) {
uint8_t mod = value % 16;
*ptr++ = "0123456789ABCDEF"[mod];
value /= 16;
}
*ptr-- = '\0';
strreverse(ptr1, ptr);
return str;
}
int atoi(const char* str) {
int res = 0;
int sign = 1;
while (*str == ' ' || *str == '\t') str++;
if (*str == '-') { sign = -1; str++; }
else if (*str == '+') { str++; }
while (*str >= '0' && *str <= '9') {
res = res * 10 + (*str - '0');
str++;
}
return res * sign;
}
+199
View File
@@ -0,0 +1,199 @@
#include <lib/printf.h>
#include <lib/string.h>
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
static int format_number(char* buf, size_t size, uint64_t num, int base, bool is_signed, bool upper, int width, char pad, bool left_align) {
char temp[65];
int pos = 0;
bool negative = false;
if (is_signed && (int64_t)num < 0) {
negative = true;
num = (uint64_t)(-(int64_t)num);
}
const char* digits = upper ? "0123456789ABCDEF" : "0123456789abcdef";
if (num == 0) {
temp[pos++] = '0';
} else {
while (num > 0) {
temp[pos++] = digits[num % base];
num /= base;
}
}
if (negative) {
temp[pos++] = '-';
}
int total_len = pos;
int pad_count = (width > total_len) ? (width - total_len) : 0;
int written = 0;
// Right-aligned padding
if (!left_align) {
while (pad_count > 0 && (size_t)written < size - 1) {
buf[written++] = pad;
pad_count--;
}
}
// Write number in reverse
for (int i = pos - 1; i >= 0 && (size_t)written < size - 1; i--) {
buf[written++] = temp[i];
}
// Left-aligned padding
if (left_align) {
while (pad_count > 0 && (size_t)written < size - 1) {
buf[written++] = ' ';
pad_count--;
}
}
return written;
}
int vsnprintf(char* buf, size_t size, const char* fmt, va_list args) {
if (!buf || size == 0) return 0;
size_t out_idx = 0;
for (size_t i = 0; fmt[i] != '\0' && out_idx < size - 1; i++) {
if (fmt[i] != '%') {
buf[out_idx++] = fmt[i];
continue;
}
i++; // Skip '%'
if (fmt[i] == '\0') break;
// Flags
bool left_align = false;
if (fmt[i] == '-') {
left_align = true;
i++;
}
char pad = ' ';
if (fmt[i] == '0' && !left_align) {
pad = '0';
i++;
}
// Width
int width = 0;
while (fmt[i] >= '0' && fmt[i] <= '9') {
width = width * 10 + (fmt[i] - '0');
i++;
}
// Length modifiers
bool is_long = false;
bool is_long_long = false;
if (fmt[i] == 'l') {
is_long = true;
i++;
if (fmt[i] == 'l') {
is_long_long = true;
i++;
}
}
switch (fmt[i]) {
case 'c': {
char c = (char)va_arg(args, int);
if (out_idx < size - 1) buf[out_idx++] = c;
break;
}
case 's': {
const char* s = va_arg(args, const char*);
if (!s) s = "(null)";
size_t s_len = strlen(s);
int pad_count = (width > (int)s_len) ? (width - (int)s_len) : 0;
if (!left_align) {
while (pad_count > 0 && out_idx < size - 1) {
buf[out_idx++] = ' ';
pad_count--;
}
}
while (*s && out_idx < size - 1) {
buf[out_idx++] = *s++;
}
if (left_align) {
while (pad_count > 0 && out_idx < size - 1) {
buf[out_idx++] = ' ';
pad_count--;
}
}
break;
}
case 'd':
case 'i': {
int64_t val = is_long_long ? va_arg(args, int64_t) : (is_long ? va_arg(args, long) : va_arg(args, int));
out_idx += format_number(buf + out_idx, size - out_idx, (uint64_t)val, 10, true, false, width, pad, left_align);
break;
}
case 'u': {
uint64_t val = is_long_long ? va_arg(args, uint64_t) : (is_long ? va_arg(args, unsigned long) : va_arg(args, unsigned int));
out_idx += format_number(buf + out_idx, size - out_idx, val, 10, false, false, width, pad, left_align);
break;
}
case 'x': {
uint64_t val = is_long_long ? va_arg(args, uint64_t) : (is_long ? va_arg(args, unsigned long) : va_arg(args, unsigned int));
out_idx += format_number(buf + out_idx, size - out_idx, val, 16, false, false, width, pad, left_align);
break;
}
case 'X': {
uint64_t val = is_long_long ? va_arg(args, uint64_t) : (is_long ? va_arg(args, unsigned long) : va_arg(args, unsigned int));
out_idx += format_number(buf + out_idx, size - out_idx, val, 16, false, true, width, pad, left_align);
break;
}
case 'p': {
uint64_t ptr = (uint64_t)va_arg(args, void*);
if (out_idx < size - 3) {
buf[out_idx++] = '0';
buf[out_idx++] = 'x';
}
out_idx += format_number(buf + out_idx, size - out_idx, ptr, 16, false, false, 16, '0', false);
break;
}
case '%': {
if (out_idx < size - 1) buf[out_idx++] = '%';
break;
}
default:
if (out_idx < size - 1) buf[out_idx++] = fmt[i];
break;
}
}
buf[out_idx] = '\0';
return (int)out_idx;
}
int sprintf(char* buf, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
int ret = vsnprintf(buf, 4096, fmt, args);
va_end(args);
return ret;
}
int snprintf(char* buf, size_t size, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
int ret = vsnprintf(buf, size, fmt, args);
va_end(args);
return ret;
}
int vsprintf(char* buf, const char* fmt, va_list args) {
return vsnprintf(buf, 4096, fmt, args);
}
+41
View File
@@ -0,0 +1,41 @@
ENTRY(kernel_entry)
SECTIONS
{
/* Kernel starts at 1MB */
. = 0x100000;
_kernel_start = .;
.text : ALIGN(4K)
{
*(.text*)
}
.rodata : ALIGN(4K)
{
*(.rodata*)
}
.data : ALIGN(4K)
{
*(.data*)
}
.bss : ALIGN(4K)
{
PROVIDE(__bss_start = .);
*(COMMON)
*(.bss*)
PROVIDE(__bss_end = .);
}
.stack : ALIGN(4K)
{
PROVIDE(stack_bottom = .);
. += 0x10000; /* 64 KB Dedicated Kernel Stack */
PROVIDE(stack_top = .);
}
_kernel_end = .;
}
+164
View File
@@ -0,0 +1,164 @@
#include <mm/kmalloc.h>
#include <mm/pmm.h>
#include <lib/string.h>
#include <kernel/sync.h>
#include <kernel/printk.h>
#define HEAP_MAGIC 0x53554248 // "SUBH"
#define HEAP_INITIAL_PAGES 1024 // 4 MB initial kernel heap
typedef struct heap_block {
uint32_t magic;
bool is_free;
size_t size; // payload size in bytes
struct heap_block* next;
struct heap_block* prev;
} heap_block_t;
#define BLOCK_HEADER_SIZE sizeof(heap_block_t)
static heap_block_t* heap_start = NULL;
static size_t heap_used_bytes = 0;
static size_t heap_free_bytes = 0;
static size_t heap_total_bytes = 0;
static spinlock_t heap_lock = SPINLOCK_INIT;
void heap_init(void) {
void* initial_mem = pmm_alloc_pages(HEAP_INITIAL_PAGES);
if (!initial_mem) {
printk(KERN_ERR "Heap: Failed to allocate initial %d pages!\n", HEAP_INITIAL_PAGES);
return;
}
heap_start = (heap_block_t*)initial_mem;
heap_total_bytes = HEAP_INITIAL_PAGES * PMM_PAGE_SIZE;
heap_start->magic = HEAP_MAGIC;
heap_start->is_free = true;
heap_start->size = heap_total_bytes - BLOCK_HEADER_SIZE;
heap_start->next = NULL;
heap_start->prev = NULL;
heap_used_bytes = 0;
heap_free_bytes = heap_start->size;
}
void* kmalloc(size_t size) {
if (size == 0) return NULL;
// Align size to 16 bytes for SIMD/64-bit performance
size = (size + 15) & ~15;
spin_lock(&heap_lock);
heap_block_t* curr = heap_start;
while (curr) {
if (curr->magic != HEAP_MAGIC) {
printk(KERN_ERR "Heap Corruption detected at %p!\n", curr);
spin_unlock(&heap_lock);
return NULL;
}
if (curr->is_free && curr->size >= size) {
// Check if block can be split
if (curr->size >= size + BLOCK_HEADER_SIZE + 16) {
heap_block_t* new_block = (heap_block_t*)((uint8_t*)curr + BLOCK_HEADER_SIZE + size);
new_block->magic = HEAP_MAGIC;
new_block->is_free = true;
new_block->size = curr->size - size - BLOCK_HEADER_SIZE;
new_block->next = curr->next;
new_block->prev = curr;
if (curr->next) {
curr->next->prev = new_block;
}
curr->next = new_block;
curr->size = size;
}
curr->is_free = false;
heap_used_bytes += curr->size;
heap_free_bytes -= curr->size;
spin_unlock(&heap_lock);
return (void*)((uint8_t*)curr + BLOCK_HEADER_SIZE);
}
curr = curr->next;
}
spin_unlock(&heap_lock);
printk(KERN_WARNING "Heap: Out of memory for size %llu bytes!\n", size);
return NULL;
}
void* kzalloc(size_t size) {
void* ptr = kmalloc(size);
if (ptr) {
memset(ptr, 0, size);
}
return ptr;
}
void kfree(void* ptr) {
if (!ptr) return;
spin_lock(&heap_lock);
heap_block_t* block = (heap_block_t*)((uint8_t*)ptr - BLOCK_HEADER_SIZE);
if (block->magic != HEAP_MAGIC) {
printk(KERN_ERR "kfree: Invalid pointer / heap corruption %p!\n", ptr);
spin_unlock(&heap_lock);
return;
}
block->is_free = true;
heap_used_bytes -= block->size;
heap_free_bytes += block->size;
// Coalesce with next block if free
if (block->next && block->next->is_free) {
block->size += BLOCK_HEADER_SIZE + block->next->size;
block->next = block->next->next;
if (block->next) {
block->next->prev = block;
}
}
// Coalesce with prev block if free
if (block->prev && block->prev->is_free) {
block->prev->size += BLOCK_HEADER_SIZE + block->size;
block->prev->next = block->next;
if (block->next) {
block->next->prev = block->prev;
}
}
spin_unlock(&heap_lock);
}
void* krealloc(void* ptr, size_t new_size) {
if (!ptr) return kmalloc(new_size);
if (new_size == 0) {
kfree(ptr);
return NULL;
}
heap_block_t* block = (heap_block_t*)((uint8_t*)ptr - BLOCK_HEADER_SIZE);
if (block->magic != HEAP_MAGIC) return NULL;
if (block->size >= new_size) {
return ptr;
}
void* new_ptr = kmalloc(new_size);
if (new_ptr) {
memcpy(new_ptr, ptr, block->size);
kfree(ptr);
}
return new_ptr;
}
size_t heap_get_used_bytes(void) { return heap_used_bytes; }
size_t heap_get_free_bytes(void) { return heap_free_bytes; }
size_t heap_get_total_bytes(void) { return heap_total_bytes; }
+128
View File
@@ -0,0 +1,128 @@
#include <mm/pmm.h>
#include <lib/bitmap.h>
#include <lib/string.h>
#include <kernel/printk.h>
#define MAX_PHYSICAL_PAGES (1024 * 1024) // 4 GB (1,048,576 4KB pages)
#define BITMAP_SIZE (MAX_PHYSICAL_PAGES / 64)
static bitmap_word_t page_bitmap[BITMAP_SIZE];
static uint64_t total_pages = 0;
static uint64_t used_pages = 0;
static uint64_t total_memory_bytes = 0;
static uint64_t usable_memory_bytes = 0;
void pmm_init(void* memory_map, uint64_t memory_map_count) {
// Initially mark all pages as reserved (1 in bitmap)
memset(page_bitmap, 0xFF, sizeof(page_bitmap));
total_pages = 0;
used_pages = 0;
total_memory_bytes = 0;
usable_memory_bytes = 0;
e820_entry_t* entries = (e820_entry_t*)memory_map;
for (uint64_t i = 0; i < memory_map_count; i++) {
uint64_t base = entries[i].base;
uint64_t length = entries[i].length;
uint32_t type = entries[i].type;
total_memory_bytes += length;
if (type == E820_TYPE_USABLE) {
usable_memory_bytes += length;
uint64_t start_page = base / PMM_PAGE_SIZE;
uint64_t page_count = length / PMM_PAGE_SIZE;
for (uint64_t p = 0; p < page_count; p++) {
uint64_t page = start_page + p;
if (page < MAX_PHYSICAL_PAGES) {
bitmap_clear(page_bitmap, page);
if (page >= total_pages) {
total_pages = page + 1;
}
}
}
}
}
// Fallback if no E820 usable regions
if (usable_memory_bytes == 0 || total_pages == 0) {
total_pages = 32768; // 128 MB
total_memory_bytes = 128ULL * 1024 * 1024;
usable_memory_bytes = 128ULL * 1024 * 1024;
for (uint64_t p = 0; p < total_pages; p++) {
bitmap_clear(page_bitmap, p);
}
}
// Reserve lower 4 MB (bootloader, page tables, kernel image)
size_t kernel_reserved_pages = (4 * 1024 * 1024) / PMM_PAGE_SIZE; // 1024 pages
for (size_t p = 0; p < kernel_reserved_pages; p++) {
bitmap_set(page_bitmap, p);
}
// Count actual used pages (bits set in bitmap up to total_pages)
used_pages = 0;
for (uint64_t p = 0; p < total_pages; p++) {
if (bitmap_test(page_bitmap, p)) {
used_pages++;
}
}
printk(KERN_INFO "PMM: Total Memory: %llu MB, Usable: %llu MB, Free Pages: %llu\n",
total_memory_bytes / (1024 * 1024),
usable_memory_bytes / (1024 * 1024),
pmm_get_free_pages());
}
void* pmm_alloc_page(void) {
int64_t page = bitmap_find_first_free(page_bitmap, total_pages);
if (page < 0) {
return NULL; // Out of memory
}
bitmap_set(page_bitmap, (size_t)page);
used_pages++;
return (void*)(page * PMM_PAGE_SIZE);
}
void* pmm_alloc_pages(size_t count) {
if (count == 0) return NULL;
if (count == 1) return pmm_alloc_page();
int64_t start_page = bitmap_find_contiguous_free(page_bitmap, total_pages, count);
if (start_page < 0) return NULL;
for (size_t i = 0; i < count; i++) {
bitmap_set(page_bitmap, (size_t)(start_page + i));
}
used_pages += count;
return (void*)(start_page * PMM_PAGE_SIZE);
}
void pmm_free_page(void* page) {
uint64_t page_idx = (uint64_t)page / PMM_PAGE_SIZE;
if (page_idx < total_pages && bitmap_test(page_bitmap, page_idx)) {
bitmap_clear(page_bitmap, page_idx);
used_pages--;
}
}
void pmm_free_pages(void* page, size_t count) {
uint64_t start_idx = (uint64_t)page / PMM_PAGE_SIZE;
for (size_t i = 0; i < count; i++) {
uint64_t page_idx = start_idx + i;
if (page_idx < total_pages && bitmap_test(page_bitmap, page_idx)) {
bitmap_clear(page_bitmap, page_idx);
used_pages--;
}
}
}
uint64_t pmm_get_total_pages(void) { return total_pages; }
uint64_t pmm_get_used_pages(void) { return used_pages; }
uint64_t pmm_get_free_pages(void) { return (total_pages > used_pages) ? (total_pages - used_pages) : 0; }
uint64_t pmm_get_total_memory(void) { return total_memory_bytes; }
uint64_t pmm_get_usable_memory(void) { return usable_memory_bytes; }
+323
View File
@@ -0,0 +1,323 @@
#include <net/net.h>
#include <drivers/e1000.h>
#include <lib/string.h>
#include <lib/printf.h>
#include <mm/kmalloc.h>
#include <arch/x86_64/pit.h>
#include <kernel/printk.h>
#define MAX_ARP_ENTRIES 16
static net_if_t primary_if;
static arp_entry_t arp_cache[MAX_ARP_ENTRIES];
static int arp_cache_count = 0;
static volatile bool ping_received = false;
static volatile uint16_t ping_id = 0;
static volatile uint16_t ping_seq = 0;
static volatile uint64_t ping_time = 0;
static const uint8_t eth_broadcast[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
static uint16_t net_checksum(const void* data, size_t len) {
const uint16_t* ptr = (const uint16_t*)data;
uint32_t sum = 0;
while (len > 1) {
sum += *ptr++;
len -= 2;
}
if (len > 0) {
sum += *(const uint8_t*)ptr;
}
while (sum >> 16) {
sum = (sum & 0xFFFF) + (sum >> 16);
}
return (uint16_t)(~sum);
}
void ip_to_str(uint32_t ip, char* buf) {
uint8_t* p = (uint8_t*)&ip;
sprintf(buf, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
}
void mac_to_str(const uint8_t* mac, char* buf) {
sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
uint32_t ip_parse(const char* ip_str) {
if (!ip_str) return 0;
uint32_t parts[4] = {0, 0, 0, 0};
int idx = 0;
while (*ip_str && idx < 4) {
if (*ip_str >= '0' && *ip_str <= '9') {
parts[idx] = parts[idx] * 10 + (*ip_str - '0');
} else if (*ip_str == '.') {
idx++;
}
ip_str++;
}
if (idx != 3) return 0;
return parts[0] | (parts[1] << 8) | (parts[2] << 16) | (parts[3] << 24);
}
static void arp_cache_insert(uint32_t ip, const uint8_t* mac) {
for (int i = 0; i < arp_cache_count; i++) {
if (arp_cache[i].ip == ip) {
memcpy(arp_cache[i].mac, mac, 6);
arp_cache[i].valid = true;
return;
}
}
if (arp_cache_count < MAX_ARP_ENTRIES) {
arp_cache[arp_cache_count].ip = ip;
memcpy(arp_cache[arp_cache_count].mac, mac, 6);
arp_cache[arp_cache_count].valid = true;
arp_cache_count++;
} else {
arp_cache[0].ip = ip;
memcpy(arp_cache[0].mac, mac, 6);
arp_cache[0].valid = true;
}
}
static bool arp_cache_lookup(uint32_t ip, uint8_t* mac_out) {
for (int i = 0; i < arp_cache_count; i++) {
if (arp_cache[i].valid && arp_cache[i].ip == ip) {
memcpy(mac_out, arp_cache[i].mac, 6);
return true;
}
}
return false;
}
void net_send_eth(const uint8_t* dst_mac, uint16_t ethertype, const void* payload, uint16_t len) {
uint16_t total_len = sizeof(eth_header_t) + len;
if (total_len < 60) total_len = 60; // Minimum Ethernet frame
uint8_t* frame = (uint8_t*)kzalloc(total_len);
if (!frame) return;
eth_header_t* eth = (eth_header_t*)frame;
memcpy(eth->dst_mac, dst_mac, 6);
memcpy(eth->src_mac, primary_if.mac, 6);
eth->ethertype = htons(ethertype);
if (payload && len > 0) {
memcpy(frame + sizeof(eth_header_t), payload, len);
}
e1000_send(frame, total_len);
kfree(frame);
}
void net_send_arp_req(uint32_t target_ip) {
arp_header_t arp;
arp.htype = htons(1);
arp.ptype = htons(ETHERTYPE_IPV4);
arp.hlen = 6;
arp.plen = 4;
arp.opcode = htons(1); // ARP Request
memcpy(arp.sender_mac, primary_if.mac, 6);
arp.sender_ip = primary_if.ip;
memset(arp.target_mac, 0, 6);
arp.target_ip = target_ip;
net_send_eth(eth_broadcast, ETHERTYPE_ARP, &arp, sizeof(arp_header_t));
}
void net_send_ip(uint32_t dst_ip, uint8_t protocol, const void* payload, uint16_t len) {
uint8_t dst_mac[6];
uint32_t lookup_ip = dst_ip;
if ((dst_ip & primary_if.subnet) != (primary_if.ip & primary_if.subnet)) {
lookup_ip = primary_if.gateway;
}
if (!arp_cache_lookup(lookup_ip, dst_mac)) {
net_send_arp_req(lookup_ip);
memcpy(dst_mac, eth_broadcast, 6);
}
uint16_t ip_len = sizeof(ip_header_t) + len;
uint8_t* buf = (uint8_t*)kmalloc(ip_len);
if (!buf) return;
ip_header_t* ip = (ip_header_t*)buf;
ip->ihl_version = 0x45;
ip->tos = 0;
ip->total_length = htons(ip_len);
ip->id = htons((uint16_t)pit_get_ticks());
ip->flags_fragment = htons(0x4000);
ip->ttl = 64;
ip->protocol = protocol;
ip->checksum = 0;
ip->src_ip = primary_if.ip;
ip->dst_ip = dst_ip;
ip->checksum = net_checksum(ip, sizeof(ip_header_t));
if (payload && len > 0) {
memcpy(buf + sizeof(ip_header_t), payload, len);
}
net_send_eth(dst_mac, ETHERTYPE_IPV4, buf, ip_len);
kfree(buf);
}
static void net_handle_arp(const uint8_t* data, uint16_t len) {
if (len < sizeof(arp_header_t)) return;
const arp_header_t* arp = (const arp_header_t*)data;
uint16_t op = ntohs(arp->opcode);
arp_cache_insert(arp->sender_ip, arp->sender_mac);
if (op == 1) { // Request for our IP
if (arp->target_ip == primary_if.ip) {
arp_header_t reply;
reply.htype = htons(1);
reply.ptype = htons(ETHERTYPE_IPV4);
reply.hlen = 6;
reply.plen = 4;
reply.opcode = htons(2); // Reply
memcpy(reply.sender_mac, primary_if.mac, 6);
reply.sender_ip = primary_if.ip;
memcpy(reply.target_mac, arp->sender_mac, 6);
reply.target_ip = arp->sender_ip;
net_send_eth(arp->sender_mac, ETHERTYPE_ARP, &reply, sizeof(arp_header_t));
}
}
}
static void net_handle_icmp(uint32_t src_ip, const uint8_t* data, uint16_t len) {
if (len < sizeof(icmp_header_t)) return;
const icmp_header_t* icmp = (const icmp_header_t*)data;
if (icmp->type == 8) { // Echo Request -> Auto-Reply
uint8_t* rep = (uint8_t*)kmalloc(len);
if (!rep) return;
memcpy(rep, data, len);
icmp_header_t* rep_icmp = (icmp_header_t*)rep;
rep_icmp->type = 0; // Echo Reply
rep_icmp->code = 0;
rep_icmp->checksum = 0;
rep_icmp->checksum = net_checksum(rep, len);
net_send_ip(src_ip, IP_PROTO_ICMP, rep, len);
kfree(rep);
} else if (icmp->type == 0) { // Echo Reply
ping_id = ntohs(icmp->id);
ping_seq = ntohs(icmp->sequence);
ping_time = pit_get_ticks();
ping_received = true;
}
}
void net_receive(const uint8_t* packet, uint16_t length) {
if (!packet || length < sizeof(eth_header_t)) return;
const eth_header_t* eth = (const eth_header_t*)packet;
uint16_t type = ntohs(eth->ethertype);
const uint8_t* payload = packet + sizeof(eth_header_t);
uint16_t payload_len = length - sizeof(eth_header_t);
if (type == ETHERTYPE_ARP) {
net_handle_arp(payload, payload_len);
} else if (type == ETHERTYPE_IPV4) {
if (payload_len >= sizeof(ip_header_t)) {
const ip_header_t* ip = (const ip_header_t*)payload;
uint8_t ihl = (ip->ihl_version & 0x0F) * 4;
if (payload_len >= ihl) {
if (ip->protocol == IP_PROTO_ICMP) {
net_handle_icmp(ip->src_ip, payload + ihl, payload_len - ihl);
}
}
}
}
}
int net_ping(uint32_t target_ip, uint32_t count, uint32_t timeout_ms) {
char target_str[16];
ip_to_str(target_ip, target_str);
printk(KERN_INFO "PING %s (56 data bytes):\n", target_str);
int received = 0;
uint16_t p_id = 0x5355; // 'SU'
for (uint32_t seq = 1; seq <= count; seq++) {
ping_received = false;
uint64_t t_start = pit_get_ticks();
const char* msg = "SUB-OS ICMP 2026";
uint16_t msg_len = (uint16_t)strlen(msg);
uint16_t icmp_sz = sizeof(icmp_header_t) + msg_len;
uint8_t* ibuf = (uint8_t*)kmalloc(icmp_sz);
if (ibuf) {
icmp_header_t* icmp = (icmp_header_t*)ibuf;
icmp->type = 8;
icmp->code = 0;
icmp->checksum = 0;
icmp->id = htons(p_id);
icmp->sequence = htons((uint16_t)seq);
memcpy(ibuf + sizeof(icmp_header_t), msg, msg_len);
icmp->checksum = net_checksum(ibuf, icmp_sz);
net_send_ip(target_ip, IP_PROTO_ICMP, ibuf, icmp_sz);
kfree(ibuf);
}
uint64_t wait_ticks = timeout_ms / 10;
if (wait_ticks == 0) wait_ticks = 100;
while (!ping_received && (pit_get_ticks() - t_start < wait_ticks)) {
__asm__ volatile ("hlt");
}
if (ping_received && ping_id == p_id && ping_seq == seq) {
uint64_t elapsed_ms = (ping_time - t_start) * 10;
printk(KERN_INFO "64 bytes from %s: icmp_seq=%u ttl=64 time=%llu ms\n", target_str, seq, elapsed_ms);
received++;
} else {
printk(KERN_INFO "Request timeout for icmp_seq %u\n", seq);
}
pit_sleep(400);
}
printk(KERN_INFO "--- %s ping statistics ---\n", target_str);
printk(KERN_INFO "%u packets transmitted, %d received, %u%% packet loss\n",
count, received, ((count - received) * 100) / count);
return received;
}
void net_init(void) {
strcpy(primary_if.name, "eth0");
e1000_get_mac(primary_if.mac);
primary_if.ip = ip_parse("10.0.2.15");
primary_if.gateway = ip_parse("10.0.2.2");
primary_if.subnet = ip_parse("255.255.255.0");
primary_if.dns = ip_parse("10.0.2.3");
primary_if.is_up = true;
// Seed gateway in ARP cache
uint8_t qemu_gw[6] = {0x52, 0x54, 0x00, 0x12, 0x34, 0x56};
arp_cache_insert(primary_if.gateway, qemu_gw);
printk(KERN_INFO "NET: eth0 configured (IP: 10.0.2.15, GW: 10.0.2.2, Mask: 255.255.255.0)\n");
}
net_if_t* net_get_primary_if(void) {
return &primary_if;
}
arp_entry_t* net_get_arp_table(int* count_out) {
if (count_out) *count_out = arp_cache_count;
return arp_cache;
}
+115
View File
@@ -0,0 +1,115 @@
#!/bin/bash
# =============================================================================
# SUB-OS Cross-Compiler Build Script
# Builds x86_64-elf-gcc and x86_64-elf-binutils from source
# =============================================================================
set -e
# Configuration
export TARGET=x86_64-elf
export PREFIX="/usr/local/cross"
export PATH="$PREFIX/bin:$PATH"
BINUTILS_VERSION="2.42"
GCC_VERSION="13.3.0"
BUILD_DIR="/tmp/cross-compiler-build"
JOBS=$(nproc)
echo "============================================"
echo " Building x86_64-elf Cross-Compiler"
echo "============================================"
echo " Target: $TARGET"
echo " Prefix: $PREFIX"
echo " Binutils: $BINUTILS_VERSION"
echo " GCC: $GCC_VERSION"
echo " Jobs: $JOBS"
echo "============================================"
# Create directories
sudo mkdir -p "$PREFIX"
mkdir -p "$BUILD_DIR"
cd "$BUILD_DIR"
# ---- Step 1: Download sources ----
echo ""
echo "[1/4] Downloading sources..."
if [ ! -f "binutils-${BINUTILS_VERSION}.tar.xz" ]; then
curl -LO "https://ftp.gnu.org/gnu/binutils/binutils-${BINUTILS_VERSION}.tar.xz"
fi
if [ ! -f "gcc-${GCC_VERSION}.tar.xz" ]; then
curl -LO "https://ftp.gnu.org/gnu/gcc/gcc-${GCC_VERSION}/gcc-${GCC_VERSION}.tar.xz"
fi
# ---- Step 2: Extract sources ----
echo ""
echo "[2/4] Extracting sources..."
if [ ! -d "binutils-${BINUTILS_VERSION}" ]; then
tar xf "binutils-${BINUTILS_VERSION}.tar.xz"
fi
if [ ! -d "gcc-${GCC_VERSION}" ]; then
tar xf "gcc-${GCC_VERSION}.tar.xz"
fi
# ---- Step 3: Build Binutils ----
echo ""
echo "[3/4] Building binutils for ${TARGET}..."
mkdir -p build-binutils
cd build-binutils
../binutils-${BINUTILS_VERSION}/configure \
--target=$TARGET \
--prefix="$PREFIX" \
--with-sysroot \
--disable-nls \
--disable-werror
make -j$JOBS
sudo make install
cd "$BUILD_DIR"
# ---- Step 4: Build GCC ----
echo ""
echo "[4/4] Building GCC for ${TARGET}..."
mkdir -p build-gcc
cd build-gcc
../gcc-${GCC_VERSION}/configure \
--target=$TARGET \
--prefix="$PREFIX" \
--disable-nls \
--enable-languages=c \
--without-headers
make -j$JOBS all-gcc
make -j$JOBS all-target-libgcc
sudo make install-gcc
sudo make install-target-libgcc
cd "$BUILD_DIR"
# ---- Verify ----
echo ""
echo "============================================"
echo " Cross-Compiler Build Complete!"
echo "============================================"
echo ""
$PREFIX/bin/$TARGET-gcc --version
$PREFIX/bin/$TARGET-ld --version | head -1
echo ""
echo "Installed to: $PREFIX/bin/"
echo ""
echo "Add to your PATH:"
echo " export PATH=\"$PREFIX/bin:\$PATH\""
echo ""
echo "Or add to ~/.bashrc for persistence:"
echo " echo 'export PATH=\"$PREFIX/bin:\$PATH\"' >> ~/.bashrc"
echo "============================================"
Executable
+40
View File
@@ -0,0 +1,40 @@
#!/bin/bash
echo "Setting up SUB-OS build environment..."
if [ -f /etc/os-release ]; then
. /etc/os-release
OS=$ID
else
echo "Cannot detect OS. Please manually install dependencies."
exit 1
fi
case $OS in
ubuntu|debian)
echo "Detected Debian/Ubuntu-based OS."
sudo apt-get update
sudo apt-get install -y nasm gcc binutils make qemu-system-x86
;;
fedora)
echo "Detected Fedora."
sudo dnf install -y nasm gcc binutils make qemu-system-x86
;;
arch)
echo "Detected Arch Linux."
sudo pacman -Sy --noconfirm nasm gcc binutils make qemu-system-x86
;;
*)
echo "Unsupported OS: $OS. Please install: nasm, gcc, binutils, make, qemu-system-x86."
;;
esac
if ! command -v x86_64-elf-gcc &> /dev/null; then
echo ""
echo "WARNING: x86_64-elf-gcc (cross-compiler) not found in PATH."
echo "The Makefile will fallback to the default gcc."
echo "For the best results, it is highly recommended to build an x86_64-elf GCC cross-compiler."
echo "Instructions to build a cross-compiler: https://wiki.osdev.org/GCC_Cross-Compiler"
fi
echo "Setup script finished!"
+456
View File
@@ -0,0 +1,456 @@
#include <userland/lazybox.h>
#include <fs/vfs.h>
#include <net/net.h>
#include <drivers/e1000.h>
#include <drivers/ata.h>
#include <drivers/tty.h>
#include <crypto/crypto.h>
#include <mm/pmm.h>
#include <mm/kmalloc.h>
#include <arch/x86_64/pit.h>
#include <arch/x86_64/cpuid.h>
#include <kernel/printk.h>
#include <lib/string.h>
#include <lib/printf.h>
// -------------------------------------------------------------
// Core Utilities
// -------------------------------------------------------------
static int applet_ls(int argc, char** argv) {
const char* path = (argc >= 2) ? argv[1] : "/";
vfs_node_t* dir = vfs_namei(path);
if (!dir) {
printk(KERN_ERR "ls: cannot access '%s': No such file or directory\n", path);
return 1;
}
if (!(dir->flags & FS_DIRECTORY)) {
printk(KERN_INFO "%s\n", path);
return 0;
}
printk(ANSI_BRIGHT_CYAN "Type Size (B) Inode Name\n" ANSI_RESET);
printk("-----------------------------------------\n");
uint32_t idx = 0;
struct vfs_dirent* ent;
while ((ent = dir->readdir(dir, idx++)) != NULL) {
const char* color = ANSI_WHITE;
const char* type_str = "FILE ";
if (ent->type & FS_DIRECTORY) {
color = ANSI_BRIGHT_BLUE;
type_str = "DIR ";
} else if (ent->type & FS_CHARDEVICE) {
color = ANSI_BRIGHT_YELLOW;
type_str = "CHR ";
}
vfs_node_t* child = dir->finddir ? dir->finddir(dir, ent->name) : NULL;
size_t sz = child ? child->length : 0;
printk("%s %8llu %6llu %s%s" ANSI_RESET "\n",
type_str, sz, ent->inode, color, ent->name);
}
return 0;
}
static int applet_cat(int argc, char** argv) {
if (argc < 2) {
printk(KERN_INFO "Usage: cat <file>\n");
return 1;
}
for (int i = 1; i < argc; i++) {
int fd = vfs_open(argv[i], O_RDONLY);
if (fd < 0) {
printk(KERN_ERR "cat: %s: No such file or directory\n", argv[i]);
continue;
}
char buf[512];
ssize_t bytes;
while ((bytes = vfs_read(fd, buf, sizeof(buf) - 1)) > 0) {
buf[bytes] = '\0';
printk("%s", buf);
}
vfs_close(fd);
}
return 0;
}
static int applet_touch(int argc, char** argv) {
if (argc < 2) {
printk(KERN_INFO "Usage: touch <file...>\n");
return 1;
}
for (int i = 1; i < argc; i++) {
int fd = vfs_open(argv[i], O_CREAT | O_RDWR);
if (fd >= 0) {
vfs_close(fd);
}
}
return 0;
}
static int applet_mkdir(int argc, char** argv) {
if (argc < 2) {
printk(KERN_INFO "Usage: mkdir <directory>\n");
return 1;
}
for (int i = 1; i < argc; i++) {
if (vfs_mkdir(argv[i], 0755) != 0) {
printk(KERN_ERR "mkdir: cannot create directory '%s'\n", argv[i]);
}
}
return 0;
}
static int applet_echo(int argc, char** argv) {
for (int i = 1; i < argc; i++) {
printk("%s%s", argv[i], (i == argc - 1) ? "" : " ");
}
printk("\n");
return 0;
}
static int applet_wc(int argc, char** argv) {
if (argc < 2) {
printk(KERN_INFO "Usage: wc <file>\n");
return 1;
}
int fd = vfs_open(argv[1], O_RDONLY);
if (fd < 0) {
printk(KERN_ERR "wc: %s: No such file\n", argv[1]);
return 1;
}
int lines = 0, words = 0, bytes = 0;
bool in_word = false;
char buf[256];
ssize_t n;
while ((n = vfs_read(fd, buf, sizeof(buf))) > 0) {
bytes += (int)n;
for (ssize_t i = 0; i < n; i++) {
if (buf[i] == '\n') lines++;
if (buf[i] == ' ' || buf[i] == '\t' || buf[i] == '\n' || buf[i] == '\r') {
in_word = false;
} else if (!in_word) {
in_word = true;
words++;
}
}
}
vfs_close(fd);
printk(KERN_INFO "%4d %4d %4d %s\n", lines, words, bytes, argv[1]);
return 0;
}
// -------------------------------------------------------------
// Cryptographic Hash Utilities
// -------------------------------------------------------------
static int applet_md5sum(int argc, char** argv) {
if (argc < 2) {
printk(KERN_INFO "Usage: md5sum <file|text>\n");
return 1;
}
int fd = vfs_open(argv[1], O_RDONLY);
if (fd >= 0) {
md5_ctx_t ctx;
md5_init(&ctx);
char buf[512];
ssize_t n;
while ((n = vfs_read(fd, buf, sizeof(buf))) > 0) {
md5_update(&ctx, buf, (size_t)n);
}
vfs_close(fd);
uint8_t hash[16];
md5_final(hash, &ctx);
for (int i = 0; i < 16; i++) printk("%02x", hash[i]);
printk(" %s\n", argv[1]);
} else {
// String mode
char out[33];
md5_string(argv[1], out);
printk("%s \"%s\"\n", out, argv[1]);
}
return 0;
}
static int applet_sha256sum(int argc, char** argv) {
if (argc < 2) {
printk(KERN_INFO "Usage: sha256sum <file|text>\n");
return 1;
}
int fd = vfs_open(argv[1], O_RDONLY);
if (fd >= 0) {
sha256_ctx_t ctx;
sha256_init(&ctx);
char buf[512];
ssize_t n;
while ((n = vfs_read(fd, buf, sizeof(buf))) > 0) {
sha256_update(&ctx, buf, (size_t)n);
}
vfs_close(fd);
uint8_t hash[32];
sha256_final(hash, &ctx);
for (int i = 0; i < 32; i++) printk("%02x", hash[i]);
printk(" %s\n", argv[1]);
} else {
char out[65];
sha256_string(argv[1], out);
printk("%s \"%s\"\n", out, argv[1]);
}
return 0;
}
static int applet_crc32(int argc, char** argv) {
if (argc < 2) {
printk(KERN_INFO "Usage: crc32 <text>\n");
return 1;
}
uint32_t val = crc32(0, argv[1], strlen(argv[1]));
printk("0x%08X \"%s\"\n", val, argv[1]);
return 0;
}
// -------------------------------------------------------------
// Network Utilities
// -------------------------------------------------------------
static int applet_ifconfig(int argc, char** argv) {
(void)argc; (void)argv;
net_if_t* net_if = net_get_primary_if();
char ip_s[16], gw_s[16], mask_s[16], mac_s[18];
ip_to_str(net_if->ip, ip_s);
ip_to_str(net_if->gateway, gw_s);
ip_to_str(net_if->subnet, mask_s);
mac_to_str(net_if->mac, mac_s);
printk(ANSI_BRIGHT_GREEN "%s: " ANSI_RESET "flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500\n", net_if->name);
printk(" inet " ANSI_BRIGHT_YELLOW "%s" ANSI_RESET " netmask %s broadcast %s\n", ip_s, mask_s, gw_s);
printk(" ether " ANSI_BRIGHT_CYAN "%s" ANSI_RESET " txqueuelen 1000 (Ethernet)\n", mac_s);
printk(" RX packets %llu bytes %llu\n", e1000_get_rx_packets(), e1000_get_rx_bytes());
printk(" TX packets %llu bytes %llu\n", e1000_get_tx_packets(), e1000_get_tx_bytes());
printk(" Link Status: %s\n", e1000_is_link_up() ? ANSI_GREEN "UP" ANSI_RESET : ANSI_RED "DOWN" ANSI_RESET);
return 0;
}
static int applet_ping(int argc, char** argv) {
if (argc < 2) {
printk(KERN_INFO "Usage: ping <ip-address> [count]\n");
return 1;
}
uint32_t target_ip = ip_parse(argv[1]);
if (target_ip == 0) {
printk(KERN_ERR "Invalid IP address: %s\n", argv[1]);
return 1;
}
uint32_t count = 4;
if (argc >= 3) {
int val = atoi(argv[2]);
if (val > 0) count = (uint32_t)val;
}
net_ping(target_ip, count, 1000);
return 0;
}
static int applet_arp(int argc, char** argv) {
(void)argc; (void)argv;
int count = 0;
arp_entry_t* tbl = net_get_arp_table(&count);
printk(ANSI_BRIGHT_CYAN "Address HWtype HWaddress Flags Iface\n" ANSI_RESET);
char ip_s[16], mac_s[18];
for (int i = 0; i < count; i++) {
if (tbl[i].valid) {
ip_to_str(tbl[i].ip, ip_s);
mac_to_str(tbl[i].mac, mac_s);
printk("%-16s ether %-18s C eth0\n", ip_s, mac_s);
}
}
return 0;
}
// -------------------------------------------------------------
// System & Hardware Utilities
// -------------------------------------------------------------
static int applet_uname(int argc, char** argv) {
bool all = (argc >= 2 && strcmp(argv[1], "-a") == 0);
if (all) {
printk("SUB-OS sub-node 0.2.0-lts #1 SMP PREEMPT Sun Aug 16 2026 x86_64 GNU/LazyBox\n");
} else {
printk("SUB-OS\n");
}
return 0;
}
static int applet_free(int argc, char** argv) {
(void)argc; (void)argv;
uint64_t total_kb = (pmm_get_total_pages() * 4096) / 1024;
uint64_t used_kb = (pmm_get_used_pages() * 4096) / 1024;
uint64_t free_kb = (pmm_get_free_pages() * 4096) / 1024;
size_t heap_used = heap_get_used_bytes();
size_t heap_free = heap_get_free_bytes();
printk(ANSI_BRIGHT_CYAN " total used free shared buff/cache available\n" ANSI_RESET);
printk("Mem: %12llu%12llu%12llu 0%12llu%12llu\n",
total_kb, used_kb, free_kb, (heap_used / 1024), free_kb);
printk("Heap: %12llu%12llu%12llu\n",
(heap_used + heap_free) / 1024, heap_used / 1024, heap_free / 1024);
return 0;
}
static int applet_uptime(int argc, char** argv) {
(void)argc; (void)argv;
uint64_t ticks = pit_get_ticks();
uint64_t secs = ticks / 100;
uint64_t mins = secs / 60;
uint64_t hours = mins / 60;
secs %= 60;
mins %= 60;
printk("up %02llu:%02llu:%02llu, 1 user, load average: 0.00, 0.01, 0.00\n", hours, mins, secs);
return 0;
}
static int applet_dmesg(int argc, char** argv) {
(void)argc; (void)argv;
dmesg_dump();
return 0;
}
static int applet_hdparm(int argc, char** argv) {
(void)argc; (void)argv;
const ata_device_t* dev = ata_get_primary_master();
if (!dev || !dev->present) {
printk(KERN_ERR "No ATA Hard Disk Drive detected.\n");
return 1;
}
printk(ANSI_BRIGHT_CYAN "/dev/sda (ATA Primary Master):\n" ANSI_RESET);
printk(" Model Number: %s\n", dev->model);
printk(" Capacity: %llu MB (%u sectors)\n",
((uint64_t)dev->sector_count * 512) / (1024 * 1024), dev->sector_count);
printk(" Sector Size: 512 bytes logical/physical\n");
printk(" Addressing: 28-bit LBA Mode\n");
return 0;
}
static int applet_clear(int argc, char** argv) {
(void)argc; (void)argv;
tty_clear();
return 0;
}
static int applet_sleep(int argc, char** argv) {
if (argc < 2) {
printk(KERN_INFO "Usage: sleep <seconds>\n");
return 1;
}
int secs = atoi(argv[1]);
if (secs > 0) {
pit_sleep((uint32_t)secs * 1000);
}
return 0;
}
static int applet_lazybox(int argc, char** argv);
// Applet Dispatch Table
static const lazybox_applet_t applets[] = {
{"lazybox", applet_lazybox, "lazybox [applet]", "Multi-call utility manager", "Core"},
{"ls", applet_ls, "ls [path]", "List directory contents", "Filesystem"},
{"cat", applet_cat, "cat <file...>", "Concatenate files to stdout","Filesystem"},
{"touch", applet_touch, "touch <file...>", "Create empty files", "Filesystem"},
{"mkdir", applet_mkdir, "mkdir <dir>", "Create directory", "Filesystem"},
{"wc", applet_wc, "wc <file>", "Count lines, words, bytes", "Filesystem"},
{"echo", applet_echo, "echo [text...]", "Display text to stdout", "Core"},
{"md5sum", applet_md5sum, "md5sum <file|text>", "Compute MD5 hash", "Crypto"},
{"sha256sum", applet_sha256sum, "sha256sum <file|text>", "Compute SHA-256 hash", "Crypto"},
{"crc32", applet_crc32, "crc32 <text>", "Calculate CRC32 checksum", "Crypto"},
{"ifconfig", applet_ifconfig, "ifconfig", "Display network interface", "Network"},
{"ping", applet_ping, "ping <ip> [count]", "ICMP Echo ping utility", "Network"},
{"arp", applet_arp, "arp", "View ARP cache table", "Network"},
{"hdparm", applet_hdparm, "hdparm", "Inspect ATA hard disk", "Storage"},
{"uname", applet_uname, "uname [-a]", "Print system architecture", "System"},
{"free", applet_free, "free", "Display RAM and Heap usage", "System"},
{"uptime", applet_uptime, "uptime", "System running duration", "System"},
{"dmesg", applet_dmesg, "dmesg", "Dump kernel boot ringbuffer","System"},
{"sleep", applet_sleep, "sleep <seconds>", "Delay execution", "System"},
{"clear", applet_clear, "clear", "Clear console screen", "Terminal"},
{NULL, NULL, NULL, NULL, NULL}
};
static int applet_lazybox(int argc, char** argv) {
if (argc >= 2) {
return lazybox_run_applet(argv[1], argc - 1, &argv[1]);
}
printk(ANSI_BRIGHT_CYAN "LazyBox v%s (2026-08-16) Linux-Compatible Multi-Call Suite\n" ANSI_RESET, LAZYBOX_VERSION);
printk("Usage: lazybox [function] [arguments]...\n\n");
printk(ANSI_YELLOW "Defined Applet Categories:\n" ANSI_RESET);
const char* cats[] = {"Filesystem", "Crypto", "Network", "Storage", "System", "Terminal", "Core", NULL};
for (int c = 0; cats[c] != NULL; c++) {
printk(ANSI_BRIGHT_GREEN " [%s]\n " ANSI_RESET, cats[c]);
for (int i = 0; applets[i].name != NULL; i++) {
if (strcmp(applets[i].category, cats[c]) == 0) {
printk(" %-12s", applets[i].name);
}
}
printk("\n");
}
printk("\n");
return 0;
}
void lazybox_init(void) {
// Initialized
}
bool lazybox_has_applet(const char* name) {
if (!name) return false;
for (int i = 0; applets[i].name != NULL; i++) {
if (strcmp(applets[i].name, name) == 0) {
return true;
}
}
return false;
}
int lazybox_run_applet(const char* name, int argc, char** argv) {
if (!name) return -1;
for (int i = 0; applets[i].name != NULL; i++) {
if (strcmp(applets[i].name, name) == 0) {
return applets[i].func(argc, argv);
}
}
printk(KERN_ERR "lazybox: %s: applet not found\n", name);
return 127;
}
const lazybox_applet_t* lazybox_get_applets(int* count_out) {
int count = 0;
while (applets[count].name != NULL) count++;
if (count_out) *count_out = count;
return applets;
}
+429
View File
@@ -0,0 +1,429 @@
#include <userland/shell.h>
#include <userland/lazybox.h>
#include <drivers/tty.h>
#include <drivers/keyboard.h>
#include <drivers/speaker.h>
#include <arch/x86_64/pit.h>
#include <arch/x86_64/cpuid.h>
#include <arch/x86_64/io.h>
#include <mm/pmm.h>
#include <mm/kmalloc.h>
#include <kernel/printk.h>
#include <lib/string.h>
#include <lib/printf.h>
#define HISTORY_SIZE 16
static char history[HISTORY_SIZE][MAX_COMMAND_LENGTH];
static int history_count = 0;
static int history_head = 0;
static const char* shell_builtins[] = {
"lazybox", "ls", "cat", "touch", "mkdir", "wc", "echo",
"md5sum", "sha256sum", "crc32", "ifconfig", "ping", "arp",
"hdparm", "uname", "free", "uptime", "dmesg", "sleep", "clear",
"help", "neofetch", "calc", "hexdump", "matrix", "history", "tty",
"beep", "reboot", "shutdown", NULL
};
static void history_add(const char* cmd) {
if (!cmd || cmd[0] == '\0') return;
if (history_count > 0) {
int last_idx = (history_head - 1 + HISTORY_SIZE) % HISTORY_SIZE;
if (strcmp(history[last_idx], cmd) == 0) return;
}
strncpy(history[history_head], cmd, MAX_COMMAND_LENGTH - 1);
history[history_head][MAX_COMMAND_LENGTH - 1] = '\0';
history_head = (history_head + 1) % HISTORY_SIZE;
if (history_count < HISTORY_SIZE) history_count++;
}
static void redraw_line(const char* prompt, const char* buffer, size_t len, size_t cursor_pos) {
printk("\r\033[K%s%s", prompt, buffer);
if (cursor_pos < len) {
size_t diff = len - cursor_pos;
for (size_t i = 0; i < diff; i++) {
printk("\033[D");
}
}
}
static void cmd_help(void) {
printk(ANSI_BRIGHT_CYAN "================== SUB-OS Production Command Reference ==================\n" ANSI_RESET);
printk(ANSI_YELLOW " [File & Storage Tools]\n" ANSI_RESET);
printk(" " ANSI_GREEN "ls [path]" ANSI_RESET " - Directory list with type & inode numbers\n");
printk(" " ANSI_GREEN "cat <file>" ANSI_RESET " - Display file contents (supports /proc & /dev)\n");
printk(" " ANSI_GREEN "touch / mkdir" ANSI_RESET " - Create files and directories in VFS\n");
printk(" " ANSI_GREEN "hdparm" ANSI_RESET " - Inspect ATA hard disk parameters & sectors\n\n");
printk(ANSI_YELLOW " [Cryptography & Security]\n" ANSI_RESET);
printk(" " ANSI_GREEN "sha256sum <file>" ANSI_RESET " - FIPS 180-4 SHA-256 secure hash\n");
printk(" " ANSI_GREEN "md5sum <file>" ANSI_RESET " - RFC 1321 MD5 message digest\n");
printk(" " ANSI_GREEN "crc32 <text>" ANSI_RESET " - IEEE 802.3 32-bit CRC calculation\n\n");
printk(ANSI_YELLOW " [Networking Suite]\n" ANSI_RESET);
printk(" " ANSI_GREEN "ifconfig" ANSI_RESET " - Ethernet eth0 configuration & RX/TX metrics\n");
printk(" " ANSI_GREEN "ping <ip>" ANSI_RESET " - Send ICMP echo requests with latency ms\n");
printk(" " ANSI_GREEN "arp" ANSI_RESET " - Display kernel ARP resolution cache table\n\n");
printk(ANSI_YELLOW " [System & Diagnostics]\n" ANSI_RESET);
printk(" " ANSI_GREEN "neofetch" ANSI_RESET " - System information & OS ASCII badge\n");
printk(" " ANSI_GREEN "free / uptime" ANSI_RESET " - Memory metrics and CPU uptime\n");
printk(" " ANSI_GREEN "dmesg" ANSI_RESET " - Kernel boot ring buffer log\n");
printk(" " ANSI_GREEN "hexdump [addr] [n]" ANSI_RESET " - Memory hex inspector\n");
printk(" " ANSI_GREEN "calc [A] [op] [B]" ANSI_RESET " - Arithmetic calculator (+, -, *, /, %%)\n");
printk(" " ANSI_GREEN "matrix" ANSI_RESET " - Digital rain screen animation\n");
printk(" " ANSI_GREEN "tty [1-4]" ANSI_RESET " - Switch virtual console (or Alt+F1-F4)\n");
printk(" " ANSI_GREEN "reboot / shutdown" ANSI_RESET " - Power management\n");
printk(ANSI_BRIGHT_BLACK "Tip: Use TAB for autocomplete, Up/Down for command history.\n" ANSI_RESET);
}
static void cmd_neofetch(void) {
uint64_t total = pmm_get_total_pages();
uint64_t used = pmm_get_used_pages();
uint64_t free = pmm_get_free_pages();
uint64_t total_mb = (total * 4096) / (1024 * 1024);
uint64_t used_mb = (used * 4096) / (1024 * 1024);
uint64_t ticks = pit_get_ticks();
uint64_t secs = ticks / 100;
uint64_t mins = secs / 60;
uint64_t hours = mins / 60;
secs %= 60;
mins %= 60;
const cpu_info_t* cpu = cpuid_get_info();
printk("\n");
printk(ANSI_BRIGHT_CYAN " _____ _ _ ____ " ANSI_BRIGHT_GREEN "OS: " ANSI_RESET "SUB-OS v0.2.0-lts (Modular Monolithic)\n");
printk(ANSI_BRIGHT_CYAN " / ____| | | | _ \\ " ANSI_BRIGHT_GREEN "Arch: " ANSI_RESET "x86_64 (64-Bit Long Mode)\n");
printk(ANSI_BRIGHT_CYAN " | (___ | | | | |_) | " ANSI_BRIGHT_GREEN "Kernel: " ANSI_RESET "Modular Drivers + VFS + Crypto + Net\n");
printk(ANSI_BRIGHT_CYAN " \\___ \\| | | | _ < " ANSI_BRIGHT_GREEN "CPU: " ANSI_RESET "%s (%s)\n", cpu->model, cpu->vendor);
printk(ANSI_BRIGHT_CYAN " ____) | |__| | |_) | " ANSI_BRIGHT_GREEN "Memory: " ANSI_RESET "%llu MB / %llu MB (Free: %llu MB)\n", used_mb, total_mb, (free * 4096) / (1024 * 1024));
printk(ANSI_BRIGHT_CYAN " |_____/ \\____/|____/ " ANSI_BRIGHT_GREEN "Heap: " ANSI_RESET "%llu KB used / %llu KB total\n", heap_get_used_bytes() / 1024, (heap_get_used_bytes() + heap_get_free_bytes()) / 1024);
printk(ANSI_BRIGHT_CYAN " " ANSI_BRIGHT_GREEN "Uptime: " ANSI_RESET "%02llu:%02llu:%02llu\n", hours, mins, secs);
printk(ANSI_BRIGHT_CYAN " " ANSI_BRIGHT_GREEN "TTY: " ANSI_RESET "tty%d (Alt+F1-F4 to switch)\n", tty_get_current() + 1);
printk(" \n");
printk(ANSI_BLACK "\xdb\xdb" ANSI_RED "\xdb\xdb" ANSI_GREEN "\xdb\xdb" ANSI_YELLOW "\xdb\xdb" ANSI_BLUE "\xdb\xdb" ANSI_MAGENTA "\xdb\xdb" ANSI_CYAN "\xdb\xdb" ANSI_WHITE "\xdb\xdb" ANSI_RESET "\n\n");
}
static void cmd_calc(const char* args) {
while (*args == ' ') args++;
int64_t a = 0, b = 0;
char op = 0;
bool neg_a = false;
if (*args == '-') { neg_a = true; args++; }
while (*args >= '0' && *args <= '9') { a = a * 10 + (*args - '0'); args++; }
if (neg_a) a = -a;
while (*args == ' ') args++;
if (*args) op = *args++;
while (*args == ' ') args++;
bool neg_b = false;
if (*args == '-') { neg_b = true; args++; }
while (*args >= '0' && *args <= '9') { b = b * 10 + (*args - '0'); args++; }
if (neg_b) b = -b;
int64_t res = 0;
if (op == '+') res = a + b;
else if (op == '-') res = a - b;
else if (op == '*') res = a * b;
else if (op == '/') {
if (b == 0) { printk(ANSI_RED "Division by zero\n" ANSI_RESET); return; }
res = a / b;
} else if (op == '%') {
if (b == 0) { printk(ANSI_RED "Modulo by zero\n" ANSI_RESET); return; }
res = a % b;
} else {
printk("Usage: calc 15 + 27\n");
return;
}
printk("%lld %c %lld = " ANSI_BRIGHT_GREEN "%lld\n" ANSI_RESET, a, op, b, res);
}
static void cmd_hexdump(const char* args) {
uint64_t addr = 0x100000;
uint64_t len = 64;
while (*args == ' ') args++;
if (*args) {
if (args[0] == '0' && (args[1] == 'x' || args[1] == 'X')) args += 2;
addr = 0;
while ((*args >= '0' && *args <= '9') || (*args >= 'a' && *args <= 'f') || (*args >= 'A' && *args <= 'F')) {
addr <<= 4;
if (*args >= '0' && *args <= '9') addr |= (*args - '0');
else if (*args >= 'a' && *args <= 'f') addr |= (*args - 'a' + 10);
else if (*args >= 'A' && *args <= 'F') addr |= (*args - 'A' + 10);
args++;
}
while (*args == ' ') args++;
if (*args >= '0' && *args <= '9') {
len = 0;
while (*args >= '0' && *args <= '9') {
len = len * 10 + (*args - '0');
args++;
}
}
}
if (len > 512) len = 512;
uint8_t* ptr = (uint8_t*)addr;
printk("Hexdump of 0x%lx (%llu bytes):\n", addr, len);
for (uint64_t i = 0; i < len; i += 16) {
printk(ANSI_BRIGHT_BLACK "%016lx: " ANSI_RESET, addr + i);
for (uint64_t j = 0; j < 16; j++) {
if (i + j < len) printk("%02x ", ptr[i + j]);
else printk(" ");
if (j == 7) printk(" ");
}
printk(" |");
for (uint64_t j = 0; j < 16; j++) {
if (i + j < len) {
uint8_t b = ptr[i + j];
printk("%c", (b >= 32 && b <= 126) ? (char)b : '.');
}
}
printk("|\n");
}
}
static void cmd_matrix(void) {
tty_clear();
printk(ANSI_BRIGHT_GREEN "Press any key to exit Matrix mode...\n" ANSI_RESET);
pit_sleep(600);
tty_clear();
int drops[TTY_WIDTH];
for (int i = 0; i < TTY_WIDTH; i++) drops[i] = -(i % 25);
const char charset[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!@#$%^&*";
int charset_len = sizeof(charset) - 1;
uint32_t rand_seed = (uint32_t)pit_get_ticks();
while (!keyboard_has_key()) {
for (int x = 0; x < TTY_WIDTH; x += 2) {
rand_seed = rand_seed * 1103515245 + 12345;
int y = drops[x];
if (y >= 0 && y < TTY_HEIGHT) {
tty_set_cursor(y, x);
printk("\033[92m%c\033[0m", charset[rand_seed % charset_len]);
}
if (y - 8 >= 0 && y - 8 < TTY_HEIGHT) {
tty_set_cursor(y - 8, x);
printk(" ");
}
drops[x]++;
if (drops[x] - 8 >= TTY_HEIGHT) drops[x] = 0;
}
pit_sleep(40);
}
keyboard_get_key();
tty_clear();
}
static void shell_process(const char* cmd) {
while (*cmd == ' ') cmd++;
if (*cmd == '\0') return;
char cmd_copy[MAX_COMMAND_LENGTH];
strncpy(cmd_copy, cmd, sizeof(cmd_copy) - 1);
cmd_copy[sizeof(cmd_copy) - 1] = '\0';
char* argv[16];
int argc = 0;
char* token = cmd_copy;
while (*token) {
while (*token == ' ') *token++ = '\0';
if (*token == '\0') break;
if (argc < 16) argv[argc++] = token;
while (*token && *token != ' ') token++;
}
if (argc == 0) return;
// 1. LazyBox Applets
if (lazybox_has_applet(argv[0])) {
lazybox_run_applet(argv[0], argc, argv);
return;
}
// 2. Builtins
if (strcmp(argv[0], "help") == 0) {
cmd_help();
} else if (strcmp(argv[0], "neofetch") == 0 || strcmp(argv[0], "version") == 0) {
cmd_neofetch();
} else if (strcmp(argv[0], "calc") == 0) {
cmd_calc(cmd + 4);
} else if (strcmp(argv[0], "hexdump") == 0) {
cmd_hexdump(cmd + 7);
} else if (strcmp(argv[0], "matrix") == 0) {
cmd_matrix();
} else if (strcmp(argv[0], "beep") == 0) {
speaker_beep(587, 100);
} else if (strcmp(argv[0], "tty") == 0) {
if (argc >= 2 && argv[1][0] >= '1' && argv[1][0] <= '4') {
tty_switch(argv[1][0] - '1');
} else {
printk("Active TTY: tty%d (Switch with 'tty 1-4' or Alt+F1-F4)\n", tty_get_current() + 1);
}
} else if (strcmp(argv[0], "history") == 0) {
for (int i = 0; i < history_count; i++) {
int idx = (history_head - history_count + i + HISTORY_SIZE) % HISTORY_SIZE;
printk(" %2d: %s\n", i + 1, history[idx]);
}
} else if (strcmp(argv[0], "reboot") == 0) {
printk(ANSI_YELLOW "Rebooting...\n" ANSI_RESET);
pit_sleep(200);
outb(0x64, 0xFE);
} else if (strcmp(argv[0], "shutdown") == 0) {
printk(ANSI_YELLOW "System halted.\n" ANSI_RESET);
while (1) hlt();
} else {
printk(ANSI_RED "Unknown command: %s. Type 'help' or 'lazybox'.\n" ANSI_RESET, argv[0]);
}
}
void shell_run(void) {
char cmd_buffer[MAX_COMMAND_LENGTH];
size_t cmd_len = 0;
size_t cursor_pos = 0;
int history_idx = -1;
const char* prompt = ANSI_BRIGHT_GREEN "sub-os> " ANSI_RESET;
printk(ANSI_BRIGHT_CYAN "\nWelcome to SUB-OS Modular Monolithic Linux Core!\n" ANSI_RESET);
printk("Type '" ANSI_YELLOW "help" ANSI_RESET "', '" ANSI_YELLOW "lazybox" ANSI_RESET "', or '" ANSI_YELLOW "neofetch" ANSI_RESET "' to begin.\n\n");
while (true) {
printk("%s", prompt);
cmd_len = 0;
cursor_pos = 0;
cmd_buffer[0] = '\0';
history_idx = -1;
while (true) {
uint16_t key = keyboard_get_key();
if (key & KEY_SPECIAL_FLAG) {
switch (key) {
case KEY_LEFT:
if (cursor_pos > 0) { cursor_pos--; printk("\033[D"); }
break;
case KEY_RIGHT:
if (cursor_pos < cmd_len) { cursor_pos++; printk("\033[C"); }
break;
case KEY_HOME:
while (cursor_pos > 0) { cursor_pos--; printk("\033[D"); }
break;
case KEY_END:
while (cursor_pos < cmd_len) { cursor_pos++; printk("\033[C"); }
break;
case KEY_DELETE:
if (cursor_pos < cmd_len) {
for (size_t i = cursor_pos; i < cmd_len - 1; i++) cmd_buffer[i] = cmd_buffer[i + 1];
cmd_len--;
cmd_buffer[cmd_len] = '\0';
redraw_line(prompt, cmd_buffer, cmd_len, cursor_pos);
}
break;
case KEY_UP:
if (history_count > 0) {
if (history_idx == -1) history_idx = history_count - 1;
else if (history_idx > 0) history_idx--;
int actual = (history_head - history_count + history_idx + HISTORY_SIZE) % HISTORY_SIZE;
strncpy(cmd_buffer, history[actual], MAX_COMMAND_LENGTH - 1);
cmd_buffer[MAX_COMMAND_LENGTH - 1] = '\0';
cmd_len = strlen(cmd_buffer);
cursor_pos = cmd_len;
redraw_line(prompt, cmd_buffer, cmd_len, cursor_pos);
}
break;
case KEY_DOWN:
if (history_idx != -1) {
if (history_idx < history_count - 1) {
history_idx++;
int actual = (history_head - history_count + history_idx + HISTORY_SIZE) % HISTORY_SIZE;
strncpy(cmd_buffer, history[actual], MAX_COMMAND_LENGTH - 1);
cmd_buffer[MAX_COMMAND_LENGTH - 1] = '\0';
cmd_len = strlen(cmd_buffer);
cursor_pos = cmd_len;
} else {
history_idx = -1;
cmd_buffer[0] = '\0';
cmd_len = 0;
cursor_pos = 0;
}
redraw_line(prompt, cmd_buffer, cmd_len, cursor_pos);
}
break;
}
continue;
}
char c = (char)(key & 0xFF);
if (c == 0x03) {
printk("^C\n%s", prompt);
cmd_len = 0; cursor_pos = 0; cmd_buffer[0] = '\0';
continue;
}
if (c == 0x0C) {
tty_clear();
printk("%s%s", prompt, cmd_buffer);
continue;
}
if (c == '\b') {
if (cursor_pos > 0) {
for (size_t i = cursor_pos - 1; i < cmd_len - 1; i++) cmd_buffer[i] = cmd_buffer[i + 1];
cmd_len--;
cursor_pos--;
cmd_buffer[cmd_len] = '\0';
redraw_line(prompt, cmd_buffer, cmd_len, cursor_pos);
}
} else if (c == '\t') {
if (cmd_len > 0) {
int matches = 0;
const char* last = NULL;
for (int i = 0; shell_builtins[i] != NULL; i++) {
if (strncmp(shell_builtins[i], cmd_buffer, cmd_len) == 0) {
matches++;
last = shell_builtins[i];
}
}
if (matches == 1 && last) {
strncpy(cmd_buffer, last, MAX_COMMAND_LENGTH - 1);
cmd_len = strlen(cmd_buffer);
cursor_pos = cmd_len;
redraw_line(prompt, cmd_buffer, cmd_len, cursor_pos);
} else if (matches > 1) {
printk("\n");
for (int i = 0; shell_builtins[i] != NULL; i++) {
if (strncmp(shell_builtins[i], cmd_buffer, cmd_len) == 0) {
printk(" %s", shell_builtins[i]);
}
}
printk("\n");
redraw_line(prompt, cmd_buffer, cmd_len, cursor_pos);
}
}
} else if (c == '\n' || c == '\r') {
printk("\n");
cmd_buffer[cmd_len] = '\0';
break;
} else if ((unsigned char)c >= 32 && (unsigned char)c <= 126) {
if (cmd_len < MAX_COMMAND_LENGTH - 1) {
for (size_t i = cmd_len; i > cursor_pos; i--) cmd_buffer[i] = cmd_buffer[i - 1];
cmd_buffer[cursor_pos] = c;
cmd_len++;
cursor_pos++;
cmd_buffer[cmd_len] = '\0';
redraw_line(prompt, cmd_buffer, cmd_len, cursor_pos);
}
}
}
if (cmd_len > 0) {
history_add(cmd_buffer);
shell_process(cmd_buffer);
}
}
}