mirror of
https://github.com/subhobhai943/SUB-OS.git
synced 2026-10-25 16:52:29 +00:00
Initial commit: SUB-OS 64-Bit Production Monolithic Operating System with LazyBox userland suite
This commit is contained in:
commit
cd9c786d14
88 files changed
+7132
No files matched your search
+10
@@ -0,0 +1,10 @@
|
||||
build/
|
||||
*.bin
|
||||
*.img
|
||||
*.elf
|
||||
*.o
|
||||
*.iso
|
||||
*.log
|
||||
*.tmp
|
||||
.DS_Store
|
||||
.system_generated/
|
||||
@@ -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.
|
||||
@@ -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)
|
||||
@@ -0,0 +1,140 @@
|
||||
# SUB-OS 64-Bit Production Monolithic Operating System
|
||||
|
||||
[]()
|
||||
[]()
|
||||
[]()
|
||||
[](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).
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
[BITS 64]
|
||||
|
||||
global idt_flush
|
||||
|
||||
section .text
|
||||
idt_flush:
|
||||
lidt [rdi]
|
||||
ret
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
@@ -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"
|
||||
@@ -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
@@ -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';
|
||||
}
|
||||
@@ -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
@@ -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';
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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; }
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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; }
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
Executable
+115
@@ -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
@@ -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!"
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user