mirror of
https://github.com/subhobhai943/SUB-OS.git
synced 2026-10-25 16:52:29 +00:00
feat: Add certs, init, io_uring, security, usr, virt subsystems, Nano editor & full LazyBox suite
This commit is contained in:
1 parent
ae5f4a96c4
commit
5662be29f5
27 files changed
+1870
-333
No files matched your search
@@ -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))
|
||||
|
||||
@@ -11,11 +11,12 @@
|
||||
|
||||
[]()
|
||||
[]()
|
||||
[]()
|
||||
[-purple.svg?style=flat-square)]()
|
||||
[]()
|
||||
[]()
|
||||
[](LICENSE)
|
||||
[](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).
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
#include <certs/certs.h>
|
||||
#include <crypto/crypto.h>
|
||||
#include <lib/string.h>
|
||||
#include <kernel/printk.h>
|
||||
|
||||
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];
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
#ifndef _CERTS_CERTS_H
|
||||
#define _CERTS_CERTS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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
|
||||
+14
-1
@@ -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);
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
#ifndef _INIT_INIT_H
|
||||
#define _INIT_INIT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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
|
||||
@@ -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
|
||||
@@ -0,0 +1,60 @@
|
||||
#ifndef _IO_URING_IO_URING_H
|
||||
#define _IO_URING_IO_URING_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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
|
||||
@@ -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);
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
#ifndef _SECURITY_CAPABILITY_H
|
||||
#define _SECURITY_CAPABILITY_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* 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
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef _SECURITY_SECURITY_H
|
||||
#define _SECURITY_SECURITY_H
|
||||
|
||||
#include <security/capability.h>
|
||||
#include <kernel/types.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
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
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef _USERLAND_NANO_H
|
||||
#define _USERLAND_NANO_H
|
||||
|
||||
int nano_main(int argc, char** argv);
|
||||
|
||||
#endif // _USERLAND_NANO_H
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef _USR_INITRAMFS_H
|
||||
#define _USR_INITRAMFS_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* 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
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef _VIRT_VIRT_H
|
||||
#define _VIRT_VIRT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
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
|
||||
@@ -0,0 +1,37 @@
|
||||
#ifndef _VIRT_VIRTIO_H
|
||||
#define _VIRT_VIRTIO_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,85 @@
|
||||
#include <init/init.h>
|
||||
#include <init/version.h>
|
||||
#include <lib/string.h>
|
||||
#include <kernel/printk.h>
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
#include <io_uring/io_uring.h>
|
||||
#include <fs/vfs.h>
|
||||
#include <lib/string.h>
|
||||
#include <kernel/printk.h>
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
+43
-20
@@ -21,6 +21,13 @@
|
||||
#include <fs/vfs.h>
|
||||
#include <net/net.h>
|
||||
#include <crypto/crypto.h>
|
||||
#include <certs/certs.h>
|
||||
#include <security/security.h>
|
||||
#include <io_uring/io_uring.h>
|
||||
#include <usr/initramfs.h>
|
||||
#include <virt/virt.h>
|
||||
#include <init/init.h>
|
||||
#include <init/version.h>
|
||||
#include <userland/lazybox.h>
|
||||
#include <userland/shell.h>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
#include <security/security.h>
|
||||
#include <security/capability.h>
|
||||
#include <kernel/printk.h>
|
||||
#include <lib/string.h>
|
||||
|
||||
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";
|
||||
}
|
||||
+508
-147
@@ -1,20 +1,34 @@
|
||||
#include <userland/lazybox.h>
|
||||
#include <userland/nano.h>
|
||||
#include <fs/vfs.h>
|
||||
#include <fs/ramfs.h>
|
||||
#include <net/net.h>
|
||||
#include <drivers/e1000.h>
|
||||
#include <drivers/ata.h>
|
||||
#include <drivers/tty.h>
|
||||
#include <drivers/speaker.h>
|
||||
#include <drivers/pci.h>
|
||||
#include <crypto/crypto.h>
|
||||
#include <certs/certs.h>
|
||||
#include <security/security.h>
|
||||
#include <security/capability.h>
|
||||
#include <io_uring/io_uring.h>
|
||||
#include <virt/virt.h>
|
||||
#include <virt/virtio.h>
|
||||
#include <init/version.h>
|
||||
#include <init/init.h>
|
||||
#include <mm/pmm.h>
|
||||
#include <mm/kmalloc.h>
|
||||
#include <arch/x86_64/pit.h>
|
||||
#include <arch/x86_64/cpuid.h>
|
||||
#include <arch/x86_64/io.h>
|
||||
#include <kernel/printk.h>
|
||||
#include <kernel/task.h>
|
||||
#include <lib/string.h>
|
||||
#include <lib/printf.h>
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// 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 <file>\n");
|
||||
printk(KERN_INFO "Usage: cat <file...>\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 <directory>\n");
|
||||
printk(KERN_INFO "Usage: mkdir <directory...>\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 <file>\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 <file|text>\n");
|
||||
printk(KERN_INFO "Usage: head [-n lines] <file>\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 <file>\n");
|
||||
return 1;
|
||||
}
|
||||
return applet_cat(argc, argv);
|
||||
}
|
||||
|
||||
static int applet_stat(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
printk(KERN_INFO "Usage: stat <file>\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 <source> <dest>\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 <pattern> <file>\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 <file>\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 <file|string>\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 <file|text>\n");
|
||||
printk(KERN_INFO "Usage: sha256sum <file|string>\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 <text>\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<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);
|
||||
printk("eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> 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 <ip-address> [count]\n");
|
||||
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;
|
||||
}
|
||||
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 <seconds>\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 <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"},
|
||||
// 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 <file...>", "Concatenate files to stdout","Filesystem"},
|
||||
{"touch", applet_touch, "touch <file...>", "Create empty files", "Filesystem"},
|
||||
{"mkdir", applet_mkdir, "mkdir <dir...>", "Create directories", "Filesystem"},
|
||||
{"pwd", applet_pwd, "pwd", "Print current directory", "Filesystem"},
|
||||
{"cd", applet_cd, "cd <dir>", "Change directory", "Filesystem"},
|
||||
{"wc", applet_wc, "wc <file>", "Count lines, words, bytes", "Filesystem"},
|
||||
{"head", applet_head, "head [-n lines] <file>", "Output first lines of file", "Filesystem"},
|
||||
{"tail", applet_tail, "tail <file>", "Output last lines of file", "Filesystem"},
|
||||
{"stat", applet_stat, "stat <file>", "Display file status", "Filesystem"},
|
||||
{"cp", applet_cp, "cp <src> <dst>", "Copy files", "Filesystem"},
|
||||
{"grep", applet_grep, "grep <pattern> <file>", "Search pattern in file", "Filesystem"},
|
||||
{"hexdump", applet_hexdump, "hexdump <file>", "Display hex dump of file", "Filesystem"},
|
||||
{"nano", applet_nano_wrapper, "nano [file]", "Visual full-screen editor", "Filesystem"},
|
||||
|
||||
// Cryptography & Security
|
||||
{"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"},
|
||||
{"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 <ip> [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 <freq> <dur_ms>", "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 <seconds>", "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;
|
||||
}
|
||||
@@ -0,0 +1,307 @@
|
||||
#include <userland/nano.h>
|
||||
#include <fs/vfs.h>
|
||||
#include <drivers/keyboard.h>
|
||||
#include <drivers/tty.h>
|
||||
#include <lib/string.h>
|
||||
#include <lib/printf.h>
|
||||
#include <kernel/printk.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#include <usr/initramfs.h>
|
||||
#include <fs/vfs.h>
|
||||
#include <fs/ramfs.h>
|
||||
#include <lib/string.h>
|
||||
#include <kernel/printk.h>
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
#include <virt/virt.h>
|
||||
#include <virt/virtio.h>
|
||||
#include <arch/x86_64/cpuid.h>
|
||||
#include <lib/string.h>
|
||||
#include <kernel/printk.h>
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#include <virt/virtio.h>
|
||||
#include <lib/string.h>
|
||||
#include <kernel/printk.h>
|
||||
|
||||
#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];
|
||||
}
|
||||
Reference in new issue
Block a user