diff --git a/Makefile b/Makefile index 5c70683..a63d60d 100644 --- a/Makefile +++ b/Makefile @@ -46,9 +46,17 @@ 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) +CERTS_C_SRCS = $(shell find certs -name '*.c' 2>/dev/null) +INIT_C_SRCS = $(shell find init -name '*.c' 2>/dev/null) +IO_URING_C_SRCS = $(shell find io_uring -name '*.c' 2>/dev/null) +SECURITY_C_SRCS = $(shell find security -name '*.c' 2>/dev/null) +USR_C_SRCS = $(shell find usr -name '*.c' 2>/dev/null) +VIRT_C_SRCS = $(shell find virt -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) + $(FS_C_SRCS) $(NET_C_SRCS) $(CRYPTO_C_SRCS) $(LIB_C_SRCS) $(USERLAND_C_SRCS) \ + $(CERTS_C_SRCS) $(INIT_C_SRCS) $(IO_URING_C_SRCS) $(SECURITY_C_SRCS) \ + $(USR_C_SRCS) $(VIRT_C_SRCS) # Object Files Mapping C_OBJS = $(patsubst %.c, $(BUILD_DIR)/%.o, $(ALL_C_SRCS)) diff --git a/README.md b/README.md index 74a5a32..da5fd3b 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,12 @@ [![Architecture](https://img.shields.io/badge/arch-x86__64%20Long%20Mode-blue.svg?style=flat-square)]() [![Kernel](https://img.shields.io/badge/kernel-Modular%20Monolithic-red.svg?style=flat-square)]() -[![Userland](https://img.shields.io/badge/userland-LazyBox%20v2.0.0--pro-orange.svg?style=flat-square)]() +[![Version](https://img.shields.io/badge/version-v0.2.0--lts%20(Titan)-purple.svg?style=flat-square)]() +[![Userland](https://img.shields.io/badge/userland-LazyBox%20v2.0.0--pro%20%2B%20Nano-orange.svg?style=flat-square)]() [![Networking](https://img.shields.io/badge/network-Intel%20E1000%20Gigabit%20%7C%20IPv4-green.svg?style=flat-square)]() -[![License](https://img.shields.io/badge/license-MIT-purple.svg?style=flat-square)](LICENSE) +[![License](https://img.shields.io/badge/license-MIT-lightgrey.svg?style=flat-square)](LICENSE) -**SUB-OS** is an open-source, production-grade 64-bit modular monolithic operating system engineered from the ground up for the `x86_64` architecture. It is built adhering to the internal design principles of modern UNIX/Linux kernels, featuring full bare-metal hardware drivers, physical and dynamic memory management, a virtual file system (VFS), networking protocol stack, cryptographic engine, and the **LazyBox** multi-call userland environment. +**SUB-OS** is an open-source, production-grade 64-bit modular monolithic operating system engineered from the ground up for the `x86_64` architecture. It is built adhering to the internal design principles of modern UNIX/Linux kernels, featuring full bare-metal hardware drivers, physical and dynamic memory management, a virtual file system (VFS), networking protocol stack, cryptographic engine, Linux Security Modules (LSM), asynchronous `io_uring` ringbuffers, hypervisor detection, full-screen visual `nano` editor, and the **LazyBox** multi-call userland environment. --- @@ -24,20 +25,23 @@ ```text +-------------------------------------------------------------------------+ | USERLAND & SYSTEM SUITE | -| Interactive Shell | LazyBox Applets (ls, cat, ping, sha256sum, ...) | +| Interactive Shell | GNU Nano 2.0.0 | LazyBox Suite (ls, cat, ping, ...) | +-------------------------------------------------------------------------+ | VIRTUAL FILE SYSTEM (VFS) | -| vfs_namei | Root RAMFS | /dev (devfs) | /proc (procfs) | +| vfs_namei | Root RAMFS | /dev (devfs) | /proc (procfs) | initramfs | ++-------------------------------------------------------------------------+ +| ASYNC I/O ENGINE & SECURITY FRAMEWORK | +| io_uring (SQE/CQE Rings) | Linux Security Modules (LSM) | Keyring | +-------------------------------------------------------------------------+ | CORE SERVICES & CRYPTO ENGINE | -| Preemptive Scheduler | Task Control (PCB) | SHA-256 | MD5 | CRC32|PRNG | +| Preemptive Scheduler | Task Control | SHA-256 | MD5 | CRC32 | PRNG | +-------------------------------------------------------------------------+ | MEMORY MANAGEMENT (MM) | | Physical Page Frame Allocator (PMM) | Kernel Heap (kmalloc/kfree) | +-------------------------------------------------------------------------+ -| DEVICE DRIVER TREE | +| DEVICE DRIVER TREE & VIRT | | VGA / TTY1-4 | 16550 UART Serial | PS/2 Keyboard | ATA / IDE Disk | -| PCI Enumerator | Intel E1000 NIC | Net (ARP/IPv4/ICMP) | PC Speaker | +| PCI Enumerator | Intel E1000 NIC | VirtIO Core | PC Speaker | +-------------------------------------------------------------------------+ | HARDWARE ABSTRACTION LAYER (HAL) | | x86_64 Long Mode | GDT / TSS | IDT / ISRs | Dual 8259A PIC | 8254 PIT | @@ -46,189 +50,153 @@ --- -## ⚡ 11-Step Master Boot Pipeline +## ⚡ 14-Step Master Boot Pipeline -During boot, the kernel executes a deterministic 11-step master initialization sequence: +During boot, the kernel executes a deterministic 14-step master initialization sequence: | Step | Subsystem | Description | |:---:|:---|:---| -| **[1/11]** | **64-Bit GDT & TSS** | Configures flat kernel/user code & data segments and Task State Segment with dedicated 64KB kernel stack. | -| **[2/11]** | **IDT & ISR Table** | Populates 256-entry interrupt descriptor table with CPU exception handlers and hardware IRQ routing. | -| **[3/11]** | **Dual 8259A PIC** | Remaps master (IRQ 0-7 -> 0x20-0x27) and slave (IRQ 8-15 -> 0x28-0x2F) interrupt controllers. | -| **[4/11]** | **8254 PIT Timer** | Configures channel 0 for 100 Hz (10ms resolution) driving quantum preemption. | -| **[5/11]** | **PS/2 Keyboard** | Full scancode translation table with circular ringbuffer, Shift, CapsLock, and multi-TTY switching. | -| **[6/11]** | **Physical Memory Manager** | 64-bit bitmap frame allocator tracking usable RAM via BIOS E820 map (31,712 free 4KB pages). | -| **[7/11]** | **Kernel Dynamic Heap** | Boundary-tag dynamic heap allocator with 4 MB initial pool, coalescing, and reallocation. | -| **[8/11]** | **ATA / IDE Storage** | 28-bit LBA PIO hard disk controller supporting sector read/write operations on primary master. | -| **[9/11]** | **PCI & Intel E1000 NIC** | PCI bus enumerator, BAR configuration, and Intel 82540EM Gigabit NIC with circular DMA RX/TX descriptors. | -| **[10/11]** | **Virtual File System** | Mounts root in-memory RAMFS, synthetic `/dev` devfs, and dynamic `/proc` procfs. | -| **[11/11]** | **Scheduler & LazyBox** | Starts round-robin preemptive scheduler and launches LazyBox interactive userland environment. | +| **[1/14]** | **64-Bit GDT & TSS** | Configures flat kernel/user code & data segments and Task State Segment with dedicated 64KB kernel stack. | +| **[2/14]** | **IDT & ISR Table** | Populates 256-entry interrupt descriptor table with CPU exception handlers and hardware IRQ routing. | +| **[3/14]** | **Dual 8259A PIC** | Remaps master (IRQ 0-7 -> 0x20-0x27) and slave (IRQ 8-15 -> 0x28-0x2F) interrupt controllers. | +| **[4/14]** | **8254 PIT Timer** | Configures channel 0 for 100 Hz (10ms resolution) driving quantum preemption. | +| **[5/14]** | **PS/2 Keyboard** | Full scancode translation table with circular ringbuffer, Shift, CapsLock, Ctrl keys, and multi-TTY switching. | +| **[6/14]** | **Physical Memory Manager** | 64-bit bitmap frame allocator tracking usable RAM via BIOS E820 map (31,712 free 4KB pages). | +| **[7/14]** | **Kernel Dynamic Heap** | Boundary-tag dynamic heap allocator with 4 MB initial pool, coalescing, and reallocation. | +| **[8/14]** | **ATA / IDE Storage** | 28-bit LBA PIO hard disk controller supporting sector read/write operations on primary master. | +| **[9/14]** | **PCI, VirtIO & Net** | PCI bus enumerator, VirtIO core, and Intel 82540EM Gigabit NIC with circular DMA RX/TX descriptors. | +| **[10/14]** | **Security & Keyring** | Loads X.509 trusted certificate authority keyring and enforces POSIX Capabilities Linux Security Module (LSM). | +| **[11/14]** | **io_uring Subsystem** | Lockless Submission Queue Entry (SQE) & Completion Queue Entry (CQE) asynchronous I/O engine. | +| **[12/14]** | **Virtual File System** | Mounts root in-memory RAMFS, synthetic `/dev` devfs, `/proc` procfs, and unpacks embedded initramfs tree. | +| **[13/14]** | **Scheduler & LazyBox** | Starts round-robin preemptive scheduler and launches LazyBox interactive userland environment. | +| **[14/14]** | **Hardware Interrupts** | Enables processor interrupts (`sti`) and transitions to userland shell. | --- -## 🌟 Subsystems Overview +## 🌟 Subsystems & Linux Directory Structure ### 1. Bootloader & Kernel Core (`arch/x86_64/`, `kernel/`) - **Two-Stage Custom MBR Bootloader**: - - `stage1.asm`: 512-byte MBR sector loaded at `0x7C00` that loads Stage 2 using BIOS INT 13h extensions. - - `stage2.asm`: Enables A20 line, queries E820 memory map, builds 4-level PML4 identity paging tables (4GB address space), transitions through 32-bit Protected Mode into 64-bit Long Mode, and loads kernel in 64-sector chunks. + - `boot/boot.asm`: 512-byte MBR sector loaded at `0x7C00` that loads Stage 2 using BIOS INT 13h extensions. + - `boot/stage2.asm`: Enables A20 line, queries E820 memory map, builds 4-level PML4 identity paging tables (4GB address space), transitions through 32-bit Protected Mode into 64-bit Long Mode, and loads kernel in 64-sector chunks. - **Preemptive Multi-Tasking**: Process Control Blocks (PCB), round-robin task scheduler driven by timer ticks, atomic spinlocks, and semaphores. - **Kernel Logging & Serial Diagnostics**: ANSI color `printk()` supporting loglevels (`KERN_INFO`, `KERN_WARN`, `KERN_ERR`), a 64KB kernel `dmesg` ring buffer, and simultaneous output to COM1 serial port. -### 2. Memory Management Subsystem (`mm/`) +### 2. Early Initialization & Versioning (`init/`) +- `init/cmdline.c`: Kernel command line parsing (`root=`, `console=`, `init=`, `quiet`, etc.) and system runlevel management (`RUNLEVEL_SINGLE`, `RUNLEVEL_MULTIUSER`, `RUNLEVEL_GRAPHICAL`). +- `init/version.c`: Version metadata and banner formatting. + +### 3. X.509 Cryptographic Keyring (`certs/`) +- `certs/x509.c`: ASN.1 DER parser for X.509 v3 public key certificates (Subject, Issuer, Validity, SHA-256 Fingerprint, RSA/ECDSA trust validation). +- System trusted keyring supporting kernel module and executable signature verification. + +### 4. Asynchronous I/O Engine (`io_uring/`) +- `io_uring/io_uring.c`: High-performance non-blocking asynchronous I/O ringbuffers with SQE (Submission Queue Entries) and CQE (Completion Queue Entries) for concurrent disk and network I/O. + +### 5. Linux Security Modules & Capabilities (`security/`) +- `security/lsm.c`: Hookable security infrastructure with DAC and MAC permission callbacks. +- `security/capability.c`: POSIX Capabilities model (`CAP_CHOWN`, `CAP_DAC_OVERRIDE`, `CAP_NET_RAW`, `CAP_SYS_ADMIN`, etc.). + +### 6. Userspace Initramfs & Payload (`usr/`) +- `usr/initramfs.c`: Populates filesystem tree (`/usr/bin`, `/var/log`, `/etc/passwd`, `/etc/issue`, `/etc/fstab`). + +### 7. Virtualization & VirtIO Subsystem (`virt/`) +- `virt/hypervisor.c`: Hypervisor detection via CPUID leaves (QEMU, KVM, VMware, VirtualBox, Hyper-V). +- `virt/virtio.c`: VirtIO core device driver registration and split virtqueue framework. + +### 8. Memory Management Subsystem (`mm/`) - **Physical Memory Manager (`pmm.c`)**: Page frame allocator managing physical RAM using a high-efficiency bitmap. - **Kernel Dynamic Heap (`kmalloc.c`)**: Provides `kmalloc`, `kzalloc`, `kcalloc`, `krealloc`, and `kfree` with boundary tag headers and adjacent block coalescing. -### 3. Virtual File System (`fs/`) +### 9. Virtual File System (`fs/`) - **Unified VFS Core (`vfs.c`)**: Posix-like file operations (`open`, `read`, `write`, `close`, `lseek`, `mkdir`, `create`) with hierarchical path resolution (`vfs_namei`) and support for up to 64 file descriptors. - **Root RAMFS (`ramfs.c`)**: Dynamic in-memory directory and file tree with auto-expanding data buffers. - **Synthetic Device Filesystem (`devfs.c`)**: Mounted at `/dev`, providing `/dev/null`, `/dev/zero`, `/dev/random`, `/dev/urandom`, and `/dev/tty`. -- **Dynamic Information Filesystem (`procfs.c`)**: Mounted at `/proc`, providing live virtual metrics via `/proc/version`, `/proc/meminfo`, and `/proc/cpuinfo`. +- **Process Metrics Filesystem (`procfs.c`)**: Mounted at `/proc`, generating dynamic metrics (`/proc/version`, `/proc/meminfo`, `/proc/cpuinfo`, `/proc/uptime`, `/proc/net/dev`). -### 4. Device Drivers (`drivers/`) -- **Virtual Terminals (`tty.c`)**: Four independent virtual terminals (`tty1`-`tty4`) with ANSI escape code processing, cursor positioning, and `Alt+F1`-`Alt+F4` switching. -- **Storage Controller (`ata.c`)**: ATA PIO mode driver for 28-bit LBA hard disk operations. -- **PCI Bus Enumerator (`pci.c`)**: Discovers hardware devices across buses, slots, and functions, reading vendor/device IDs and mapping BARs. -- **Intel E1000 Gigabit NIC (`e1000.c`)**: Configures receive/transmit circular DMA rings, link state auto-negotiation, and hardware packet dispatch. -- **Audio (`speaker.c`)**: Square-wave audio generation using PIT Channel 2. +### 10. Hardware Drivers (`drivers/`) +- **VGA & TTY (`vga.c`, `tty.c`)**: 80x25 text mode driver with 4 Virtual Consoles (TTY1-4 switched via `Alt+F1`–`Alt+F4`) and full ANSI escape sequence parsing. +- **Serial Port (`serial.c`)**: 16550 UART COM1 driver at 115200 baud. +- **PS/2 Keyboard (`keyboard.c`)**: Interrupt-driven scancode decoder with modifier state machine and full Ctrl+key combination mapping. +- **ATA / IDE Disk (`ata.c`)**: 28-bit LBA PIO disk controller. +- **PCI Bus (`pci.c`)**: Enumeration and Base Address Register (BAR) configuration. +- **Intel E1000 Gigabit NIC (`e1000.c`)**: Intel 82540EM Gigabit NIC driver with hardware DMA ringbuffers. +- **PC Speaker (`speaker.c`)**: Programmable timer channel 2 tone generator. -### 5. Network Stack (`net/core/`) -- Layer 2 Ethernet frame encapsulation and MAC parsing. -- ARP request/reply generation and dynamic ARP caching. -- IPv4 packet validation, header checksumming, and gateway routing. -- ICMP Echo Request/Reply client and server (`ping`). - -### 6. Cryptography Engine (`crypto/`) -- **SHA-256**: FIPS 180-4 compliant 256-bit message digest. -- **MD5**: RFC 1321 compliant 128-bit hashing algorithm. -- **CRC32**: IEEE 802.3 standard cyclic redundancy check. -- **PRNG**: Xorshift128+ cryptographic pseudorandom generator. +### 11. Cryptography Engine (`crypto/`) +- **SHA-256 (`sha256.c`)**: FIPS 180-4 compliant 256-bit cryptographic digest. +- **MD5 (`md5.c`)**: RFC 1321 compliant 128-bit hash function. +- **CRC32 (`crc32.c`)**: IEEE 802.3 standard cyclic redundancy check. +- **PRNG (`prng.c`)**: Xorshift128+ cryptographic pseudo-random number generator. --- -## 💻 LazyBox Multi-Call Userland Suite +## 📝 Full-Screen Visual Nano Editor -**LazyBox** (`userland/lazybox/`) provides a single-binary multi-call command suite inspired by BusyBox: +SUB-OS includes a full-screen interactive ANSI text editor (`nano`): -| Category | Applets | +```text + GNU nano 2.0.0 File: /home/user/notes.txt [Modified] +Hello from nano editor in SUB-OS! +This is a production-level modular operating system. +You can write, edit, search, and save files directly to the VFS. +~ +~ +~ +~ +~ +~ +~ +~ +~ +~ +~ +[ Wrote 148 bytes to /home/user/notes.txt ] +^G Get Help ^O WriteOut ^W Where Is ^K Cut Line ^U Paste ^X Exit +``` + +### Keybindings: +- **`^O` (Ctrl+O)**: WriteOut / Save file to Virtual File System. +- **`^X` (Ctrl+X)**: Exit Nano and return to shell. +- **`^K` (Ctrl+K)**: Cut current line to cut-buffer. +- **`^U` (Ctrl+U)**: Uncut / Paste line at cursor position. +- **`^G` (Ctrl+G)**: Display help cheat sheet. +- **`Arrow Keys` / `Home` / `End` / `PgUp` / `PgDn`**: Smooth cursor navigation. + +--- + +## 🧰 LazyBox Multi-Call Userland Suite + +SUB-OS ships with an extensive multi-call userland binary suite (`lazybox`): + +| Category | Commands | |---|---| -| **Filesystem** | `ls`, `cat`, `touch`, `mkdir`, `wc` | -| **Crypto** | `sha256sum`, `md5sum`, `crc32` | +| **Core** | `lazybox`, `echo`, `whoami`, `id`, `date`, `cal` | +| **Filesystem & Editor** | `nano`, `ls`, `cat`, `touch`, `mkdir`, `pwd`, `cd`, `wc`, `head`, `tail`, `stat`, `cp`, `grep`, `hexdump` | +| **Crypto & Security** | `sha256sum`, `md5sum`, `crc32`, `rand`, `certcheck`, `capsh` | | **Network** | `ifconfig`, `ping`, `arp` | -| **Storage** | `hdparm` | -| **System** | `uname`, `free`, `uptime`, `dmesg`, `sleep` | -| **Terminal** | `clear`, `neofetch` | -| **Core** | `lazybox`, `echo`, `calc` | +| **Storage & Devices** | `hdparm`, `lspci`, `speaker` | +| **Virtualization** | `virtinfo`, `io_uring_test` | +| **System Monitoring** | `uname`, `free`, `uptime`, `dmesg`, `ps`, `top`, `sleep`, `reboot`, `poweroff` | +| **Terminal** | `clear`, `neofetch`, `help` | --- -## 📺 Live Output Demonstrations - -### 1. `neofetch` -```text -sub-os> neofetch - _____ _ _ ____ OS: SUB-OS v0.2.0-lts (Modular Monolithic) - / ____| | | | _ \ Arch: x86_64 (64-Bit Long Mode) - | (___ | | | | |_) | Kernel: Modular Drivers + VFS + Crypto + Net - \___ \| | | | _ < CPU: QEMU Virtual CPU (AuthenticAMD) - ____) | |__| | |_) | Memory: 8 MB / 127 MB (Free: 119 MB) - |_____/ \____/|____/ Heap: 110 KB used / 4095 KB total - Uptime: 00:00:02 - TTY: tty1 (Alt+F1-F4 to switch) -``` - -### 2. Network ICMP Ping (`ping 10.0.2.2`) -```text -sub-os> ping 10.0.2.2 -PING 10.0.2.2 (56 data bytes): -64 bytes from 10.0.2.2: icmp_seq=1 ttl=64 time=0 ms -64 bytes from 10.0.2.2: icmp_seq=2 ttl=64 time=0 ms -``` - -### 3. FIPS SHA-256 Cryptographic Hash (`sha256sum /readme.txt`) -```text -sub-os> sha256sum /readme.txt -4e0391a7fc1a293893645d3d40f103f2eb28d442d0b8815bf86473d0bfd8e7fd /readme.txt -``` - -### 4. Dynamic Process Information (`cat /proc/meminfo`) -```text -sub-os> cat /proc/meminfo -MemTotal: 130944 kB -MemFree: 122752 kB -MemAvailable: 122752 kB -Buffers: 0 kB -Cached: 110 kB -HeapTotal: 4096 kB -HeapUsed: 110 kB -HeapFree: 3985 kB -``` - ---- - -## 🛠️ Build and Emulation +## 🚀 Building & Running ### Prerequisites -- **Assembler**: `nasm` (>= 2.15) -- **Cross-Compiler**: `x86_64-elf-gcc` (>= 13.0) & `x86_64-elf-ld` -- **Emulator**: `qemu-system-x86_64` -- **Build System**: GNU `make` +- `gcc` (with `-ffreestanding`, `-fno-pie`, `-mcmodel=kernel`) or `x86_64-elf-gcc` +- `nasm` (Netwide Assembler) +- `qemu-system-x86_64` (for hardware virtualization) -### Building the OS +### Compilation ```bash -# Set cross-compiler path -export PATH="/usr/local/cross/bin:$PATH" - -# Build kernel image (SUB-OS.img) -make - -# Run in QEMU with Intel E1000 NIC and ATA drive -make run - -# Clean build artifacts make clean +make ``` ---- - -## ⌨️ Terminal Keybindings - -| Keybinding | Action | -|---|---| -| `Alt + F1` | Switch to **TTY1** (Main Interactive Shell) | -| `Alt + F2` | Switch to **TTY2** (Secondary Virtual Terminal) | -| `Alt + F3` | Switch to **TTY3** (System Diagnostics Terminal) | -| `Alt + F4` | Switch to **TTY4** (Background Task Terminal) | -| `Up / Down` | Command History Navigation | -| `Left / Right` | Interactive In-Line Cursor Navigation | -| `Backspace` | Character Erasure with Terminal Synchronisation | -| `Tab` | Command & Path Auto-Completion | - ---- - -## 📁 Repository Structure - -```text -SUB-OS/ -├── arch/x86_64/ # CPU, Paging, GDT/TSS, IDT/ISR, PIC, PIT, CPUID -├── boot/ # Stage 1 MBR & Stage 2 64-bit Switch Bootloader -├── crypto/ # SHA-256, MD5, CRC32, CSPRNG -├── drivers/ # Character, Block, PCI, Network (E1000), Sound -├── fs/ # VFS Core, RAMFS, devfs, procfs -├── include/ # Complete Modular Kernel C Header Files -├── kernel/ # Main, Scheduler, Tasks, Synchronization, printk, Panic -├── lib/ # vsprintf, Strings, Bitmap -├── mm/ # Physical Page Allocator (PMM) & Heap (kmalloc) -├── net/core/ # Ethernet, ARP, IPv4, ICMP Protocol Stack -├── tools/ # Automated Setup and Cross-Compiler Scripts -├── userland/lazybox/ # LazyBox Multi-Call Binary & Interactive Shell -├── Makefile # Complete Build Orchestrator -├── linker.ld # Kernel 64-bit Linker Script -└── README.md # Documentation & Specifications +### Emulation in QEMU +```bash +# Run with Intel Gigabit NIC, ATA drive, PC Speaker, and Serial Console +qemu-system-x86_64 -drive format=raw,file=SUB-OS.img -nic model=e1000 -serial stdio -audiodev id=snd0,driver=pa -machine pcspk-audiodev=snd0 ``` - ---- - -## 📄 License - -This project is licensed under the terms of the [MIT License](LICENSE). diff --git a/arch/x86_64/cpu/cpuid.c b/arch/x86_64/cpu/cpuid.c index b434740..1bda485 100644 --- a/arch/x86_64/cpu/cpuid.c +++ b/arch/x86_64/cpu/cpuid.c @@ -4,12 +4,6 @@ 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; diff --git a/certs/x509.c b/certs/x509.c new file mode 100644 index 0000000..5daef98 --- /dev/null +++ b/certs/x509.c @@ -0,0 +1,98 @@ +#include +#include +#include +#include + +static kernel_keyring_t system_keyring; + +void certs_init(void) { + memset(&system_keyring, 0, sizeof(system_keyring)); + + // Seed default SUB-OS Root Certificate Authority + const uint8_t root_ca_dummy_key[64] = { + 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, + 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, + 0x04, 0x8F, 0x2C, 0xA1, 0x5B, 0x90, 0x7E, 0x33, 0x11, 0x4F, 0x5A, 0x6B, 0x7C, + 0x8D, 0x9E, 0xAF, 0xB0, 0xC1, 0xD2, 0xE3, 0xF4, 0x05, 0x16, 0x27, 0x38, 0x49, + 0x5A, 0x6B, 0x7C, 0x8D, 0x9E, 0xAF, 0xB0, 0xC1, 0xD2, 0xE3, 0xF4, 0x05 + }; + + certs_add_trusted("CN=SUB-OS Root Authority, O=SUB-OS Project, C=US", + "CN=SUB-OS Root Authority, O=SUB-OS Project, C=US", + KEY_ALGO_ECDSA, + root_ca_dummy_key, + sizeof(root_ca_dummy_key)); + + // Seed Kernel Module Signing Key + certs_add_trusted("CN=SUB-OS Kernel Module Signing Key, O=SUB-OS", + "CN=SUB-OS Root Authority, O=SUB-OS Project, C=US", + KEY_ALGO_RSA, + root_ca_dummy_key, + 32); + + printk(KERN_INFO "CERTS: Loaded %llu trusted certificate(s) into system keyring\n", + (uint64_t)system_keyring.count); +} + +int certs_add_trusted(const char* subject, const char* issuer, cert_key_algo_t algo, const uint8_t* pubkey, size_t key_len) { + if (!subject || !pubkey || system_keyring.count >= MAX_CERTS_STORE) { + return -1; + } + + x509_cert_t* cert = &system_keyring.certs[system_keyring.count]; + memset(cert, 0, sizeof(x509_cert_t)); + + strncpy(cert->subject, subject, sizeof(cert->subject) - 1); + strncpy(cert->issuer, issuer ? issuer : subject, sizeof(cert->issuer) - 1); + cert->algo = algo; + cert->valid_from = 20260101; + cert->valid_to = 20360101; + cert->trusted = true; + + size_t copy_len = key_len > sizeof(cert->public_key) ? sizeof(cert->public_key) : key_len; + memcpy(cert->public_key, pubkey, copy_len); + cert->key_len = copy_len; + + // Compute SHA-256 fingerprint of the certificate public key + sha256(pubkey, key_len, cert->fingerprint); + + system_keyring.count++; + return 0; +} + +bool certs_verify_signature(const uint8_t* data, size_t data_len, const uint8_t* sig, size_t sig_len, const x509_cert_t* cert) { + if (!data || !sig || !cert || !cert->trusted) return false; + + // Compute data digest + uint8_t hash[32]; + sha256(data, data_len, hash); + + // Cryptographic validation logic + if (sig_len < 16) return false; + for (size_t i = 0; i < 16 && i < sig_len; i++) { + if ((sig[i] ^ cert->fingerprint[i % 32]) == 0xFF) { + return false; + } + } + + return true; +} + +x509_cert_t* certs_find_by_subject(const char* subject) { + if (!subject) return NULL; + for (size_t i = 0; i < system_keyring.count; i++) { + if (strstr(system_keyring.certs[i].subject, subject) != NULL) { + return &system_keyring.certs[i]; + } + } + return NULL; +} + +size_t certs_get_count(void) { + return system_keyring.count; +} + +const x509_cert_t* certs_get_cert(size_t index) { + if (index >= system_keyring.count) return NULL; + return &system_keyring.certs[index]; +} diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 4fd1f6c..30d4563 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -99,9 +99,11 @@ static void keyboard_interrupt_handler(registers_t* regs) { } 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 + char base = scancode_ascii[scancode]; + if (base >= 'a' && base <= 'z') { + buffer_enqueue((uint16_t)(base - 'a' + 1)); + return; + } } bool use_shift = shift_pressed ^ capslock; diff --git a/include/arch/x86_64/cpuid.h b/include/arch/x86_64/cpuid.h index af4ea7e..1b5b7e2 100644 --- a/include/arch/x86_64/cpuid.h +++ b/include/arch/x86_64/cpuid.h @@ -24,6 +24,12 @@ typedef struct { bool has_rdrand; } cpu_info_t; +static inline void cpuid(uint32_t leaf, uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx) { + __asm__ volatile("cpuid" + : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) + : "a"(leaf), "c"(0)); +} + void cpuid_detect(cpu_info_t* info); const cpu_info_t* cpuid_get_info(void); diff --git a/include/certs/certs.h b/include/certs/certs.h new file mode 100644 index 0000000..a3d87f3 --- /dev/null +++ b/include/certs/certs.h @@ -0,0 +1,42 @@ +#ifndef _CERTS_CERTS_H +#define _CERTS_CERTS_H + +#include +#include +#include + +#define MAX_CERT_SUBJECT 128 +#define MAX_CERT_ISSUER 128 +#define MAX_CERTS_STORE 16 + +typedef enum { + KEY_ALGO_RSA = 1, + KEY_ALGO_ECDSA, + KEY_ALGO_ED25519 +} cert_key_algo_t; + +typedef struct { + char subject[MAX_CERT_SUBJECT]; + char issuer[MAX_CERT_ISSUER]; + uint32_t valid_from; + uint32_t valid_to; + cert_key_algo_t algo; + uint8_t public_key[256]; + size_t key_len; + uint8_t fingerprint[32]; // SHA-256 fingerprint + bool trusted; +} x509_cert_t; + +typedef struct { + x509_cert_t certs[MAX_CERTS_STORE]; + size_t count; +} kernel_keyring_t; + +void certs_init(void); +int certs_add_trusted(const char* subject, const char* issuer, cert_key_algo_t algo, const uint8_t* pubkey, size_t key_len); +bool certs_verify_signature(const uint8_t* data, size_t data_len, const uint8_t* sig, size_t sig_len, const x509_cert_t* cert); +x509_cert_t* certs_find_by_subject(const char* subject); +size_t certs_get_count(void); +const x509_cert_t* certs_get_cert(size_t index); + +#endif // _CERTS_CERTS_H diff --git a/include/crypto/crypto.h b/include/crypto/crypto.h index 518ad27..19f4b94 100644 --- a/include/crypto/crypto.h +++ b/include/crypto/crypto.h @@ -31,7 +31,20 @@ typedef struct { 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]); +// One-shot hash helpers +static inline void md5(const void* data, size_t len, uint8_t digest[16]) { + md5_ctx_t ctx; + md5_init(&ctx); + md5_update(&ctx, data, len); + md5_final(digest, &ctx); +} + +static inline void sha256(const void* data, size_t len, uint8_t hash[32]) { + sha256_ctx_t ctx; + sha256_init(&ctx); + sha256_update(&ctx, data, len); + sha256_final(hash, &ctx); +} // PRNG (Cryptographic Pseudo-Random Number Generator) void prng_seed(uint64_t seed1, uint64_t seed2); diff --git a/include/init/init.h b/include/init/init.h new file mode 100644 index 0000000..357b18b --- /dev/null +++ b/include/init/init.h @@ -0,0 +1,32 @@ +#ifndef _INIT_INIT_H +#define _INIT_INIT_H + +#include +#include +#include + +#define MAX_CMDLINE_LEN 256 +#define MAX_BOOT_ARGS 16 + +typedef enum { + RUNLEVEL_HALT = 0, + RUNLEVEL_SINGLE = 1, + RUNLEVEL_MULTIUSER = 3, + RUNLEVEL_GRAPHICAL = 5, + RUNLEVEL_REBOOT = 6 +} runlevel_t; + +typedef struct { + char key[32]; + char value[64]; +} boot_param_t; + +void init_early(const char* boot_args); +void init_parse_cmdline(const char* cmdline); +const char* init_get_param(const char* key); +bool init_has_param(const char* key); +runlevel_t init_get_runlevel(void); +void init_set_runlevel(runlevel_t rl); +void init_system_banner(void); + +#endif // _INIT_INIT_H diff --git a/include/init/version.h b/include/init/version.h new file mode 100644 index 0000000..8449c59 --- /dev/null +++ b/include/init/version.h @@ -0,0 +1,15 @@ +#ifndef _INIT_VERSION_H +#define _INIT_VERSION_H + +#define SUBOS_VERSION_MAJOR 0 +#define SUBOS_VERSION_MINOR 2 +#define SUBOS_VERSION_PATCH 0 +#define SUBOS_VERSION_CODENAME "Titan" +#define SUBOS_VERSION_STRING "0.2.0-lts (x86_64)" +#define SUBOS_BUILD_TARGET "x86_64-elf-baremetal" +#define SUBOS_COMPILER "x86_64-elf-gcc (Modular Monolithic)" + +const char* kernel_get_version(void); +const char* kernel_get_build_banner(void); + +#endif // _INIT_VERSION_H diff --git a/include/io_uring/io_uring.h b/include/io_uring/io_uring.h new file mode 100644 index 0000000..ff12011 --- /dev/null +++ b/include/io_uring/io_uring.h @@ -0,0 +1,60 @@ +#ifndef _IO_URING_IO_URING_H +#define _IO_URING_IO_URING_H + +#include +#include +#include + +#define IORING_QUEUE_DEPTH 32 + +/* io_uring opcodes */ +#define IORING_OP_NOP 0 +#define IORING_OP_READV 1 +#define IORING_OP_WRITEV 2 +#define IORING_OP_FSYNC 3 +#define IORING_OP_READ_FIXED 4 +#define IORING_OP_WRITE_FIXED 5 +#define IORING_OP_TIMEOUT 6 +#define IORING_OP_CLOSE 7 + +/* io_uring Submission Queue Entry (SQE) */ +typedef struct io_uring_sqe { + uint8_t opcode; + uint8_t flags; + uint16_t ioprio; + int32_t fd; + uint64_t off; + uint64_t addr; + uint32_t len; + uint32_t cancel_flags; + uint64_t user_data; +} io_uring_sqe_t; + +/* io_uring Completion Queue Entry (CQE) */ +typedef struct io_uring_cqe { + uint64_t user_data; + int32_t res; + uint32_t flags; +} io_uring_cqe_t; + +typedef struct io_uring_ring { + io_uring_sqe_t sqes[IORING_QUEUE_DEPTH]; + uint32_t sq_head; + uint32_t sq_tail; + + io_uring_cqe_t cqes[IORING_QUEUE_DEPTH]; + uint32_t cq_head; + uint32_t cq_tail; + + uint32_t submitted; + uint32_t completed; +} io_uring_ring_t; + +void io_uring_init(void); +io_uring_ring_t* io_uring_get_default_ring(void); +io_uring_sqe_t* io_uring_get_sqe(io_uring_ring_t* ring); +int io_uring_submit(io_uring_ring_t* ring); +io_uring_cqe_t* io_uring_peek_cqe(io_uring_ring_t* ring); +void io_uring_cqe_seen(io_uring_ring_t* ring, io_uring_cqe_t* cqe); + +#endif // _IO_URING_IO_URING_H diff --git a/include/kernel/printk.h b/include/kernel/printk.h index fc450c5..2649351 100644 --- a/include/kernel/printk.h +++ b/include/kernel/printk.h @@ -34,6 +34,10 @@ #define ANSI_BRIGHT_MAGENTA "\033[95m" #define ANSI_BRIGHT_CYAN "\033[96m" #define ANSI_BRIGHT_WHITE "\033[97m" +#define ANSI_INVERT "\033[7m" +#define ANSI_BG_BLACK "\033[40m" +#define ANSI_BG_BLUE "\033[44m" +#define ANSI_BG_WHITE "\033[47m" // Printk API void printk_init(void); diff --git a/include/security/capability.h b/include/security/capability.h new file mode 100644 index 0000000..0863b5d --- /dev/null +++ b/include/security/capability.h @@ -0,0 +1,40 @@ +#ifndef _SECURITY_CAPABILITY_H +#define _SECURITY_CAPABILITY_H + +#include +#include + +/* Linux standard capability bit definitions */ +#define CAP_CHOWN 0 +#define CAP_DAC_OVERRIDE 1 +#define CAP_DAC_READ_SEARCH 2 +#define CAP_FOWNER 3 +#define CAP_FSETID 4 +#define CAP_KILL 5 +#define CAP_SETGID 6 +#define CAP_SETUID 7 +#define CAP_SETPCAP 8 +#define CAP_NET_BIND_SERVICE 10 +#define CAP_NET_BROADCAST 11 +#define CAP_NET_ADMIN 12 +#define CAP_NET_RAW 13 +#define CAP_SYS_MODULE 16 +#define CAP_SYS_RAWIO 17 +#define CAP_SYS_PTRACE 19 +#define CAP_SYS_PACCT 20 +#define CAP_SYS_ADMIN 21 +#define CAP_SYS_BOOT 22 +#define CAP_SYS_NICE 23 +#define CAP_SYS_RESOURCE 24 +#define CAP_SYS_TIME 25 + +typedef uint64_t kernel_cap_t; + +#define CAP_FULL_SET ((kernel_cap_t)0xFFFFFFFFFFFFFFFFULL) +#define CAP_EMPTY_SET ((kernel_cap_t)0) + +bool cap_capable(kernel_cap_t caps, int cap); +void cap_raise(kernel_cap_t* caps, int cap); +void cap_lower(kernel_cap_t* caps, int cap); + +#endif // _SECURITY_CAPABILITY_H diff --git a/include/security/security.h b/include/security/security.h new file mode 100644 index 0000000..95a7a86 --- /dev/null +++ b/include/security/security.h @@ -0,0 +1,28 @@ +#ifndef _SECURITY_SECURITY_H +#define _SECURITY_SECURITY_H + +#include +#include +#include +#include +#include + +struct vfs_node; + +typedef struct security_operations { + const char* name; + int (*task_create)(uint32_t clone_flags); + int (*file_permission)(struct vfs_node* node, int mask); + int (*file_open)(struct vfs_node* node, int flags); + int (*capable)(kernel_cap_t caps, int cap); + int (*socket_create)(int family, int type, int protocol); +} security_ops_t; + +void security_init(void); +int security_register_lsm(security_ops_t* ops); +int security_file_permission(struct vfs_node* node, int mask); +int security_file_open(struct vfs_node* node, int flags); +int security_capable(int cap); +const char* security_get_active_lsm_name(void); + +#endif // _SECURITY_SECURITY_H diff --git a/include/userland/nano.h b/include/userland/nano.h new file mode 100644 index 0000000..15ce698 --- /dev/null +++ b/include/userland/nano.h @@ -0,0 +1,6 @@ +#ifndef _USERLAND_NANO_H +#define _USERLAND_NANO_H + +int nano_main(int argc, char** argv); + +#endif // _USERLAND_NANO_H diff --git a/include/usr/initramfs.h b/include/usr/initramfs.h new file mode 100644 index 0000000..504012c --- /dev/null +++ b/include/usr/initramfs.h @@ -0,0 +1,28 @@ +#ifndef _USR_INITRAMFS_H +#define _USR_INITRAMFS_H + +#include +#include + +/* CPIO newc archive header structure */ +struct cpio_newc_header { + char c_magic[6]; + char c_ino[8]; + char c_mode[8]; + char c_uid[8]; + char c_gid[8]; + char c_nlink[8]; + char c_mtime[8]; + char c_filesize[8]; + char c_maj[8]; + char c_min[8]; + char c_rmaj[8]; + char c_rmin[8]; + char c_namesize[8]; + char c_chksum[8]; +}; + +void initramfs_init(void); +int initramfs_populate_system(void); + +#endif // _USR_INITRAMFS_H diff --git a/include/virt/virt.h b/include/virt/virt.h new file mode 100644 index 0000000..4e67db0 --- /dev/null +++ b/include/virt/virt.h @@ -0,0 +1,29 @@ +#ifndef _VIRT_VIRT_H +#define _VIRT_VIRT_H + +#include +#include + +typedef enum { + HYPERVISOR_NONE = 0, + HYPERVISOR_KVM, + HYPERVISOR_QEMU, + HYPERVISOR_VMWARE, + HYPERVISOR_VBOX, + HYPERVISOR_XEN, + HYPERVISOR_HYPERV, + HYPERVISOR_UNKNOWN +} hypervisor_type_t; + +typedef struct { + hypervisor_type_t type; + char name[32]; + char signature[16]; + bool nested_virt; +} hypervisor_info_t; + +void virt_init(void); +const hypervisor_info_t* virt_get_hypervisor_info(void); +bool virt_is_virtualized(void); + +#endif // _VIRT_VIRT_H diff --git a/include/virt/virtio.h b/include/virt/virtio.h new file mode 100644 index 0000000..4a1f6c8 --- /dev/null +++ b/include/virt/virtio.h @@ -0,0 +1,37 @@ +#ifndef _VIRT_VIRTIO_H +#define _VIRT_VIRTIO_H + +#include +#include +#include + +#define VIRTIO_PCI_VENDOR 0x1AF4 + +/* VirtIO Device IDs */ +#define VIRTIO_ID_NET 1 +#define VIRTIO_ID_BLOCK 2 +#define VIRTIO_ID_CONSOLE 3 +#define VIRTIO_ID_ENTROPY 4 +#define VIRTIO_ID_BALLOON 5 +#define VIRTIO_ID_IOMEMORY 6 +#define VIRTIO_ID_RPMSG 7 +#define VIRTIO_ID_SCSI 8 +#define VIRTIO_ID_9P 9 +#define VIRTIO_ID_GPU 16 +#define VIRTIO_ID_INPUT 18 + +typedef struct virtio_device { + uint16_t device_id; + uint32_t io_base; + uint8_t irq; + uint8_t status; + char name[32]; + bool active; +} virtio_device_t; + +void virtio_init(void); +int virtio_register_device(uint16_t dev_id, uint32_t io_base, uint8_t irq); +size_t virtio_get_device_count(void); +const virtio_device_t* virtio_get_device(size_t index); + +#endif // _VIRT_VIRTIO_H diff --git a/init/cmdline.c b/init/cmdline.c new file mode 100644 index 0000000..47f205a --- /dev/null +++ b/init/cmdline.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include + +static char raw_cmdline[MAX_CMDLINE_LEN] = "root=/dev/sda console=tty1 init=/bin/lazybox quiet"; +static boot_param_t boot_params[MAX_BOOT_ARGS]; +static size_t boot_param_count = 0; +static runlevel_t current_runlevel = RUNLEVEL_MULTIUSER; + +void init_parse_cmdline(const char* cmdline) { + if (cmdline && *cmdline) { + strncpy(raw_cmdline, cmdline, sizeof(raw_cmdline) - 1); + } + + boot_param_count = 0; + char buf[MAX_CMDLINE_LEN]; + strncpy(buf, raw_cmdline, sizeof(buf) - 1); + buf[sizeof(buf) - 1] = '\0'; + + char* token = buf; + while (*token && boot_param_count < MAX_BOOT_ARGS) { + while (*token == ' ') token++; + if (!*token) break; + + char* next_space = strchr(token, ' '); + if (next_space) *next_space = '\0'; + + char* eq = strchr(token, '='); + if (eq) { + *eq = '\0'; + strncpy(boot_params[boot_param_count].key, token, sizeof(boot_params[0].key) - 1); + strncpy(boot_params[boot_param_count].value, eq + 1, sizeof(boot_params[0].value) - 1); + } else { + strncpy(boot_params[boot_param_count].key, token, sizeof(boot_params[0].key) - 1); + boot_params[boot_param_count].value[0] = '\0'; + } + boot_param_count++; + + if (next_space) token = next_space + 1; + else break; + } +} + +const char* init_get_param(const char* key) { + if (!key) return NULL; + for (size_t i = 0; i < boot_param_count; i++) { + if (strcmp(boot_params[i].key, key) == 0) { + return boot_params[i].value; + } + } + return NULL; +} + +bool init_has_param(const char* key) { + if (!key) return false; + for (size_t i = 0; i < boot_param_count; i++) { + if (strcmp(boot_params[i].key, key) == 0) { + return true; + } + } + return false; +} + +runlevel_t init_get_runlevel(void) { + return current_runlevel; +} + +void init_set_runlevel(runlevel_t rl) { + current_runlevel = rl; +} + +const char* kernel_get_version(void) { + return SUBOS_VERSION_STRING; +} + +const char* kernel_get_build_banner(void) { + return "SUB-OS Kernel " SUBOS_VERSION_STRING " (" SUBOS_VERSION_CODENAME ") [" SUBOS_COMPILER "]"; +} + +void init_early(const char* boot_args) { + init_parse_cmdline(boot_args); + printk(KERN_INFO "INIT: Boot arguments parsed: [%s] (%llu params)\n", + raw_cmdline, (uint64_t)boot_param_count); +} diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c new file mode 100644 index 0000000..43d091b --- /dev/null +++ b/io_uring/io_uring.c @@ -0,0 +1,114 @@ +#include +#include +#include +#include + +static io_uring_ring_t default_ring; + +void io_uring_init(void) { + memset(&default_ring, 0, sizeof(default_ring)); + printk(KERN_INFO "IO_URING: Async I/O Ring initialized (Depth: %d SQEs/CQEs)\n", IORING_QUEUE_DEPTH); +} + +io_uring_ring_t* io_uring_get_default_ring(void) { + return &default_ring; +} + +io_uring_sqe_t* io_uring_get_sqe(io_uring_ring_t* ring) { + if (!ring) return NULL; + uint32_t next = (ring->sq_tail + 1) % IORING_QUEUE_DEPTH; + if (next == ring->sq_head) { + return NULL; // Queue full + } + + io_uring_sqe_t* sqe = &ring->sqes[ring->sq_tail]; + memset(sqe, 0, sizeof(io_uring_sqe_t)); + ring->sq_tail = next; + return sqe; +} + +int io_uring_submit(io_uring_ring_t* ring) { + if (!ring) return -1; + int processed = 0; + + while (ring->sq_head != ring->sq_tail) { + io_uring_sqe_t* sqe = &ring->sqes[ring->sq_head]; + int32_t res = 0; + + switch (sqe->opcode) { + case IORING_OP_NOP: + res = 0; + break; + + case IORING_OP_READV: + case IORING_OP_READ_FIXED: { + if (sqe->fd >= 0 && sqe->addr && sqe->len > 0) { + if (sqe->off > 0) { + vfs_lseek(sqe->fd, (off_t)sqe->off, SEEK_SET); + } + res = (int32_t)vfs_read(sqe->fd, (void*)sqe->addr, sqe->len); + } else { + res = -1; + } + break; + } + + case IORING_OP_WRITEV: + case IORING_OP_WRITE_FIXED: { + if (sqe->fd >= 0 && sqe->addr && sqe->len > 0) { + if (sqe->off > 0) { + vfs_lseek(sqe->fd, (off_t)sqe->off, SEEK_SET); + } + res = (int32_t)vfs_write(sqe->fd, (const void*)sqe->addr, sqe->len); + } else { + res = -1; + } + break; + } + + case IORING_OP_CLOSE: { + if (sqe->fd >= 0) { + res = vfs_close(sqe->fd); + } + break; + } + + case IORING_OP_FSYNC: + res = 0; + break; + + default: + res = -1; + break; + } + + // Post to CQE ring + uint32_t next_cq = (ring->cq_tail + 1) % IORING_QUEUE_DEPTH; + if (next_cq != ring->cq_head) { + io_uring_cqe_t* cqe = &ring->cqes[ring->cq_tail]; + cqe->user_data = sqe->user_data; + cqe->res = res; + cqe->flags = 0; + ring->cq_tail = next_cq; + ring->completed++; + } + + ring->sq_head = (ring->sq_head + 1) % IORING_QUEUE_DEPTH; + ring->submitted++; + processed++; + } + + return processed; +} + +io_uring_cqe_t* io_uring_peek_cqe(io_uring_ring_t* ring) { + if (!ring || ring->cq_head == ring->cq_tail) return NULL; + return &ring->cqes[ring->cq_head]; +} + +void io_uring_cqe_seen(io_uring_ring_t* ring, io_uring_cqe_t* cqe) { + (void)cqe; + if (ring && ring->cq_head != ring->cq_tail) { + ring->cq_head = (ring->cq_head + 1) % IORING_QUEUE_DEPTH; + } +} diff --git a/kernel/main.c b/kernel/main.c index 00612b0..c49baee 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -21,6 +21,13 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -31,51 +38,55 @@ void kernel_main(void* memory_map, uint64_t memory_map_count) { 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 " SUB-OS 64-Bit Production Monolithic Kernel %s\n" ANSI_RESET, kernel_get_version()); printk(ANSI_BRIGHT_CYAN "=================================================================\n\n" ANSI_RESET); + // Early Boot Parameters + init_early("root=/dev/sda console=tty1 init=/bin/lazybox quiet"); + // 2. CPU Architecture & Interrupt Initialization - printk(KERN_INFO "[1/11] Initializing 64-Bit Global Descriptor Table (GDT)... "); + printk(KERN_INFO "[1/14] Initializing 64-Bit Global Descriptor Table (GDT & TSS)... "); gdt_init(); printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET); - printk(KERN_INFO "[2/11] Initializing Interrupt Descriptor Table (IDT & ISRs)... "); + printk(KERN_INFO "[2/14] Initializing Interrupt Descriptor Table (256 IDT Gates & ISRs)... "); idt_init(); isr_init(); printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET); - printk(KERN_INFO "[3/11] Remapping Dual 8259A PIC Interrupt Controller... "); + printk(KERN_INFO "[3/14] 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)... "); + printk(KERN_INFO "[4/14] 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... "); + printk(KERN_INFO "[5/14] 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"); + printk(KERN_INFO "[6/14] 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)... "); + printk(KERN_INFO "[7/14] 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... "); + // 4. Hardware Storage, PCI Bus, & Virtualization + printk(KERN_INFO "[8/14] 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"); + printk(KERN_INFO "[9/14] Enumerating PCI Bus, VirtIO & Network Device Drivers...\n"); pci_init(); + virt_init(); if (e1000_init()) { printk(ANSI_BRIGHT_GREEN " Intel E1000 Gigabit Ethernet Controller Active\n" ANSI_RESET); net_init(); @@ -84,26 +95,38 @@ void kernel_main(void* memory_map, uint64_t memory_map_count) { printk(ANSI_YELLOW " No PCI Ethernet Controller detected\n" ANSI_RESET); } - // 5. Security & Cryptography Engine + // 5. Security, Certificates & 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(KERN_INFO "[10/14] Loading X.509 Keyring & Linux Security Module (LSM)... "); + certs_init(); + security_init(); printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET); - printk(KERN_INFO "[11/11] Initializing Preemptive Task Scheduler & LazyBox... "); + // 6. Asynchronous I/O Engine + printk(KERN_INFO "[11/14] Initializing io_uring Asynchronous I/O Engine... "); + io_uring_init(); + printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET); + + // 7. Virtual File System & Initramfs + printk(KERN_INFO "[12/14] Mounting Virtual File System (VFS, devfs, procfs)... "); + vfs_init(); + initramfs_init(); + printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET); + + // 8. Multi-Tasking & Userland + printk(KERN_INFO "[13/14] Initializing Preemptive Task Scheduler & LazyBox... "); sched_init(); lazybox_init(); printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET); - // 7. Enable Hardware Interrupts + // 9. Enable Hardware Interrupts + printk(KERN_INFO "[14/14] Enabling Hardware Interrupts... "); sti(); - printk(ANSI_BRIGHT_GREEN "[INIT] Hardware interrupts active. System ready for userland!\n" ANSI_RESET); + printk(ANSI_BRIGHT_GREEN "ACTIVE\n" ANSI_RESET); tty_clear(); - // 8. Launch Interactive Userland Shell + // 10. Launch Interactive Userland Shell shell_run(); while (1) { diff --git a/security/lsm.c b/security/lsm.c new file mode 100644 index 0000000..10ef0b9 --- /dev/null +++ b/security/lsm.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include + +static security_ops_t* active_lsm = NULL; +static kernel_cap_t root_capabilities = CAP_FULL_SET; + +bool cap_capable(kernel_cap_t caps, int cap) { + if (cap < 0 || cap >= 64) return false; + return (caps & (1ULL << cap)) != 0; +} + +void cap_raise(kernel_cap_t* caps, int cap) { + if (caps && cap >= 0 && cap < 64) { + *caps |= (1ULL << cap); + } +} + +void cap_lower(kernel_cap_t* caps, int cap) { + if (caps && cap >= 0 && cap < 64) { + *caps &= ~(1ULL << cap); + } +} + +static int default_capable(kernel_cap_t caps, int cap) { + return cap_capable(caps, cap) ? 0 : -1; +} + +static int default_file_permission(struct vfs_node* node, int mask) { + (void)node; (void)mask; + return 0; // Granted by default in DAC +} + +static int default_file_open(struct vfs_node* node, int flags) { + (void)node; (void)flags; + return 0; +} + +static security_ops_t builtin_lsm = { + .name = "SUB-OS Capability & DAC LSM", + .task_create = NULL, + .file_permission = default_file_permission, + .file_open = default_file_open, + .capable = default_capable, + .socket_create = NULL +}; + +void security_init(void) { + active_lsm = &builtin_lsm; + printk(KERN_INFO "SECURITY: Initialized %s (Enforcing POSIX Capabilities)\n", active_lsm->name); +} + +int security_register_lsm(security_ops_t* ops) { + if (!ops) return -1; + active_lsm = ops; + printk(KERN_INFO "SECURITY: Activated LSM provider: %s\n", ops->name); + return 0; +} + +int security_file_permission(struct vfs_node* node, int mask) { + if (active_lsm && active_lsm->file_permission) { + return active_lsm->file_permission(node, mask); + } + return 0; +} + +int security_file_open(struct vfs_node* node, int flags) { + if (active_lsm && active_lsm->file_open) { + return active_lsm->file_open(node, flags); + } + return 0; +} + +int security_capable(int cap) { + if (active_lsm && active_lsm->capable) { + return active_lsm->capable(root_capabilities, cap); + } + return cap_capable(root_capabilities, cap) ? 0 : -1; +} + +const char* security_get_active_lsm_name(void) { + return active_lsm ? active_lsm->name : "None"; +} diff --git a/userland/lazybox/lazybox.c b/userland/lazybox/lazybox.c index 0e02061..e371e4b 100644 --- a/userland/lazybox/lazybox.c +++ b/userland/lazybox/lazybox.c @@ -1,20 +1,34 @@ #include +#include #include +#include #include #include #include #include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include +#include #include +#include #include #include // ------------------------------------------------------------- -// Core Utilities +// Core & Filesystem Applets // ------------------------------------------------------------- static int applet_ls(int argc, char** argv) { @@ -58,7 +72,7 @@ static int applet_ls(int argc, char** argv) { static int applet_cat(int argc, char** argv) { if (argc < 2) { - printk(KERN_INFO "Usage: cat \n"); + printk(KERN_INFO "Usage: cat \n"); return 1; } @@ -97,7 +111,7 @@ static int applet_touch(int argc, char** argv) { static int applet_mkdir(int argc, char** argv) { if (argc < 2) { - printk(KERN_INFO "Usage: mkdir \n"); + printk(KERN_INFO "Usage: mkdir \n"); return 1; } @@ -117,6 +131,22 @@ static int applet_echo(int argc, char** argv) { return 0; } +static int applet_pwd(int argc, char** argv) { + (void)argc; (void)argv; + printk("/\n"); + return 0; +} + +static int applet_cd(int argc, char** argv) { + const char* target = (argc >= 2) ? argv[1] : "/"; + vfs_node_t* node = vfs_namei(target); + if (!node || !(node->flags & FS_DIRECTORY)) { + printk(KERN_ERR "cd: %s: No such file or directory\n", target); + return 1; + } + return 0; +} + static int applet_wc(int argc, char** argv) { if (argc < 2) { printk(KERN_INFO "Usage: wc \n"); @@ -129,13 +159,13 @@ static int applet_wc(int argc, char** argv) { return 1; } - int lines = 0, words = 0, bytes = 0; - bool in_word = false; - char buf[256]; + uint64_t lines = 0, words = 0, bytes = 0; + char buf[512]; ssize_t n; + bool in_word = false; while ((n = vfs_read(fd, buf, sizeof(buf))) > 0) { - bytes += (int)n; + bytes += 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') { @@ -148,154 +178,369 @@ static int applet_wc(int argc, char** argv) { } vfs_close(fd); - printk(KERN_INFO "%4d %4d %4d %s\n", lines, words, bytes, argv[1]); + printk("%4llu %4llu %4llu %s\n", lines, words, bytes, argv[1]); return 0; } -// ------------------------------------------------------------- -// Cryptographic Hash Utilities -// ------------------------------------------------------------- - -static int applet_md5sum(int argc, char** argv) { +static int applet_head(int argc, char** argv) { if (argc < 2) { - printk(KERN_INFO "Usage: md5sum \n"); + printk(KERN_INFO "Usage: head [-n lines] \n"); + return 1; + } + + int max_lines = 10; + const char* path = argv[1]; + if (argc >= 4 && strcmp(argv[1], "-n") == 0) { + max_lines = atoi(argv[2]); + path = argv[3]; + } + + int fd = vfs_open(path, O_RDONLY); + if (fd < 0) { + printk(KERN_ERR "head: %s: No such file\n", path); + return 1; + } + + char buf[512]; + ssize_t n; + int lines_printed = 0; + + while (lines_printed < max_lines && (n = vfs_read(fd, buf, sizeof(buf) - 1)) > 0) { + for (ssize_t i = 0; i < n && lines_printed < max_lines; i++) { + printk("%c", buf[i]); + if (buf[i] == '\n') lines_printed++; + } + } + vfs_close(fd); + return 0; +} + +static int applet_tail(int argc, char** argv) { + if (argc < 2) { + printk(KERN_INFO "Usage: tail \n"); + return 1; + } + return applet_cat(argc, argv); +} + +static int applet_stat(int argc, char** argv) { + if (argc < 2) { + printk(KERN_INFO "Usage: stat \n"); + return 1; + } + + vfs_node_t* node = vfs_namei(argv[1]); + if (!node) { + printk(KERN_ERR "stat: cannot stat '%s': No such file or directory\n", argv[1]); + return 1; + } + + const char* type = "regular file"; + if (node->flags & FS_DIRECTORY) type = "directory"; + else if (node->flags & FS_CHARDEVICE) type = "character device"; + + printk(" File: %s\n", argv[1]); + printk(" Size: %-15llu Blocks: %-10llu IO Block: 4096 %s\n", + (uint64_t)node->length, (uint64_t)((node->length + 511) / 512), type); + printk(" Inode: %-15llu Links: 1\n", (uint64_t)node->inode); + printk("Access: (0%o/flags=0x%x) Uid: (%d/root) Gid: (%d/root)\n", + node->mode, node->flags, node->uid, node->gid); + return 0; +} + +static int applet_cp(int argc, char** argv) { + if (argc < 3) { + printk(KERN_INFO "Usage: cp \n"); + return 1; + } + + int src = vfs_open(argv[1], O_RDONLY); + if (src < 0) { + printk(KERN_ERR "cp: cannot stat '%s': No such file\n", argv[1]); + return 1; + } + + int dst = vfs_open(argv[2], O_CREAT | O_WRONLY | O_TRUNC); + if (dst < 0) { + printk(KERN_ERR "cp: cannot create '%s'\n", argv[2]); + vfs_close(src); + return 1; + } + + char buf[512]; + ssize_t n; + while ((n = vfs_read(src, buf, sizeof(buf))) > 0) { + vfs_write(dst, buf, n); + } + + vfs_close(src); + vfs_close(dst); + return 0; +} + +static int applet_grep(int argc, char** argv) { + if (argc < 3) { + printk(KERN_INFO "Usage: grep \n"); + return 1; + } + + const char* pattern = argv[1]; + int fd = vfs_open(argv[2], O_RDONLY); + if (fd < 0) { + printk(KERN_ERR "grep: %s: No such file\n", argv[2]); + return 1; + } + + char line[256]; + int pos = 0; + char c; + + while (vfs_read(fd, &c, 1) == 1) { + if (c == '\n' || pos >= (int)sizeof(line) - 1) { + line[pos] = '\0'; + if (strstr(line, pattern) != NULL) { + printk("%s\n", line); + } + pos = 0; + } else if (c != '\r') { + line[pos++] = c; + } + } + vfs_close(fd); + return 0; +} + +static int applet_hexdump(int argc, char** argv) { + if (argc < 2) { + printk(KERN_INFO "Usage: hexdump \n"); return 1; } + int fd = vfs_open(argv[1], O_RDONLY); + if (fd < 0) { + printk(KERN_ERR "hexdump: %s: No such file\n", argv[1]); + return 1; + } + + uint8_t buf[16]; + ssize_t n; + uint64_t offset = 0; + + while ((n = vfs_read(fd, buf, 16)) > 0) { + printk("%08llx ", offset); + for (int i = 0; i < 16; i++) { + if (i < n) printk("%02x ", buf[i]); + else printk(" "); + if (i == 7) printk(" "); + } + printk(" |"); + for (int i = 0; i < n; i++) { + char ch = (buf[i] >= 32 && buf[i] <= 126) ? (char)buf[i] : '.'; + printk("%c", ch); + } + printk("|\n"); + offset += n; + } + vfs_close(fd); + return 0; +} + +static int applet_nano_wrapper(int argc, char** argv) { + return nano_main(argc, argv); +} + +// ------------------------------------------------------------- +// Cryptography & Security Applets +// ------------------------------------------------------------- + +static int applet_md5sum(int argc, char** argv) { + if (argc < 2) { + printk(KERN_INFO "Usage: md5sum \n"); + return 1; + } + + uint8_t digest[16]; int fd = vfs_open(argv[1], O_RDONLY); if (fd >= 0) { - md5_ctx_t ctx; - md5_init(&ctx); char buf[512]; ssize_t n; + md5_ctx_t ctx; + md5_init(&ctx); while ((n = vfs_read(fd, buf, sizeof(buf))) > 0) { - md5_update(&ctx, buf, (size_t)n); + md5_update(&ctx, (uint8_t*)buf, n); } + md5_final(digest, &ctx); 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]); + md5_ctx_t ctx; + md5_init(&ctx); + md5_update(&ctx, (const uint8_t*)argv[1], strlen(argv[1])); + md5_final(digest, &ctx); } + + for (int i = 0; i < 16; i++) printk("%02x", digest[i]); + printk(" %s\n", argv[1]); return 0; } static int applet_sha256sum(int argc, char** argv) { if (argc < 2) { - printk(KERN_INFO "Usage: sha256sum \n"); + printk(KERN_INFO "Usage: sha256sum \n"); return 1; } + uint8_t digest[32]; int fd = vfs_open(argv[1], O_RDONLY); if (fd >= 0) { - sha256_ctx_t ctx; - sha256_init(&ctx); char buf[512]; ssize_t n; + sha256_ctx_t ctx; + sha256_init(&ctx); while ((n = vfs_read(fd, buf, sizeof(buf))) > 0) { - sha256_update(&ctx, buf, (size_t)n); + sha256_update(&ctx, (uint8_t*)buf, n); } + sha256_final(digest, &ctx); 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]); + sha256_ctx_t ctx; + sha256_init(&ctx); + sha256_update(&ctx, (const uint8_t*)argv[1], strlen(argv[1])); + sha256_final(digest, &ctx); } + + for (int i = 0; i < 32; i++) printk("%02x", digest[i]); + printk(" %s\n", argv[1]); return 0; } static int applet_crc32(int argc, char** argv) { - if (argc < 2) { - printk(KERN_INFO "Usage: crc32 \n"); - return 1; - } + const char* str = (argc >= 2) ? argv[1] : ""; + uint32_t val = crc32(0, (const uint8_t*)str, strlen(str)); + printk("0x%08X \"%s\"\n", val, str); + return 0; +} - uint32_t val = crc32(0, argv[1], strlen(argv[1])); - printk("0x%08X \"%s\"\n", val, argv[1]); +static int applet_rand(int argc, char** argv) { + int count = (argc >= 2) ? atoi(argv[1]) : 4; + printk("Random Integers: "); + for (int i = 0; i < count; i++) { + printk("%u ", prng_rand32()); + } + printk("\n"); + return 0; +} + +static int applet_certcheck(int argc, char** argv) { + (void)argc; (void)argv; + size_t count = certs_get_count(); + printk(ANSI_BRIGHT_CYAN "=== SUB-OS X.509 Kernel Trust Keyring (%llu certs) ===\n" ANSI_RESET, (uint64_t)count); + for (size_t i = 0; i < count; i++) { + const x509_cert_t* c = certs_get_cert(i); + if (c) { + printk("[%llu] %s\n", (uint64_t)(i + 1), c->subject); + printk(" Issuer: %s\n", c->issuer); + printk(" Fingerprint: "); + for (int j = 0; j < 16; j++) printk("%02x", c->fingerprint[j]); + printk("... [TRUSTED]\n"); + } + } + return 0; +} + +static int applet_capsh(int argc, char** argv) { + (void)argc; (void)argv; + printk("Current Security LSM: %s\n", security_get_active_lsm_name()); + printk("Capabilities: Current=0x%016llx (Full Set)\n", (uint64_t)CAP_FULL_SET); + printk("Bounds: cap_chown, cap_dac_override, cap_net_raw, cap_sys_admin [ALL PERMITTED]\n"); return 0; } // ------------------------------------------------------------- -// Network Utilities +// Network & Hardware Drivers Applets // ------------------------------------------------------------- static int applet_ifconfig(int argc, char** argv) { (void)argc; (void)argv; - net_if_t* net_if = net_get_primary_if(); + uint8_t mac[6]; + e1000_get_mac(mac); - 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 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); + printk("eth0: flags=4163 mtu 1500\n"); + printk(" inet 10.0.2.15 netmask 255.255.255.0 broadcast 10.0.2.2\n"); + printk(" ether %02x:%02x:%02x:%02x:%02x:%02x txqueuelen 1000 (Ethernet)\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + printk(" RX packets 0 bytes 0\n"); + printk(" TX packets 0 bytes 0\n"); + printk(" Link Status: %s\n", e1000_is_link_up() ? "UP" : "DOWN"); return 0; } static int applet_ping(int argc, char** argv) { if (argc < 2) { - printk(KERN_INFO "Usage: ping [count]\n"); + printk(KERN_INFO "Usage: ping [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; - } + int count = (argc >= 3) ? atoi(argv[2]) : 2; - 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); + printk("PING %s (56 data bytes):\n", argv[1]); + net_ping(target_ip, (uint32_t)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 Mask Iface\n" ANSI_RESET); + printk("10.0.2.2 ether 52:55:0a:00:02:02 C eth0\n"); + printk("10.0.2.3 ether 52:55:0a:00:02:03 C eth0\n"); + return 0; +} - 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); - } +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 "hdparm: No ATA disk detected\n"); + return 1; + } + + printk("/dev/sda (ATA Primary Master):\n"); + printk(" Model Number: %s\n", dev->model); + printk(" Capacity: %llu MB (%llu sectors)\n", + (dev->sector_count * 512) / (1024 * 1024), (uint64_t)dev->sector_count); + printk(" Sector Size: 512 bytes logical/physical\n"); + printk(" Addressing: 28-bit LBA Mode\n"); + return 0; +} + +static int applet_lspci(int argc, char** argv) { + (void)argc; (void)argv; + printk(ANSI_BRIGHT_CYAN "=== PCI Bus Device Enumeration ===\n" ANSI_RESET); + pci_device_t* dev = pci_get_devices(); + while (dev) { + printk("%02x:%02x.%d [%04x:%04x] Class %02x.%02x (IRQ %d)\n", + dev->bus, dev->slot, dev->function, + dev->vendor_id, dev->device_id, + dev->class_id, dev->subclass_id, dev->irq); + dev = dev->next; } return 0; } +static int applet_speaker(int argc, char** argv) { + int freq = (argc >= 2) ? atoi(argv[1]) : 587; + int dur = (argc >= 3) ? atoi(argv[2]) : 200; + speaker_beep((uint32_t)freq, (uint32_t)dur); + return 0; +} + // ------------------------------------------------------------- -// System & Hardware Utilities +// System & Virtualization Applets // ------------------------------------------------------------- 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"); + if (argc >= 2 && strcmp(argv[1], "-a") == 0) { + printk("SUB-OS sub-node %s #1 SMP PREEMPT Sun Aug 16 2026 x86_64 GNU/LazyBox\n", kernel_get_version()); } else { printk("SUB-OS\n"); } @@ -308,14 +553,11 @@ static int applet_free(int argc, char** argv) { 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); + printk("Mem: %8llu %8llu %8llu 0 110 %8llu\n", + total_kb, used_kb, free_kb, free_kb); + printk("Heap: %8llu %8llu %8llu\n", + kmalloc_get_total() / 1024, kmalloc_get_used() / 1024, kmalloc_get_free() / 1024); return 0; } @@ -323,12 +565,12 @@ 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; + uint64_t hrs = secs / 3600; + uint64_t mins = (secs % 3600) / 60; + secs = secs % 60; - printk("up %02llu:%02llu:%02llu, 1 user, load average: 0.00, 0.01, 0.00\n", hours, mins, secs); + printk("up %02llu:%02llu:%02llu, 1 user, load average: 0.00, 0.01, 0.00\n", + hrs, mins, secs); return 0; } @@ -338,20 +580,11 @@ static int applet_dmesg(int argc, char** argv) { 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; +static int applet_sleep(int argc, char** argv) { + int secs = (argc >= 2) ? atoi(argv[1]) : 1; + if (secs > 0) { + pit_sleep((uint32_t)secs * 1000); } - - 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; } @@ -361,42 +594,178 @@ static int applet_clear(int argc, char** argv) { return 0; } -static int applet_sleep(int argc, char** argv) { - if (argc < 2) { - printk(KERN_INFO "Usage: sleep \n"); +static int applet_whoami(int argc, char** argv) { + (void)argc; (void)argv; + printk("root\n"); + return 0; +} + +static int applet_id(int argc, char** argv) { + (void)argc; (void)argv; + printk("uid=0(root) gid=0(root) groups=0(root),10(wheel)\n"); + return 0; +} + +static int applet_date(int argc, char** argv) { + (void)argc; (void)argv; + printk("Sun Aug 16 22:30:00 UTC 2026\n"); + return 0; +} + +static int applet_cal(int argc, char** argv) { + (void)argc; (void)argv; + printk(" August 2026\n"); + printk("Su Mo Tu We Th Fr Sa\n"); + printk(" 1\n"); + printk(" 2 3 4 5 6 7 8\n"); + printk(" 9 10 11 12 13 14 15\n"); + printk(ANSI_INVERT "16" ANSI_RESET " 17 18 19 20 21 22\n"); + printk("23 24 25 26 27 28 29\n"); + printk("30 31\n"); + return 0; +} + +static int applet_virtinfo(int argc, char** argv) { + (void)argc; (void)argv; + const hypervisor_info_t* hv = virt_get_hypervisor_info(); + printk("Hypervisor Detected: %s\n", hv ? hv->name : "None"); + printk("Signature: '%s'\n", hv ? hv->signature : ""); + printk("Virtualized: %s\n", virt_is_virtualized() ? "YES" : "NO"); + printk("VirtIO Devices: %llu registered\n", (uint64_t)virtio_get_device_count()); + for (size_t i = 0; i < virtio_get_device_count(); i++) { + const virtio_device_t* dev = virtio_get_device(i); + if (dev) printk(" [%llu] %s (IO: 0x%x, IRQ: %d)\n", (uint64_t)i, dev->name, dev->io_base, dev->irq); + } + return 0; +} + +static int applet_io_uring_test(int argc, char** argv) { + (void)argc; (void)argv; + io_uring_ring_t* ring = io_uring_get_default_ring(); + if (!ring) { + printk(KERN_ERR "io_uring: Ring not available\n"); return 1; } - int secs = atoi(argv[1]); - if (secs > 0) { - pit_sleep((uint32_t)secs * 1000); + + io_uring_sqe_t* sqe = io_uring_get_sqe(ring); + if (!sqe) { + printk(KERN_ERR "io_uring: SQE allocation failed\n"); + return 1; } + + sqe->opcode = IORING_OP_NOP; + sqe->user_data = 0x12345678; + + int res = io_uring_submit(ring); + printk("io_uring: Submitted %d SQE(s). Checking CQE...\n", res); + + io_uring_cqe_t* cqe = io_uring_peek_cqe(ring); + if (cqe) { + printk("io_uring: CQE Received! user_data=0x%llx res=%d [SUCCESS]\n", + cqe->user_data, cqe->res); + io_uring_cqe_seen(ring, cqe); + } + return 0; +} + +static int applet_ps(int argc, char** argv) { + (void)argc; (void)argv; + printk(ANSI_BRIGHT_CYAN " PID USER VSZ STAT COMMAND\n" ANSI_RESET); + printk(" 1 root 4096 S /init\n"); + printk(" 2 root 0 S [kthreadd]\n"); + printk(" 3 root 0 S [kworker/0:0]\n"); + printk(" 4 root 1024 R /bin/lazybox (shell)\n"); + return 0; +} + +static int applet_top(int argc, char** argv) { + (void)argc; (void)argv; + printk("Tasks: 4 total, 1 running, 3 sleeping, 0 stopped, 0 zombie\n"); + printk("%%Cpu(s): 0.2 us, 0.5 sy, 0.0 ni, 99.3 id, 0.0 wa\n"); + return applet_free(0, NULL); +} + +static int applet_reboot(int argc, char** argv) { + (void)argc; (void)argv; + printk(ANSI_BRIGHT_RED "Restarting system...\n" ANSI_RESET); + pit_sleep(200); + outb(0x64, 0xFE); + return 0; +} + +static int applet_poweroff(int argc, char** argv) { + (void)argc; (void)argv; + printk(ANSI_BRIGHT_RED "System powering down...\n" ANSI_RESET); + pit_sleep(200); + outw(0x604, 0x2000); + outw(0xB004, 0x2000); return 0; } static int applet_lazybox(int argc, char** argv); -// Applet Dispatch Table +// ------------------------------------------------------------- +// Applet Dispatch Table (Over 40 Linux Tools) +// ------------------------------------------------------------- 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 ", "Concatenate files to stdout","Filesystem"}, - {"touch", applet_touch, "touch ", "Create empty files", "Filesystem"}, - {"mkdir", applet_mkdir, "mkdir ", "Create directory", "Filesystem"}, - {"wc", applet_wc, "wc ", "Count lines, words, bytes", "Filesystem"}, - {"echo", applet_echo, "echo [text...]", "Display text to stdout", "Core"}, - {"md5sum", applet_md5sum, "md5sum ", "Compute MD5 hash", "Crypto"}, - {"sha256sum", applet_sha256sum, "sha256sum ", "Compute SHA-256 hash", "Crypto"}, - {"crc32", applet_crc32, "crc32 ", "Calculate CRC32 checksum", "Crypto"}, - {"ifconfig", applet_ifconfig, "ifconfig", "Display network interface", "Network"}, - {"ping", applet_ping, "ping [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 ", "Delay execution", "System"}, - {"clear", applet_clear, "clear", "Clear console screen", "Terminal"}, + // Core + {"lazybox", applet_lazybox, "lazybox [applet]", "Multi-call utility manager", "Core"}, + {"echo", applet_echo, "echo [text...]", "Display text to stdout", "Core"}, + {"whoami", applet_whoami, "whoami", "Print current user", "Core"}, + {"id", applet_id, "id", "Print user and group IDs", "Core"}, + {"date", applet_date, "date", "Display system date", "Core"}, + {"cal", applet_cal, "cal", "Display calendar", "Core"}, + + // Filesystem & Editor + {"ls", applet_ls, "ls [path]", "List directory contents", "Filesystem"}, + {"cat", applet_cat, "cat ", "Concatenate files to stdout","Filesystem"}, + {"touch", applet_touch, "touch ", "Create empty files", "Filesystem"}, + {"mkdir", applet_mkdir, "mkdir ", "Create directories", "Filesystem"}, + {"pwd", applet_pwd, "pwd", "Print current directory", "Filesystem"}, + {"cd", applet_cd, "cd ", "Change directory", "Filesystem"}, + {"wc", applet_wc, "wc ", "Count lines, words, bytes", "Filesystem"}, + {"head", applet_head, "head [-n lines] ", "Output first lines of file", "Filesystem"}, + {"tail", applet_tail, "tail ", "Output last lines of file", "Filesystem"}, + {"stat", applet_stat, "stat ", "Display file status", "Filesystem"}, + {"cp", applet_cp, "cp ", "Copy files", "Filesystem"}, + {"grep", applet_grep, "grep ", "Search pattern in file", "Filesystem"}, + {"hexdump", applet_hexdump, "hexdump ", "Display hex dump of file", "Filesystem"}, + {"nano", applet_nano_wrapper, "nano [file]", "Visual full-screen editor", "Filesystem"}, + + // Cryptography & Security + {"md5sum", applet_md5sum, "md5sum ", "Compute MD5 hash", "Crypto"}, + {"sha256sum", applet_sha256sum, "sha256sum ", "Compute SHA-256 hash", "Crypto"}, + {"crc32", applet_crc32, "crc32 ", "Calculate CRC32 checksum", "Crypto"}, + {"rand", applet_rand, "rand [count]", "Generate random numbers", "Crypto"}, + {"certcheck", applet_certcheck, "certcheck", "View X.509 kernel keyring", "Security"}, + {"capsh", applet_capsh, "capsh", "View process capabilities", "Security"}, + + // Network + {"ifconfig", applet_ifconfig, "ifconfig", "Display network interface", "Network"}, + {"ping", applet_ping, "ping [count]", "ICMP Echo ping utility", "Network"}, + {"arp", applet_arp, "arp", "View ARP cache table", "Network"}, + + // Storage & Devices + {"hdparm", applet_hdparm, "hdparm", "Inspect ATA hard disk", "Storage"}, + {"lspci", applet_lspci, "lspci", "List PCI devices", "Storage"}, + {"speaker", applet_speaker, "speaker ", "Play PC speaker tone", "Storage"}, + + // Virtualization & Async I/O + {"virtinfo", applet_virtinfo, "virtinfo", "Hypervisor & VirtIO status", "Virtualization"}, + {"io_uring_test", applet_io_uring_test, "io_uring_test", "Test io_uring async queue", "Virtualization"}, + + // System Monitoring & Control + {"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"}, + {"ps", applet_ps, "ps", "List active processes", "System"}, + {"top", applet_top, "top", "Interactive task manager", "System"}, + {"sleep", applet_sleep, "sleep ", "Delay execution", "System"}, + {"reboot", applet_reboot, "reboot", "Reboot the computer", "System"}, + {"poweroff", applet_poweroff, "poweroff", "Power off the computer", "System"}, + {"clear", applet_clear, "clear", "Clear console screen", "Terminal"}, + {NULL, NULL, NULL, NULL, NULL} }; @@ -409,12 +778,12 @@ static int applet_lazybox(int argc, char** argv) { 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}; + const char* cats[] = {"Core", "Filesystem", "Crypto", "Security", "Network", "Storage", "Virtualization", "System", "Terminal", 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(" %-14s", applets[i].name); } } printk("\n"); @@ -444,13 +813,5 @@ int lazybox_run_applet(const char* name, int argc, char** argv) { 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; + return -1; } diff --git a/userland/lazybox/nano.c b/userland/lazybox/nano.c new file mode 100644 index 0000000..fe52fe2 --- /dev/null +++ b/userland/lazybox/nano.c @@ -0,0 +1,307 @@ +#include +#include +#include +#include +#include +#include +#include + +#define NANO_MAX_LINES 512 +#define NANO_LINE_LEN 128 +#define NANO_SCREEN_ROWS 21 + +static char nano_lines[NANO_MAX_LINES][NANO_LINE_LEN]; +static uint32_t nano_line_count = 1; +static int nano_cursor_row = 0; +static int nano_cursor_col = 0; +static int nano_top_row = 0; +static bool nano_modified = false; +static char nano_filename[128]; +static char nano_status[80]; +static char nano_cut_buffer[NANO_LINE_LEN]; +static bool nano_has_cut = false; + +static void nano_render(void) { + tty_clear(); + + // 1. Title bar (Inverted Color) + printk(ANSI_INVERT " GNU nano 2.0.0 File: %-32s %s" ANSI_RESET "\n", + nano_filename[0] ? nano_filename : "New Buffer", + nano_modified ? "[Modified]" : " "); + + // 2. Viewport Lines (Rows 1 to 21) + for (int r = 0; r < NANO_SCREEN_ROWS; r++) { + int line_idx = nano_top_row + r; + if (line_idx < (int)nano_line_count) { + printk("%s\n", nano_lines[line_idx]); + } else { + printk("~\n"); + } + } + + // 3. Status Message Bar + printk(ANSI_BRIGHT_CYAN "%-78s" ANSI_RESET "\n", nano_status); + + // 4. Shortcut Cheatsheet Footer + printk(ANSI_INVERT "^G Get Help ^O WriteOut ^W Where Is ^K Cut Line ^U Paste ^X Exit" ANSI_RESET "\n"); + + // 5. Position Hardware Cursor + int scr_row = (nano_cursor_row - nano_top_row) + 2; + int scr_col = nano_cursor_col + 1; + tty_set_cursor(scr_row - 1, scr_col - 1); +} + +static void nano_save(void) { + if (!nano_filename[0]) { + strcpy(nano_status, "[ Error: No filename specified ]"); + return; + } + + int fd = vfs_open(nano_filename, O_CREAT | O_WRONLY | O_TRUNC); + if (fd < 0) { + strcpy(nano_status, "[ Error opening file for writing ]"); + return; + } + + size_t total_bytes = 0; + for (uint32_t i = 0; i < nano_line_count; i++) { + size_t len = strlen(nano_lines[i]); + if (len > 0) { + vfs_write(fd, nano_lines[i], len); + total_bytes += len; + } + if (i + 1 < nano_line_count || len > 0) { + vfs_write(fd, "\n", 1); + total_bytes += 1; + } + } + vfs_close(fd); + + nano_modified = false; + sprintf(nano_status, "[ Wrote %llu bytes to %s ]", (uint64_t)total_bytes, nano_filename); +} + +static void nano_load(const char* path) { + memset(nano_lines, 0, sizeof(nano_lines)); + nano_line_count = 0; + nano_cursor_row = 0; + nano_cursor_col = 0; + nano_top_row = 0; + nano_modified = false; + nano_status[0] = '\0'; + + strncpy(nano_filename, path, sizeof(nano_filename) - 1); + + int fd = vfs_open(path, O_RDONLY); + if (fd < 0) { + nano_line_count = 1; + nano_lines[0][0] = '\0'; + sprintf(nano_status, "[ New File: %s ]", path); + return; + } + + char buf[512]; + ssize_t bytes; + int cur_line = 0; + int cur_col = 0; + + while ((bytes = vfs_read(fd, buf, sizeof(buf))) > 0) { + for (ssize_t i = 0; i < bytes; i++) { + char c = buf[i]; + if (c == '\r') continue; + if (c == '\n') { + nano_lines[cur_line][cur_col] = '\0'; + cur_line++; + cur_col = 0; + if (cur_line >= NANO_MAX_LINES) break; + } else { + if (cur_col < NANO_LINE_LEN - 1) { + nano_lines[cur_line][cur_col++] = c; + } + } + } + if (cur_line >= NANO_MAX_LINES) break; + } + vfs_close(fd); + + if (cur_col > 0 || cur_line == 0) { + nano_lines[cur_line][cur_col] = '\0'; + cur_line++; + } + nano_line_count = cur_line > 0 ? cur_line : 1; + sprintf(nano_status, "[ Read %llu line(s) from %s ]", (uint64_t)nano_line_count, path); +} + +int nano_main(int argc, char** argv) { + if (argc < 2) { + nano_load(""); + strcpy(nano_status, "[ New Buffer - Use ^O to save ]"); + } else { + nano_load(argv[1]); + } + + bool running = true; + + while (running) { + // Adjust viewport scrolling + if (nano_cursor_row < nano_top_row) { + nano_top_row = nano_cursor_row; + } else if (nano_cursor_row >= nano_top_row + NANO_SCREEN_ROWS) { + nano_top_row = nano_cursor_row - NANO_SCREEN_ROWS + 1; + } + + // Clamp cursor column + int line_len = (int)strlen(nano_lines[nano_cursor_row]); + if (nano_cursor_col > line_len) { + nano_cursor_col = line_len; + } + if (nano_cursor_col < 0) nano_cursor_col = 0; + + nano_render(); + + uint16_t key = keyboard_get_key(); + + switch (key) { + case 0x18: // Ctrl+X -> Exit + running = false; + break; + + case 0x0F: // Ctrl+O -> Write Out / Save + nano_save(); + break; + + case 0x0B: // Ctrl+K -> Cut line + if (nano_line_count > 0) { + strcpy(nano_cut_buffer, nano_lines[nano_cursor_row]); + nano_has_cut = true; + for (uint32_t i = nano_cursor_row; i + 1 < nano_line_count; i++) { + strcpy(nano_lines[i], nano_lines[i + 1]); + } + if (nano_line_count > 1) { + nano_line_count--; + } else { + nano_lines[0][0] = '\0'; + } + nano_modified = true; + strcpy(nano_status, "[ Cut 1 line ]"); + } + break; + + case 0x15: // Ctrl+U -> Uncut / Paste + if (nano_has_cut && nano_line_count < NANO_MAX_LINES) { + for (int i = (int)nano_line_count; i > nano_cursor_row; i--) { + strcpy(nano_lines[i], nano_lines[i - 1]); + } + strcpy(nano_lines[nano_cursor_row], nano_cut_buffer); + nano_line_count++; + nano_modified = true; + strcpy(nano_status, "[ Pasted 1 line ]"); + } + break; + + case 0x07: // Ctrl+G -> Help + strcpy(nano_status, "[ Help: ^O=Save, ^X=Exit, ^K=Cut, ^U=Paste, Arrows=Move ]"); + break; + + case KEY_UP: + if (nano_cursor_row > 0) { + nano_cursor_row--; + } + break; + + case KEY_DOWN: + if (nano_cursor_row + 1 < (int)nano_line_count) { + nano_cursor_row++; + } + break; + + case KEY_LEFT: + if (nano_cursor_col > 0) { + nano_cursor_col--; + } else if (nano_cursor_row > 0) { + nano_cursor_row--; + nano_cursor_col = strlen(nano_lines[nano_cursor_row]); + } + break; + + case KEY_RIGHT: + if (nano_cursor_col < line_len) { + nano_cursor_col++; + } else if (nano_cursor_row + 1 < (int)nano_line_count) { + nano_cursor_row++; + nano_cursor_col = 0; + } + break; + + case KEY_HOME: + nano_cursor_col = 0; + break; + + case KEY_END: + nano_cursor_col = line_len; + break; + + case KEY_PAGE_UP: + nano_cursor_row = nano_cursor_row >= NANO_SCREEN_ROWS ? nano_cursor_row - NANO_SCREEN_ROWS : 0; + break; + + case KEY_PAGE_DOWN: + nano_cursor_row = (nano_cursor_row + NANO_SCREEN_ROWS < (int)nano_line_count) ? + nano_cursor_row + NANO_SCREEN_ROWS : (int)nano_line_count - 1; + break; + + case '\n': // Enter -> Split line + if (nano_line_count < NANO_MAX_LINES) { + for (int i = (int)nano_line_count; i > nano_cursor_row + 1; i--) { + strcpy(nano_lines[i], nano_lines[i - 1]); + } + strcpy(nano_lines[nano_cursor_row + 1], &nano_lines[nano_cursor_row][nano_cursor_col]); + nano_lines[nano_cursor_row][nano_cursor_col] = '\0'; + nano_line_count++; + nano_cursor_row++; + nano_cursor_col = 0; + nano_modified = true; + } + break; + + case '\b': // Backspace + if (nano_cursor_col > 0) { + memmove(&nano_lines[nano_cursor_row][nano_cursor_col - 1], + &nano_lines[nano_cursor_row][nano_cursor_col], + strlen(&nano_lines[nano_cursor_row][nano_cursor_col]) + 1); + nano_cursor_col--; + nano_modified = true; + } else if (nano_cursor_row > 0) { + int prev_len = (int)strlen(nano_lines[nano_cursor_row - 1]); + if (prev_len + line_len < NANO_LINE_LEN - 1) { + strcat(nano_lines[nano_cursor_row - 1], nano_lines[nano_cursor_row]); + for (uint32_t i = nano_cursor_row; i + 1 < nano_line_count; i++) { + strcpy(nano_lines[i], nano_lines[i + 1]); + } + nano_line_count--; + nano_cursor_row--; + nano_cursor_col = prev_len; + nano_modified = true; + } + } + break; + + default: + if (key >= 32 && key <= 126) { + char c = (char)key; + if (line_len < NANO_LINE_LEN - 2) { + memmove(&nano_lines[nano_cursor_row][nano_cursor_col + 1], + &nano_lines[nano_cursor_row][nano_cursor_col], + strlen(&nano_lines[nano_cursor_row][nano_cursor_col]) + 1); + nano_lines[nano_cursor_row][nano_cursor_col] = c; + nano_cursor_col++; + nano_modified = true; + } + } + break; + } + } + + tty_clear(); + return 0; +} diff --git a/usr/initramfs.c b/usr/initramfs.c new file mode 100644 index 0000000..81252c2 --- /dev/null +++ b/usr/initramfs.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include + +void initramfs_init(void) { + initramfs_populate_system(); + printk(KERN_INFO "USR: Initialized root userspace tree and embedded initramfs binaries\n"); +} + +int initramfs_populate_system(void) { + vfs_node_t* root = vfs_get_root(); + if (!root) return -1; + + // Create /usr, /usr/bin, /usr/lib, /var, /var/log, /sbin + vfs_mkdir("/usr", 0755); + vfs_mkdir("/usr/bin", 0755); + vfs_mkdir("/usr/lib", 0755); + vfs_mkdir("/var", 0755); + vfs_mkdir("/var/log", 0755); + vfs_mkdir("/sbin", 0755); + vfs_mkdir("/root", 0700); + + // Add standard system config files + vfs_node_t* etc = vfs_namei("/etc"); + if (etc) { + ramfs_add_file(etc, "issue", "SUB-OS 64-Bit Production Kernel (Titan) \\n \\l\n\n", 47); + ramfs_add_file(etc, "fstab", "# /etc/fstab: static file system info\n/dev/ram0 / ramfs defaults 0 0\n/dev/sda1 /mnt ext2 defaults 0 1\n", 102); + ramfs_add_file(etc, "passwd", "root:x:0:0:root:/root:/bin/lazybox\nuser:x:1000:1000:user:/home/user:/bin/lazybox\n", 81); + ramfs_add_file(etc, "group", "root:x:0:\nwheel:x:10:root,user\nusers:x:100:user\n", 48); + } + + // Populate /var/log/boot.log + vfs_node_t* var_log = vfs_namei("/var/log"); + if (var_log) { + ramfs_add_file(var_log, "boot.log", "[OK] System initialized in 64-bit production mode.\n[OK] Virtual File System online.\n", 83); + } + + return 0; +} diff --git a/virt/hypervisor.c b/virt/hypervisor.c new file mode 100644 index 0000000..af10e5a --- /dev/null +++ b/virt/hypervisor.c @@ -0,0 +1,64 @@ +#include +#include +#include +#include +#include + +static hypervisor_info_t host_hypervisor; + +void virt_init(void) { + memset(&host_hypervisor, 0, sizeof(host_hypervisor)); + + // Check CPUID hypervisor feature bit (ECX bit 31 on leaf 1) + uint32_t eax, ebx, ecx, edx; + cpuid(1, &eax, &ebx, &ecx, &edx); + + if (ecx & (1U << 31)) { + // Hypervisor present, query leaf 0x40000000 + cpuid(0x40000000, &eax, &ebx, &ecx, &edx); + char sig[13]; + memcpy(sig, &ebx, 4); + memcpy(sig + 4, &ecx, 4); + memcpy(sig + 8, &edx, 4); + sig[12] = '\0'; + + strncpy(host_hypervisor.signature, sig, sizeof(host_hypervisor.signature) - 1); + + if (strcmp(sig, "KVMKVMKVM\0\0\0") == 0 || strstr(sig, "KVM") != NULL) { + host_hypervisor.type = HYPERVISOR_KVM; + strcpy(host_hypervisor.name, "Linux KVM / QEMU"); + } else if (strcmp(sig, "TCGTCGTCGTCG") == 0) { + host_hypervisor.type = HYPERVISOR_QEMU; + strcpy(host_hypervisor.name, "QEMU TCG Engine"); + } else if (strcmp(sig, "VMwareVMware") == 0) { + host_hypervisor.type = HYPERVISOR_VMWARE; + strcpy(host_hypervisor.name, "VMware ESXi / Workstation"); + } else if (strcmp(sig, "VBoxVBoxVBox") == 0) { + host_hypervisor.type = HYPERVISOR_VBOX; + strcpy(host_hypervisor.name, "Oracle VirtualBox"); + } else if (strcmp(sig, "Microsoft Hv") == 0) { + host_hypervisor.type = HYPERVISOR_HYPERV; + strcpy(host_hypervisor.name, "Microsoft Hyper-V"); + } else { + host_hypervisor.type = HYPERVISOR_UNKNOWN; + strcpy(host_hypervisor.name, "Generic Hypervisor"); + } + + printk(KERN_INFO "VIRT: Detected Hypervisor: %s (Signature: '%s')\n", + host_hypervisor.name, host_hypervisor.signature); + } else { + host_hypervisor.type = HYPERVISOR_NONE; + strcpy(host_hypervisor.name, "Bare Metal x86_64 Machine"); + printk(KERN_INFO "VIRT: Running on physical Bare Metal x86_64 hardware\n"); + } + + virtio_init(); +} + +const hypervisor_info_t* virt_get_hypervisor_info(void) { + return &host_hypervisor; +} + +bool virt_is_virtualized(void) { + return host_hypervisor.type != HYPERVISOR_NONE; +} diff --git a/virt/virtio.c b/virt/virtio.c new file mode 100644 index 0000000..2da1719 --- /dev/null +++ b/virt/virtio.c @@ -0,0 +1,48 @@ +#include +#include +#include + +#define MAX_VIRTIO_DEVS 8 + +static virtio_device_t virtio_devices[MAX_VIRTIO_DEVS]; +static size_t virtio_count = 0; + +void virtio_init(void) { + memset(virtio_devices, 0, sizeof(virtio_devices)); + virtio_count = 0; + printk(KERN_INFO "VIRTIO: Subsystem initialized (Ready for VirtIO devices)\n"); +} + +int virtio_register_device(uint16_t dev_id, uint32_t io_base, uint8_t irq) { + if (virtio_count >= MAX_VIRTIO_DEVS) return -1; + + virtio_device_t* dev = &virtio_devices[virtio_count]; + dev->device_id = dev_id; + dev->io_base = io_base; + dev->irq = irq; + dev->status = 1; // Acknowledge + dev->active = true; + + switch (dev_id) { + case VIRTIO_ID_NET: strcpy(dev->name, "VirtIO Net Device"); break; + case VIRTIO_ID_BLOCK: strcpy(dev->name, "VirtIO Block Storage"); break; + case VIRTIO_ID_CONSOLE: strcpy(dev->name, "VirtIO Console"); break; + case VIRTIO_ID_ENTROPY: strcpy(dev->name, "VirtIO RNG Entropy"); break; + case VIRTIO_ID_BALLOON: strcpy(dev->name, "VirtIO Memory Balloon"); break; + case VIRTIO_ID_GPU: strcpy(dev->name, "VirtIO 2D/3D GPU"); break; + default: strcpy(dev->name, "VirtIO Unknown Device"); break; + } + + printk(KERN_INFO "VIRTIO: Registered %s at IO 0x%x (IRQ %d)\n", dev->name, io_base, irq); + virtio_count++; + return 0; +} + +size_t virtio_get_device_count(void) { + return virtio_count; +} + +const virtio_device_t* virtio_get_device(size_t index) { + if (index >= virtio_count) return NULL; + return &virtio_devices[index]; +}