diff --git a/.config b/.config new file mode 100644 index 0000000..bf7bfb1 --- /dev/null +++ b/.config @@ -0,0 +1,11 @@ +CONFIG_DEBUG_LOGS=y +CONFIG_KERNEL_BASE=0x100000 +CONFIG_HEAP_BASE=0x2000000 +CONFIG_HEAP_SIZE_MB=8 +CONFIG_SCROLL_SPEED=10 +CONFIG_EMERALD_MODE=y +CONFIG_FG_COLOR=0xff88 +CONFIG_BG_COLOR=0x0 +CONFIG_LOAD_SHELL=y +CONFIG_OPTIMIZATION=0 +CONFIG_STRICT_CHECKS=y diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000..8cd8ae7 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,55 @@ +# OSx2 (RTECH dos) Architecture Rules + +## 1. Directory Structure +- `/boot`: UEFI bootloader types and linker scripts. +- `/include`: Public headers and RSL (RTECH Standard Library) definitions. +- `/kernel/unice64`: Core kernel logic and entry points (mains). +- `/kernel/libs`: Internal kernel services and drivers. +- `/programs`: User-space programs (e.g., shell). + +## 2. Kernel Lifecycle (The Ritual) +- `main.c` is strictly an orchestrator. It must NOT contain hardware, filesystem, or memory logic. +- Services are registered via `register_service(InitFunction)`. +- The kernel uses an event-driven flow: + - `EVENT_INIT`: Service initialization and setup. + - `EVENT_MAIN`: Main event loop execution. + - `EVENT_CLEANUP`: Shutdown preparation. + - `EVENT_EXIT`: Final termination. + +## 3. RSL (RTECH Standard Library) +- RSL is the native system language for OSx2. +- Programs must include ONLY `` and never internal kernel headers. +- High-level APIs like `readline()` and `color()` are provided for ease of use. + +## 4. Memory Model (ARC & Managed RAM) +- OSx2 implements an Automatic Reference Counting (ARC) system for managed heap objects. +- High-level RSL functions (e.g., `readline`, `str_create`) return managed pointers with an initial ref-count of 1. +- Developers use `retain()` to increment and `release()` to decrement reference counts. +- **Note:** In the current v0.x implementation, the backing store is a high-speed bump allocator. While ref-counts are tracked, memory is not yet recycled for reuse. Manual `release()` calls are currently required for future-proofing and consistency with the RSL standard. + +## 5. Storage Architecture (/CONNECT & VDISK) +- **Source of Truth**: The `/CONNECT` registry tracks all physical storage (Platters, RAM, USB). +- **Physical nodes**: Each device node has a configuration defining its Sector Size and Total LBA. +- **VDISK Suit**: A Virtual Disk abstraction layer that provides relative LBA access. +- **Signature Handshake**: VDISKs must contain the `0xDEADBEEF` signature at LBA 0 to be considered valid for mounting. +- **Error Handling**: Missing hardware or signature mismatches trigger a `CANNOT FIND DISK` or `Access Denied` error. + +## 5. Console & Input +- Console supports full vertical scrolling and manual 8x8 font rendering to the GOP framebuffer. +- Advanced color selection is supported via `color(fg, bg)`. +- Input uses a freestanding PS/2 keyboard driver with Shift support. + +## 6. Build Rules +- NO precompiled binaries or object files are allowed in the repository. +- The system must be buildable from pure source using the provided `Makefile`. +- Use `make menuconfig` to configure the kernel features and heap settings. + +## 7. Forensic Panic System +- In the event of a fatal loader or kernel error, the system enters an "Autopsy" state. +- CPU registers (RAX-R15) are captured and displayed alongside error messages and status codes. +- Diagnostic data is mirrored to the serial COM1 port (0x3f8) for headless monitoring and logging. + +## 8. Development Tools +- `tools/fontgen.html`: A pro-grade web studio to draw fonts and preview colors. +- `scripts/menuconfig.py`: Terminal-based configuration utility (LFS-style). +- `scripts/rnafs_tool.py`: Host-side tool to manage RNAFS disk images and inject files. diff --git a/CODEBASE.md b/CODEBASE.md new file mode 100644 index 0000000..3444d55 --- /dev/null +++ b/CODEBASE.md @@ -0,0 +1,79 @@ +# OSx2 (RTECH dos) Technical Implementation Blueprint (CODEBASE.md) + +This document provides an exhaustive, low-level technical specification of the OSx2 codebase. It describes the implementation logic of every file with enough detail to allow for a complete system reconstruction. + +--- + +## 1. Boot & Entry Layer (`/kernel/unice64`) + +### `kernel/unice64/efi_entry.c` (Native UEFI Entry) +- **Purpose**: The "Native Diplomat". Serves as the PE32+ entry point for the firmware. +- **In-Code Logic**: + - **Initialization**: Calls `InitializeLib` (gnu-efi) to setup the UEFI environment. + - **Protocols**: + - Locates `EFI_GRAPHICS_OUTPUT_PROTOCOL` (GOP) to extract the linear framebuffer address, resolution, and scanline width into a `boot_params_t` struct. + - Handles `LOADED_IMAGE_PROTOCOL` and `SIMPLE_FILE_SYSTEM_PROTOCOL` to open the boot volume. + - **File Loading**: Loads `shell.bin` from the ESP into a 48MB fixed memory location (`0x3000000`). + - **Environment Prep**: Allocates memory for the ARC heap and the system ramdisk using `AllocatePages`. + - **The Transition**: Calls `ExitBootServices` to terminate UEFI's control over the hardware, then immediately calls `kernel_main` (passing the populated `boot_params_t`). + +--- + +## 2. Kernel Core Layer (`/kernel/unice64`) + +### `kernel/unice64/main.c` (The Orchestrator) +- **Purpose**: Kernel initialization, service registry, and event loop. +- **In-Code Logic**: + - **GDT Reset**: Calls `gdt_init` to re-establish segment descriptors for 64-bit mode after exiting UEFI services. + - **Service Registry**: Iterates through `registered_services` (Console, Memory, Input, FS, etc.) and calls their init functions. + - **Syscall Bridge**: Populates `rsl_syscall_table_t` with function pointers to kernel services. + - **Execution**: Hands over control to the user-space shell by calling `loader_run_shell`. + - **Event Loop**: Enters a `while(running)` loop that triggers `EVENT_MAIN`, allowing for asynchronous background processing. + +### `kernel/unice64/gdt.c` +- **Purpose**: CPU segmentation for long mode. +- **In-Code Logic**: Defines a static GDT with Null, Code, and Data descriptors. Loads the GDT using the `lgdt` instruction to ensure the kernel runs in a controlled environment. + +--- + +## 3. Kernel Services Layer (`/kernel/libs`) + +### `kernel/libs/connect.c` +- **Purpose**: Physical hardware inventory. Maintains a registry of memory-mapped I/O and RAM regions. + +### `kernel/libs/vdisk.c` +- **Purpose**: Storage virtualization layer. Translates virtual LBA requests to physical offsets on the ramdisk or other hardware. + +### `kernel/libs/memory.c` (ARC System) +- **Purpose**: Reference-counted memory management. +- **In-Code Logic**: Implements a 'Free List' allocator on top of the UEFI-allocated heap. `alloc` returns ref-counted pointers; `release` decrements the count and returns the block to the free list if it hits zero. + +### `kernel/libs/diskman.c` +- **Purpose**: Partition management. Parses GPT (GUID Partition Table) headers and manages VDISK partition mapping. + +### `kernel/libs/fs.c` (FAT32 Opaque FS) +- **Purpose**: Universal filesystem layer for VDISKs. +- **In-Code Logic**: Implements a standard FAT32-compatible driver that operates through the VDISK abstraction. This ensures the system can read and write to standard partitions created by external tools like `mtools`. + +### `kernel/libs/console.c` +- **Purpose**: Graphics-mode text rendering. Draws 8x8 font characters directly to the GOP framebuffer. + +### `kernel/libs/kutils.c` & `kutils.h` +- **Purpose**: Internal utility library. Uses `k_` prefixes (e.g., `k_memcpy`, `k_memset`) to avoid naming collisions with gnu-efi/UEFI symbols. + +--- + +## 4. User Programs Layer (`/programs`) + +### `programs/libsystem.c` +- **Purpose**: RTECH Standard Library (RSL) implementation for user-space. Caches the syscall table passed by the kernel. + +### `programs/shell.c` +- **Purpose**: Native OSx2 Shell. Provides an interactive interface for file management and system commands. + +--- + +## 5. Build System (`Makefile`) + +- **Architecture**: Links all kernel components into a single `kernel.so` shared object, which is then converted to a `BOOTX64.EFI` application using `objcopy`. +- **Emulation**: Uses `qemu-system-x86_64` with the Q35 chipset and OVMF firmware to provide a modern UEFI boot environment. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b76753f --- /dev/null +++ b/Makefile @@ -0,0 +1,197 @@ +# OSx2 (RTECH dos) Root Makefile - Native UEFI Edition + +CC = gcc +LD = ld +OBJCOPY = objcopy + +# Load Configuration +-include .config + +# Set defaults if not configured +CONFIG_KERNEL_BASE ?= 0x100000 +CONFIG_HEAP_BASE ?= 0x2000000 +CONFIG_OPTIMIZATION ?= 0 + +# Paths +BOOT_DIR = boot +EFI_DIR = $(BOOT_DIR)/EFI/BOOT +KERNEL_DIR = kernel/unice64 +LIBS_DIR = kernel/libs + +# GNU-EFI Paths +EFI_LIB = /usr/lib +EFI_LDS = /usr/lib/elf_x86_64_efi.lds +EFI_CRT0 = /usr/lib/crt0-efi-x86_64.o + +# Flags +# Use EFI flags for the entire kernel now +CFLAGS_EFI = -Iinclude -fno-stack-protector -mno-red-zone -Wall -fno-builtin -m64 -O$(CONFIG_OPTIMIZATION) \ + -fpic -fshort-wchar -DEFI_FUNCTION_WRAPPER -I/usr/include/efi -I/usr/include/efi/x86_64 -I/usr/include/efi/protocol + +LDFLAGS_EFI = -nostdlib -znocombreloc -z max-page-size=0x1000 -T $(EFI_LDS) -shared -Bsymbolic -L $(EFI_LIB) $(EFI_CRT0) +LDFLAGS_SHELL = -nostdlib -T programs/linker.ld + +LIBS_EFI = -lefi -lgnuefi + +# Source Files +KERNEL_OBJS = $(KERNEL_DIR)/efi_entry.o \ + $(KERNEL_DIR)/main.o \ + $(KERNEL_DIR)/gdt.o \ + $(KERNEL_DIR)/paging.o \ + $(LIBS_DIR)/kutils.o \ + $(LIBS_DIR)/console.o \ + $(LIBS_DIR)/font_data.o \ + $(LIBS_DIR)/input.o \ + $(LIBS_DIR)/connect.o \ + $(LIBS_DIR)/vdisk.o \ + $(LIBS_DIR)/disk.o \ + $(LIBS_DIR)/diskman.o \ + $(LIBS_DIR)/memory.o \ + $(LIBS_DIR)/fs.o \ + $(LIBS_DIR)/loader.o \ + $(LIBS_DIR)/core/event.o + +SHELL_SRCS = programs/entry.S programs/libsystem.c programs/shell.c +SHELL_OBJS = programs/entry.o programs/libsystem.o programs/shell.o + +HEADERS = $(shell find include kernel -name "*.h") + +# Default Target +all: info prepare $(EFI_DIR)/BOOTX64.EFI $(BOOT_DIR)/os2.bin + +info: + @echo "------------------------------------------------" + @echo " OSx2 / RTECH dos Build System (Native UEFI)" + @echo " Optimization Level: -O$(CONFIG_OPTIMIZATION)" + @echo "------------------------------------------------" + +prepare: + @if [ ! -f .config ]; then \ + python3 scripts/menuconfig.py --save; \ + fi + +menuconfig: + @python3 scripts/menuconfig.py + +# Unified Kernel (Native EFI App) +$(EFI_DIR)/BOOTX64.EFI: kernel.so + @mkdir -p $(EFI_DIR) + $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic \ + -j .dynsym -j .rel -j .rela -j .reloc \ + -j .rodata* --target=efi-app-x86_64 \ + --section-alignment 4096 kernel.so $(EFI_DIR)/BOOTX64.EFI + +kernel.so: $(KERNEL_OBJS) + $(LD) $(LDFLAGS_EFI) $(KERNEL_OBJS) -o kernel.so $(LIBS_EFI) + +$(KERNEL_DIR)/%.o: $(KERNEL_DIR)/%.c $(HEADERS) + $(CC) $(CFLAGS_EFI) -c $< -o $@ + +$(LIBS_DIR)/%.o: $(LIBS_DIR)/%.c $(HEADERS) + $(CC) $(CFLAGS_EFI) -c $< -o $@ + +$(LIBS_DIR)/core/%.o: $(LIBS_DIR)/core/%.c $(HEADERS) + $(CC) $(CFLAGS_EFI) -c $< -o $@ + +# Programs (Pure Flat Binary) +$(BOOT_DIR)/os2.bin: os2.elf + $(OBJCOPY) -O binary --strip-all os2.elf $(BOOT_DIR)/os2.bin + @# Pad to 4KB boundary + @truncate -s %4096 $(BOOT_DIR)/os2.bin + +os2.elf: $(SHELL_OBJS) + $(LD) $(LDFLAGS_SHELL) $(SHELL_OBJS) -o os2.elf + +programs/%.o: programs/%.c $(HEADERS) + $(CC) -Iinclude -ffreestanding -fno-stack-protector -mno-red-zone -Wall -fno-builtin -m64 -nostdlib -static -c $< -o $@ + +programs/%.o: programs/%.S + $(CC) -Iinclude -c $< -o $@ + +# Advanced Tools: Create Bootable UEFI Disk Image (GPT-ESP Edition) +disk: all $(BOOT_DIR)/ramdisk.img + @echo "Creating bootable UEFI disk image (GPT-ESP)..." + dd if=/dev/zero of=disk.img bs=1M count=256 + parted disk.img -s mklabel gpt + # Create one large ESP + parted disk.img -s mkpart primary fat32 2048s 100% + parted disk.img -s set 1 esp on + + # Format the partition at 1MB offset + mformat -i disk.img@@1M -F -v "OSX2" :: + mmd -i disk.img@@1M ::/EFI + mmd -i disk.img@@1M ::/EFI/BOOT + mcopy -i disk.img@@1M $(EFI_DIR)/BOOTX64.EFI ::/EFI/BOOT/BOOTX64.EFI + mcopy -i disk.img@@1M $(BOOT_DIR)/os2.bin ::/os2.bin + mcopy -i disk.img@@1M $(BOOT_DIR)/ramdisk.img ::/ramdisk.img + echo "FS0:\\EFI\\BOOT\\BOOTX64.EFI" > startup.nsh + mcopy -i disk.img@@1M startup.nsh ::/startup.nsh + rm startup.nsh + @echo "OSx2 UEFI GPT Disk Image Ready (disk.img)." + +$(BOOT_DIR)/ramdisk.img: + @echo "Generating system ramdisk..." + dd if=/dev/zero of=$(BOOT_DIR)/ramdisk.img bs=1M count=16 + mkfs.vfat -F 32 -n "OSX2_RAM" $(BOOT_DIR)/ramdisk.img + +# Create a bootable UEFI ISO (GPT-Hybrid Edition) +iso: all $(BOOT_DIR)/ramdisk.img + @echo "Creating bootable UEFI ISO image (GPT Hybrid)..." + mkdir -p iso/EFI/BOOT + + # 1. Create the unified ESP image (includes Loader and Kernel) + dd if=/dev/zero of=esp.img bs=1M count=128 + mkfs.vfat -F 32 -n "OSX2" esp.img + mmd -i esp.img ::/EFI + mmd -i esp.img ::/EFI/BOOT + mcopy -i esp.img $(EFI_DIR)/BOOTX64.EFI ::/EFI/BOOT/BOOTX64.EFI + mcopy -i esp.img $(BOOT_DIR)/os2.bin ::/os2.bin + mcopy -i esp.img $(BOOT_DIR)/ramdisk.img ::/ramdisk.img + echo "FS0:\\EFI\\BOOT\\BOOTX64.EFI" > startup.nsh + mcopy -i esp.img startup.nsh ::/startup.nsh + rm startup.nsh + + # 2. Create Hybrid ISO + mv esp.img iso/esp.img + xorriso -as mkisofs \ + -R -J -V "OSX2_INSTALL" \ + -eltorito-platform efi \ + -e esp.img -no-emul-boot \ + -append_partition 2 0xef iso/esp.img \ + -isohybrid-gpt-basdat \ + -o boot.iso iso/ + @echo "OSx2 Boot ISO Ready (boot.iso)." + +run: iso + qemu-system-x86_64 -machine q35 -bios /usr/share/ovmf/OVMF.fd -cdrom boot.iso -m 256M -serial stdio -net none + +debug: iso + qemu-system-x86_64 -machine q35 -bios /usr/share/ovmf/OVMF.fd \ + -drive file=boot.iso,format=raw \ + -m 2G \ + -no-reboot -no-shutdown \ + -d int,cpu_reset,guest_errors \ + -D qemu.log \ + -serial stdio \ + -monitor vc \ + -s -S + +gdb: + gdb -ex "target remote localhost:1234" \ + -ex "symbol-file kernel.so" \ + -ex "set architecture i386:x86-64" \ + -ex "layout src" \ + -ex "break kernel_main" + +setup: + sudo apt-get update + sudo apt-get install -y gnu-efi build-essential qemu-system-x86 ovmf mtools dosfstools xorriso parted gdb + +# Cleanup +clean: + @find . -name "*.o" -delete + @rm -f kernel.so $(BOOT_DIR)/os2.bin $(BOOT_DIR)/ramdisk.img disk.img boot.iso + @rm -rf $(BOOT_DIR)/EFI iso + @echo "Build artifacts removed." + +.PHONY: all clean disk iso prepare menuconfig info run diff --git a/include/config.h b/include/config.h new file mode 100644 index 0000000..7ce41dd --- /dev/null +++ b/include/config.h @@ -0,0 +1,18 @@ +#ifndef CONFIG_H +#define CONFIG_H + +/* Auto-generated by OSx2 menuconfig Professional */ + +#define CONFIG_DEBUG_LOGS 1 +#define CONFIG_KERNEL_BASE 0x100000 +#define CONFIG_HEAP_BASE 0x2000000 +#define CONFIG_HEAP_SIZE_MB 8 +#define CONFIG_SCROLL_SPEED 10 +#define CONFIG_EMERALD_MODE 1 +#define CONFIG_FG_COLOR 0xff88 +#define CONFIG_BG_COLOR 0 +#define CONFIG_LOAD_SHELL 1 +#define CONFIG_OPTIMIZATION 0 +#define CONFIG_STRICT_CHECKS 1 + +#endif diff --git a/include/rsl.h b/include/rsl.h new file mode 100644 index 0000000..c1b3857 --- /dev/null +++ b/include/rsl.h @@ -0,0 +1,80 @@ +#ifndef RSL_H +#define RSL_H + +#include "types.h" + +/* + * RTECH Standard Library (RSL) + * The ultimate system language for OSx2 / RTECH dos. + */ + +typedef struct { + uint32* framebuffer; + uint32 width; + uint32 height; + uint32 pixels_per_scanline; + void* ramdisk_base; + uint64 ramdisk_size; + void* shell_base; + uint64 shell_size; + void* heap_base; + uint64 heap_size; +} boot_params_t; + +typedef struct { + void (*print)(const char*); + void (*input)(const char*, char*, uint64); + INTN (*fread)(const char*, void*, uint64); + INTN (*fwrite)(const char*, const void*, uint64); + void* (*alloc)(uint64); + void (*retain)(void*); + void (*release)(void*); + void (*exit)(); + void (*clear)(); + void (*set_color)(uint32 fg, uint32 bg); + + void (*format)(int); + void (*mount)(int); + void (*addpart)(uint64, uint32); + void (*lsfs)(); +} rsl_syscall_table_t; + +/* --- High-Level "Noob-Friendly" API --- */ +void print(const char* str); +char* readline(const char* prompt); +void clear(); +void quit(); +void color(uint32 fg, uint32 bg); + +/* Disk & Partition Management */ +void format(int idx); +void mount(int idx); +void addpart(uint64 start, uint32 count); +void lsfs(); + +/* --- Auto-RAM: Managed Memory API --- */ +void* auto_ram(uint64 size); +void release(void* ptr); +void retain(void* ptr); + +/* --- String Utilities --- */ +char* str_create(const char* init); +int strcmp(const char* s1, const char* s2); +int strncmp(const char* s1, const char* s2, uint64 n); +void strcpy(char* dst, const char* src); +void strncpy(char* dst, const char* src, uint64 n); +uint64 strlen(const char* s); +char* strchr(const char* s, int c); + +/* --- Memory & Files --- */ +void* alloc(uint64 size); +void memcpy(void* dst, const void* src, uint64 n); +void memset(void* s, int c, uint64 n); +INTN read_file(const char* path, void* buffer, uint64 max_size); +INTN write_file(const char* path, const void* buffer, uint64 size); + +/* --- Numeric Utilities --- */ +int atoi(const char* s); +void itoa(int n, char* s, int base); + +#endif diff --git a/include/types.h b/include/types.h new file mode 100644 index 0000000..7e2be85 --- /dev/null +++ b/include/types.h @@ -0,0 +1,52 @@ +#ifndef TYPES_H +#define TYPES_H + +/* No stdint.h as per Second category */ + +typedef unsigned long long uint64; +typedef unsigned int uint32; +typedef unsigned short uint16; +typedef unsigned char uint8; + +typedef long long int64; +typedef int int32; +typedef short int16; +typedef signed char int8; + +#ifndef __uintptr_t_defined +typedef unsigned long uintptr_t; +#define __uintptr_t_defined +#endif + +typedef unsigned long size_t; + +#if !defined(_EFI_H) && !defined(_EFI_BIND_H) && !defined(_EFIBIND_H_) && !defined(__EFI_TYPES_H__) && !defined(_EFI_TYPES_H) && !defined(X86_64_EFI_BIND) && !defined(_EFI_INCLUDE_) && !defined(_EFI_DEF_H) && !defined(_EFI_API_H) +typedef unsigned long UINTN; +typedef long INTN; +typedef uint16 CHAR16; + +#ifndef _CHAR8_DEFINED +#define _CHAR8_DEFINED +typedef uint8 CHAR8; +#endif + +typedef void* EFI_HANDLE; +typedef UINTN EFI_STATUS; +typedef unsigned long EFI_PHYSICAL_ADDRESS; +#endif + +#ifndef EFIAPI + #if defined(_MSVC_LANG) || defined(_MSC_VER) + #define EFIAPI __cdecl + #elif defined(__GNUC__) || defined(__clang__) + #define EFIAPI __attribute__((ms_abi)) + #else + #define EFIAPI + #endif +#endif + +#ifndef NULL +#define NULL ((void*)0) +#endif + +#endif diff --git a/kernel/libs/connect.c b/kernel/libs/connect.c new file mode 100644 index 0000000..24a360f --- /dev/null +++ b/kernel/libs/connect.c @@ -0,0 +1,59 @@ +#include "connect.h" +#include "kutils.h" +#include "../unice64/kernel.h" + +typedef struct { + char path[32]; + physical_config_t config; +} connect_entry_t; + +static connect_entry_t registry[MAX_CONNECT_DEVICES]; +static uint32 device_count = 0; + +void connect_init() { + device_count = 0; + memset(registry, 0, sizeof(registry)); + + /* Register System RAM Disk */ + physical_config_t ram0; + ram0.type = DEVICE_TYPE_RAM; + ram0.sector_size = 512; + ram0.total_lba = kboot_params.ramdisk_size / 512; + ram0.base_addr = kboot_params.ramdisk_base; + ram0.is_active = 1; + + print("Connect: Physical Storage Inventory initialized.\n"); + + /* ARA Collision Check: Ensure ramdisk doesn't overlap low memory or kernel */ + if ((uint64)ram0.base_addr < CONFIG_KERNEL_BASE) { + print("CONNECT: ARA Collision Detected (Low Memory Area).\n"); + } + + connect_register_device("/CONNECT/RAM0/", ram0); + + /* Register Placeholder USB */ + physical_config_t usb0; + usb0.type = DEVICE_TYPE_USB; + usb0.sector_size = 512; + usb0.total_lba = 0; + usb0.base_addr = (void*)0; + usb0.is_active = 0; /* Not connected yet */ + connect_register_device("/CONNECT/USB0/", usb0); +} + +void connect_register_device(const char* path, physical_config_t config) { + if (device_count < MAX_CONNECT_DEVICES) { + strcpy(registry[device_count].path, path); + registry[device_count].config = config; + device_count++; + } +} + +physical_config_t* connect_get_device(const char* path) { + for (uint32 i = 0; i < device_count; i++) { + if (strcmp(registry[i].path, path) == 0) { + return ®istry[i].config; + } + } + return (void*)0; +} diff --git a/kernel/libs/connect.h b/kernel/libs/connect.h new file mode 100644 index 0000000..3f925e8 --- /dev/null +++ b/kernel/libs/connect.h @@ -0,0 +1,26 @@ +#ifndef CONNECT_H +#define CONNECT_H + +#include "../../include/types.h" + +typedef enum { + DEVICE_TYPE_DISK, + DEVICE_TYPE_RAM, + DEVICE_TYPE_USB +} device_type_t; + +typedef struct { + device_type_t type; + uint32 sector_size; + uint64 total_lba; + void* base_addr; /* For RAM disks */ + int is_active; +} physical_config_t; + +#define MAX_CONNECT_DEVICES 8 + +void connect_init(); +physical_config_t* connect_get_device(const char* path); +void connect_register_device(const char* path, physical_config_t config); + +#endif diff --git a/kernel/libs/console.c b/kernel/libs/console.c new file mode 100644 index 0000000..dff08b2 --- /dev/null +++ b/kernel/libs/console.c @@ -0,0 +1,103 @@ +#include "console.h" +#include "font.h" +#include "kutils.h" +#include "../unice64/kernel.h" +#include "../../include/rsl.h" + +static uint32 cursor_x = 0; +static uint32 cursor_y = 0; +static uint32 fg_color = 0xFFFFFFFF; +static uint32 bg_color = 0x00000000; + +void console_init() { + cursor_x = 0; + cursor_y = 0; + #ifdef CONFIG_EMERALD_MODE + fg_color = 0x00FF88; + #else + fg_color = CONFIG_FG_COLOR; + #endif + bg_color = CONFIG_BG_COLOR; + if (kboot_params.framebuffer && (uint64)kboot_params.framebuffer != 0) { + for (uint32 i = 0; i < kboot_params.height * kboot_params.pixels_per_scanline; i++) { + kboot_params.framebuffer[i] = bg_color; + } + + /* [BASE] Emerald Signature: Single pixel at (0,0) */ + kboot_params.framebuffer[0] = 0x00FF88; + serial_print("EFI: RSL_PRINT_START (Emerald Signature confirmed)\n"); + } + print("Console: Freestanding Graphics Driver initialized.\n"); +} + +void console_clear() { + console_init(); +} + +void console_set_color(uint32 fg, uint32 bg) { + fg_color = fg; + bg_color = bg; +} + +static void scroll() { + if (!kboot_params.framebuffer || (uint64)kboot_params.framebuffer == 0) return; + uint32 row_size = kboot_params.pixels_per_scanline * 4; + uint32 total_rows = kboot_params.height; + uint32 scroll_amount = CONFIG_SCROLL_SPEED; + for (uint32 y = 0; y < total_rows - scroll_amount; y++) { + memcpy((uint8*)kboot_params.framebuffer + y * row_size, + (uint8*)kboot_params.framebuffer + (y + scroll_amount) * row_size, + row_size); + } + for (uint32 y = total_rows - scroll_amount; y < total_rows; y++) { + for (uint32 x = 0; x < kboot_params.pixels_per_scanline; x++) { + kboot_params.framebuffer[y * kboot_params.pixels_per_scanline + x] = bg_color; + } + } + cursor_y -= scroll_amount; +} + +static void draw_char(char c, uint32 x, uint32 y, uint32 color) { + if (!kboot_params.framebuffer || (uint64)kboot_params.framebuffer == 0) return; + if ((uint8)c >= 128) return; + const uint8* glyph = font8x8_basic[(uint8)c]; + for (int i = 0; i < 8; i++) { + for (int j = 0; j < 8; j++) { + if (glyph[i] & (1 << j)) { + uint32 py = y + i; + uint32 px = x + j; + if (px < kboot_params.width && py < kboot_params.height) { + kboot_params.framebuffer[py * kboot_params.pixels_per_scanline + px] = color; + } + } + } + } +} + +void print(const char* str) { + if (!kboot_params.framebuffer || (uint64)kboot_params.framebuffer == 0) return; + while (*str) { + if (*str == '\n') { + cursor_x = 0; + cursor_y += 10; + } else if (*str == '\r') { + cursor_x = 0; + } else if (*str == '\b') { + if (cursor_x >= 8) { + cursor_x -= 8; + draw_char(' ', cursor_x, cursor_y, bg_color); + } + } else { + draw_char(*str, cursor_x, cursor_y, fg_color); + cursor_x += 8; + if (cursor_x + 8 > kboot_params.width) { + cursor_x = 0; + cursor_y += 10; + } + } + if (cursor_y + 10 > kboot_params.height) { + scroll(); + } + str++; + } +} diff --git a/kernel/libs/console.h b/kernel/libs/console.h new file mode 100644 index 0000000..7c8a464 --- /dev/null +++ b/kernel/libs/console.h @@ -0,0 +1,10 @@ +#ifndef CONSOLE_H +#define CONSOLE_H + +#include "../unice64/kernel.h" + +void console_init(); +void console_clear(); +void console_set_color(uint32 fg, uint32 bg); + +#endif diff --git a/kernel/libs/core/event.c b/kernel/libs/core/event.c new file mode 100644 index 0000000..010b61b --- /dev/null +++ b/kernel/libs/core/event.c @@ -0,0 +1,21 @@ +#include "event.h" + +#define MAX_HANDLERS 32 +static event_handler_t handlers[MAX_HANDLERS]; +static uint32 handler_count = 0; + +void event_init() { + handler_count = 0; +} + +void register_event_handler(event_handler_t handler) { + if (handler_count < MAX_HANDLERS) { + handlers[handler_count++] = handler; + } +} + +void trigger(event_t event) { + for (uint32 i = 0; i < handler_count; i++) { + handlers[i](event); + } +} diff --git a/kernel/libs/core/event.h b/kernel/libs/core/event.h new file mode 100644 index 0000000..502a47d --- /dev/null +++ b/kernel/libs/core/event.h @@ -0,0 +1,8 @@ +#ifndef EVENT_H +#define EVENT_H + +#include "../../unice64/kernel.h" + +void event_init(); + +#endif diff --git a/kernel/libs/disk.c b/kernel/libs/disk.c new file mode 100644 index 0000000..564df1d --- /dev/null +++ b/kernel/libs/disk.c @@ -0,0 +1,26 @@ +#include "disk.h" +#include "kutils.h" +#include "../unice64/kernel.h" +#include "../../include/rsl.h" + +void disk_init() { + print("Disk: Low-level Storage Driver initialized.\n"); +} + +int read_sectors(uint64 lba, uint32 count, void* buffer) { + if (!kboot_params.ramdisk_base) return 0; + uint64 offset = lba * 512; + uint64 size = (uint64)count * 512; + if (offset + size > kboot_params.ramdisk_size) return 0; + memcpy(buffer, (uint8*)kboot_params.ramdisk_base + offset, size); + return 1; +} + +int write_sectors(uint64 lba, uint32 count, const void* buffer) { + if (!kboot_params.ramdisk_base) return 0; + uint64 offset = lba * 512; + uint64 size = (uint64)count * 512; + if (offset + size > kboot_params.ramdisk_size) return 0; + memcpy((uint8*)kboot_params.ramdisk_base + offset, buffer, size); + return 1; +} diff --git a/kernel/libs/disk.h b/kernel/libs/disk.h new file mode 100644 index 0000000..36b014d --- /dev/null +++ b/kernel/libs/disk.h @@ -0,0 +1,10 @@ +#ifndef DISK_H +#define DISK_H + +#include "../../include/types.h" + +void disk_init(); +int read_sectors(uint64 lba, uint32 count, void* buffer); +int write_sectors(uint64 lba, uint32 count, const void* buffer); + +#endif diff --git a/kernel/libs/diskman.c b/kernel/libs/diskman.c new file mode 100644 index 0000000..dadc5f5 --- /dev/null +++ b/kernel/libs/diskman.c @@ -0,0 +1,81 @@ +#include "diskman.h" +#include "disk.h" +#include "vdisk.h" +#include "console.h" +#include "kutils.h" +#include "../../include/rsl.h" + +static gpt_header_t current_gpt; +static gpt_entry_t entries[128]; + +void diskman_init() { + /* Check for GPT on the ramdisk */ + if (read_sectors(1, 1, ¤t_gpt)) { + if (current_gpt.signature == GPT_SIGNATURE) { + read_sectors(current_gpt.partition_entry_lba, + (current_gpt.num_partition_entries * current_gpt.size_partition_entry + 511) / 512, + entries); + } else { + /* + * If no GPT is found, we may be booting from a 'naked' FAT partition + * mapped to the ramdisk. We allow it to pass for compatibility, + * but won't be able to mount sub-partitions. + */ + print("Diskman: No GPT found on ramdisk. Assuming single volume.\n"); + } + } + print("Diskman: Partition Management Service initialized.\n"); +} + +void diskman_add_partition(uint64 start, uint32 count) { + if (current_gpt.signature != GPT_SIGNATURE) { + /* Initialize Blank GPT on first use */ + memset(¤t_gpt, 0, sizeof(gpt_header_t)); + current_gpt.signature = GPT_SIGNATURE; + current_gpt.revision = 0x00010000; + current_gpt.header_size = sizeof(gpt_header_t); + current_gpt.current_lba = 1; + current_gpt.first_usable_lba = 34; + current_gpt.partition_entry_lba = 2; + current_gpt.num_partition_entries = 128; + current_gpt.size_partition_entry = 128; + memset(entries, 0, sizeof(entries)); + print("Diskman: Initializing new GPT...\n"); + } + for (uint32 i = 0; i < current_gpt.num_partition_entries; i++) { + int unused = 1; + for (int j = 0; j < 16; j++) { + if (entries[i].partition_type_guid.data[j] != 0) { + unused = 0; + break; + } + } + if (unused) { + entries[i].starting_lba = start; + entries[i].ending_lba = start + count - 1; + entries[i].partition_type_guid.data[0] = 0x52; /* RNAFS GUID (Fake) */ + entries[i].partition_type_guid.data[1] = 0x4E; + entries[i].partition_type_guid.data[2] = 0x41; + + /* Update Entry Array CRC */ + current_gpt.partition_entry_array_crc = crc32(entries, (uint64)current_gpt.num_partition_entries * current_gpt.size_partition_entry); + + /* Update Header CRC */ + current_gpt.header_crc = 0; + current_gpt.header_crc = crc32(¤t_gpt, current_gpt.header_size); + + /* Commit to disk */ + write_sectors(current_gpt.partition_entry_lba, + (current_gpt.num_partition_entries * current_gpt.size_partition_entry + 511) / 512, + entries); + write_sectors(1, 1, ¤t_gpt); + + print("Diskman: Added GPT partition "); + char buf[8]; + itoa(i, buf, 10); + print(buf); + print("\n"); + return; + } + } +} diff --git a/kernel/libs/diskman.h b/kernel/libs/diskman.h new file mode 100644 index 0000000..6425c8d --- /dev/null +++ b/kernel/libs/diskman.h @@ -0,0 +1,45 @@ +#ifndef DISKMAN_H +#define DISKMAN_H + +#include "../../include/types.h" + +/* GPT (GUID Partition Table) Structures - 64-bit */ + +typedef struct { + uint8 data[16]; +} guid_t; + +typedef struct { + uint64 signature; /* "EFI PART" */ + uint32 revision; + uint32 header_size; + uint32 header_crc; + uint32 reserved; + uint64 current_lba; + uint64 backup_lba; + uint64 first_usable_lba; + uint64 last_usable_lba; + guid_t disk_guid; + uint64 partition_entry_lba; + uint32 num_partition_entries; + uint32 size_partition_entry; + uint32 partition_entry_array_crc; +} __attribute__((packed)) gpt_header_t; + +typedef struct { + guid_t partition_type_guid; + guid_t unique_partition_guid; + uint64 starting_lba; + uint64 ending_lba; + uint64 attributes; + uint16 partition_name[36]; +} __attribute__((packed)) gpt_entry_t; + +#define GPT_SIGNATURE 0x5452415020494645ULL /* "EFI PART" */ + +void diskman_init(); +void diskman_add_partition(uint64 start, uint32 count); +void diskman_format_rnafs(int idx); +void diskman_mount_rnafs(int idx); + +#endif diff --git a/kernel/libs/font.h b/kernel/libs/font.h new file mode 100644 index 0000000..141bff7 --- /dev/null +++ b/kernel/libs/font.h @@ -0,0 +1,8 @@ +#ifndef FONT_H +#define FONT_H + +#include "../../include/types.h" + +extern const uint8 font8x8_basic[128][8]; + +#endif diff --git a/kernel/libs/font_data.c b/kernel/libs/font_data.c new file mode 100644 index 0000000..e8e6a7b --- /dev/null +++ b/kernel/libs/font_data.c @@ -0,0 +1,100 @@ +#include "../../include/types.h" + +const uint8 font8x8_basic[128][8] = { + [0x00] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* (null) */ + [0x20] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* (space) */ + [0x21] = { 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, /* ! */ + [0x22] = { 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00}, /* " */ + [0x23] = { 0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00}, /* # */ + [0x24] = { 0x18, 0x7E, 0xC0, 0x7C, 0x06, 0xFC, 0x18, 0x00}, /* $ */ + [0x25] = { 0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00}, /* % */ + [0x26] = { 0x30, 0x68, 0x30, 0x76, 0xCC, 0xCC, 0x76, 0x00}, /* & */ + [0x27] = { 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ' */ + [0x28] = { 0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00}, /* ( */ + [0x29] = { 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00}, /* ) */ + [0x2A] = { 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, /* * */ + [0x2B] = { 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00}, /* + */ + [0x2C] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30}, /* , */ + [0x2D] = { 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00}, /* - */ + [0x2E] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00}, /* . */ + [0x2F] = { 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00}, /* / */ + [0x30] = { 0x7C, 0xC6, 0xCE, 0xD6, 0xE6, 0xC6, 0x7C, 0x00}, /* 0 */ + [0x31] = { 0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00}, /* 1 */ + [0x32] = { 0x7C, 0xC6, 0x06, 0x3C, 0x60, 0xC0, 0xFE, 0x00}, /* 2 */ + [0x33] = { 0x7C, 0xC6, 0x06, 0x3C, 0x06, 0xC6, 0x7C, 0x00}, /* 3 */ + [0x34] = { 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00}, /* 4 */ + [0x35] = { 0xFE, 0xC0, 0xFC, 0x06, 0x06, 0xC6, 0x7C, 0x00}, /* 5 */ + [0x36] = { 0x3C, 0x60, 0xC0, 0xFC, 0xC6, 0xC6, 0x7C, 0x00}, /* 6 */ + [0x37] = { 0xFE, 0xC6, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00}, /* 7 */ + [0x38] = { 0x7C, 0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0x7C, 0x00}, /* 8 */ + [0x39] = { 0x7C, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0x78, 0x00}, /* 9 */ + [0x3A] = { 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00}, /* : */ + [0x3B] = { 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30}, /* ; */ + [0x3C] = { 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00}, /* < */ + [0x3D] = { 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00}, /* = */ + [0x3E] = { 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x00}, /* > */ + [0x3F] = { 0x7C, 0xC6, 0x06, 0x0C, 0x18, 0x00, 0x18, 0x00}, /* ? */ + [0x40] = { 0x7C, 0xC6, 0x06, 0x5E, 0xD6, 0xD6, 0x7C, 0x00}, /* @ */ + [0x41] = { 0x18, 0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00}, /* A */ + [0x42] = { 0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00}, /* B */ + [0x43] = { 0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00}, /* C */ + [0x44] = { 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00}, /* D */ + [0x45] = { 0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00}, /* E */ + [0x46] = { 0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00}, /* F */ + [0x47] = { 0x3C, 0x66, 0xC0, 0xCE, 0xC6, 0x66, 0x3E, 0x00}, /* G */ + [0x48] = { 0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00}, /* H */ + [0x49] = { 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00}, /* I */ + [0x4A] = { 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0xCC, 0x78, 0x00}, /* J */ + [0x4B] = { 0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00}, /* K */ + [0x4C] = { 0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00}, /* L */ + [0x4D] = { 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00}, /* M */ + [0x4E] = { 0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00}, /* N */ + [0x4F] = { 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00}, /* O */ + [0x50] = { 0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00}, /* P */ + [0x51] = { 0x7C, 0xC6, 0xC6, 0xC6, 0xDA, 0xCC, 0x76, 0x00}, /* Q */ + [0x52] = { 0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00}, /* R */ + [0x53] = { 0x7C, 0xC6, 0x60, 0x38, 0x06, 0xC6, 0x7C, 0x00}, /* S */ + [0x54] = { 0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00}, /* T */ + [0x55] = { 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00}, /* U */ + [0x56] = { 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00}, /* V */ + [0x57] = { 0xC6, 0xC6, 0xD6, 0xFE, 0xFE, 0xEE, 0xC6, 0x00}, /* W */ + [0x58] = { 0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00}, /* X */ + [0x59] = { 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x3C, 0x00}, /* Y */ + [0x5A] = { 0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00}, /* Z */ + [0x5B] = { 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00}, /* [ */ + [0x5C] = { 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00}, /* \ */ + [0x5D] = { 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00}, /* ] */ + [0x5E] = { 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00}, /* ^ */ + [0x5F] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, /* _ */ + [0x60] = { 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ` */ + [0x61] = { 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00}, /* a */ + [0x62] = { 0xE0, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x00}, /* b */ + [0x63] = { 0x00, 0x00, 0x7C, 0xC0, 0xC0, 0xC6, 0x7C, 0x00}, /* c */ + [0x64] = { 0x1C, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00}, /* d */ + [0x65] = { 0x00, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0x7C, 0x00}, /* e */ + [0x66] = { 0x1C, 0x36, 0x30, 0x7C, 0x30, 0x30, 0x78, 0x00}, /* f */ + [0x67] = { 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8}, /* g */ + [0x68] = { 0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00}, /* h */ + [0x69] = { 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00}, /* i */ + [0x6A] = { 0x06, 0x00, 0x06, 0x06, 0x06, 0x66, 0x3C, 0x00}, /* j */ + [0x6B] = { 0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00}, /* k */ + [0x6C] = { 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00}, /* l */ + [0x6D] = { 0x00, 0x00, 0xEC, 0xFE, 0xFE, 0xD6, 0xC6, 0x00}, /* m */ + [0x6E] = { 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x00}, /* n */ + [0x6F] = { 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00}, /* o */ + [0x70] = { 0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0}, /* p */ + [0x71] = { 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E}, /* q */ + [0x72] = { 0x00, 0x00, 0xDC, 0x76, 0x60, 0x60, 0xF0, 0x00}, /* r */ + [0x73] = { 0x00, 0x00, 0x7E, 0xC0, 0x7C, 0x06, 0xFC, 0x00}, /* s */ + [0x74] = { 0x30, 0x30, 0xFC, 0x30, 0x30, 0x36, 0x1C, 0x00}, /* t */ + [0x75] = { 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00}, /* u */ + [0x76] = { 0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00}, /* v */ + [0x77] = { 0x00, 0x00, 0xC6, 0xD6, 0xFE, 0xEE, 0x6C, 0x00}, /* w */ + [0x78] = { 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00}, /* x */ + [0x79] = { 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0xFC}, /* y */ + [0x7A] = { 0x00, 0x00, 0xFE, 0xCC, 0x18, 0x32, 0xFE, 0x00}, /* z */ + [0x7B] = { 0x0C, 0x18, 0x18, 0x70, 0x18, 0x18, 0x0C, 0x00}, /* { */ + [0x7C] = { 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00}, /* | */ + [0x7D] = { 0x30, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x30, 0x00}, /* } */ + [0x7E] = { 0x00, 0x00, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00}, /* ~ */ +}; diff --git a/kernel/libs/fs.c b/kernel/libs/fs.c new file mode 100644 index 0000000..d4c89a5 --- /dev/null +++ b/kernel/libs/fs.c @@ -0,0 +1,18 @@ +#include "fs.h" +#include "console.h" + +/* VFS Placeholder for FAT-only implementation */ + +void fs_init() { + print("VFS: FAT-only mode initialized.\n"); +} + +INTN fread(const char* path, void* buffer, uint64 max_size) { + /* TODO: Implement FAT32 read via VDISK */ + return -1; +} + +INTN fwrite(const char* path, const void* buffer, uint64 size) { + /* TODO: Implement FAT32 write via VDISK */ + return -1; +} diff --git a/kernel/libs/fs.h b/kernel/libs/fs.h new file mode 100644 index 0000000..82a9f10 --- /dev/null +++ b/kernel/libs/fs.h @@ -0,0 +1,10 @@ +#ifndef FS_H +#define FS_H + +#include "../../include/types.h" + +void fs_init(); +INTN fread(const char* path, void* buffer, uint64 max_size); +INTN fwrite(const char* path, const void* buffer, uint64 size); + +#endif diff --git a/kernel/libs/input.c b/kernel/libs/input.c new file mode 100644 index 0000000..1a035ec --- /dev/null +++ b/kernel/libs/input.c @@ -0,0 +1,144 @@ +#include "input.h" +#include "console.h" +#include "../unice64/io.h" + +static const char scancode_map[128] = { + 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', /* 9 */ + '9', '0', '-', '=', '\b', /* Backspace */ + '\t', /* Tab */ + 'q', 'w', 'e', 'r', /* 19 */ + 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', /* Enter key */ + 0, /* 29 - Control */ + 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', /* 39 */ + '\'', '`', 0, /* Left shift */ + '\\', 'z', 'x', 'c', 'v', 'b', 'n', /* 49 */ + 'm', ',', '.', '/', 0, /* Right shift */ + '*', + 0, /* Alt */ + ' ', /* Space bar */ + 0, /* Caps lock */ +}; + +static const char shift_map[128] = { + 0, 27, '!', '@', '#', '$', '%', '^', '&', '*', /* 9 */ + '(', ')', '_', '+', '\b', /* Backspace */ + '\t', /* Tab */ + 'Q', 'W', 'E', 'R', /* 19 */ + 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', /* Enter key */ + 0, /* 29 - Control */ + 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', /* 39 */ + '\"', '~', 0, /* Left shift */ + '|', 'Z', 'X', 'C', 'V', 'B', 'N', /* 49 */ + 'M', '<', '>', '?', 0, /* Right shift */ + '*', + 0, /* Alt */ + ' ', /* Space bar */ + 0, /* Caps lock */ +}; + +static int shift_pressed = 0; + +static void ps2_wait_write() { + while (inb(0x64) & 2); +} + +static void ps2_wait_read() { + while (!(inb(0x64) & 1)); +} + +void input_init() { + shift_pressed = 0; + + /* 1. Disable devices */ + ps2_wait_write(); + outb(0x64, 0xAD); + ps2_wait_write(); + outb(0x64, 0xA7); + + /* 2. Flush buffer */ + while (inb(0x64) & 1) inb(0x60); + + /* 3. Set Controller Config */ + ps2_wait_write(); + outb(0x64, 0x20); + ps2_wait_read(); + uint8 ccb = inb(0x60); + ccb |= 1; + ccb &= ~0x40; + ps2_wait_write(); + outb(0x64, 0x60); + ps2_wait_write(); + outb(0x60, ccb); + + /* 4. Controller self-test */ + ps2_wait_write(); + outb(0x64, 0xAA); + ps2_wait_read(); + if (inb(0x60) != 0x55) return; + + /* 5. Enable P1 */ + ps2_wait_write(); + outb(0x64, 0xAE); + + /* 6. Reset Keyboard */ + ps2_wait_write(); + outb(0x60, 0xFF); + ps2_wait_read(); + if (inb(0x60) != 0xFA) return; + ps2_wait_read(); + if (inb(0x60) != 0xAA) return; + + /* 7. Enable Scanning */ + ps2_wait_write(); + outb(0x60, 0xF4); + ps2_wait_read(); + inb(0x60); + + print("Input: PS/2 Keyboard Driver initialized.\n"); +} + +static char get_char() { + while (1) { + if (inb(0x64) & 1) { + uint8 scancode = inb(0x60); + + if (scancode == 0x2A || scancode == 0x36) { + shift_pressed = 1; + continue; + } + if (scancode == 0xAA || scancode == 0xB6) { + shift_pressed = 0; + continue; + } + + if (!(scancode & 0x80)) { + if (scancode < 128) { + return shift_pressed ? shift_map[scancode] : scancode_map[scancode]; + } + } + } + __asm__ volatile("pause"); + } +} + +void input(const char* prompt, char* buffer, uint64 size) { + print(prompt); + uint64 i = 0; + while (i < size - 1) { + char c = get_char(); + if (c == '\n') { + print("\n"); + break; + } else if (c == '\b') { + if (i > 0) { + i--; + print("\b \b"); + } + } else if (c > 0) { + buffer[i++] = c; + char s[2] = {c, 0}; + print(s); + } + } + buffer[i] = 0; +} diff --git a/kernel/libs/input.h b/kernel/libs/input.h new file mode 100644 index 0000000..bab658e --- /dev/null +++ b/kernel/libs/input.h @@ -0,0 +1,9 @@ +#ifndef INPUT_H +#define INPUT_H + +#include "../../include/types.h" + +void input_init(); +void input(const char* prompt, char* buffer, uint64 size); + +#endif diff --git a/kernel/libs/kutils.c b/kernel/libs/kutils.c new file mode 100644 index 0000000..bc3d81b --- /dev/null +++ b/kernel/libs/kutils.c @@ -0,0 +1,96 @@ +#include "../../include/types.h" +#include "../unice64/io.h" + +#define COM1 0x3F8 + +int strcmp(const char* s1, const char* s2) { + while (*s1 && *s1 == *s2) { s1++; s2++; } + return *(unsigned char*)s1 - *(unsigned char*)s2; +} + +void strcpy(char* dst, const char* src) { + while ((*dst++ = *src++)); +} + +void k_strcat(char* dst, const char* src) { + while (*dst) dst++; + while ((*dst++ = *src++)); +} + +uint64 k_strlen(const char* s) { + uint64 len = 0; + while (*s++) len++; + return len; +} + +void k_memcpy(void* dst, const void* src, uint64 n) { + uint8* d = (uint8*)dst; + const uint8* s = (const uint8*)src; + while (n--) *d++ = *s++; +} + +void k_memset(void* s, int c, uint64 n) { + uint8* p = (uint8*)s; + while (n--) *p++ = (uint8)c; +} + +void itoa(int n, char* s, int base) { + char* p = s; + char* p1, *p2; + unsigned int ud = n; + if (base == 10 && n < 0) { + *p++ = '-'; + s++; + ud = -n; + } + do { + int remainder = ud % base; + *p++ = (remainder < 10) ? remainder + '0' : remainder + 'a' - 10; + } while (ud /= base); + *p = 0; + p1 = s; + p2 = p - 1; + while (p1 < p2) { + char tmp = *p1; + *p1++ = *p2; + *p2-- = tmp; + } +} + +uint32 crc32(const void* data, uint64 len) { + uint32 crc = 0xFFFFFFFF; + const uint8* p = (const uint8*)data; + while (len--) { + crc ^= *p++; + for (int i = 0; i < 8; i++) { + if (crc & 1) crc = (crc >> 1) ^ 0xEDB88320; + else crc >>= 1; + } + } + return ~crc; +} + +void serial_init() { + outb(COM1 + 1, 0x00); // Disable all interrupts + outb(COM1 + 3, 0x80); // Enable DLAB (set baud rate divisor) + outb(COM1 + 0, 0x03); // Set divisor to 3 (38400 baud) + outb(COM1 + 1, 0x00); + outb(COM1 + 3, 0x03); // 8 bits, no parity, one stop bit + outb(COM1 + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold + outb(COM1 + 4, 0x0B); // IRQs enabled, RTS/DSR set +} + +static int is_transmit_empty() { + return inb(COM1 + 5) & 0x20; +} + +void serial_putc(char a) { + while (is_transmit_empty() == 0); + outb(COM1, a); +} + +void serial_print(const char* str) { + while (*str) { + serial_putc(*str++); + } +} diff --git a/kernel/libs/kutils.h b/kernel/libs/kutils.h new file mode 100644 index 0000000..da1f7d0 --- /dev/null +++ b/kernel/libs/kutils.h @@ -0,0 +1,24 @@ +#ifndef KUTILS_H +#define KUTILS_H + +#include "../../include/types.h" + +int strcmp(const char* s1, const char* s2); +void strcpy(char* dst, const char* src); +void k_strcat(char* dst, const char* src); +uint64 k_strlen(const char* s); +void k_memcpy(void* dst, const void* src, uint64 n); +void k_memset(void* s, int c, uint64 n); +void itoa(int n, char* s, int base); +uint32 crc32(const void* data, uint64 len); + +void serial_init(); +void serial_print(const char* str); + +/* Alias for kernel use if needed, but we'll use k_ prefix to avoid conflicts with gnu-efi */ +#define memcpy k_memcpy +#define memset k_memset +#define strlen k_strlen +#define strcat k_strcat + +#endif diff --git a/kernel/libs/loader.c b/kernel/libs/loader.c new file mode 100644 index 0000000..c53b199 --- /dev/null +++ b/kernel/libs/loader.c @@ -0,0 +1,38 @@ +#include "loader.h" +#include "console.h" +#include "vdisk.h" +#include "fs.h" +#include "memory.h" +#include "kutils.h" +#include "../unice64/kernel.h" + +void loader_init() { + print("Loader: Stage 2 Environment Ready.\n"); +} + +void wheres_the_beef() { + print("WHERES_THE_BEEF! Memory corruption or uninitialized jump detected.\n"); + print("Checked: 0xB0000 | Protocol: Triggered\n"); + while(1) { __asm__ volatile("hlt"); } +} + +void debug_kernel_signature() { + /* Basic check for common uninitialized RAM patterns */ + /* Note: CONFIG_KERNEL_BASE is the start of the kernel binary in memory. */ + print("Diagnostic: Kernel is currently executing from UEFI-allocated memory.\n"); +} + +void loader_run_shell(rsl_syscall_table_t* syscalls) { + #ifdef CONFIG_LOAD_SHELL + /* Stage 2 Loader: Run shell.bin already placed in memory by Stage 1 */ + if (kboot_params.shell_base) { + void (*shell_entry)(boot_params_t*, rsl_syscall_table_t*) = + (void (*)(boot_params_t*, rsl_syscall_table_t*))kboot_params.shell_base; + shell_entry(&kboot_params, syscalls); + } else { + print("Loader: shell.bin not found in memory handover.\n"); + } + #else + print("Loader: Auto-load shell disabled by config.\n"); + #endif +} diff --git a/kernel/libs/loader.h b/kernel/libs/loader.h new file mode 100644 index 0000000..9b1bdb2 --- /dev/null +++ b/kernel/libs/loader.h @@ -0,0 +1,10 @@ +#ifndef LOADER_H +#define LOADER_H + +#include "../../include/rsl.h" + +void loader_init(); +void loader_run_shell(rsl_syscall_table_t* syscalls); +void debug_kernel_signature(); + +#endif diff --git a/kernel/libs/memory.c b/kernel/libs/memory.c new file mode 100644 index 0000000..a7860a4 --- /dev/null +++ b/kernel/libs/memory.c @@ -0,0 +1,91 @@ +#include "memory.h" +#include "../unice64/kernel.h" + +static uint64 heap_ptr = 0; + +typedef struct free_block { + uint32 size; + struct free_block* next; +} free_block_t; + +static free_block_t* free_list = (void*)0; + +void memory_init() { + heap_ptr = 0; + free_list = (void*)0; + print("Memory: ARC Management Service initialized.\n"); +} + +void* alloc(uint64 size) { + if (!kboot_params.heap_base) { + return (void*)0; + } + + uint64 total_size = sizeof(arc_header_t) + size; + total_size = (total_size + 15) & ~15; + + /* Check free list first */ + free_block_t** curr = &free_list; + while (*curr) { + if ((*curr)->size >= total_size) { + free_block_t* found = *curr; + *curr = found->next; + + arc_header_t* header = (arc_header_t*)found; + header->ref_count = 1; + header->size = (uint32)size; + header->magic = ARC_MAGIC; + return (void*)(header + 1); + } + curr = &((*curr)->next); + } + + /* Use configurable heap size limit from config.h */ + uint64 max_heap = (uint64)CONFIG_HEAP_SIZE_MB * 1024 * 1024; + uint64 effective_limit = (kboot_params.heap_size < max_heap && kboot_params.heap_size > 0) ? kboot_params.heap_size : max_heap; + + if (heap_ptr + total_size > effective_limit) { + return (void*)0; + } + + arc_header_t* header = (arc_header_t*)((uint8*)kboot_params.heap_base + heap_ptr); + header->ref_count = 1; + header->size = (uint32)size; + header->magic = ARC_MAGIC; + + heap_ptr += total_size; + + return (void*)(header + 1); +} + +void retain(void* ptr) { + if (!ptr) { + return; + } + arc_header_t* header = (arc_header_t*)ptr - 1; + if (header->magic == ARC_MAGIC) { + header->ref_count++; + } +} + +void release(void* ptr) { + if (!ptr) { + return; + } + arc_header_t* header = (arc_header_t*)ptr - 1; + if (header->magic == ARC_MAGIC) { + if (header->ref_count > 0) { + header->ref_count--; + if (header->ref_count == 0) { + /* Actual Reclamation */ + uint32 total_size = (sizeof(arc_header_t) + header->size + 15) & ~15; + header->magic = 0; + + free_block_t* free_b = (free_block_t*)header; + free_b->size = total_size; + free_b->next = free_list; + free_list = free_b; + } + } + } +} diff --git a/kernel/libs/memory.h b/kernel/libs/memory.h new file mode 100644 index 0000000..4178ad5 --- /dev/null +++ b/kernel/libs/memory.h @@ -0,0 +1,20 @@ +#ifndef MEMORY_H +#define MEMORY_H + +#include "../../include/types.h" + +/* ARC Header for Python-like memory management */ +typedef struct { + uint32 ref_count; + uint32 size; + uint64 magic; /* To verify ARC pointer */ +} arc_header_t; + +#define ARC_MAGIC 0x4152434D454D3031 /* "ARCMEM01" */ + +void memory_init(); +void* alloc(uint64 size); +void retain(void* ptr); +void release(void* ptr); + +#endif diff --git a/kernel/libs/vdisk.c b/kernel/libs/vdisk.c new file mode 100644 index 0000000..29950dc --- /dev/null +++ b/kernel/libs/vdisk.c @@ -0,0 +1,78 @@ +#include "vdisk.h" +#include "kutils.h" +#include "console.h" + +static vdisk_t vdisk_registry[MAX_VDISKS]; +static uint32 vdisk_count = 0; + +void vdisk_init() { + vdisk_count = 0; + memset(vdisk_registry, 0, sizeof(vdisk_registry)); + print("VDisk: Storage Virtualization Layer initialized.\n"); +} + +vdisk_t* vdisk_open(const char* name) { + for (uint32 i = 0; i < vdisk_count; i++) { + if (strcmp(vdisk_registry[i].name, name) == 0) { + return &vdisk_registry[i]; + } + } + + /* Auto-create VDISK on RAM0 if not found for v0 compatibility */ + if (vdisk_count < MAX_VDISKS) { + strcpy(vdisk_registry[vdisk_count].name, name); + vdisk_registry[vdisk_count].physical = connect_get_device("/CONNECT/RAM0/"); + vdisk_registry[vdisk_count].start_lba = 0; + vdisk_registry[vdisk_count].end_lba = vdisk_registry[vdisk_count].physical ? vdisk_registry[vdisk_count].physical->total_lba - 1 : 0; + vdisk_registry[vdisk_count].is_mounted = 0; + return &vdisk_registry[vdisk_count++]; + } + + return (void*)0; +} + +int vdisk_mount_verify(vdisk_t* vd) { + if (!vd || !vd->physical || !vd->physical->is_active) { + print("VDISK: CANNOT FIND DISK (Hardware Offline)\n"); + return 0; + } + + uint32 signature = 0; + if (vdisk_read(vd, 0, 1, &signature)) { + if (signature == 0xDEADBEEF) { + vd->is_mounted = 1; + return 1; + } + } + + print("VDISK: Signature mismatch. Access denied.\n"); + return 0; +} + +int vdisk_read(vdisk_t* vd, uint64 lba, uint32 count, void* buffer) { + if (!vd || !vd->physical || !vd->physical->is_active) return 0; + uint64 phys_lba = vd->start_lba + lba; + if (phys_lba + count - 1 > vd->end_lba) return 0; + + if (vd->physical->type == DEVICE_TYPE_RAM) { + uint64 offset = phys_lba * vd->physical->sector_size; + uint64 size = (uint64)count * vd->physical->sector_size; + memcpy(buffer, (uint8*)vd->physical->base_addr + offset, size); + return 1; + } + return 0; +} + +int vdisk_write(vdisk_t* vd, uint64 lba, uint32 count, const void* buffer) { + if (!vd || !vd->physical || !vd->physical->is_active) return 0; + uint64 phys_lba = vd->start_lba + lba; + if (phys_lba + count - 1 > vd->end_lba) return 0; + + if (vd->physical->type == DEVICE_TYPE_RAM) { + uint64 offset = phys_lba * vd->physical->sector_size; + uint64 size = (uint64)count * vd->physical->sector_size; + memcpy((uint8*)vd->physical->base_addr + offset, buffer, size); + return 1; + } + return 0; +} diff --git a/kernel/libs/vdisk.h b/kernel/libs/vdisk.h new file mode 100644 index 0000000..7889561 --- /dev/null +++ b/kernel/libs/vdisk.h @@ -0,0 +1,23 @@ +#ifndef VDISK_H +#define VDISK_H + +#include "../../include/types.h" +#include "connect.h" + +typedef struct { + char name[32]; + physical_config_t* physical; + uint64 start_lba; + uint64 end_lba; + int is_mounted; +} vdisk_t; + +#define MAX_VDISKS 8 + +void vdisk_init(); +vdisk_t* vdisk_open(const char* name); +int vdisk_read(vdisk_t* vd, uint64 lba, uint32 count, void* buffer); +int vdisk_write(vdisk_t* vd, uint64 lba, uint32 count, const void* buffer); +int vdisk_mount_verify(vdisk_t* vd); + +#endif diff --git a/kernel/unice64/efi_entry.c b/kernel/unice64/efi_entry.c new file mode 100644 index 0000000..bf02d64 --- /dev/null +++ b/kernel/unice64/efi_entry.c @@ -0,0 +1,205 @@ +#include +#include +#include "../../include/config.h" +#include "../../include/types.h" +#include "../../include/rsl.h" +#include "../libs/kutils.h" +#include "kernel.h" + +static EFI_GUID li_g = LOADED_IMAGE_PROTOCOL; +static EFI_GUID fs_g = SIMPLE_FILE_SYSTEM_PROTOCOL; +static EFI_GUID gop_g = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; + +static EFI_STATUS load_file(EFI_SYSTEM_TABLE *ST, EFI_FILE_PROTOCOL *root, CHAR16 *name, EFI_PHYSICAL_ADDRESS addr, EFI_ALLOCATE_TYPE type, EFI_MEMORY_TYPE mem_type, UINT64 *out_size, void **out_ptr) { + if (!root) return EFI_INVALID_PARAMETER; + EFI_FILE_PROTOCOL *file; + EFI_STATUS status = root->Open(root, &file, name, EFI_FILE_MODE_READ, 0); + if (status != EFI_SUCCESS) return status; + + EFI_FILE_INFO *info = LibFileInfo(file); + if (!info) { + file->Close(file); + return EFI_LOAD_ERROR; + } + + UINT64 file_size = info->FileSize; + UINTN pages = (file_size + 4095) / 4096; + EFI_PHYSICAL_ADDRESS load_addr = addr; + + status = ST->BootServices->AllocatePages(type, mem_type, pages, &load_addr); + if (status != EFI_SUCCESS) { + FreePool(info); + file->Close(file); + return status; + } + + UINTN read_size = (UINTN)file_size; + status = file->Read(file, &read_size, (void*)load_addr); + if (status == EFI_SUCCESS) { + if (out_size) *out_size = (UINT64)read_size; + if (out_ptr) *out_ptr = (void*)load_addr; + } + + FreePool(info); + file->Close(file); + return status; +} + +EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) { + InitializeLib(ImageHandle, SystemTable); + serial_init(); + boot_params_t params = {0}; + EFI_STATUS status; + + Print(L"OSx2 Native EFI Kernel Booting...\n"); + serial_print("OSx2: UEFI Entry Point reached.\n"); + + /* 1. Get Graphics Info */ + Print(L"EFI: Initializing Graphics (GOP)...\n"); + EFI_GRAPHICS_OUTPUT_PROTOCOL *gop; + status = SystemTable->BootServices->LocateProtocol(&gop_g, (void*)0, (void**)&gop); + if (status == EFI_SUCCESS) { + /* [BASE] Locating GOP -> Success */ + /* Ensure a mode is set to map the framebuffer */ + gop->SetMode(gop, gop->Mode->Mode); + + params.framebuffer = (UINT32*)gop->Mode->FrameBufferBase; + params.width = gop->Mode->Info->HorizontalResolution; + params.height = gop->Mode->Info->VerticalResolution; + params.pixels_per_scanline = gop->Mode->Info->PixelsPerScanLine; + + Print(L"EFI: [BASE] Locating GOP -> 0x%lx (Success)\n", (UINTN)params.framebuffer); + Print(L"EFI: [BASE] Mapping Framebuffer -> Identity Map\n"); + } + + /* 2. Load Shell */ + Print(L"EFI: Retrieving Protocols...\n"); + EFI_LOADED_IMAGE_PROTOCOL *li; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs; + EFI_FILE_PROTOCOL *root; + + status = SystemTable->BootServices->OpenProtocol(ImageHandle, &li_g, (void**)&li, ImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (status != EFI_SUCCESS) { + Print(L"FATAL: LoadedImage Protocol Failed! %r\n", status); + while(1); + } + + fs = NULL; + status = SystemTable->BootServices->OpenProtocol(li->DeviceHandle, &fs_g, (void**)&fs, ImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (status != EFI_SUCCESS || fs == NULL) { + Print(L"Opaque Error: FileSystem is NULL! (Status: %r)\n", status); + Print(L"This usually means the boot partition is not correctly recognized.\n"); + while(1); + } + + Print(L"EFI: Opening Boot Volume...\n"); + status = fs->OpenVolume(fs, &root); + if (status != EFI_SUCCESS || root == NULL) { + Print(L"Opaque Error: Root Volume is NULL! (Status: %r)\n", status); + while(1); + } + + /* Single-Partition Strategy: os2.bin is on the same volume as the loader */ + EFI_FILE_PROTOCOL* os_root = root; + + /* Load Kernel (Sheep) at 48MB (or wherever specified) */ + /* Using EfiLoaderCode for execution compatibility */ + Print(L"EFI: Loading Kernel (os2.bin)...\n"); + UINT64 shell_size = 0; + void* shell_base = NULL; + + /* Overlap Check: Ensure Stage 2 doesn't hit the framebuffer */ + EFI_PHYSICAL_ADDRESS fb_base = (EFI_PHYSICAL_ADDRESS)params.framebuffer; + EFI_PHYSICAL_ADDRESS fb_end = fb_base + (params.height * params.pixels_per_scanline * 4); + if (0x3000000 < fb_end && (0x3000000 + 16*1024*1024) > fb_base) { + Print(L"Opaque Error: Stage 2 load address overlaps with Framebuffer!\n"); + while(1); + } + + status = load_file(SystemTable, os_root, L"os2.bin", 0x3000000, AllocateAddress, EfiLoaderCode, &shell_size, &shell_base); + if (status == EFI_SUCCESS) { + params.shell_size = (uint64)shell_size; + params.shell_base = shell_base; + Print(L"EFI: Kernel loaded at %p (%lu bytes).\n", params.shell_base, params.shell_size); + } else { + Print(L"Warning: os2.bin not found on OS partition. %r\n", status); + } + + /* 3. Prepare System Disk (Ramdisk) */ + /* Attempt to load ramdisk.img from boot volume, otherwise create blank */ + Print(L"EFI: Preparing RAM Disk...\n"); + UINT64 ramdisk_size = 512 * 1024 * 1024; /* Support up to 512MB ramdisk */ + void* ramdisk_base = NULL; + status = load_file(SystemTable, os_root, L"ramdisk.img", 0, AllocateAnyPages, EfiLoaderData, &ramdisk_size, &ramdisk_base); + params.ramdisk_size = (uint64)ramdisk_size; + if (status == EFI_SUCCESS) { + params.ramdisk_base = ramdisk_base; + Print(L"EFI: RAM Disk loaded at %p (%lu bytes).\n", params.ramdisk_base, params.ramdisk_size); + } else { + /* Create fallback zeroed ramdisk */ + EFI_PHYSICAL_ADDRESS disk_addr = 0; + UINTN disk_pages = (params.ramdisk_size + 4095) / 4096; + status = SystemTable->BootServices->AllocatePages(AllocateAnyPages, EfiLoaderData, disk_pages, &disk_addr); + if (status == EFI_SUCCESS) { + params.ramdisk_base = (void*)disk_addr; + /* Zero the disk */ + UINT8* p = (UINT8*)params.ramdisk_base; + for (UINT64 i = 0; i < params.ramdisk_size; i++) p[i] = 0; + } + } + + /* 4. Allocate Heap */ + Print(L"EFI: Allocating Kernel Heap...\n"); + UINTN heap_size = (UINTN)CONFIG_HEAP_SIZE_MB * 1024 * 1024; + EFI_PHYSICAL_ADDRESS heap_addr = 0; + UINTN heap_pages = (heap_size + 4095) / 4096; + status = SystemTable->BootServices->AllocatePages(AllocateAnyPages, EfiLoaderData, heap_pages, &heap_addr); + if (status == EFI_SUCCESS) { + params.heap_base = (void*)heap_addr; + params.heap_size = (uint64)heap_size; + /* Zero the heap */ + UINT8* p = (UINT8*)params.heap_base; + for (UINT64 i = 0; i < (UINT64)heap_size; i++) p[i] = 0; + Print(L"EFI: Heap allocated at %p (%lu MB).\n", params.heap_base, (uint64)CONFIG_HEAP_SIZE_MB); + } + + Print(L"EFI: Handover complete. Exiting Boot Services...\n"); + + /* 5. Exit Boot Services with Retry Loop */ + UINTN map_size = 0, map_key = 0, descriptor_size = 0; + UINT32 descriptor_version = 0; + void* map_buffer = NULL; + int retry = 5; + + while (retry--) { + status = SystemTable->BootServices->GetMemoryMap(&map_size, (void*)0, &map_key, &descriptor_size, &descriptor_version); + map_size += 4 * descriptor_size; /* Buffer for potential growth */ + + status = SystemTable->BootServices->AllocatePool(EfiLoaderData, map_size, &map_buffer); + if (status != EFI_SUCCESS) break; + + status = SystemTable->BootServices->GetMemoryMap(&map_size, map_buffer, &map_key, &descriptor_size, &descriptor_version); + if (status == EFI_SUCCESS) { + status = SystemTable->BootServices->ExitBootServices(ImageHandle, map_key); + if (status == EFI_SUCCESS) { + /* SUCCESS: No more Boot Services calls allowed! */ + serial_print("EFI: [BASE] Jumping to Kernel -> 0x3000000 + 0\n"); + kernel_main(¶ms); + /* The kernel should never return. If it does, we must not call UEFI services. */ + while(1) { __asm__ volatile("hlt"); } + } + /* ONLY free if ExitBootServices failed */ + SystemTable->BootServices->FreePool(map_buffer); + map_buffer = NULL; + } else { + /* map_buffer allocation failed or GetMemoryMap failed */ + if (map_buffer) SystemTable->BootServices->FreePool(map_buffer); + map_buffer = NULL; + } + } + + /* We can only use UEFI print if ExitBootServices failed all retries */ + Print(L"FATAL: ExitBootServices failed after retries!\n"); + while(1) { __asm__ volatile("hlt"); } + return EFI_SUCCESS; +} diff --git a/kernel/unice64/gdt.c b/kernel/unice64/gdt.c new file mode 100644 index 0000000..644bb15 --- /dev/null +++ b/kernel/unice64/gdt.c @@ -0,0 +1,54 @@ +#include "../../include/types.h" + +typedef struct { + uint16 limit_low; + uint16 base_low; + uint8 base_mid; + uint8 access; + uint8 granularity; + uint8 base_high; +} __attribute__((packed)) gdt_entry_t; + +typedef struct { + uint16 limit; + uint64 base; +} __attribute__((packed)) gdt_ptr_t; + +static gdt_entry_t gdt[3]; +static gdt_ptr_t gdt_ptr; + +void gdt_init() { + /* Null descriptor */ + gdt[0] = (gdt_entry_t){0, 0, 0, 0, 0, 0}; + + /* 64-bit Code segment: Access 0x9A (present, ring 0, code, readable), Gran 0x20 (long mode) */ + gdt[1] = (gdt_entry_t){0, 0, 0, 0x9A, 0x20, 0}; + + /* 64-bit Data segment: Access 0x92 (present, ring 0, data, writable) */ + gdt[2] = (gdt_entry_t){0, 0, 0, 0x92, 0, 0}; + + gdt_ptr.limit = sizeof(gdt) - 1; + gdt_ptr.base = (uint64)&gdt; + + __asm__ volatile ("lgdt %0" : : "m"(gdt_ptr)); + + /* Reload segment registers - PIC friendly */ + __asm__ volatile ( + "push $0x10\n" /* Data segment (index 2 * 8 = 16 = 0x10) */ + "push %%rsp\n" + "pushfq\n" + "push $0x08\n" /* Code segment (index 1 * 8 = 8 = 0x08) */ + "lea 1f(%%rip), %%rax\n" + "push %%rax\n" + "iretq\n" + "1:\n" + "mov $0x10, %%ax\n" + "mov %%ax, %%ds\n" + "mov %%ax, %%es\n" + "mov %%ax, %%ss\n" + "mov $0x00, %%ax\n" /* GS/FS are often kept at 0 in simple kernels */ + "mov %%ax, %%fs\n" + "mov %%ax, %%gs\n" + : : : "rax", "memory" + ); +} diff --git a/kernel/unice64/io.h b/kernel/unice64/io.h new file mode 100644 index 0000000..881b095 --- /dev/null +++ b/kernel/unice64/io.h @@ -0,0 +1,16 @@ +#ifndef IO_H +#define IO_H + +#include "../../include/types.h" + +static inline uint8 inb(uint16 port) { + uint8 ret; + __asm__ volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port)); + return ret; +} + +static inline void outb(uint16 port, uint8 val) { + __asm__ volatile ("outb %0, %1" : : "a"(val), "Nd"(port)); +} + +#endif diff --git a/kernel/unice64/kernel.h b/kernel/unice64/kernel.h new file mode 100644 index 0000000..0218365 --- /dev/null +++ b/kernel/unice64/kernel.h @@ -0,0 +1,35 @@ +#ifndef KERNEL_H +#define KERNEL_H + +#include "../../include/types.h" +#include "../../include/rsl.h" +#include "../../include/config.h" + +/* Events */ +typedef enum { + EVENT_INIT, + EVENT_MAIN, + EVENT_CLEANUP, + EVENT_EXIT +} event_t; + +/* Service Registry */ +typedef void (*service_init_t)(); +void register_service(service_init_t init_func); + +/* Event System */ +void trigger(event_t event); +typedef void (*event_handler_t)(event_t event); +void register_event_handler(event_handler_t handler); + +/* Global State */ +extern int running; +extern boot_params_t kboot_params; + +/* Entry point defined in main.c */ +void EFIAPI kernel_main(boot_params_t* params); + +/* GDT initialization */ +void gdt_init(void); + +#endif diff --git a/kernel/unice64/main.c b/kernel/unice64/main.c new file mode 100644 index 0000000..a5a3261 --- /dev/null +++ b/kernel/unice64/main.c @@ -0,0 +1,117 @@ +#include "kernel.h" +#include "paging.h" +#include "../../include/rsl.h" +#include "../libs/console.h" +#include "../libs/kutils.h" +#include "../libs/memory.h" +#include "../libs/input.h" +#include "../libs/connect.h" +#include "../libs/vdisk.h" +#include "../libs/disk.h" +#include "../libs/diskman.h" +#include "../libs/fs.h" +#include "../libs/loader.h" +#include "../libs/core/event.h" + +boot_params_t kboot_params; +int running = 1; + +#define MAX_SERVICES 16 +static service_init_t registered_services[MAX_SERVICES]; +static uint32 service_count = 0; + +void register_service(service_init_t init_func) { + if (service_count < MAX_SERVICES) { + registered_services[service_count++] = init_func; + } +} + +void exit_kernel() { + running = 0; +} + +/* Syscall Wrappers */ +static void sys_mount(int idx) { + char name[16]; + strcpy(name, "VDISK"); + char num[4]; + itoa(idx, num, 10); + strcat(name, num); + + vdisk_t* vd = vdisk_open(name); + if (vd) { + vdisk_mount_verify(vd); + } +} + +static void sys_format(int idx) { + print("Format: FAT32 auto-format not yet implemented in Opaque Mode.\n"); +} + +static void sys_lsfs() { + print("FS: FAT32 directory listing via VFS.\n"); +} + +/* + * The God-Machine Entry Point + */ +void EFIAPI kernel_main(boot_params_t* params) { + serial_init(); + if (!params) { + serial_print("FATAL: EFI passed NULL to Self-Sustaining Kernel\n"); + while(1) { __asm__ volatile("hlt"); } + } + kboot_params = *params; + + /* GDT and Interrupts are usually reset after ExitBootServices for full control */ + gdt_init(); + + /* Transition to Sovereign Paging before initializing console */ + paging_init(); + + register_service(console_init); + register_service(memory_init); + register_service(input_init); + register_service(connect_init); + register_service(vdisk_init); + register_service(disk_init); + register_service(diskman_init); + register_service(fs_init); + register_service(loader_init); + + for (uint32 i = 0; i < service_count; i++) { + print("Kernel: Initializing service...\n"); + registered_services[i](); + } + + print("OSx2 God-Mode: Kernel Handover Successful.\n"); + serial_print("Kernel: Handover complete. Triggering initialization events.\n"); + debug_kernel_signature(); + trigger(EVENT_INIT); + + rsl_syscall_table_t syscalls = { + .print = print, + .input = input, + .fread = fread, + .fwrite = fwrite, + .alloc = alloc, + .retain = retain, + .release = release, + .exit = exit_kernel, + .clear = console_clear, + .set_color = console_set_color, + .format = sys_format, + .mount = sys_mount, + .addpart = diskman_add_partition, + .lsfs = sys_lsfs + }; + + loader_run_shell(&syscalls); + + while (running) { + trigger(EVENT_MAIN); + } + + trigger(EVENT_CLEANUP); + trigger(EVENT_EXIT); +} diff --git a/kernel/unice64/paging.c b/kernel/unice64/paging.c new file mode 100644 index 0000000..205018d --- /dev/null +++ b/kernel/unice64/paging.c @@ -0,0 +1,64 @@ +#include "paging.h" +#include "kernel.h" +#include "../libs/console.h" +#include "../libs/kutils.h" + +/* Sovereign Paging: 2MB Huge Pages Identity Map */ + +#define PAGE_PRESENT (1ULL << 0) +#define PAGE_WRITABLE (1ULL << 1) +#define PAGE_HUGE (1ULL << 7) +#define PAGE_CACHE_DISABLE (1ULL << 4) + +/* Allocated statically in the kernel BSS */ +static uint64 pml4[512] __attribute__((aligned(4096))); +static uint64 pdpt[512] __attribute__((aligned(4096))); +static uint64 pd[4][512] __attribute__((aligned(4096))); /* 4 PDs = 4GB coverage */ + +void paging_init() { + serial_print("EFI: RSL_PAGING_HANDOVER\n"); + + k_memset(pml4, 0, 4096); + k_memset(pdpt, 0, 4096); + k_memset(pd, 0, 4096 * 4); + + /* 1. Link PML4 -> PDPT */ + pml4[0] = (uint64)pdpt | PAGE_PRESENT | PAGE_WRITABLE; + + /* 2. Link PDPT -> PDs */ + for (int i = 0; i < 4; i++) { + pdpt[i] = (uint64)&pd[i] | PAGE_PRESENT | PAGE_WRITABLE; + } + + /* 3. Identity Map first 4GB with 2MB Huge Pages */ + for (uint64 i = 0; i < 2048; i++) { + uint64 addr = i * 2 * 1024 * 1024; + uint64 pd_idx = i / 512; + uint64 entry_idx = i % 512; + pd[pd_idx][entry_idx] = addr | PAGE_PRESENT | PAGE_WRITABLE | PAGE_HUGE; + } + + /* 4. Ensure Framebuffer is mapped and Cache-Disabled if outside 4GB (Safety) */ + /* Note: If within 4GB, it's already mapped. We'll add a specific map for it regardless. */ + if (kboot_params.framebuffer) { + uint64 fb_addr = (uint64)kboot_params.framebuffer; + char buf[64]; + k_memset(buf, 0, 64); + serial_print("EFI: MAP_FRAMEBUFFER: 0x"); + /* Simple hex print logic */ + k_memset(buf, 0, 64); + itoa((int)(fb_addr >> 32), buf, 16); + serial_print(buf); + itoa((int)fb_addr, buf, 16); + serial_print(buf); + serial_print("fb\n"); + + /* For simplicity, we assume the framebuffer is in the first 4GB for identity mapping. + If it's higher, a more complex PDPT/PD allocation is needed. */ + } + + /* 5. Load CR3 */ + __asm__ volatile("mov %0, %%cr3" : : "r"(pml4) : "memory"); + + serial_print("EFI: Paging Active (Sovereign Mode).\n"); +} diff --git a/kernel/unice64/paging.h b/kernel/unice64/paging.h new file mode 100644 index 0000000..4b6816c --- /dev/null +++ b/kernel/unice64/paging.h @@ -0,0 +1,8 @@ +#ifndef PAGING_H +#define PAGING_H + +#include "../../include/types.h" + +void paging_init(); + +#endif diff --git a/programs/entry.S b/programs/entry.S new file mode 100644 index 0000000..6898b9e --- /dev/null +++ b/programs/entry.S @@ -0,0 +1,31 @@ +.section .text.prologue +.global _start +.extern kernel_entry + +_start: + /* + * Handover from OSx2 Kernel (System V ABI): + * RDI = boot_params_t* + * RSI = rsl_syscall_table_t* + */ + + /* Serial Heartbeat 'A' (Assembly Entry) */ + /* Preserve RDI/RSI across IO operation */ + push %rdi + push %rsi + + mov $0x3F8, %dx + mov $'A', %al + out %al, %dx + + pop %rsi + pop %rdi + + /* + * Already in System V ABI: + * RDI = arg0 (boot_params_t*) + * RSI = arg1 (rsl_syscall_table_t*) + */ + + /* Call C entry */ + jmp kernel_entry diff --git a/programs/libsystem.c b/programs/libsystem.c new file mode 100644 index 0000000..6bd6ee0 --- /dev/null +++ b/programs/libsystem.c @@ -0,0 +1,197 @@ +#include "../include/rsl.h" + +/* RTECH Standard Library (RSL) Implementation */ + +static rsl_syscall_table_t* g_syscalls = (void*)0; +boot_params_t kboot_params; + +int program_main(); + +void print(const char* str) { + if (g_syscalls && g_syscalls->print) { + g_syscalls->print(str); + } +} + +void* alloc(uint64 size) { + if (g_syscalls && g_syscalls->alloc) { + return g_syscalls->alloc(size); + } + return (void*)0; +} + +void retain(void* ptr) { + if (g_syscalls && g_syscalls->retain) { + g_syscalls->retain(ptr); + } +} + +void release(void* ptr) { + if (g_syscalls && g_syscalls->release) { + g_syscalls->release(ptr); + } +} + +INTN read_file(const char* path, void* buffer, uint64 max_size) { + if (g_syscalls && g_syscalls->fread) { + return g_syscalls->fread(path, buffer, max_size); + } + return -1; +} + +INTN write_file(const char* path, const void* buffer, uint64 size) { + if (g_syscalls && g_syscalls->fwrite) { + return g_syscalls->fwrite(path, buffer, size); + } + return -1; +} + +void clear() { + if (g_syscalls && g_syscalls->clear) { + g_syscalls->clear(); + } +} + +void quit() { + if (g_syscalls && g_syscalls->exit) { + g_syscalls->exit(); + } +} + +void color(uint32 fg, uint32 bg) { + if (g_syscalls && g_syscalls->set_color) { + g_syscalls->set_color(fg, bg); + } +} + +void lsfs() { +} + +void format(int idx) { +} + +void mount(int idx) { +} + +void addpart(uint64 start, uint32 count) { + if (g_syscalls && g_syscalls->addpart) { + g_syscalls->addpart(start, count); + } +} + +/* --- Auto-RAM: Simplified API --- */ + +void* auto_ram(uint64 size) { + /* Everything in RSL is managed by ARC by default */ + return alloc(size); +} + +char* str_create(const char* init) { + uint64 len = strlen(init); + char* s = (char*)auto_ram(len + 1); + if (s) { + strcpy(s, init); + } + return s; +} + +char* readline(const char* prompt) { + char* buf = (char*)auto_ram(128); + if (!buf) return (void*)0; + + if (g_syscalls && g_syscalls->input) { + g_syscalls->input(prompt, buf, 128); + } + return buf; +} + +/* --- Utilities --- */ + +int strcmp(const char* s1, const char* s2) { + while (*s1 && *s1 == *s2) { s1++; s2++; } + return *(unsigned char*)s1 - *(unsigned char*)s2; +} + +int strncmp(const char* s1, const char* s2, uint64 n) { + for (uint64 i = 0; i < n; i++) { + if (s1[i] != s2[i]) return (unsigned char)s1[i] - (unsigned char)s2[i]; + if (s1[i] == 0) return 0; + } + return 0; +} + +void strcpy(char* dst, const char* src) { + while ((*dst++ = *src++)); +} + +void strncpy(char* dst, const char* src, uint64 n) { + uint64 i; + for (i = 0; i < n && src[i] != '\0'; i++) dst[i] = src[i]; + for (; i < n; i++) dst[i] = '\0'; +} + +uint64 strlen(const char* s) { + uint64 n = 0; + while (s[n]) n++; + return n; +} + +char* strchr(const char* s, int c) { + while (s && *s != (char)c) { + if (!*s++) return (void*)0; + } + return (char*)s; +} + +void memcpy(void* dst, const void* src, uint64 n) { + uint8* d = (uint8*)dst; + const uint8* s = (const uint8*)src; + while (n--) *d++ = *s++; +} + +void memset(void* s, int c, uint64 n) { + uint8* p = (uint8*)s; + while (n--) *p++ = (uint8)c; +} + +int atoi(const char* s) { + int res = 0; + while (s && *s >= '0' && *s <= '9') { + res = res * 10 + (*s - '0'); + s++; + } + return res; +} + +void itoa(int n, char* s, int base) { + char* p = s; + char* p1, *p2; + unsigned int ud = n; + if (base == 10 && n < 0) { + *p++ = '-'; + s++; + ud = -n; + } + do { + int remainder = ud % base; + *p++ = (remainder < 10) ? remainder + '0' : remainder + 'a' - 10; + } while (ud /= base); + *p = 0; + p1 = s; + p2 = p - 1; + while (p1 < p2) { + char tmp = *p1; + *p1++ = *p2; + *p2-- = tmp; + } +} + +void kernel_entry(boot_params_t* params, rsl_syscall_table_t* syscalls) { + /* Serial Heartbeat 'C' (C Entry) */ + #define COM1 0x3F8 + __asm__ volatile ("outb %0, %1" : : "a"((unsigned char)'C'), "Nd"((unsigned short)COM1)); + + if (params) kboot_params = *params; + if (syscalls) g_syscalls = syscalls; + program_main(); +} diff --git a/programs/linker.ld b/programs/linker.ld new file mode 100644 index 0000000..917c08c --- /dev/null +++ b/programs/linker.ld @@ -0,0 +1,26 @@ +ENTRY(_start) +SECTIONS +{ + . = 0x3000000; /* Linked to match Stage 1 load address */ + + /* 1. THE UNIFIED BRAIN (All Symbols at Byte 0) */ + .text : { + *(.text.prologue) + *(.text*) + } + + /* 2. THE DATA */ + .data : { + *(.data*) + } + + /* 3. THE BSS */ + .bss : { + *(.bss*) + } + + /* 4. THE ENGLISH WALL (Moved to the BACK) */ + .rodata : { + *(.rodata*) + } +} diff --git a/programs/shell.c b/programs/shell.c new file mode 100644 index 0000000..98e155c --- /dev/null +++ b/programs/shell.c @@ -0,0 +1,85 @@ +#include "../include/rsl.h" + +/* + * OSx2 Standard Shell + * Powering RTECH dos via the RSL (RTECH Standard Library). + */ + +static void handle_command(char* cmd); + +int program_main() { + clear(); + color(0x00FF88, 0x000000); + print("OSx2 (RTECH dos) - Kernel Expert Mode (64-bit)\n"); + print("Partition Table: GPT (GUID Partition Table)\n"); + print("Permanent Storage: FAT32 (Opaque Mode)\n\n"); + + while (1) { + char* input_str = readline("> "); + if (input_str) { + handle_command(input_str); + release(input_str); + } + } + return 0; +} + +static void handle_command(char* cmd) { + if (strcmp(cmd, "help") == 0) { + print("Commands:\n"); + print(" lsfs - List files on mounted FAT32\n"); + print(" cat [file] - Read file content\n"); + print(" write [f] [t] - Write text to file\n"); + print(" addpart [s] [c]- Add GPT partition (Start LBA, Count)\n"); + print(" format [idx] - Format GPT partition with FAT32\n"); + print(" mount [idx] - Mount FAT32 partition\n"); + print(" clear - Clear screen\n"); + print(" exit - Shutdown\n"); + } else if (strcmp(cmd, "exit") == 0) { + quit(); + } else if (strcmp(cmd, "clear") == 0) { + clear(); + } else if (strncmp(cmd, "lsfs", 4) == 0) { + lsfs(); + } else if (strncmp(cmd, "addpart ", 8) == 0) { + char* start_str = cmd + 8; + char* count_str = strchr(start_str, ' '); + if (start_str && count_str) { + *count_str = 0; + count_str++; + addpart((uint64)atoi(start_str), (uint32)atoi(count_str)); + } + } else if (strncmp(cmd, "format ", 7) == 0) { + format(atoi(cmd + 7)); + } else if (strncmp(cmd, "mount ", 6) == 0) { + mount(atoi(cmd + 6)); + } else if (strncmp(cmd, "cat ", 4) == 0) { + char* buf = (char*)auto_ram(4096); + if (buf) { + memset(buf, 0, 4096); + if (read_file(cmd + 4, buf, 4096) >= 0) { + print(buf); + print("\n"); + } else { + print("Error: File not found or FAT32 not mounted.\n"); + } + release(buf); + } + } else if (strncmp(cmd, "write ", 6) == 0) { + char* arg = cmd + 6; + char* text = strchr(arg, ' '); + if (text) { + *text = 0; + text++; + if (write_file(arg, text, strlen(text)) >= 0) { + print("Write successful.\n"); + } else { + print("Write failed.\n"); + } + } + } else if (cmd[0] != 0) { + print("Unknown command: "); + print(cmd); + print("\n"); + } +} diff --git a/scripts/menuconfig.py b/scripts/menuconfig.py new file mode 100644 index 0000000..620d9f8 --- /dev/null +++ b/scripts/menuconfig.py @@ -0,0 +1,147 @@ +import curses +import os +import sys + +# OSx2 Configuration Options - Professional Suite +OPTIONS = [ + {"id": "CONFIG_DEBUG_LOGS", "label": "Enable Debug Logging", "type": "bool", "default": True}, + {"id": "CONFIG_KERNEL_BASE", "label": "Kernel Base Address (Hex)", "type": "hex", "default": 0x100000}, + {"id": "CONFIG_HEAP_BASE", "label": "ARC Heap Base Address (Hex)", "type": "hex", "default": 0x2000000}, + {"id": "CONFIG_HEAP_SIZE_MB", "label": "Global Heap Size (MB)", "type": "int", "default": 8}, + {"id": "CONFIG_SCROLL_SPEED", "label": "Console Scroll Speed (Pixels)", "type": "int", "default": 10}, + {"id": "CONFIG_EMERALD_MODE", "label": "Enable High-Contrast Emerald Theme", "type": "bool", "default": True}, + {"id": "CONFIG_FG_COLOR", "label": "Default FG Color (RGB Hex)", "type": "hex", "default": 0x00FF88}, + {"id": "CONFIG_BG_COLOR", "label": "Default BG Color (RGB Hex)", "type": "hex", "default": 0x000000}, + {"id": "CONFIG_LOAD_SHELL", "label": "Auto-load shell.bin on boot", "type": "bool", "default": True}, + {"id": "CONFIG_OPTIMIZATION", "label": "Compiler Optimization (-O0, -O1, -O2)", "type": "int", "default": 0}, + {"id": "CONFIG_STRICT_CHECKS", "label": "Enable Strict Memory Bounds Checking", "type": "bool", "default": True}, +] + +class MenuConfig: + def __init__(self, stdscr): + self.stdscr = stdscr + self.cursor = 0 + self.values = {} + self.load_config() + + def load_config(self): + if os.path.exists(".config"): + with open(".config", "r") as f: + for line in f: + if "=" in line: + parts = line.strip().split("=") + if len(parts) == 2: + k, v = parts + if v == "y": self.values[k] = True + elif v == "n": self.values[k] = False + elif v.startswith("0x"): self.values[k] = int(v, 16) + elif v.isdigit(): self.values[k] = int(v) + else: self.values[k] = v + + for opt in OPTIONS: + if opt["id"] not in self.values: + self.values[opt["id"]] = opt["default"] + + def save_config(self): + # Save .config for Makefile + with open(".config", "w") as f: + for k, v in self.values.items(): + if isinstance(v, bool): + f.write(f"{k}={'y' if v else 'n'}\n") + elif isinstance(v, int): + # Check if it was originally hex + is_hex = False + for opt in OPTIONS: + if opt["id"] == k and opt["type"] == "hex": + is_hex = True + break + if is_hex: f.write(f"{k}={hex(v)}\n") + else: f.write(f"{k}={v}\n") + else: + f.write(f"{k}={v}\n") + + # Save include/config.h for C + with open("include/config.h", "w") as f: + f.write("#ifndef CONFIG_H\n#define CONFIG_H\n\n") + f.write("/* Auto-generated by OSx2 menuconfig Professional */\n\n") + for k, v in self.values.items(): + if isinstance(v, bool): + if v: f.write(f"#define {k} 1\n") + else: f.write(f"/* #undef {k} */\n") + elif isinstance(v, int): + f.write(f"#define {k} {hex(v) if v > 1000 else v}\n") + else: + f.write(f"#define {k} {v}\n") + f.write("\n#endif\n") + + def run(self): + curses.curs_set(0) + self.stdscr.nodelay(0) + self.stdscr.keypad(True) + + while True: + self.stdscr.clear() + h, w = self.stdscr.getmaxyx() + + # Draw header + self.stdscr.attron(curses.A_REVERSE) + self.stdscr.addstr(0, 0, " OSx2 / RTECH dos Advanced Configuration Utility ".center(w)) + self.stdscr.attroff(curses.A_REVERSE) + + # Draw options + for i, opt in enumerate(OPTIONS): + val = self.values[opt["id"]] + if isinstance(val, bool): + prefix = "[*]" if val else "[ ]" + elif i == self.cursor: + prefix = f"({hex(val) if isinstance(val, int) and val > 1000 else val})" + else: + prefix = f" {hex(val) if isinstance(val, int) and val > 1000 else val} " + + label = f"{prefix.ljust(12)} {opt['label']}" + + if i == self.cursor: + self.stdscr.attron(curses.A_BOLD | curses.A_REVERSE) + self.stdscr.addstr(i + 2, 2, f" > {label} ") + self.stdscr.attroff(curses.A_BOLD | curses.A_REVERSE) + else: + self.stdscr.addstr(i + 2, 2, f" {label}") + + # Draw footer + self.stdscr.addstr(h - 3, 2, "-" * (w - 4)) + self.stdscr.addstr(h - 2, 2, "Space/Enter: Edit | S: Save & Exit | Q: Discard & Quit") + + key = self.stdscr.getch() + if key == ord('q'): break + if key == ord('s'): + self.save_config() + break + elif key == curses.KEY_UP: + self.cursor = (self.cursor - 1) % len(OPTIONS) + elif key == curses.KEY_DOWN: + self.cursor = (self.cursor + 1) % len(OPTIONS) + elif key in [ord(' '), 10, 13]: + opt = OPTIONS[self.cursor] + if opt["type"] == "bool": + self.values[opt["id"]] = not self.values[opt["id"]] + else: + curses.echo() + self.stdscr.addstr(h - 1, 2, f"Set {opt['id']}: ".ljust(w-4)) + self.stdscr.move(h - 1, len(opt['id']) + 7) + new_val = self.stdscr.getstr().decode() + curses.noecho() + try: + if opt["type"] == "hex": + if new_val.startswith("0x"): self.values[opt["id"]] = int(new_val, 16) + else: self.values[opt["id"]] = int(new_val, 16) + elif opt["type"] == "int": + self.values[opt["id"]] = int(new_val) + except: + pass + +if __name__ == "__main__": + if len(sys.argv) > 1 and sys.argv[1] == "--save": + mc = MenuConfig(None) + mc.save_config() + else: + curses.wrapper(lambda s: MenuConfig(s).run()) diff --git a/tools/fontgen.html b/tools/fontgen.html new file mode 100644 index 0000000..1727b53 --- /dev/null +++ b/tools/fontgen.html @@ -0,0 +1,211 @@ + + + + + + OSx2 Pro Font & Color Studio + + + +
+

OSx2 / RTECH FONT STUDIO

+
+ +
+ + +
+
+ +
+ +
A
+ +
+
+
+ + + +