diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..73be39d --- /dev/null +++ b/Makefile @@ -0,0 +1,42 @@ +CC = gcc +LD = ld +OBJCOPY = objcopy +NASM = nasm + +CFLAGS = -m32 -ffreestanding -O2 -Wall -Wextra -I. -std=gnu99 -MMD +# Use -f win32 for MinGW, -f elf32 for Linux/Cross-Compiler +NASMFLAGS = -f win32 +LDFLAGS = -T linker.ld + +# Auto-detect all .c files in the current folder +C_SOURCES = $(wildcard *.c) +# Exclude spinlock.c if it exists (replaced by sync.h implementation) +C_SOURCES := $(filter-out spinlock.c, $(C_SOURCES)) +# Create a list of .o files to build +OBJ = $(C_SOURCES:.c=.o) + +# Default target +all: os.img + +os.img: boot.bin kernel.bin + cat boot.bin kernel.bin > os.img + +boot.bin: boot.asm + $(NASM) -f bin boot.asm -o boot.bin + +kernel.bin: kernel.tmp + $(OBJCOPY) -O binary kernel.tmp kernel.bin + +kernel.tmp: $(OBJ) interrupt.o + $(LD) $(LDFLAGS) -o kernel.tmp $(OBJ) interrupt.o + +interrupt.o: interrupt.asm + $(NASM) $(NASMFLAGS) interrupt.asm -o interrupt.o + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +-include $(OBJ:.o=.d) + +clean: + rm -f *.o *.d *.bin *.tmp os.img \ No newline at end of file diff --git a/NIC.C b/NIC.C index d66ca70..ed816c2 100644 --- a/NIC.C +++ b/NIC.C @@ -37,7 +37,7 @@ void rtl8139_handler(registers_t *r) { void rtl8139_init(void) { vga_print_string("Initializing RTL8139... "); - // --- Find the card (same as before) --- + // --- Find the card --- uint8_t found = 0; for (uint16_t bus = 0; bus < 256; bus++) { for (uint8_t device = 0; device < 32; device++) { @@ -65,9 +65,8 @@ void rtl8139_init(void) { // 2. Software Reset outb(rtl8139_io_base + REG_COMMAND, 0x10); while((inb(rtl8139_io_base + REG_COMMAND) & 0x10) != 0) { /* wait */ } - - // 3. Allocate Receive Buffer (8K + 16 bytes) - rx_buffer = (uint8_t*)pmm_alloc(8192 + 16); + // 3. Allocate an 16KB block, ie 4 blocks (order 1) for the receive buffer. + rx_buffer = (uint8_t*)pmm_alloc_blocks(4); outl(rtl8139_io_base + REG_RX_BUF, (uint32_t)rx_buffer); // 4. Set Interrupt Mask (Enable Receive OK interrupt) diff --git a/README.md b/README.md index 9c390d2..703c939 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,192 @@ -Operating System still under development -This is a lightweight, Machine Learning based (under the hood for memory management, process allocation etc ) based operating system +# SimpleOS - A Lightweight x86 Operating System + +SimpleOS is a lightweight, robust operating system for the x86 architecture, written in C and Assembly. It provides a foundational set of OS features, including protected mode, memory segmentation, and a full interrupt handling system, making it ideal for embedded applications, legacy system revival, or as a base for custom OS development. + +## Features + +- **Bootloader**: Custom 16-bit bootloader that transitions to protected mode +- **GDT (Global Descriptor Table)**: Memory segmentation with kernel/user segments +- **IDT (Interrupt Descriptor Table)**: Complete interrupt handling system with exception messages +- **VGA Text Driver**: Full-featured text output with scrolling, colors, and formatting +- **Keyboard Driver**: PS/2 keyboard support with scan code translation +- **Interactive Shell**: Command-line interface with built-in commands +- **Memory Management**: Basic protected mode memory setup +- **Interrupt Handling**: Proper CPU exception and hardware interrupt handling + +## Architecture + +### Boot Process +1. **Real Mode Boot**: 16-bit bootloader loads from sector 0 +2. **A20 Line**: Enable extended memory access +3. **Protected Mode**: Switch to 32-bit protected mode +4. **Kernel Entry**: Jump to kernel main function + +### Kernel Components + +#### VGA Driver (`vga.c`, `vga.h`) +- Text mode output at 0xB8000 +- 80x25 character display +- 16-color palette support +- Automatic scrolling +- Hex/decimal number formatting + +#### GDT Manager (`gdt.c`, `gdt.h`) +- 5-entry descriptor table (null, kernel code/data, user code/data) +- Proper segment reloading +- 4GB flat memory model + +#### IDT Manager (`idt.c`, `idt.h`) +- 256 interrupt descriptors +- Exception handlers with descriptive messages +- Hardware interrupt support (PIC reprogramming) +- Assembly interrupt stubs (`interrupt.asm`) + +#### Keyboard Driver (`keyboard.c`, `keyboard.h`) +- PS/2 keyboard interrupt handler (IRQ1) +- Scan code to ASCII translation +- Shift and Caps Lock support +- Key buffer for input queuing +- Integration with shell interface + +#### Interactive Shell (`shell.c`, `shell.h`) +- Command-line interface +- Built-in commands: help, clear, about, reboot, halt +- Command history and input processing +- Backspace support and line editing + +#### Kernel Main (`kernel.c`) +- System initialization sequence +- Colorized boot messages +- Shell initialization and main loop + +## Building + +### Prerequisites + +You need a cross-compilation toolchain for i686-elf: +- `i686-elf-gcc` (C compiler) +- `i686-elf-ld` (Linker) +- `nasm` (Netwide Assembler) + +### Installation on Ubuntu/Debian: +```bash +sudo apt-get install build-essential nasm qemu-system-x86 +# For the cross-compiler, you can build it from source. +# A good guide can be found here: https://wiki.osdev.org/GCC_Cross-Compiler +# Alternatively, some package managers might have pre-built toolchains. +``` + +### Installation on Windows: +1. Install MSYS2 +2. Install cross-compilation tools: +```bash +pacman -S mingw-w64-i686-gcc nasm +``` + +### Compilation +```bash +make all # Build OS image +make clean # Remove build files +make qemu # Run with QEMU (if installed) +make bochs # Run with Bochs (if installed) +make help # Show available targets +``` + +## Running + +### QEMU (Recommended) +```bash +qemu-system-i386 -fda build/os.img +``` + +### Bochs +```bash +bochs -f bochsrc.txt +``` + +### VirtualBox/VMware +1. Create new VM with floppy disk +2. Mount `build/os.img` as floppy image +3. Boot from floppy + +## Using the Shell + +Once the system boots, you'll see the SimpleOS shell prompt: + +``` +SimpleOS> +``` + +The agent will process your request and respond accordingly. + +### Example Interactions +- `> what time is it?` +- `> create a new file named notes.txt` +- `> tell me about the CPU` +- `> reboot the machine in 5 minutes` + +## File Structure + +``` +SimpleOS/ +├── boot/ +│ └── boot.asm # 16-bit bootloader +├── kernel/ +│ ├── kernel.c # Kernel main and initialization +│ ├── gdt.c/.h # Global Descriptor Table +│ ├── idt.c/.h # Interrupt Descriptor Table +│ ├── vga.c/.h # VGA text driver +│ ├── keyboard.c/.h # PS/2 keyboard driver +│ ├── agent.c/.h # The core AI agent logic +│ └── interrupt.asm # Assembly interrupt handlers +├── build/ # Build output (auto-generated) +├── Makefile # Build configuration +├── linker.ld # Linker script +└── README.md # This file +``` + +## Technical Details + +### Memory Layout +- **0x00007C00**: Bootloader load address +- **0x00100000**: Kernel load address (1MB) +- **0x000B8000**: VGA text buffer +- **0x00090000**: Stack pointer + +### Interrupts +- **ISR 0-31**: CPU exceptions (division error, page fault, etc.) +- **IRQ 0-15**: Hardware interrupts (timer, keyboard, etc.) +- **PIC Remapping**: Master PIC (0x20-0x27), Slave PIC (0x28-0x2F) + +### Color Codes (VGA) +- 0=Black, 1=Blue, 2=Green, 3=Cyan, 4=Red, 5=Magenta +- 6=Brown, 7=Light Grey, 8=Dark Grey, 9=Light Blue +- 10=Light Green, 11=Light Cyan, 12=Light Red +- 13=Light Magenta, 14=Light Brown, 15=White + +## Roadmap + +Future development is focused on expanding the kernel's capabilities. Key areas on our roadmap include: + +- **Agent Tooling**: Expanding the set of kernel functions (tools) the LLM agent can use. +- **Long-Term Memory**: Implementing a file system to give the agent persistent memory. +- **Multitasking**: Allowing the agent to manage and execute multiple background processes. + +### Debugging +- Connect GDB: `gdb -ex "target remote :1234"` +- Enable QEMU monitor: Add `-monitor stdio` + +## Contributing + +SimpleOS is an open-source product and we welcome contributions from the community. If you are interested in contributing, please feel free to fork the repository, make your changes, and submit a pull request. We are actively looking for improvements in drivers, memory management, and performance optimizations. + +## License + +This product is released under the MIT License. See the LICENSE file for details. + +## References + +- [OSDev Wiki](https://wiki.osdev.org/) - Comprehensive OS development resource +- [Intel 80386 Manual](https://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-3a-part-1-manual.html) +- [Bran's Kernel Development Tutorial](http://www.osdever.net/bkerndev/Docs/title.htm) +- [JamesM's Kernel Development Tutorials](https://web.archive.org/web/20160412174753/http://www.jamesmolloy.co.uk/tutorial_html/index.html) \ No newline at end of file diff --git a/boot.asm b/boot.asm new file mode 100644 index 0000000..5049190 --- /dev/null +++ b/boot.asm @@ -0,0 +1,236 @@ +bits 16 +org 0x7c00 + +; --- Memory Definitions --- +VBE_INFO_BLOCK equ 0x9000 +MODE_INFO_BLOCK equ 0x9200 + +; --- Constants --- +VBE_MAGIC equ 0x4F +VBE_GET_INFO equ 0x00 +VBE_GET_MODE_INFO equ 0x01 +VBE_SET_MODE equ 0x02 +TARGET_WIDTH equ 1280 +TARGET_HEIGHT equ 720 +TARGET_BPP equ 32 + +; Kernel placement +KERNEL_TEMP_ADDR equ 0x1000 +KERNEL_TARGET_ADDR equ 0x100000 +SECTORS_TO_READ equ 100 + +start: + jmp 0:init_segments + +init_segments: + xor ax, ax + mov ds, ax + mov es, ax + mov ss, ax + mov sp, 0x7c00 + + mov [boot_drive], dl ; Save boot drive + + ; 1. Load Kernel (Fixed Routine) + call load_kernel_safe + + ; CRITICAL FIX: Ensure ES is 0 for VBE calls + xor ax, ax + mov es, ax + + ; 2. Enable A20 + in al, 0x92 + or al, 2 + out 0x92, al + + ; 3. VBE Graphics Setup + mov ax, VBE_MAGIC + VBE_GET_INFO + mov di, VBE_INFO_BLOCK + int 0x10 + cmp ax, 0x004F + jne .graphics_error + + ; Get video modes list pointer + mov cx, [VBE_INFO_BLOCK + 14] ; Offset + mov si, [VBE_INFO_BLOCK + 16] ; Segment + mov fs, si ; Use FS to access the mode list segment + + ; Note: The list is a far pointer (Seg:Off). + ; We need to read from FS:CX (Seg:Off). + ; But for simplicity in Real Mode flat memory (if Seg is not 0), + ; we usually normalize. + ; If BIOS returns a segment for the list, we must use it. + ; Simplification: Many BIOSes return Segment in SI. + + mov si, cx ; Move Offset to SI + mov ax, [VBE_INFO_BLOCK + 16] + mov ds, ax ; Point DS to the VBE Mode List Segment + +.mode_loop: + mov cx, [si] ; Read mode number + cmp cx, 0xFFFF ; End of list? + je .graphics_error + + push cx + + ; Restore DS to 0 for the Interrupt buffer access + push ds + xor ax, ax + mov ds, ax + + mov ax, VBE_MAGIC + VBE_GET_MODE_INFO + mov di, MODE_INFO_BLOCK + int 0x10 + + cmp ax, 0x004F + pop ds ; Restore Mode List Segment + jne .next_mode_pop + + ; Check resolution (Need to use ES or explicit segment 0 override since DS is changed) + ; But wait, MODE_INFO_BLOCK is at 0x9200. We need to check it using DS=0. + ; It's cleaner to just switch DS back to 0 for the check. + push ds + xor ax, ax + mov ds, ax + + cmp word [MODE_INFO_BLOCK + 18], TARGET_WIDTH + jne .check_failed + cmp word [MODE_INFO_BLOCK + 20], TARGET_HEIGHT + jne .check_failed + cmp word [MODE_INFO_BLOCK + 25], TARGET_BPP + jne .check_failed + + ; FOUND IT! + pop ds ; Restore stack balance (pushed DS) + pop cx ; Restore Mode Number (pushed CX) + jmp .set_mode + +.check_failed: + pop ds +.next_mode_pop: + pop cx + add si, 2 + jmp .mode_loop + +.set_mode: + ; CX holds the mode number + mov bx, cx + or bx, 1 << 14 ; Linear Frame Buffer bit + + ; Reset DS to 0 before final call + xor ax, ax + mov ds, ax + + mov ax, VBE_MAGIC + VBE_SET_MODE + int 0x10 + cmp ax, 0x004F + jne .graphics_error + + ; Save VBE info for kernel + ; Copy from 0x9200 (MODE_INFO_BLOCK) to 0x8000 + xor ax, ax + mov es, ax + mov ds, ax + mov edi, 0x8000 + mov esi, MODE_INFO_BLOCK + mov ecx, 64 ; Copy 256 bytes (64 dwords) + rep movsd ; Use movsd for speed (32-bit width in 16-bit mode needs 0x66 prefix usually, but `rep movsd` works in real mode on 386+) + + jmp enter_pm + +.graphics_error: + cli + hlt + +; --- Safe Disk Loading (CHS Loop) --- +load_kernel_safe: + mov ax, KERNEL_TEMP_ADDR + mov es, ax ; Buffer segment + xor bx, bx ; Buffer offset 0 + + mov dl, [boot_drive] + mov ch, 0 ; Cylinder 0 + mov dh, 0 ; Head 0 + mov cl, 2 ; Start at Sector 2 + + mov si, SECTORS_TO_READ + +.read_loop: + mov ah, 0x02 + mov al, 1 ; Read 1 sector at a time + int 0x13 + jc .disk_error + + dec si + jz .done + + add bx, 512 ; Move buffer pointer + ; Handle Segment overflow (64KB) if necessary, but 50KB fits in one segment. + + ; Update CHS + inc cl ; Next sector + cmp cl, 19 ; 18 sectors per track? + jl .read_loop + + ; Next Track/Head logic + mov cl, 1 ; Reset sector + inc dh ; Next head + cmp dh, 2 ; 2 heads? + jl .read_loop + + mov dh, 0 ; Reset head + inc ch ; Next cylinder + jmp .read_loop + +.done: + ret + +.disk_error: + cli + hlt + +; --- Protected Mode Entry --- +enter_pm: + cli + lgdt [gdt_descriptor] + mov eax, cr0 + or eax, 1 + mov cr0, eax + jmp 0x08:start_protected_mode + +bits 32 +start_protected_mode: + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + mov esp, 0x90000 + + ; Copy Kernel to 1MB + mov esi, 0x10000 + mov edi, KERNEL_TARGET_ADDR + mov ecx, (SECTORS_TO_READ * 512) / 4 + rep movsd + + ; Jump to Kernel + ; Ensure kernel_entry.o is linked FIRST + jmp KERNEL_TARGET_ADDR + + cli + hlt + +; Variables +boot_drive db 0 +gdt_start: + dd 0x0, 0x0 + dw 0xFFFF, 0x0000, 0x9A, 0xCF, 0x00 + dw 0xFFFF, 0x0000, 0x92, 0xCF, 0x00 +gdt_end: +gdt_descriptor: + dw gdt_end - gdt_start - 1 + dd gdt_start + +times 510-($-$$) db 0 +dw 0xAA55 \ No newline at end of file diff --git a/boot.bin b/boot.bin new file mode 100644 index 0000000..29b9bce Binary files /dev/null and b/boot.bin differ diff --git a/build_iso.sh b/build_iso.sh new file mode 100644 index 0000000..0c8476b --- /dev/null +++ b/build_iso.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# Check if the raw OS image exists +if [ ! -f os-image.bin ]; then + echo "Error: os-image.bin not found. Run the build commands first." + exit 1 +fi + +# 1. Create a blank 1.44MB floppy image (1474560 bytes) +dd if=/dev/zero of=floppy.img bs=1024 count=1440 + +# 2. Write the OS image (bootloader + kernel) to the floppy image +# conv=notrunc ensures we overwrite the start without truncating the file +dd if=os-image.bin of=floppy.img conv=notrunc + +# 3. Create the ISO directory structure +mkdir -p iso_root +cp floppy.img iso_root/ + +# 4. Generate the ISO using mkisofs (Floppy Emulation Mode) +# -b specifies the boot image. Since it is 1.44MB, mkisofs enables floppy emulation. +mkisofs -o simpleos.iso -b floppy.img iso_root/ + +echo "Done! You can now boot simpleos.iso in a VM." \ No newline at end of file diff --git a/console.c b/console.c new file mode 100644 index 0000000..9da1bd2 --- /dev/null +++ b/console.c @@ -0,0 +1,51 @@ +#include "console.h" +#include "graphics.h" +static FrameBuffer* console_fb = NULL; +static Font* console_font = NULL; +void console_init(FrameBuffer* fb, Font* font) { + console_fb = fb; + console_font = font; +} +void console_write(const char* str) { + if (!console_fb || !console_font) return; + static uint32_t cursor_x = 0; + static uint32_t cursor_y = 0; + + while (*str) { + char c = *str++; + if (c == '\n') { + cursor_x = 0; + cursor_y += console_font->char_height; + // Simple scrolling + if (cursor_y + console_font->char_height > console_fb->height) { + // This would require a memcpy-like function to move screen contents up. + // For now, we'll just wrap around. + cursor_y = 0; + } + continue; + } + + draw_char(console_fb, console_font, c, cursor_x, cursor_y, 0xFFFFFF); + + cursor_x += console_font->char_width; + if (cursor_x + console_font->char_width > console_fb->width) { + cursor_x = 0; + cursor_y += console_font->char_height; + } + } +} + +void console_write_dec(uint32_t n) { + if (n == 0) { + console_write("0"); + return; + } + char buf[11]; + char* p = &buf[10]; + *p = '\0'; + do { + *--p = '0' + (n % 10); + n /= 10; + } while (n > 0); + console_write(p); +} \ No newline at end of file diff --git a/console.h b/console.h new file mode 100644 index 0000000..8df9832 --- /dev/null +++ b/console.h @@ -0,0 +1,9 @@ +#ifndef CONSOLE_H +#define CONSOLE_H +#include +#include +#include +void console_init(FrameBuffer* fb, Font* font); +void console_write(const char* str); +void console_write_dec(uint32_t n); +#endif // CONSOLE_H \ No newline at end of file diff --git a/console.o b/console.o new file mode 100644 index 0000000..01ef4fc Binary files /dev/null and b/console.o differ diff --git a/create_iso.sh b/create_iso.sh new file mode 100644 index 0000000..b24fb4e --- /dev/null +++ b/create_iso.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +# Stop on error +set -e + +echo "Assembling entry point..." +nasm -f win32 kernel_entry.asm -o kernel_entry.o + +echo "Assembling bootloader..." +nasm -f bin boot.asm -o boot.bin + +echo "Assembling interrupts..." +nasm -f win32 interrupt.asm -o interrupt.o + +echo "Compiling C sources..." +# Note: nic.c is used +C_SOURCES="console.c cursor.c dirty_rect.c font.c gdt.c graphics.c heap.c idt.c kernel.c keyboard.c mouse.c mutex.c paging.c pci.c pmm.c shell.c syscall.c task.c timer.c vga.c widget.c window.c nic.c lib.c" + +OBJ_FILES="kernel_entry.o interrupt.o" + +for file in $C_SOURCES; do + obj="${file%.*}.o" + i686-w64-mingw32-gcc -m32 -ffreestanding -O2 -Wall -Wextra -I. -c "$file" -o "$obj" + OBJ_FILES="$OBJ_FILES $obj" +done + +echo "Linking kernel..." +# Linking kernel_entry.o FIRST is crucial so it ends up at 0x100000 +# -Wl,--image-base,0 fixes "section below image base" error on MinGW +i686-w64-mingw32-gcc -Wl,--image-base,0 -Ttext 0x100000 -o kernel.elf -ffreestanding -O2 -nostdlib $OBJ_FILES -lgcc + +echo "Extracting binary..." +# Try to find the correct objcopy +if command -v i686-w64-mingw32-objcopy &> /dev/null; then + i686-w64-mingw32-objcopy -O binary kernel.elf kernel.bin +else + objcopy -O binary kernel.elf kernel.bin +fi + +echo "Creating OS image..." +cat boot.bin kernel.bin > os-image.bin + +echo "Creating Floppy Image..." +# Create 1.44MB floppy image +dd if=/dev/zero of=floppy.img bs=1024 count=1440 2>/dev/null +dd if=os-image.bin of=floppy.img conv=notrunc 2>/dev/null + +echo "Creating ISO..." +mkdir -p iso_root +cp floppy.img iso_root/ + +# Generate ISO with floppy emulation +if command -v mkisofs &> /dev/null; then + mkisofs -quiet -o simpleos.iso -b floppy.img iso_root/ + echo "Build Complete: simpleos.iso" +else + echo "Warning: 'mkisofs' not found. Skipping ISO creation." + echo "You can use 'floppy.img' directly in VirtualBox (Floppy Controller) or QEMU." + echo "Build Complete: floppy.img" +fi \ No newline at end of file diff --git a/cursor.c b/cursor.c new file mode 100644 index 0000000..1ac98a5 --- /dev/null +++ b/cursor.c @@ -0,0 +1,89 @@ +#include "cursor.h" +#include "dirty_rect.h" +#define CURSOR_WIDTH 16 +#define CURSOR_HEIGHT 16 +static const uint8_t cursor_bitmap[CURSOR_HEIGHT][CURSOR_WIDTH / 8] = { + {0b00000000, 0b00000000}, + {0b00000000, 0b10000000}, + {0b00000001, 0b11000000}, + {0b00000011, 0b11100000}, + {0b00000111, 0b11110000}, + {0b00001111, 0b11111000}, + {0b00011111, 0b11111100}, + {0b00111111, 0b11111110}, + {0b01111111, 0b11111111}, + {0b00111111, 0b11111110}, + {0b00011111, 0b11111100}, + {0b00001111, 0b11111000}, + {0b00000111, 0b11110000}, + {0b00000011, 0b11100000}, + {0b00000001, 0b11000000}, + {0b00000000, 0b10000000} +}; +static uint32_t cursor_bg_buffer[CURSOR_HEIGHT*CURSOR_WIDTH]; +static uint32_t cursor_fg_buffer[CURSOR_HEIGHT*CURSOR_WIDTH]; +static int prev_x = -1, prev_y = -1; +static int visible = 0; +void cursor_init(void) { + // Initialization if needed + prev_x = -1; + prev_y = -1; + visible = 0; +} +void cursor_draw(FrameBuffer* fb, int x, int y) { + for (int cy = 0; cy < CURSOR_HEIGHT; cy++) { + for (int cx = 0; cx < CURSOR_WIDTH; cx++) { + int byte_index = cx / 8; + int bit_index = 7 - (cx % 8); + uint8_t mask = 1 << bit_index; + int fb_x = x + cx; + int fb_y = y + cy; + if (fb_x < 0 || fb_x >=(int)fb->width || fb_y < 0 || fb_y >= (int)fb->height) continue; + uint32_t* fb_pixel = (uint32_t*)((uint8_t*)fb->address + (fb_y * fb->pitch) + (fb_x * (fb->bitsPerPixel / 8))); + if (cursor_bitmap[cy][byte_index] & mask) { + cursor_fg_buffer[cy * CURSOR_WIDTH + cx] = *fb_pixel; + *fb_pixel = 0xFFFFFFFF; // White color for cursor + } else { + cursor_bg_buffer[cy * CURSOR_WIDTH + cx] = *fb_pixel; + *fb_pixel = 0x00000000; // Black color for cursor background + } + } + } + visible = 1; + prev_x = x; + prev_y = y; +} +void cursor_hide(void) { + if (!visible) return; + visible = 0; +} +void cursor_update(FrameBuffer* fb, int x, int y) { + if (visible) { + // Invalidate the area where the cursor was + dirty_rect_add(prev_x, prev_y, CURSOR_WIDTH, CURSOR_HEIGHT); + + for (int cy = 0; cy < CURSOR_HEIGHT; cy++) { + for (int cx = 0; cx < CURSOR_WIDTH; cx++) { + int fb_x = prev_x + cx; + int fb_y = prev_y + cy; + if (fb_x < 0 || fb_x >= (int)fb->width || fb_y < 0 || fb_y >= (int)fb->height) continue; + uint32_t* fb_pixel = (uint32_t*)((uint8_t*)fb->address + (fb_y * fb->pitch) + (fb_x * (fb->bitsPerPixel / 8))); + if (cursor_bitmap[cy][cx / 8] & (1 << (7 - (cx % 8)))) { + *fb_pixel = cursor_fg_buffer[cy * CURSOR_WIDTH + cx]; + } else { + *fb_pixel = cursor_bg_buffer[cy * CURSOR_WIDTH + cx]; + } + } + } + } + // Invalidate the area where the cursor will be + dirty_rect_add(x, y, CURSOR_WIDTH, CURSOR_HEIGHT); + + cursor_draw(fb, x, y); +} +#undef CURSOR_WIDTH +#undef CURSOR_HEIGHT +#undef cursor_bitmap +#undef CURSOR_BG_BUFFER +#undef CURSOR_FG_BUFFER +#undef CURSOR_VISIBLE \ No newline at end of file diff --git a/cursor.h b/cursor.h new file mode 100644 index 0000000..a694c71 --- /dev/null +++ b/cursor.h @@ -0,0 +1,8 @@ +#ifndef CURSOR_H +#define CURSOR_H +#include +#include "graphics.h" +void cursor_init(void); +void cursor_update(FrameBuffer*fb,int x,int y); +void cursor_draw(FrameBuffer*fb,int x,int y); +#endif // CURSOR_H \ No newline at end of file diff --git a/cursor.o b/cursor.o new file mode 100644 index 0000000..781f289 Binary files /dev/null and b/cursor.o differ diff --git a/dirty_rect.c b/dirty_rect.c new file mode 100644 index 0000000..219c408 --- /dev/null +++ b/dirty_rect.c @@ -0,0 +1,52 @@ +#include "dirty_rect.h" +#include + +static Rect dirty_rects[MAX_DIRTY_RECTS]; +static int dirty_rect_count = 0; + +static inline int max(int a, int b) { return a > b ? a : b; } +static inline int min(int a, int b) { return a < b ? a : b; } + +void dirty_rect_init() { + dirty_rect_count = 0; +} + +void dirty_rect_add(int x, int y, int width, int height) { + if (width <= 0 || height <= 0) { + return; + } + + Rect new_rect = {x, y, width, height}; +restart_scan: + for (int i = 0; i < dirty_rect_count; ++i) { + Rect* existing = &dirty_rects[i]; + if (!(new_rect.x >= existing->x + existing->width || + new_rect.x + new_rect.width <= existing->x || + new_rect.y >= existing->y + existing->height || + new_rect.y + new_rect.height <= existing->y)) + { + new_rect.x = min(existing->x, new_rect.x); + new_rect.y = min(existing->y, new_rect.y); + int x2 = max(existing->x + existing->width, new_rect.x + new_rect.width); + int y2 = max(existing->y + existing->height, new_rect.y + new_rect.height); + new_rect.width = x2 - new_rect.x; + new_rect.height = y2 - new_rect.y; + dirty_rects[i] = dirty_rects[dirty_rect_count - 1]; + dirty_rect_count--; + goto restart_scan; + } + } + if (dirty_rect_count < MAX_DIRTY_RECTS) { + dirty_rects[dirty_rect_count++] = new_rect; + } else { + for (int i = 1; i < dirty_rect_count; i++) { + dirty_rect_add(dirty_rects[i].x, dirty_rects[i].y, dirty_rects[i].width, dirty_rects[i].height); + } + dirty_rect_count = 1; + } +} + +const Rect* dirty_rect_get_all(int* count) { + *count = dirty_rect_count; + return dirty_rects; +} \ No newline at end of file diff --git a/dirty_rect.h b/dirty_rect.h new file mode 100644 index 0000000..6b1adcf --- /dev/null +++ b/dirty_rect.h @@ -0,0 +1,28 @@ +#ifndef DIRTY_RECT_H +#define DIRTY_RECT_H + +#include "graphics.h" + +#define MAX_DIRTY_RECTS 32 + +typedef struct { + int x, y, width, height; +} Rect; + +/** + * @brief Initializes or clears the dirty rectangle list. + */ +void dirty_rect_init(); + +/** + * @brief Adds a new rectangle to the list of dirty regions. + * This function will attempt to merge the new rectangle with existing ones. + */ +void dirty_rect_add(int x, int y, int width, int height); + +/** + * @brief Provides access to the list of dirty rectangles for the renderer. + */ +const Rect* dirty_rect_get_all(int* count); + +#endif // DIRTY_RECT_H \ No newline at end of file diff --git a/dirty_rect.o b/dirty_rect.o new file mode 100644 index 0000000..a3a4291 Binary files /dev/null and b/dirty_rect.o differ diff --git a/floppy.img b/floppy.img new file mode 100644 index 0000000..e20ac89 Binary files /dev/null and b/floppy.img differ diff --git a/font.c b/font.c new file mode 100644 index 0000000..b091638 --- /dev/null +++ b/font.c @@ -0,0 +1,260 @@ +#include "font.h" + +const uint8_t font[256][16] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x00 Null + {0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x01 SOH + {0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x02 STX + {0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x03 ETX + {0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x04 EOT + {0x38, 0x7C, 0x38, 0xFE, 0xFE, 0x7C, 0x38, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x05 ENQ + {0x10, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x06 ACK + {0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x07 BEL + {0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x08 BS + {0x00, 0x3C, 0x7E, 0x7E, 0x7E, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x09 HT + {0x00, 0x3C, 0x7E, 0x7E, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0A LF + {0x0C, 0x18, 0x30, 0x7E, 0x7E, 0x7E, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0B VT + {0x38, 0x7C, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0C FF + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0D CR + {0x0C, 0x1E, 0x3F, 0x3F, 0x1E, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0E SO + {0x38, 0x7C, 0xFE, 0x38, 0x38, 0xFE, 0x7C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0F SI + {0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x10 DLE + {0x30, 0x78, 0x78, 0x78, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x11 DC1 + {0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x12 DC2 + {0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x13 DC3 + {0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x14 DC4 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x15 NAK + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x16 SYN + {0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x17 ETB + {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x18 CAN + {0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x19 EM + {0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1A SUB + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1B ESC + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1C FS + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1D GS + {0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1E RS + {0x18, 0x18, 0x18, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1F US + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x20 Space + {0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x21 ! + {0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x22 " + {0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x23 # + {0x38, 0x7C, 0xA0, 0x78, 0x2C, 0xF8, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x24 $ + {0xC6, 0xC6, 0x0C, 0x18, 0x30, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x25 % + {0x38, 0x7C, 0x80, 0x80, 0x7C, 0x86, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x26 & + {0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x27 ' + {0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x28 ( + {0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x29 ) + {0x00, 0x6C, 0x38, 0xFE, 0x38, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x2A * + {0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x2B + + {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x2C , + {0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x2D - + {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x2E . + {0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x2F / + {0x7C, 0x82, 0x82, 0x82, 0x82, 0x82, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x30 0 + {0x10, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x31 1 + {0x7C, 0x82, 0x02, 0x7C, 0x80, 0x80, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x32 2 + {0x7C, 0x02, 0x02, 0x3C, 0x02, 0x82, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x33 3 + {0x84, 0x84, 0x84, 0xFE, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x34 4 + {0xFE, 0x80, 0x80, 0xFC, 0x02, 0x82, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x35 5 + {0x7C, 0x80, 0x80, 0xFC, 0x82, 0x82, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x36 6 + {0xFE, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x37 7 + {0x7C, 0x82, 0x82, 0x7C, 0x82, 0x82, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x38 8 + {0x7C, 0x82, 0x82, 0x7E, 0x02, 0x02, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x39 9 + {0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x3A : + {0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x3B ; + {0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x3C < + {0x00, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x3D = + {0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x3E > + {0x7C, 0x82, 0x02, 0x0C, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x3F ? + {0x7C, 0x82, 0xBA, 0xAA, 0xAA, 0xB8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x40 @ + {0x7C, 0x82, 0x82, 0xFE, 0x82, 0x82, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x41 A + {0xFC, 0x82, 0x82, 0xFC, 0x82, 0x82, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x42 B + {0x7C, 0x82, 0x80, 0x80, 0x80, 0x82, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x43 C + {0xF8, 0x84, 0x82, 0x82, 0x82, 0x84, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x44 D + {0xFE, 0x80, 0x80, 0xF8, 0x80, 0x80, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x45 E + {0xFE, 0x80, 0x80, 0xF8, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x46 F + {0x7C, 0x82, 0x80, 0x8E, 0x82, 0x82, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x47 G + {0x82, 0x82, 0x82, 0xFE, 0x82, 0x82, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x48 H + {0x7C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x49 I + {0x0E, 0x02, 0x02, 0x02, 0x82, 0x82, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x4A J + {0x82, 0x84, 0x88, 0xF0, 0x88, 0x84, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x4B K + {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x4C L + {0x82, 0xC6, 0xAA, 0x92, 0x82, 0x82, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x4D M + {0x82, 0xC2, 0xA2, 0x92, 0x8A, 0x86, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x4E N + {0x7C, 0x82, 0x82, 0x82, 0x82, 0x82, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x4F O + {0xFC, 0x82, 0x82, 0xFC, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x50 P + {0x7C, 0x82, 0x82, 0x82, 0x8A, 0x84, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x51 Q + {0xFC, 0x82, 0x82, 0xFC, 0x88, 0x84, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x52 R + {0x7C, 0x80, 0x80, 0x7C, 0x02, 0x02, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x53 S + {0xFE, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x54 T + {0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x55 U + {0x82, 0x82, 0x82, 0x44, 0x44, 0x28, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x56 V + {0x82, 0x82, 0x82, 0x92, 0x92, 0xAA, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x57 W + {0x82, 0x82, 0x44, 0x38, 0x44, 0x82, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x58 X + {0x82, 0x82, 0x44, 0x28, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x59 Y + {0xFE, 0x04, 0x08, 0x10, 0x20, 0x40, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x5A Z + {0x7C, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x5B [ + {0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x5C '\' + {0x7C, 0x06, 0x06, 0x06, 0x06, 0x06, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x5D ] + {0x10, 0x28, 0x44, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x5E ^ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x5F _ + {0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x60 ` + {0x00, 0x00, 0x78, 0x84, 0x84, 0x78, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x61 a + {0x80, 0x80, 0xF8, 0x84, 0x84, 0x84, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x62 b + {0x00, 0x00, 0x78, 0x80, 0x80, 0x80, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x63 c + {0x04, 0x04, 0x7C, 0x84, 0x84, 0x84, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x64 d + {0x00, 0x00, 0x78, 0x84, 0xF4, 0x80, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x65 e + {0x0C, 0x10, 0x10, 0xF8, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x66 f + {0x00, 0x00, 0x7C, 0x84, 0x84, 0x7C, 0x04, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x67 g + {0x80, 0x80, 0xF8, 0x84, 0x84, 0x84, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x68 h + {0x30, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x69 i + {0x0C, 0x00, 0x0C, 0x0C, 0x0C, 0x0C, 0x8C, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x6A j + {0x80, 0x80, 0x88, 0x90, 0xA0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x6B k + {0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x6C l + {0x00, 0x00, 0xCC, 0xAA, 0xAA, 0xAA, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x6D m + {0x00, 0x00, 0xF8, 0x84, 0x84, 0x84, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x6E n + {0x00, 0x00, 0x78, 0x84, 0x84, 0x84, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x6F o + {0x00, 0x00, 0xF8, 0x84, 0x84, 0xF8, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x70 p + {0x00, 0x00, 0x7C, 0x84, 0x84, 0x7C, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x71 q + {0x00, 0x00, 0xAC, 0x94, 0x90, 0x90, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x72 r + {0x00, 0x00, 0x70, 0x88, 0x70, 0x10, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x73 s + {0x10, 0x10, 0xF8, 0x10, 0x10, 0x10, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x74 t + {0x00, 0x00, 0x84, 0x84, 0x84, 0x84, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x75 u + {0x00, 0x00, 0x84, 0x84, 0x48, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x76 v + {0x00, 0x00, 0x84, 0x84, 0x94, 0x94, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x77 w + {0x00, 0x00, 0x84, 0x50, 0x28, 0x50, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x78 x + {0x00, 0x00, 0x84, 0x84, 0x84, 0x7C, 0x04, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x79 y + {0x00, 0x00, 0xF8, 0x10, 0x20, 0x40, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x7A z + {0x1C, 0x30, 0x30, 0x60, 0x30, 0x30, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x7B { + {0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x7C | + {0xE0, 0x30, 0x30, 0x18, 0x30, 0x30, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x7D } + {0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x7E ~ + {0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x7F DEL + {0x7C, 0x82, 0x82, 0x82, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x80 Ç + {0x84, 0x84, 0x84, 0x84, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x81 ü + {0x78, 0x84, 0xF4, 0x80, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x82 é + {0x78, 0x84, 0x84, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x83 â + {0x78, 0x84, 0x84, 0x78, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x84 ä + {0x78, 0x84, 0x84, 0x78, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x85 à + {0x78, 0x84, 0x84, 0x78, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x86 å + {0x78, 0x80, 0x80, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x87 ç + {0x78, 0x84, 0xF4, 0x80, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x88 ê + {0x78, 0x84, 0xF4, 0x80, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x89 ë + {0x78, 0x84, 0xF4, 0x80, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8A è + {0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8B ï + {0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8C î + {0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8D ì + {0x78, 0x84, 0x84, 0x78, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8E Ä + {0x78, 0x84, 0x84, 0x78, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8F Å + {0x78, 0x84, 0xF4, 0x80, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x90 É + {0x78, 0x84, 0x84, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x91 æ + {0x78, 0x84, 0x84, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x92 Æ + {0x78, 0x84, 0x84, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x93 ô + {0x78, 0x84, 0x84, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x94 ö + {0x78, 0x84, 0x84, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x95 ò + {0x84, 0x84, 0x84, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x96 û + {0x84, 0x84, 0x84, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x97 ù + {0x84, 0x84, 0x84, 0x7C, 0x04, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x98 ÿ + {0x78, 0x84, 0x84, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x99 Ö + {0x84, 0x84, 0x84, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9A Ü + {0x7C, 0x80, 0xFC, 0x82, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9B ø + {0xFC, 0x80, 0x80, 0xF8, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9C £ + {0x7C, 0x80, 0xFC, 0x82, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9D Ø + {0x82, 0x44, 0x38, 0x44, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9E × + {0x80, 0x80, 0xF8, 0x84, 0x84, 0x84, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9F ƒ + {0x78, 0x84, 0x84, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA0 á + {0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA1 í + {0x78, 0x84, 0x84, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA2 ó + {0x84, 0x84, 0x84, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA3 ú + {0x82, 0xC2, 0xA2, 0x92, 0x8A, 0x86, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA4 ñ + {0x82, 0xC2, 0xA2, 0x92, 0x8A, 0x86, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA5 Ñ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA6 ª + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA7 º + {0x7C, 0x82, 0x02, 0x0C, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA8 ¿ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA9 ® + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xAA ¬ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xAB ½ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xAC ¼ + {0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xAD ¡ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xAE « + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xAF » + {0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB0 ░ + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB1 ▒ + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB2 ▓ + {0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB3 │ + {0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB4 ┤ + {0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB5 ╡ + {0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB6 ╢ + {0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB7 ╖ + {0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB8 ╕ + {0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB9 ╣ + {0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBA ║ + {0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBB ╗ + {0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBC ╝ + {0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBD ╜ + {0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBE ╛ + {0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBF ┐ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xC0 └ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xC1 ┴ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xC2 ┬ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xC3 ├ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xC4 ─ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xC5 ┼ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xC6 ╞ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xC7 ╟ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xC8 ╚ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xC9 ╔ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xCA ╩ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xCB ╦ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xCC ╠ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xCD ═ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xCE ╬ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xCF ╧ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xD0 ╨ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xD1 ╤ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xD2 ╥ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xD3 ╙ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xD4 ╘ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xD5 ╒ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xD6 ╓ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xD7 ╫ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xD8 ╪ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xD9 ┘ + {0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xDA ┌ + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xDB █ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xDC ▄ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xDD ▌ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xDE ▐ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xDF ▀ + {0x7C, 0x82, 0x82, 0xFE, 0x82, 0x82, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xE0 α + {0xFC, 0x82, 0x82, 0xFC, 0x82, 0x82, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xE1 ß + {0x7C, 0x82, 0x80, 0x8E, 0x82, 0x82, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xE2 Γ + {0x82, 0x82, 0x82, 0xFE, 0x82, 0x82, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xE3 π + {0xFE, 0x80, 0x80, 0xF8, 0x80, 0x80, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xE4 Σ + {0xFE, 0x80, 0x80, 0xF8, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xE5 σ + {0x7C, 0x82, 0x82, 0x7C, 0x82, 0x82, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xE6 µ + {0x82, 0x82, 0x44, 0x28, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xE7 τ + {0x7C, 0x82, 0x82, 0x82, 0x82, 0x82, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xE8 Φ + {0xFE, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xE9 Θ + {0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xEA Ω + {0x82, 0x82, 0x82, 0x44, 0x44, 0x28, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xEB δ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xEC ∞ + {0x82, 0x82, 0x44, 0x38, 0x44, 0x82, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xED φ + {0x78, 0x84, 0xF4, 0x80, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xEE ε + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xEF ∩ + {0x00, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xF0 ≡ + {0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xF1 ± + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xF2 ≥ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xF3 ≤ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xF4 ⌠ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xF5 ⌡ + {0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xF6 ÷ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xF7 ≈ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xF8 ° + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xF9 ∙ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xFA · + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xFB √ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xFC ⁿ + {0x7C, 0x82, 0x02, 0x7C, 0x80, 0x80, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xFD ² + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xFE ■ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xFF (NBSP) +}; \ No newline at end of file diff --git a/font.h b/font.h new file mode 100644 index 0000000..f2dfd2d --- /dev/null +++ b/font.h @@ -0,0 +1,6 @@ +#ifndef FONT_H +#define FONT_H +#include +#include "graphics.h" +extern const uint8_t font[256][16]; +#endif \ No newline at end of file diff --git a/font.o b/font.o new file mode 100644 index 0000000..b96c625 Binary files /dev/null and b/font.o differ diff --git a/gdt.c b/gdt.c index 4cebf5b..2952465 100644 --- a/gdt.c +++ b/gdt.c @@ -1,4 +1,5 @@ #include "gdt.h" +#include #define GDT_ENTRIES 5 @@ -20,8 +21,8 @@ void gdt_install(void) { gdt_set_gate(0, 0, 0, 0, 0); // Null segment gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // Kernel code segment (Ring 0) gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // Kernel data segment (Ring 0) - gdt_set_gate(3, 0, 0x7FFFFFFF, 0xFA, 0xCF); // User code segment (Ring 3, limited) - gdt_set_gate(4, 0, 0x7FFFFFFF, 0xF2, 0xCF); // User data segment (Ring 3, limited) + gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // User code segment (Ring 3, limited) + gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // User data segment (Ring 3, limited) gdt_flush(); } @@ -29,7 +30,7 @@ void gdt_install(void) { extern void gdt_flush_asm(void); void gdt_flush(void) { - asm volatile ( + __asm__ __volatile__ ( "lgdt %0\n\t" "mov $0x10, %%ax\n\t" "mov %%ax, %%ds\n\t" @@ -37,8 +38,8 @@ void gdt_flush(void) { "mov %%ax, %%fs\n\t" "mov %%ax, %%gs\n\t" "mov %%ax, %%ss\n\t" - "ljmp $0x08, $flush_cs\n\t" - "flush_cs:\n\t" + "ljmp $0x08, $1f\n\t" + "1:\n\t" : : "m"(gp) : "eax" diff --git a/gdt.h b/gdt.h index af184d8..1a217de 100644 --- a/gdt.h +++ b/gdt.h @@ -10,12 +10,12 @@ struct gdt_entry { uint8_t access; uint8_t granularity; uint8_t base_high; -} __attribute__((packed)); +} __attribute__((packed)); // <--- THIS IS MANDATORY struct gdt_ptr { uint16_t limit; uint32_t base; -} __attribute__((packed)); +} __attribute__((packed)); // <--- THIS IS MANDATORY void gdt_set_gate(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran); void gdt_install(void); diff --git a/gdt.o b/gdt.o new file mode 100644 index 0000000..caff50e Binary files /dev/null and b/gdt.o differ diff --git a/graphics.c b/graphics.c new file mode 100644 index 0000000..e249d13 --- /dev/null +++ b/graphics.c @@ -0,0 +1,126 @@ +#include "graphics.h" +void put_pixel(FrameBuffer* fb, int32_t x, int32_t y, uint32_t color) { + if (x < 0 || x >= (int32_t)fb->width || y < 0 || y >= (int32_t)fb->height) return; + + uint8_t* pixel = (uint8_t*)fb->address + y * fb->pitch + x * fb->bytesPerPixel; + + if (fb->bitsPerPixel == 24) { + pixel[0] = color & 0xFF; + pixel[1] = (color >> 8) & 0xFF; + pixel[2] = (color >> 16) & 0xFF; + } else if (fb->bitsPerPixel == 32) { + *(uint32_t*)pixel = color; + } +} + +void clear_screen(FrameBuffer* fb, uint32_t color) { + // Optimization: We could use memset/memcpy here for speed + for (uint32_t y = 0; y < fb->height; y++) { + for (uint32_t x = 0; x < fb->width; x++) { + put_pixel(fb, x, y, color); + } + } +} + +void draw_circle(FrameBuffer* fb, int32_t xc, int32_t yc, int32_t r, uint32_t color) { + int32_t x = r; + int32_t y = 0; + int32_t err = 3 - (2 * r); + + while (x >= y) { + put_pixel(fb, xc + x, yc + y, color); + put_pixel(fb, xc + y, yc + x, color); + put_pixel(fb, xc - y, yc + x, color); + put_pixel(fb, xc - x, yc + y, color); + put_pixel(fb, xc - x, yc - y, color); + put_pixel(fb, xc - y, yc - x, color); + put_pixel(fb, xc + y, yc - x, color); + put_pixel(fb, xc + x, yc - y, color); + + if (err > 0) { + err += 4 * (y - x) + 10; + x--; + } else { + err += 4 * y + 6; + } + y++; + } +} + +void draw_line(FrameBuffer* fb, int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color) { + int32_t dx = (x1 > x0) ? (x1 - x0) : (x0 - x1); + int32_t dy = (y1 > y0) ? (y1 - y0) : (y0 - y1); + int32_t sx = (x0 < x1) ? 1 : -1; + int32_t sy = (y0 < y1) ? 1 : -1; + int32_t err = dx - dy; + while (1) { + put_pixel(fb, x0, y0, color); + if (x0 == x1 && y0 == y1) break; + int32_t e2 = 2 * err; + if (e2 > -dy) { + err -= dy; + x0 += sx; + } + if (e2 < dx) { + err += dx; + y0 += sy; + } + } +} + +void draw_rectangle(FrameBuffer* fb, int32_t x, int32_t y, int32_t width, int32_t height, uint32_t color) { + if (width <= 0 || height <= 0) return; + int32_t x1 = x + width - 1; + int32_t y1 = y + height - 1; + draw_line(fb, x, y, x1, y, color); + draw_line(fb, x, y1, x1, y1, color); + draw_line(fb, x, y, x, y1, color); + draw_line(fb, x1, y, x1, y1, color); +} + +void fill_rectangle(FrameBuffer* fb, int32_t x, int32_t y, int32_t width, int32_t height, uint32_t color) { + for (int32_t j = y; j < y + height; j++) { + for (int32_t i = x; i < x + width; i++) { + put_pixel(fb, i, j, color); + } + } +} + +void draw_bitmap(FrameBuffer* fb, Bitmap* bmp, int32_t x, int32_t y, uint32_t color) { + if (!bmp || !bmp->data) return; + for (uint32_t j = 0; j < bmp->height; j++) { + for (uint32_t i = 0; i < bmp->width; i++) { + // [FIX] bmp->data is now a pointer, so we access it as an array + uint8_t pixel = bmp->data[j * bmp->width + i]; + if (pixel) { + put_pixel(fb, x + i, y + j, color); + } + } + } +} + +// [FIX] Completely rewritten to match the font.c raw array format +void draw_char(FrameBuffer* fb, Font* font, char c, int32_t x, int32_t y, uint32_t color) { + if (!font || !font->bitmap) return; + + // Get the pointer to the 16 bytes for this character + const uint8_t* glyph = font->bitmap[(unsigned char)c]; + + for (uint32_t cy = 0; cy < font->char_height; cy++) { + uint8_t row = glyph[cy]; + for (uint32_t cx = 0; cx < font->char_width; cx++) { + // Check the bit at this position (Bit 7 is leftmost) + if ((row >> (7 - cx)) & 1) { + put_pixel(fb, x + cx, y + cy, color); + } + } + } +} + +void draw_string(FrameBuffer* fb, Font* font, const char* str, int32_t x, int32_t y, uint32_t color) { + while (*str) { + draw_char(fb, font, *str, x, y, color); + x += font->char_width; + str++; + } +} \ No newline at end of file diff --git a/graphics.h b/graphics.h new file mode 100644 index 0000000..a006221 --- /dev/null +++ b/graphics.h @@ -0,0 +1,55 @@ +#ifndef GRAPHICS_H +#define GRAPHICS_H +#include +typedef struct { + uint16_t attributes; + uint8_t windowA, windowB; + uint16_t granularity; + uint16_t windowSize; + uint16_t windowASegment, windowBSegment; + uint32_t winFuncPtr; + uint16_t pitch; + uint16_t resolution_x, resolution_y; + uint8_t wChar, yChar, planes, bitsPerPixel, banks; + uint8_t memoryModel, bankSize, imagePages; + uint8_t reserved1; + uint8_t redMask, redMaskPosition; + uint8_t greenMask, greenMaskPosition; + uint8_t blueMask, blueMaskPosition; + uint8_t rsvdMask, rsvdMaskPosition; + uint8_t directColorAttributes; + uint32_t physbase; + uint32_t reserved2; + uint16_t reserved3; +} VbeModeInfo; + +extern VbeModeInfo vbe_mode_info; +typedef struct{ + void* address; + uint32_t width; + uint32_t height; + uint32_t pitch; + uint8_t bitsPerPixel; + uint8_t bytesPerPixel; +} FrameBuffer; +typedef struct { + uint32_t width; + uint32_t height; + uint8_t* data; +} Bitmap; +typedef struct { + uint32_t char_width; + uint32_t char_height; + const uint8_t (*bitmap)[16]; +} Font; +void clear_screen(FrameBuffer* fb, uint32_t color); +void put_pixel(FrameBuffer* fb, int32_t x, int32_t y, uint32_t color); +void draw_line(FrameBuffer* fb, int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color); +void draw_rectangle(FrameBuffer* fb, int32_t x, int32_t y, int32_t width, int32_t height, uint32_t color); +void fill_rectangle(FrameBuffer* fb, int32_t x, int32_t y, int32_t width, int32_t height, uint32_t color); +void draw_circle(FrameBuffer* fb, int32_t x, int32_t y, int32_t radius, uint32_t color); +void draw_bitmap(FrameBuffer* fb, Bitmap* bmp, int32_t x, int32_t y, uint32_t color); +void draw_char(FrameBuffer* fb, Font* font, char c, int32_t x, int32_t y, uint32_t color); +void draw_string(FrameBuffer* fb, Font* font, const char* str, int32_t x, int32_t y, uint32_t color); + +#endif \ No newline at end of file diff --git a/graphics.o b/graphics.o new file mode 100644 index 0000000..0215d05 Binary files /dev/null and b/graphics.o differ diff --git a/heap.c b/heap.c new file mode 100644 index 0000000..ff5c5c5 --- /dev/null +++ b/heap.c @@ -0,0 +1,119 @@ +#include +#include +#define HEAP_ALIGNMENT 4 +#define HEAP_MAGIC 0x12345678 + +typedef struct heap_segment_header{ + uint32_t magic; // Should always be HEAP_MAGIC + size_t size; + bool free; + struct heap_segment_header* next; + struct heap_segment_header* prev; +}heap_header_t; + +static void* heap_start_address = NULL; +static size_t heap_size = 0; +static heap_header_t* first_segment = NULL; +static spinlock_t heap_lock; + +static inline size_t align(size_t size) { + return (size + HEAP_ALIGNMENT - 1) & ~(HEAP_ALIGNMENT - 1); +} + +void heap_init(uint32_t start_address, uint32_t size){ + if (size < sizeof(heap_header_t) + HEAP_ALIGNMENT) { + // Not enough space for even one small allocation. + return; + } + heap_start_address = (void*)start_address; + heap_size = size; + first_segment = (heap_header_t*)heap_start_address; + spinlock_init(&heap_lock); + first_segment->magic = HEAP_MAGIC; + first_segment->size = size - sizeof(heap_header_t); + first_segment->free = true; + first_segment->next = NULL; + first_segment->prev = NULL; +} + +void* heap_alloc(size_t size){ + spinlock_acquire(&heap_lock); + + if (size == 0) { + spinlock_release(&heap_lock); + return NULL; + } + size_t aligned_size = align(size); + heap_header_t* current = first_segment; + while (current != NULL) { + if (current->free && current->size >= aligned_size) { + // Check if the remaining space is large enough for a new header and a minimal allocation. + if (current->size >= aligned_size + sizeof(heap_header_t) + HEAP_ALIGNMENT) { // Smallest alloc is HEAP_ALIGNMENT + heap_header_t* new_segment = (heap_header_t*)((uint8_t*)current + sizeof(heap_header_t) + aligned_size); + new_segment->magic = HEAP_MAGIC; + new_segment->size = current->size - aligned_size - sizeof(heap_header_t); + new_segment->free = true; + new_segment->next = current->next; + new_segment->prev = current; + + if (current->next != NULL) { + current->next->prev = new_segment; + } + current->next = new_segment; + current->size = aligned_size; + } + current->free = false; + spinlock_release(&heap_lock); + return (void*)((uint8_t*)current + sizeof(heap_header_t)); + } + current = current->next; + } + // Out of memory + spinlock_release(&heap_lock); + return NULL; +} + +void heap_free(void* ptr){ + spinlock_acquire(&heap_lock); + + if (ptr == NULL) { + spinlock_release(&heap_lock); + return; + } + heap_header_t* header = (heap_header_t*)((uint8_t*)ptr - sizeof(heap_header_t)); + if (header->magic != HEAP_MAGIC) { + // PANIC("Heap corruption detected!"); + spinlock_release(&heap_lock); + return; // Or better, panic. + } + + header->free = true; + heap_header_t* next = header->next; + if (next != NULL && next->free) { + header->size += sizeof(heap_header_t) + next->size; + header->next = next->next; + if (next->next != NULL) { + next->next->prev = header; + } + } + + // Coalesce with previous block if it's free + heap_header_t* prev = header->prev; + if (prev != NULL && prev->free) { + prev->size += sizeof(heap_header_t) + header->size; + prev->next = header->next; + if (prev->next != NULL) { // This was header->next before, which is wrong + prev->next->prev = prev; + } + } + + spinlock_release(&heap_lock); +} + +void* kmalloc(size_t size) { + return heap_alloc(size); +} + +void kfree(void* ptr) { + heap_free(ptr); +} diff --git a/heap.h b/heap.h new file mode 100644 index 0000000..9349645 --- /dev/null +++ b/heap.h @@ -0,0 +1,11 @@ +#ifndef HEAP_H +#define HEAP_H +#include +#include +#include +void heap_init(uint32_t start_address, uint32_t size); +void* kmalloc(size_t size); +void kfree(void* ptr); +#define malloc(size) kmalloc(size) +#define free(ptr) kfree(ptr) +#endif // HEAP_H \ No newline at end of file diff --git a/heap.o b/heap.o new file mode 100644 index 0000000..3d6f21d Binary files /dev/null and b/heap.o differ diff --git a/idt.c b/idt.c index 98a1aa8..69fd519 100644 --- a/idt.c +++ b/idt.c @@ -1,52 +1,84 @@ #include "idt.h" #include "vga.h" - +#include "syscall.h" +#include static struct idt_entry idt[256]; static struct idt_ptr ip; - +static isr_t interrupt_handlers[256]; static inline void outb(uint16_t port, uint8_t val) { - asm volatile("outb %0, %1" : : "a"(val), "Nd"(port)); + __asm__ __volatile__("outb %0, %1" : : "a"(val), "Nd"(port)); } -static inline uint8_t inb(uint16_t port) { +static __inline__ uint8_t inb(uint16_t port) { uint8_t ret; - asm volatile("inb %1, %0" : "=a"(ret) : "Nd"(port)); + __asm__ __volatile__("inb %1, %0" : "=a"(ret) : "Nd"(port)); return ret; } + static const char *exception_messages[] = { - "Division By Zero", - "Debug", - "Non Maskable Interrupt", - "Breakpoint", - "Into Detected Overflow", - "Out of Bounds", - "Invalid Opcode", - "No Coprocessor", - "Double Fault", - "Coprocessor Segment Overrun", - "Bad TSS", - "Segment Not Present", - "Stack Fault", - "General Protection Fault", - "Page Fault", - "Unknown Interrupt", - "Coprocessor Fault", - "Alignment Check", - "Machine Check", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved" + "Division By Zero", "Debug", "Non Maskable Interrupt", "Breakpoint", + "Into Detected Overflow", "Out of Bounds", "Invalid Opcode", "No Coprocessor", + "Double Fault", "Coprocessor Segment Overrun", "Bad TSS", "Segment Not Present", + "Stack Fault", "General Protection Fault", "Page Fault", "Unknown Interrupt", + "Coprocessor Fault", "Alignment Check", "Machine Check", "Reserved", + "Reserved", "Reserved", "Reserved", "Reserved", + "Reserved", "Reserved", "Reserved", "Reserved", + "Reserved", "Reserved", "Reserved", "Reserved" }; + +// External Assembly ISR handlers +extern void isr0(void); +extern void isr1(void); +extern void isr2(void); +extern void isr3(void); +extern void isr4(void); +extern void isr5(void); +extern void isr6(void); +extern void isr7(void); +extern void isr8(void); +extern void isr9(void); +extern void isr10(void); +extern void isr11(void); +extern void isr12(void); +extern void isr13(void); +extern void isr14(void); +extern void isr15(void); +extern void isr16(void); +extern void isr17(void); +extern void isr18(void); +extern void isr19(void); +extern void isr20(void); +extern void isr21(void); +extern void isr22(void); +extern void isr23(void); +extern void isr24(void); +extern void isr25(void); +extern void isr26(void); +extern void isr27(void); +extern void isr28(void); +extern void isr29(void); +extern void isr30(void); +extern void isr31(void); +extern void isr128(void); + +// External Assembly IRQ handlers +extern void irq0(void); +extern void irq1(void); +extern void irq2(void); +extern void irq3(void); +extern void irq4(void); +extern void irq5(void); +extern void irq6(void); +extern void irq7(void); +extern void irq8(void); +extern void irq9(void); +extern void irq10(void); +extern void irq11(void); +extern void irq12(void); +extern void irq13(void); +extern void irq14(void); +extern void irq15(void); + void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags) { idt[num].base_lo = base & 0xFFFF; idt[num].base_hi = (base >> 16) & 0xFFFF; @@ -54,32 +86,39 @@ void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags) { idt[num].always0 = 0; idt[num].flags = flags; } + void isr_handler(registers_t *r) { + if (r == NULL) return; + + // [FIX] Handle System Call (Interrupt 128 / 0x80) + if (r->int_no == 128) { + syscall_handler(r); + return; + } + vga_print_string("Received interrupt: "); + vga_print_dec(r->int_no); + vga_print_string("\n"); + if (r->int_no < 32) { if (r->int_no < sizeof(exception_messages) / sizeof(exception_messages[0])) { vga_print_string(exception_messages[r->int_no]); } else { vga_print_string("Unknown Exception"); } - vga_print_string("\nEIP: "); - vga_print_hex(r->eip); - vga_print_string(" CS: "); - vga_print_hex(r->cs); - vga_print_string(" EFLAGS: "); - vga_print_hex(r->eflags); - vga_print_string("\nSystem halted!\n"); - asm volatile("cli"); - for(;;) { - asm volatile("hlt"); - } + + // Loop forever on exception + __asm__ __volatile__("cli"); + for(;;) { __asm__ __volatile__("hlt"); } } } static void (*irq_routines[16])(registers_t *r); - +void register_interrupt_handler(uint8_t n, isr_t handler) { + interrupt_handlers[n] = handler; +} void irq_install_handler(int irq, void (*handler)(registers_t *r)) { - if (irq >= 0 && irq < 16 && handler != NULL) { + if (irq >= 0 && irq < 16) { irq_routines[irq] = handler; } } @@ -91,31 +130,36 @@ void irq_uninstall_handler(int irq) { } void irq_handler(registers_t *r) { - if (r->int_no < 32 || r->int_no > 47) { + if (interrupt_handlers[r->int_no]) { + isr_t handler =interrupt_handlers[r->int_no]; + handler(r); return; } - - int irq = r->int_no - 32; - if (irq >= 0 && irq < 16) { - void (*handler)(registers_t *r) = irq_routines[irq]; - if (handler) { - handler(r); - } + if (r->int_no==128){ + syscall_handler(r); + return; } - - if (r->int_no >= 40) { - outb(0xA0, 0x20); + + if (r->int_no < 32 || r->int_no > 47) return; + + void (*handler)(registers_t *r) = irq_routines[r->int_no - 32]; + if (handler) { + handler(r); } + + // EOI + if (r->int_no >= 40) outb(0xA0, 0x20); outb(0x20, 0x20); } void idt_install(void) { ip.limit = sizeof(struct idt_entry) * 256 - 1; ip.base = (uint32_t)&idt; + memset(&idt, 0, sizeof(struct idt_entry) * 256); + memset(interrupt_handlers, 0, sizeof(isr_t) * 256); + memset(irq_routines, 0, sizeof(void *) * 16); - for (int i = 0; i < 256; i++) { - idt_set_gate(i, 0, 0, 0); - } + for(int i=0; i<256; i++) idt_set_gate(i, 0, 0, 0); idt_set_gate(0, (uint32_t)isr0, 0x08, 0x8E); idt_set_gate(1, (uint32_t)isr1, 0x08, 0x8E); @@ -145,21 +189,19 @@ void idt_install(void) { idt_set_gate(25, (uint32_t)isr25, 0x08, 0x8E); idt_set_gate(26, (uint32_t)isr26, 0x08, 0x8E); idt_set_gate(27, (uint32_t)isr27, 0x08, 0x8E); - idt_set_gate(28, (uint32_t)isr28, 0x08, 0x8E); + idt_set_gate(28, (uint32_t)isr28, 0x08, 0x8E); // Now defined in header idt_set_gate(29, (uint32_t)isr29, 0x08, 0x8E); idt_set_gate(30, (uint32_t)isr30, 0x08, 0x8E); idt_set_gate(31, (uint32_t)isr31, 0x08, 0x8E); - outb(0x20, 0x11); - outb(0xA0, 0x11); - outb(0x21, 0x20); - outb(0xA1, 0x28); - outb(0x21, 0x04); - outb(0xA1, 0x02); - outb(0x21, 0x01); - outb(0xA1, 0x01); - outb(0x21, 0x0); - outb(0xA1, 0x0); + // Remap PIC + outb(0x20, 0x11); outb(0xA0, 0x11); + outb(0x21, 0x20); outb(0xA1, 0x28); + outb(0x21, 0x04); outb(0xA1, 0x02); + outb(0x21, 0x01); outb(0xA1, 0x01); + //outb(0x21, 0x0); outb(0xA1, 0x0); + outb(0x21,0xFF); outb(0xA1,0xFF); // Mask all IRQs initially + idt_set_gate(32, (uint32_t)irq0, 0x08, 0x8E); idt_set_gate(33, (uint32_t)irq1, 0x08, 0x8E); @@ -177,16 +219,9 @@ void idt_install(void) { idt_set_gate(45, (uint32_t)irq13, 0x08, 0x8E); idt_set_gate(46, (uint32_t)irq14, 0x08, 0x8E); idt_set_gate(47, (uint32_t)irq15, 0x08, 0x8E); + + // Syscall + idt_set_gate(128, (uint32_t)isr128, 0x08, 0xEE); // Ring 3 accessible - asm volatile("lidt %0" : : "m"(ip)); - asm volatile("sti"); -} -uint32_t inl(uint16_t port) { - uint32_t ret; - asm volatile("inl %1, %0" : "=a"(ret) : "Nd"(port)); - return ret; -} - -void outl(uint16_t port, uint32_t val) { - asm volatile("outl %0, %1" : : "a"(val), "Nd"(port)); + __asm__ __volatile__("lidt %0" : : "m"(ip)); } \ No newline at end of file diff --git a/idt.h b/idt.h index b104e19..1ce5f3b 100644 --- a/idt.h +++ b/idt.h @@ -22,13 +22,15 @@ typedef struct registers { uint32_t int_no, err_code; uint32_t eip, cs, eflags, useresp, ss; } registers_t; - +typedef void (*isr_t)(registers_t *); void idt_install(void); void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags); void irq_handler(registers_t *r); void isr_handler(registers_t *r); void irq_install_handler(int irq, void (*handler)(registers_t *r)); - +void page_fault_handler(registers_t *r); +void register_interrupt_handler(uint8_t n, isr_t handler); +extern void isr14(void); extern void irq0(void); extern void irq1(void); extern void irq2(void); @@ -78,6 +80,5 @@ extern void isr28(void); extern void isr29(void); extern void isr30(void); extern void isr31(void); -uint32_t inl(uint16_t port); -void outl(uint16_t port, uint32_t val); +extern void isr128(void); #endif \ No newline at end of file diff --git a/idt.o b/idt.o new file mode 100644 index 0000000..255ed2d Binary files /dev/null and b/idt.o differ diff --git a/interrupt.asm b/interrupt.asm index 83d50bf..6a2e8e5 100644 --- a/interrupt.asm +++ b/interrupt.asm @@ -1,74 +1,77 @@ section .text -global isr0 -global isr1 -global isr2 -global isr3 -global isr4 -global isr5 -global isr6 -global isr7 -global isr8 -global isr9 -global isr10 -global isr11 -global isr12 -global isr13 -global isr14 -global isr15 -global isr16 -global isr17 -global isr18 -global isr19 -global isr20 -global isr21 -global isr22 -global isr23 -global isr24 -global isr25 -global isr26 -global isr27 -global isr28 -global isr29 -global isr30 -global isr31 - -global irq0 -global irq1 -global irq2 -global irq3 -global irq4 -global irq5 -global irq6 -global irq7 -global irq8 -global irq9 -global irq10 -global irq11 -global irq12 -global irq13 -global irq14 -global irq15 - -extern isr_handler -extern irq_handler +global _isr0 +global _isr1 +global _isr2 +global _isr3 +global _isr4 +global _isr5 +global _isr6 +global _isr7 +global _isr8 +global _isr9 +global _isr10 +global _isr11 +global _isr12 +global _isr13 +global _isr14 +global _isr15 +global _isr16 +global _isr17 +global _isr18 +global _isr19 +global _isr20 +global _isr21 +global _isr22 +global _isr23 +global _isr24 +global _isr25 +global _isr26 +global _isr27 +global _isr28 +global _isr29 +global _isr30 +global _isr31 + +global _irq0 +global _irq1 +global _irq2 +global _irq3 +global _irq4 +global _irq5 +global _irq6 +global _irq7 +global _irq8 +global _irq9 +global _irq10 +global _irq11 +global _irq12 +global _irq13 +global _irq14 +global _irq15 +global _isr128 +extern _isr_handler +extern _irq_handler %macro isr_no_error 1 -isr%1: +global _isr%1 +_isr%1: cli push byte 0 - push byte %1 + push dword %1 jmp isr_common_stub %endmacro %macro isr_error 1 -isr%1: +global _isr%1 +_isr%1: cli - push byte %1 + push dword %1 jmp isr_common_stub %endmacro %macro irq_stub 2 -irq%1: +global _irq%1 +_irq%1: cli push byte 0 push byte %2 @@ -107,7 +110,7 @@ isr_no_error 28 isr_no_error 29 isr_no_error 30 isr_no_error 31 - +isr_no_error 128 irq_stub 0, 32 irq_stub 1, 33 irq_stub 2, 34 @@ -136,7 +139,7 @@ isr_common_stub: mov fs, ax mov gs, ax - call isr_handler + call _isr_handler pop eax mov ds, ax @@ -160,7 +163,7 @@ irq_common_stub: mov fs, ax mov gs, ax - call irq_handler + call _irq_handler pop eax mov ds, ax @@ -170,5 +173,4 @@ irq_common_stub: popa add esp, 8 - sti iret \ No newline at end of file diff --git a/interrupt.o b/interrupt.o new file mode 100644 index 0000000..6203da4 Binary files /dev/null and b/interrupt.o differ diff --git a/io.h b/io.h new file mode 100644 index 0000000..71d7ae4 --- /dev/null +++ b/io.h @@ -0,0 +1,29 @@ +#ifndef IO_H +#define IO_H + +#include +static inline void outb(uint16_t port, uint8_t val) { + asm volatile("outb %0, %1" : : "a"(val), "Nd"(port)); +} +static inline uint8_t inb(uint16_t port) { + uint8_t ret; + asm volatile("inb %1, %0" : "=a"(ret) : "Nd"(port)); + return ret; +} +static inline void outw(uint16_t port, uint16_t val) { + asm volatile("outw %0, %1" : : "a"(val), "Nd"(port)); +} +static inline uint16_t inw(uint16_t port) { + uint16_t ret; + asm volatile("inw %1, %0" : "=a"(ret) : "Nd"(port)); + return ret; +} +static inline void outl(uint16_t port, uint32_t val) { + asm volatile("outl %0, %1" : : "a"(val), "Nd"(port)); +} +static inline uint32_t inl(uint16_t port) { + uint32_t ret; + asm volatile("inl %1, %0" : "=a"(ret) : "Nd"(port)); + return ret; +} +#endif \ No newline at end of file diff --git a/kernel.bin b/kernel.bin new file mode 100644 index 0000000..11da8ed Binary files /dev/null and b/kernel.bin differ diff --git a/kernel.c b/kernel.c index 6c2ea9f..2bb52f5 100644 --- a/kernel.c +++ b/kernel.c @@ -1,57 +1,183 @@ +#include +#include +#include "graphics.h" #include "vga.h" #include "idt.h" #include "gdt.h" #include "keyboard.h" #include "shell.h" #include "timer.h" +#include "paging.h" //#include "pci.h" -#include "NIC.h" +#include "widget.h" +#include "font.h" +#include +#include "nic.h" #include "pmm.h" +#include "task.h" +#include "syscall.h" +#include "window.h" +#include "mouse.h" +#include "cursor.h" +#include "heap.h" +#include "console.h" +#include "dirty_rect.h" +#include +#define VBE_INFO_PTR ((VbeModeInfo*)0x8000) +void counter_task(){ + int i=0; + while(1){ + vga_putentryat('A' + (i++%26),0x0F,79,0); + } +} +Widget* widget_list_head=NULL; +Window* window_list_head=NULL; +Window* window_list_tail=NULL; +void on_my_button_click(Widget* self, int x, int y, int button){ + (void)x; (void)y; (void)button; + ButtonData* data=(ButtonData*)self->data; + if(!data)return; + data->bg_color=data->press_color; + data->border_color=data->press_border; +} +void on_my_button_release(Widget* self, int x, int y, int button){ + (void)x; (void)y; (void)button; + ButtonData* data=(ButtonData*)self->data; + if(!data)return; + data->bg_color=data->base_color; + data->border_color=data->base_color; +} + +VbeModeInfo vbe_mode_info = {0}; void kernel_main(void) { - vga_init(); - vga_setcolor(vga_entry_color(VGA_COLOR_WHITE, VGA_COLOR_BLACK)); - - vga_print_string("SimpleOS Kernel v1.0 [SECURED]\n"); - vga_print_string("===============================\n\n"); - - vga_print_string("Initializing PMM... "); - pmm_init(128*1024*1024); - vga_print_string("[OK]\n"); - - vga_print_string("Initializing GDT... "); gdt_install(); - vga_print_string("[OK]\n"); - - vga_print_string("Initializing IDT... "); idt_install(); - vga_print_string("[OK]\n"); - - paging_install(); - vga_print_string("Initializing PMM... "); pmm_init(128 * 1024 * 1024); + paging_install(); + heap_init(0x00400000, 16 * 1024 * 1024); // 16 MB heap at 4 MB + memcpy(&vbe_mode_info, (void*)0x8000, sizeof(VbeModeInfo)); + + // Initialize Framebuffer and Console + FrameBuffer fb; + fb.address=(void*)vbe_mode_info.physbase; + fb.width=vbe_mode_info.resolution_x; + fb.height=vbe_mode_info.resolution_y; + fb.pitch=vbe_mode_info.pitch; + fb.bitsPerPixel=vbe_mode_info.bitsPerPixel; + fb.bytesPerPixel = vbe_mode_info.bitsPerPixel / 8; - vga_print_string("Setting up interrupts... "); - asm volatile("sti"); - vga_print_string("[OK]\n"); + Font my_font; + my_font.char_width=8; + my_font.char_height=16; + my_font.bitmap=font; // Use the font array from font.h - keyboard_install(); + console_init(&fb, &my_font); + + console_write("SimpleOS Kernel v1.0 [SECURED]\n"); + console_write("===============================\n\n"); + + syscalls_install(); timer_install(); - //pci_scan(); + keyboard_install(); + __asm__ __volatile__("sti"); rtl8139_init(); - + tasking_install(); + mouse_install(); + cursor_init(); + uint32_t free_mem = pmm_get_free_memory(); - vga_print_string("Free memory: "); - vga_print_dec(free_mem / 1024); - vga_print_string(" KB\n"); + console_write("Free memory: "); + console_write_dec(free_mem / 1024); + console_write(" KB\n"); - vga_print_string("\nKernel initialization complete!\n"); - vga_print_string("Security features: Buffer overflow protection, bounds checking\n"); - vga_print_string("Starting shell...\n\n"); + console_write("\nKernel initialization complete!\n"); + console_write("Starting GUI...\n\n"); + + // --- GUI INITIALIZATION FIXES --- + + // 1. Initialize Managers & Fonts FIRST + init_widget_system(); + window_manager_init(); + dirty_rect_init(); + widget_set_font(&my_font); // Set font BEFORE creating/drawing widgets + + // 2. Clear Screen + clear_screen(&fb, 0xECECEC); // Use a nice gray background instead of black + + // 3. Create Window + Window* main_window = create_window(100, 100, 400, 300, "Welcome to SimpleOS!", true); + if (!main_window) { + console_write("Error: Failed to create main window!\n"); // [FIX] Use console_write + for(;;) { __asm__ __volatile__("cli; hlt"); } + } + + // 4. Create Widgets + Widget* label = create_label(20, 40, 200, 30, "Hello, SimpleOS!", 0x000000); + if (!label) { + console_write("Error: Failed to create label widget!\n"); // [FIX] Use console_write + for(;;) { __asm__ __volatile__("cli; hlt"); } + } + + Widget* button = create_button(100, 100, 100, 50, "Click Me", 0xFFFFFF, 0x0000FF, 0x000000, 0x000000, 1, 0x000000, 0x000000, 0x000000); + if (!button) { + console_write("Error: Failed to create button widget!\n"); // [FIX] Use console_write + for(;;) { __asm__ __volatile__("cli; hlt"); } + } + + // 5. Assemble UI + window_add_widget(main_window, label); + window_add_widget(main_window, button); - shell_init(); + button->onClick = on_my_button_click; + button->onRelease = on_my_button_release; + window_list_head = main_window; + window_list_tail = main_window; + + // 6. Initial Draw + window_draw(main_window, &fb); + dirty_rect_add(0, 0, fb.width, fb.height); + + uint8_t last_buttons = 0; + int32_t last_x = -1, last_y = -1; + + // Main Loop while(1) { - asm volatile("hlt"); + bool mouse_moved = (mouse_x != last_x || mouse_y != last_y); + bool buttons_changed = (mouse_buttons != last_buttons); + + if (mouse_moved || buttons_changed) { + // Redraw only affected areas + dirty_rect_add(last_x, last_y, 16, 16); // Old cursor pos + window_manager_handle_mouse(&window_list_head, &window_list_tail, mouse_x, mouse_y, mouse_buttons, last_buttons); + dirty_rect_add(mouse_x, mouse_y, 16, 16); // New cursor pos + + last_x = mouse_x; + last_y = mouse_y; + last_buttons = mouse_buttons; + } + + int dirty_count; + const Rect* rects = dirty_rect_get_all(&dirty_count); + + if (dirty_count > 0) { + for (int i = 0; i < dirty_count; i++) { + const Rect* dirty = &rects[i]; + Window* current = window_list_head; + while (current) { + // Simple AABB collision check to see if window needs update + if (!(current->x > dirty->x + dirty->width || current->x + current->width < dirty->x || + current->y > dirty->y + dirty->height || current->y + current->height < dirty->y)) { + window_draw(current, &fb); + } + current = current->next; + } + } + dirty_rect_init(); + } + + cursor_update(&fb, mouse_x, mouse_y); + __asm__ __volatile__("hlt"); } -} +} \ No newline at end of file diff --git a/kernel.elf b/kernel.elf new file mode 100644 index 0000000..3d0de9c Binary files /dev/null and b/kernel.elf differ diff --git a/kernel.o b/kernel.o new file mode 100644 index 0000000..f1ab543 Binary files /dev/null and b/kernel.o differ diff --git a/kernel.tmp b/kernel.tmp new file mode 100644 index 0000000..e88ce1a Binary files /dev/null and b/kernel.tmp differ diff --git a/kernel_entry.asm b/kernel_entry.asm new file mode 100644 index 0000000..a6f0b7d --- /dev/null +++ b/kernel_entry.asm @@ -0,0 +1,8 @@ +[bits 32] +[extern _kernel_main] +[global start] + +section .text +start: + call _kernel_main + jmp $ \ No newline at end of file diff --git a/kernel_entry.o b/kernel_entry.o new file mode 100644 index 0000000..5354fa5 Binary files /dev/null and b/kernel_entry.o differ diff --git a/keyboard.c b/keyboard.c index 49b5802..aba3900 100644 --- a/keyboard.c +++ b/keyboard.c @@ -3,16 +3,10 @@ #include "vga.h" #include "shell.h" #include +#include "window.h" +#include "io.h" -static inline uint8_t inb(uint16_t port) { - uint8_t ret; - asm volatile("inb %1, %0" : "=a"(ret) : "Nd"(port)); - return ret; -} - -static inline void outb(uint16_t port, uint8_t val) { - asm volatile("outb %0, %1" : : "a"(val), "Nd"(port)); -} +#define KEYBOARD_DATA_PORT 0x60 unsigned char kbdus[128] = { 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', @@ -71,8 +65,6 @@ void keyboard_handler(registers_t *r) { } if (ch != 0) { - shell_handle_input(ch); - int next_end = (buffer_end + 1) % 256; if (next_end != buffer_start) { key_buffer[buffer_end] = ch; @@ -89,13 +81,17 @@ char keyboard_getchar(void) { } char ch = key_buffer[buffer_start]; + if (ch !=0){ + window_handle_key(ch); + shell_handle_input(ch); + } buffer_start = (buffer_start + 1) % 256; return ch; } void keyboard_wait_for_input(void) { while (buffer_start == buffer_end) { - asm volatile("hlt"); + __asm__ __volatile__("hlt"); } } diff --git a/keyboard.o b/keyboard.o new file mode 100644 index 0000000..52a617f Binary files /dev/null and b/keyboard.o differ diff --git a/lib.c b/lib.c new file mode 100644 index 0000000..761accd --- /dev/null +++ b/lib.c @@ -0,0 +1,41 @@ +#include +#include +#include "pmm.h" + +void* memset(void* ptr, int value, size_t num) { + unsigned char* p = (unsigned char*)ptr; + while (num--) *p++ = (unsigned char)value; + return ptr; +} + +void* memcpy(void* dest, const void* src, size_t num) { + unsigned char* d = (unsigned char*)dest; + const unsigned char* s = (const unsigned char*)src; + while (num--) *d++ = *s++; + return dest; +} + +size_t strlen(const char* str) { + size_t len = 0; + while (str[len]) len++; + return len; +} + +// Simple heap implementation for malloc/free +#define HEAP_SIZE 1024 * 1024 // 1MB +static uint8_t heap_memory[HEAP_SIZE]; +static size_t heap_offset = 0; + +void* malloc(size_t size) { + if (heap_offset + size > HEAP_SIZE) return NULL; + void* ptr = &heap_memory[heap_offset]; + heap_offset += size; + return ptr; +} + +void free(void* ptr) { + (void)ptr; // No-op for simple bump allocator +} + +// Stub for syscalls +void syscalls_install(void) {} \ No newline at end of file diff --git a/lib.o b/lib.o new file mode 100644 index 0000000..cd0a0a1 Binary files /dev/null and b/lib.o differ diff --git a/linker.ld b/linker.ld new file mode 100644 index 0000000..9aa9dca --- /dev/null +++ b/linker.ld @@ -0,0 +1,27 @@ +ENTRY(kernel_main) + +SECTIONS +{ + . = 0x100000; + + .text BLOCK(4K) : ALIGN(4K) + { + *(.text) + } + + .rodata BLOCK(4K) : ALIGN(4K) + { + *(.rodata) + } + + .data BLOCK(4K) : ALIGN(4K) + { + *(.data) + } + + .bss BLOCK(4K) : ALIGN(4K) + { + *(COMMON) + *(.bss) + } +} \ No newline at end of file diff --git a/mouse.c b/mouse.c new file mode 100644 index 0000000..c77a71c --- /dev/null +++ b/mouse.c @@ -0,0 +1,64 @@ +#include "mouse.h" +#include "vga.h" +#include "idt.h" +#include "io.h" +#define MOUSE_DATA_PORT 0x60 +#define MOUSE_STATUS_PORT 0x64 +#define MOUSE_COMMAND_PORT 0x64 +#define MOUSE_IRQ 12 +volatile int32_t mouse_x = 400; +volatile int32_t mouse_y = 300; +volatile uint8_t mouse_buttons = 0; +uint8_t mouse_cycle = 0; +int8_t mouse_byte[3]; +mouse_packet_t mouse_packet; +static void mouse_handler(registers_t *regs); + +void mouse_install(void) { + // Enable the auxiliary mouse device + outb(MOUSE_COMMAND_PORT, 0xA8); + // Enable the mouse IRQ + outb(MOUSE_COMMAND_PORT, 0x20); + uint8_t status = inb(MOUSE_DATA_PORT); + status |= 2; // Enable IRQ12 + outb(MOUSE_COMMAND_PORT, 0x60); + outb(MOUSE_DATA_PORT, status); + // Tell the mouse to use default settings + outb(MOUSE_COMMAND_PORT, 0xD4); + outb(MOUSE_DATA_PORT, 0xF6); + inb(MOUSE_DATA_PORT); // Acknowledge + // Enable the mouse + outb(MOUSE_COMMAND_PORT, 0xD4); + outb(MOUSE_DATA_PORT, 0xF4); + inb(MOUSE_DATA_PORT); // Acknowledge + // Register the mouse handler + irq_install_handler(MOUSE_IRQ, mouse_handler); +} +static void mouse_handler(registers_t *regs) { + (void)regs; + static uint8_t packet_byte_index = 0; + static mouse_packet_t packet; + uint8_t status = inb(MOUSE_STATUS_PORT); + if (status & 0x20) { + uint8_t data = inb(MOUSE_DATA_PORT); + switch (packet_byte_index) { + case 0: + packet.flags = data; + break; + case 1: + packet.x_delta = (int8_t)data; + break; + case 2: + packet.y_delta = (int8_t)data; + break; + } + packet_byte_index++; + if (packet_byte_index == 3) { + mouse_packet = packet; + mouse_x += packet.x_delta; + mouse_y -= packet.y_delta; // Invert Y axis + mouse_buttons = packet.flags & 0x07; // Update button states + packet_byte_index = 0; // Reset for next packet + } + } +} \ No newline at end of file diff --git a/mouse.h b/mouse.h new file mode 100644 index 0000000..d56f7ff --- /dev/null +++ b/mouse.h @@ -0,0 +1,17 @@ +#ifndef MOUSE_H +#define MOUSE_H +#include +#include "idt.h" +typedef struct { + uint8_t flags; + int8_t x_delta; + int8_t y_delta; + +}mouse_packet_t; +//Global mouse states +extern mouse_packet_t mouse_packet; +extern volatile int32_t mouse_x; +extern volatile int32_t mouse_y; +extern volatile uint8_t mouse_buttons; //Bit 0: left, Bit 1 : Right, Bit 2: Middle +void mouse_install(void); +#endif \ No newline at end of file diff --git a/mouse.o b/mouse.o new file mode 100644 index 0000000..3420d10 Binary files /dev/null and b/mouse.o differ diff --git a/mutex.c b/mutex.c new file mode 100644 index 0000000..0a46d1f --- /dev/null +++ b/mutex.c @@ -0,0 +1,57 @@ +#include "mutex.h" +#include "idt.h" +#include "vga.h" +#include "spinlock.h" +#include "task.h" +void mutex_init(mutex_t* mutex){ + spinlock_init(&mutex->lock);//Initializing the guard + mutex->locked = false; + mutex->owner = NULL; + mutex->wait_queue = NULL; +} +void mutex_lock(mutex_t* mutex){ + unsigned long flags=spinlock_acquire_irqsave(&mutex->lock);//Acquire the guard + task_t* current=get_current_task();//Get the current task + + while (mutex->locked) { + // The mutex is locked, so we need to wait. + current->state = TASK_BLOCKED; + + // Add current task to the end of the wait queue + current->next = NULL; + if (mutex->wait_queue == NULL) { + mutex->wait_queue = current; + } else { + task_t* temp = mutex->wait_queue; + while (temp->next != NULL) { + temp = temp->next; + } + temp->next = current; + } + schedule_and_release_lock(&mutex->lock, flags); + flags = spinlock_acquire_irqsave(&mutex->lock); + } + + mutex->locked=true; + mutex->owner=current; + spinlock_release_irqrestore(&mutex->lock, flags); +} + +void mutex_unlock(mutex_t* mutex){ + unsigned long flags=spinlock_acquire_irqsave(&mutex->lock); + if (mutex->owner!=get_current_task()){ + // Error: current task does not own the mutex + spinlock_release_irqrestore(&mutex->lock,flags); + return; + } + task_t* next_task=mutex->wait_queue;//dequeue the next waiting task + if (next_task!=NULL){ + mutex->wait_queue = next_task->next; // Remove from queue + next_task->state = TASK_READY; // Corrected: TASK_READY is defined in task.h + } + else{ + mutex->locked=false; + mutex->owner=NULL; + } + spinlock_release_irqrestore(&mutex->lock,flags); +} diff --git a/mutex.h b/mutex.h new file mode 100644 index 0000000..347e070 --- /dev/null +++ b/mutex.h @@ -0,0 +1,17 @@ +#ifndef MUTEX_H +#define MUTEX_H +#include "spinlock.h" +#include +struct task; + +typedef struct mutex { + spinlock_t lock; // Spinlock in order to ensure that the atomic operations on the mutex itself are thread-safe + bool locked;// This is for checking if the mutex is currrently being held or not + struct task* owner;//The task that currently holds the lock + struct task* wait_queue;//A linked list of tasks waiting for the lock. +} mutex_t; +//Function prototypes for the mutexes operations we would be defining +void mutex_init(mutex_t* mutex); +void mutex_lock(mutex_t* mutex); +void mutex_unlock(mutex_t* mutex); +#endif//MUTEX_H \ No newline at end of file diff --git a/mutex.o b/mutex.o new file mode 100644 index 0000000..5bb733c Binary files /dev/null and b/mutex.o differ diff --git a/nic.c b/nic.c new file mode 100644 index 0000000..545caa4 --- /dev/null +++ b/nic.c @@ -0,0 +1,64 @@ +#include "nic.h" +#include "idt.h" +#include "pci.h" +#include "vga.h" +#include "pmm.h" // Include our new memory manager + +#define RTL8139_VENDOR_ID 0x10EC +#define RTL8139_DEVICE_ID 0x8139 + +// RTL8139 Register Offsets (from the I/O base) +#define REG_CONFIG_1 0x52 +#define REG_COMMAND 0x37 +#define REG_RX_BUF 0x30 +#define REG_IMR 0x3C // Interrupt Mask Register +#define REG_ISR 0x3E // Interrupt Service Register +#define REG_RCR 0x44 // Receive Config Register +#include "io.h" // For inw and outw + +uint32_t rtl8139_io_base = 0; +uint8_t* rx_buffer; +void rtl8139_handler(registers_t *r) { + (void)r; + vga_print_string("[NIC IRQ]"); + uint16_t status = inw(rtl8139_io_base + REG_ISR); + + if (status & 0x1) { // ROK: Receive OK + vga_print_string(" Packet Received "); + } + outw(rtl8139_io_base + REG_ISR, status); +} + +void rtl8139_init(void) { + vga_print_string("Initializing RTL8139... "); + + // --- Find the card --- + uint8_t found = 0; + for (uint16_t bus = 0; bus < 256; bus++) { + for (uint8_t device = 0; device < 32; device++) { + uint32_t vendor_device_id = pci_read_config(bus, device, 0, 0); + if ((vendor_device_id & 0xFFFF) == RTL8139_VENDOR_ID && (vendor_device_id >> 16) == RTL8139_DEVICE_ID) { + uint32_t bar0 = pci_read_config(bus, device, 0, 0x10); + rtl8139_io_base = bar0 & 0xFFFC; + found = 1; + break; + } + } + if (found) break; + } + + if (!found) { + vga_print_string("[NOT FOUND]\n"); + return; + } + vga_print_string("[OK]\n"); + outb(rtl8139_io_base + REG_CONFIG_1, 0x00); + outb(rtl8139_io_base + REG_COMMAND, 0x10); + while((inb(rtl8139_io_base + REG_COMMAND) & 0x10) != 0) { /* wait */ } + rx_buffer = (uint8_t*)pmm_alloc_pages(4); + outl(rtl8139_io_base + REG_RX_BUF, (uint32_t)rx_buffer); + outw(rtl8139_io_base + REG_IMR, 0x0005); + outl(rtl8139_io_base + REG_RCR, 0x0F); + outb(rtl8139_io_base + REG_COMMAND, 0x0C); + irq_install_handler(11, rtl8139_handler); +} \ No newline at end of file diff --git a/nic.h b/nic.h new file mode 100644 index 0000000..ab48e25 --- /dev/null +++ b/nic.h @@ -0,0 +1,6 @@ +#ifndef RTL8139_H +#define RTL8139_H + +void rtl8139_init(void); + +#endif \ No newline at end of file diff --git a/nic.o b/nic.o new file mode 100644 index 0000000..1ac9c28 Binary files /dev/null and b/nic.o differ diff --git a/os-image.bin b/os-image.bin new file mode 100644 index 0000000..c1a921c Binary files /dev/null and b/os-image.bin differ diff --git a/os.img b/os.img new file mode 100644 index 0000000..6527259 Binary files /dev/null and b/os.img differ diff --git a/paging.c b/paging.c index e7f8111..f686678 100644 --- a/paging.c +++ b/paging.c @@ -1,29 +1,93 @@ -//Identity-map the first 4MB of physical memory #include "paging.h" +#include "pmm.h" #include "vga.h" -//Static allocation currently, 4MB=4096-byte aligned -__attribute__((aligned(4096))) pt_entry_t page_directory[1024]; -__attribute__((aligned(4096))) pt_entry_t fpage_table[1024]; -void paging_install(void){ - vga_print_string("Installing paging... "); - for(int i=0;i<1024;i++){ - fpage_table[i].present=1; - fpage_table[i].user_supervisor=0; - fpage_table[i].pwt=0; - fpage_table[i].pcd=0; - fpage_table[i].accessed=0; - fpage_table[i].reserved=0; - fpage_table[i].rw=1; //Read-write - fpage_table[i].frame=i; +#include +#include "idt.h" +#include "graphics.h" +struct VbeInfoBlock { + uint16_t attributes; + uint8_t windowA, windowB; + uint16_t granularity; + uint16_t windowSize; + uint16_t segmentA, segmentB; + uint32_t winFuncPtr; + uint16_t pitch; + uint16_t width, height; + uint8_t wChar, yChar, planes, bpp, banks; + uint8_t memory_model, bank_size, image_pages; + uint8_t reserved0; + uint8_t red_mask, red_position; + uint8_t green_mask, green_position; + uint8_t blue_mask, blue_position; + uint8_t rsv_mask, rsv_position; + uint8_t directcolor_attributes; + uint32_t physbase; // <--- This is what we need! + uint32_t reserved1; + uint16_t reserved2; +} __attribute__((packed)); + +page_directory_t* page_directory = 0; + +void paging_map(uint32_t phys, uint32_t virt, uint32_t flags) { + (void)flags; + uint32_t pd_index = virt >> 22; + uint32_t pt_index = (virt >> 12) & 0x03FF; + + if (!page_directory->tables[pd_index]) { + // Allocate a new page table + page_table_t* new_table = (page_table_t*)pmm_alloc_page(); + memset(new_table, 0, sizeof(page_table_t)); + + // Register it in the directory + page_directory->tables[pd_index] = new_table; + // The physical address of the new table is just its pointer (in identity map) + page_directory->physical_tables[pd_index] = ((uint32_t)new_table) | 0x7; // Present, RW, User + } + + page_table_t* table = page_directory->tables[pd_index]; + table->pages[pt_index].frame = phys >> 12; + table->pages[pt_index].present = 1; + table->pages[pt_index].rw = 1; + table->pages[pt_index].user = 1; } -//Newly created page goes into the first entry of the page directoy -page_directory[0].frame=(uint32_t)fpage_table>>12; -page_directory[0].present=1; -page_directory[0].rw=1; -asm volatile("mov %0, %%cr3"::"r"(&page_directory)); -uint32_t cr0; -asm volatile("mov %%cr0, %0":"=r"(cr0)); -cr0|=0x80000000; -asm volatile("mov %0, %%cr0"::"r"(cr0)); -vga_print_string("[OK]\n"); + +void switch_page_directory(page_directory_t *dir) { + uint32_t cr0; + // Load CR3 with the address of the physical_tables array + asm volatile("mov %0, %%cr3" :: "r"(&dir->physical_tables)); + asm volatile("mov %%cr0, %0" : "=r"(cr0)); + cr0 |= 0x80000000; // Enable paging + asm volatile("mov %0, %%cr0" :: "r"(cr0)); } +void page_fault_handler(registers_t *r) { + (void)r; + uint32_t faulting_address; + __asm__ __volatile__("mov %%cr2, %0" : "=r" (faulting_address)); + vga_print_string("Page Fault at 0x"); + vga_print_hex(faulting_address); + vga_print_string("\n"); + __asm__ __volatile__("cli"); + for(;;) { __asm__ __volatile__("hlt"); } +} +void paging_install(void) { + page_directory = (page_directory_t*)pmm_alloc_page(); + memset(page_directory, 0, sizeof(page_directory_t)); + for (uint32_t i = 0; i < 0x400000; i += PAGE_SIZE) { + paging_map(i, i, 0x3); + } + for (uint32_t i = 0x00400000; i < 0x01400000; i += PAGE_SIZE) { + paging_map(i, i, 0x3); + } + struct VbeInfoBlock* info = (struct VbeInfoBlock*)0x8000; + uint32_t fb_phys = info->physbase; + + // Safety check: if 0, something is wrong with bootloader, but we try anyway + if (fb_phys != 0) { + // Map 8MB to be safe (covers 1080p easily) + for (uint32_t i = 0; i < 0x00800000; i += PAGE_SIZE) { + paging_map(fb_phys + i, fb_phys + i, 0x3); + } + } + register_interrupt_handler(14, page_fault_handler); + switch_page_directory(page_directory); +} \ No newline at end of file diff --git a/paging.h b/paging.h index 0e12110..76e91a5 100644 --- a/paging.h +++ b/paging.h @@ -1,16 +1,62 @@ -#ifndef PAGING_H +/* #ifndef PAGING_H #define PAGING_H #include -#include "idt.h" //This is for interrupt handling +#include "idt.h" +#define PAGING_STRUCTURES_START ((uint32_t)&page_directory) +#define PAGING_STRUCTURES_SIZE (8192) // 8KB for directory + table +extern pt_entry_t page_directory[1024]; +extern pt_entry_t fpage_table[1024]; //Below is for defining page table entry typedef struct pt_entry{ - uint32_t present:1; - uint32_t rw:1; - uint32_t us:1; - uint32_t accessed:1; - uint32_t dirty:1; - uint32_t unused:7;// Amalgamation of unused and reserved bits - uint32_t frame:20; //Frame address + uint32_t present:1; // Bit 0: Present + uint32_t rw:1; // Bit 1: Read/Write + uint32_t user_supervisor:1; // Bit 2: User/Supervisor + uint32_t pwt:1; // Bit 3: Page Write-Through + uint32_t pcd:1; // Bit 4: Page Cache Disable + uint32_t accessed:1; // Bit 5: Accessed + uint32_t dirty:1; // Bit 6: Dirty + uint32_t pat:1; // Bit 7: Page Attribute Table + uint32_t global:1; // Bit 8: Global + uint32_t avail:3; // Bits 9-11: Available for software use + uint32_t frame:20; // Bits 12-31: Frame address (shifted right 12 bits) } pt_entry_t; + +// Function declarations +void paging_install(void); +uint32_t paging_get_reserved_start(void); +uint32_t paging_get_reserved_end(void); +#endif */ + +#ifndef PAGING_H +#define PAGING_H + +#include +#include "idt.h" + +// Page Table Entry +typedef struct page { + uint32_t present : 1; // Page present in memory + uint32_t rw : 1; // Read-only if clear, read-write if set + uint32_t user : 1; // Supervisor level only if clear + uint32_t accessed : 1; // Has the page been accessed since last refresh? + uint32_t dirty : 1; // Has the page been written to since last refresh? + uint32_t unused : 7; // Amalgamation of unused and reserved bits + uint32_t frame : 20; // Frame address (shifted right 12 bits) +} page_t; + +typedef struct page_table { + page_t pages[1024]; +} page_table_t; + +typedef struct page_directory { + page_table_t *tables[1024]; // Array of pointers to pagetables. + uint32_t physical_tables[1024]; // Array of physical addresses of pagetables. + uint32_t physicalAddr; // The physical address of physical_tables +} page_directory_t; + void paging_install(void); +void paging_map(uint32_t phys, uint32_t virt, uint32_t flags); +void switch_page_directory(page_directory_t *dir); +extern page_directory_t* page_directory; + #endif diff --git a/paging.o b/paging.o new file mode 100644 index 0000000..7e7ccbd Binary files /dev/null and b/paging.o differ diff --git a/pci.c b/pci.c index d81aa08..489a518 100644 --- a/pci.c +++ b/pci.c @@ -1,10 +1,11 @@ #include "pci.h" #include "idt.h" #include "vga.h" +#include "io.h" #define PCI_CONFIG_ADDRESS 0xCF8 #define PCI_CONFIG_DATA 0xCFC -uint32_t pci_read_config(uint8_t bus, uint8_t device, uint8_t func, uint8_t offset) { +uint32_t pci_read_config(uint16_t bus, uint8_t device, uint8_t func, uint8_t offset) { uint32_t address; uint32_t lbus = (uint32_t)bus; uint32_t ldevice = (uint32_t)device; diff --git a/pci.h b/pci.h index 23d79d5..4602263 100644 --- a/pci.h +++ b/pci.h @@ -1,6 +1,7 @@ //This is for the connection header -#idndef PCI_H +#ifndef PCI_H #define PCI_H #include void pci_scan(void); +uint32_t pci_read_config(uint16_t bus, uint8_t slot, uint8_t func, uint8_t offset); #endif \ No newline at end of file diff --git a/pci.o b/pci.o new file mode 100644 index 0000000..883e720 Binary files /dev/null and b/pci.o differ diff --git a/pmm.c b/pmm.c index 51a1ade..108e966 100644 --- a/pmm.c +++ b/pmm.c @@ -1,86 +1,186 @@ -#include "pmm.h" #include +#include -static uint32_t memory_top; -static uint32_t memory_limit; -static uint32_t allocation_count = 0; -#define KERNEL_START_ADDRESS 0x200000 -#define MAX_ALLOCATIONS 1024 -#define MIN_ALLOCATION_SIZE 16 -#define MAX_ALLOCATION_SIZE (1024 * 1024) +#define PAGE_SIZE 4096 +#define MAX_ORDER 10 // 4KB * 2^10 = 4MB +#define KERNEL_RESERVED_END 0x200000U // bytes (2MB) -typedef struct { - uint32_t address; - uint32_t size; - int used; -} allocation_entry_t; +typedef enum { PAGE_STATE_FREE=0, PAGE_STATE_USED=1, PAGE_STATE_RESERVED=2 } page_state_t; -static allocation_entry_t allocations[MAX_ALLOCATIONS]; +typedef struct page_frame { + struct page_frame* next; + struct page_frame* prev; + uint8_t order; + page_state_t state; + // ... other metadata +} page_frame_t; -void pmm_init(uint32_t total_memory) { - if (total_memory < KERNEL_START_ADDRESS + (1024 * 1024)) { +static page_frame_t* page_frame_database = NULL; +static page_frame_t* free_lists[MAX_ORDER + 1]; +static uint32_t total_pages = 0; + +static inline uint32_t idx_from_addr(void* addr) { + return (uint32_t)((uintptr_t)addr / PAGE_SIZE); +} +static inline void* addr_from_idx(uint32_t idx) { + return (void*)((uintptr_t)idx * PAGE_SIZE); +} +static inline uint32_t get_buddy_index(uint32_t index, uint32_t order) { + return index ^ (1u << order); +} + +void pmm_init(uint32_t memory_end_bytes) { + total_pages = memory_end_bytes / PAGE_SIZE; + size_t db_size = total_pages * sizeof(page_frame_t); + uint32_t db_pages = (db_size + PAGE_SIZE - 1) / PAGE_SIZE; + + uint32_t reserved_pages = (KERNEL_RESERVED_END / PAGE_SIZE) + db_pages; + if (reserved_pages >= total_pages) { return; } - - memory_top = KERNEL_START_ADDRESS; - memory_limit = total_memory; - allocation_count = 0; - - for (int i = 0; i < MAX_ALLOCATIONS; i++) { - allocations[i].used = 0; + page_frame_database = (page_frame_t*)(uintptr_t)KERNEL_RESERVED_END; + uint32_t usable_start = reserved_pages; + for (uint32_t i = 0; i < total_pages; ++i) { + page_frame_database[i].state = PAGE_STATE_FREE; + page_frame_database[i].order = 0; + page_frame_database[i].next = NULL; + page_frame_database[i].prev = NULL; } -} + for (uint32_t i = 0; i < reserved_pages; ++i) { + page_frame_database[i].state = PAGE_STATE_RESERVED; + } + for (int i = 0; i <= MAX_ORDER; ++i) free_lists[i] = NULL; + uint32_t current = usable_start; + while (current < total_pages) { + int order = MAX_ORDER; + while (order >= 0) { + uint32_t block_size = 1u << order; + if ((current % block_size) == 0 && (current + block_size) <= total_pages) break; + --order; + } + if (order < 0) { // fallback to single page + order = 0; + } + page_frame_t* f = &page_frame_database[current]; + f->order = (uint8_t)order; + f->state = PAGE_STATE_FREE; + // push to free list head + f->prev = NULL; + f->next = free_lists[order]; + if (free_lists[order]) free_lists[order]->prev = f; + free_lists[order] = f; -void* pmm_alloc(size_t size) { - if (size == 0 || size < MIN_ALLOCATION_SIZE || size > MAX_ALLOCATION_SIZE) { - return NULL; + current += (1u << order); } - - size = (size + 15) & ~15; - - if (allocation_count >= MAX_ALLOCATIONS) { - return NULL; +} + +void* pmm_alloc_page(void) { + for (int order = 0; order <= MAX_ORDER; ++order) { + if (!free_lists[order]) continue; + page_frame_t* block = free_lists[order]; + free_lists[order] = block->next; + if (free_lists[order]) free_lists[order]->prev = NULL; + int cur_order = order; + uint32_t base_idx = (uint32_t)(block - page_frame_database); + while (cur_order > 0) { + cur_order--; + uint32_t buddy_idx = base_idx + (1u << cur_order); + page_frame_t* buddy = &page_frame_database[buddy_idx]; + buddy->order = (uint8_t)cur_order; + buddy->state = PAGE_STATE_FREE; + buddy->next = free_lists[cur_order]; + if (free_lists[cur_order]) free_lists[cur_order]->prev = buddy; + buddy->prev = NULL; + free_lists[cur_order] = buddy; + } + + block->order = 0; + block->state = PAGE_STATE_USED; + block->next = block->prev = NULL; + uint32_t idx = (uint32_t)(block - page_frame_database); + return addr_from_idx(idx); } - - if (memory_top > memory_limit || (memory_limit - memory_top) < size) { - return NULL; + return NULL; +} + +void* pmm_alloc_pages(uint32_t count) { + int order = 0; + while ((1u << order) < count) { + order++; } - - for (int i = 0; i < MAX_ALLOCATIONS; i++) { - if (!allocations[i].used) { - allocations[i].address = memory_top; - allocations[i].size = size; - allocations[i].used = 1; - allocation_count++; - - void* ptr = (void*)memory_top; - memory_top += size; - return ptr; + if (order > MAX_ORDER) return NULL; + + for (int i = order; i <= MAX_ORDER; ++i) { + if (!free_lists[i]) continue; + page_frame_t* block = free_lists[i]; + free_lists[i] = block->next; + if (free_lists[i]) free_lists[i]->prev = NULL; + + while (i > order) { + i--; + uint32_t base_idx = (uint32_t)(block - page_frame_database); + uint32_t buddy_idx = base_idx + (1u << i); + page_frame_t* buddy = &page_frame_database[buddy_idx]; + buddy->order = (uint8_t)i; + buddy->state = PAGE_STATE_FREE; + buddy->next = free_lists[i]; + if (free_lists[i]) free_lists[i]->prev = buddy; + buddy->prev = NULL; + free_lists[i] = buddy; } + block->order = (uint8_t)order; + block->state = PAGE_STATE_USED; + return addr_from_idx((uint32_t)(block - page_frame_database)); } - return NULL; } -void pmm_free(void* ptr) { - if (ptr == NULL) { - return; - } - - uint32_t addr = (uint32_t)ptr; - - for (int i = 0; i < MAX_ALLOCATIONS; i++) { - if (allocations[i].used && allocations[i].address == addr) { - allocations[i].used = 0; - allocation_count--; - break; +void pmm_free_page(void* p) { + if (!p) return; + uintptr_t addr = (uintptr_t)p; + if (addr % PAGE_SIZE) return; + + uint32_t idx = (uint32_t)(addr / PAGE_SIZE); + if (idx >= total_pages) return; + + page_frame_t* frame = &page_frame_database[idx]; + if (frame->state == PAGE_STATE_RESERVED) return; + + frame->state = PAGE_STATE_FREE; + frame->order = 0; + + for (int order = 0; order < MAX_ORDER; ++order) { + uint32_t buddy_idx = get_buddy_index(idx, order); + if (buddy_idx >= total_pages) break; + page_frame_t* buddy = &page_frame_database[buddy_idx]; + + if (buddy->state != PAGE_STATE_FREE || buddy->order != order) { + break; // can't merge } + if (buddy->prev) buddy->prev->next = buddy->next; + else free_lists[order] = buddy->next; + if (buddy->next) buddy->next->prev = buddy->prev; + if (buddy_idx < idx) idx = buddy_idx; + frame = &page_frame_database[idx]; + frame->order = (uint8_t)(order + 1); + frame->state = PAGE_STATE_FREE; } + int final_order = frame->order; + frame->next = free_lists[final_order]; + if (free_lists[final_order]) free_lists[final_order]->prev = frame; + frame->prev = NULL; + free_lists[final_order] = frame; } uint32_t pmm_get_free_memory(void) { - if (memory_limit > memory_top) { - return memory_limit - memory_top; + uint32_t total_free = 0; + for (int order = 0; order <= MAX_ORDER; ++order) { + uint32_t block_pages = (1u << order); + page_frame_t* cur = free_lists[order]; + while (cur) { + total_free += block_pages * PAGE_SIZE; + cur = cur->next; + } } - return 0; -} \ No newline at end of file + return total_free; +} diff --git a/pmm.h b/pmm.h index 5b9885f..72a96ef 100644 --- a/pmm.h +++ b/pmm.h @@ -1,12 +1,23 @@ #ifndef PMM_H #define PMM_H - #include #include -void pmm_init(uint32_t memory_size); -void* pmm_alloc(size_t size); -void pmm_free(void* ptr); -uint32_t pmm_get_free_memory(void); +#define PAGE_SIZE 4096 + +typedef enum { PAGE_STATE_FREE=0, PAGE_STATE_USED=1, PAGE_STATE_RESERVED=2 } page_state_t; +typedef struct page_frame { + struct page_frame* next; + struct page_frame* prev; + uint8_t order; + page_state_t state; + // ... other metadata + +} page_frame_t; +void pmm_init(uint32_t memory_end); +void* pmm_alloc_page(void); +void* pmm_alloc_pages(uint32_t count); +void pmm_free_page(void* p); +uint32_t pmm_get_free_memory(void); #endif \ No newline at end of file diff --git a/pmm.o b/pmm.o new file mode 100644 index 0000000..0bfd2c9 Binary files /dev/null and b/pmm.o differ diff --git a/run.sh b/run.sh new file mode 100644 index 0000000..f0fd433 --- /dev/null +++ b/run.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +# Define the ISO file +ISO="simpleos.iso" +FLOPPY="floppy.img" + +# Check if any image file exists before trying to run anything +if [ ! -f "$ISO" ] && [ ! -f "$FLOPPY" ]; then + echo "Error: Neither $ISO nor $FLOPPY found." + echo "Please run the build commands or build_iso.sh first." + exit 1 +fi + +# Try to find QEMU in PATH or common Windows locations +if command -v qemu-system-i386 &> /dev/null; then + QEMU="qemu-system-i386" +elif [ -f "/c/Program Files/qemu/qemu-system-i386.exe" ]; then + QEMU="/c/Program Files/qemu/qemu-system-i386.exe" +elif [ -f "/c/Program Files (x86)/qemu/qemu-system-i386.exe" ]; then + QEMU="/c/Program Files (x86)/qemu/qemu-system-i386.exe" +elif [ -f "/c/Program Files/qemu/qemu-system-x86_64.exe" ]; then + # 64-bit QEMU can also run 32-bit OSes + QEMU="/c/Program Files/qemu/qemu-system-x86_64.exe" +else + echo "QEMU not found. You can bypass QEMU by using the generated files:" + [ -f "$ISO" ] && echo " - $ISO (Use with VirtualBox/VMware or burn to CD/USB)" + [ -f "$FLOPPY" ] && echo " - $FLOPPY (Use with VirtualBox Floppy Controller)" + exit 0 +fi + +# Check for ISO or Floppy +if [ -f "$ISO" ]; then + echo "Booting from CD-ROM ($ISO)..." + "$QEMU" -cdrom "$ISO" +elif [ -f "$FLOPPY" ]; then + echo "ISO not found (mkisofs might be missing). Booting from Floppy ($FLOPPY)..." + "$QEMU" -drive format=raw,file="$FLOPPY",index=0,if=floppy +fi \ No newline at end of file diff --git a/shell.c b/shell.c index 5984970..710a1e1 100644 --- a/shell.c +++ b/shell.c @@ -3,6 +3,7 @@ #include "vga.h" #include #include "timer.h" +#include "io.h" #define MAX_COMMAND_LENGTH 256 @@ -48,16 +49,6 @@ static void shell_halt(void) { } } -static inline uint8_t inb(uint16_t port) { - uint8_t ret; - asm volatile("inb %1, %0" : "=a"(ret) : "Nd"(port)); - return ret; -} - -static inline void outb(uint16_t port, uint8_t val) { - asm volatile("outb %0, %1" : : "a"(val), "Nd"(port)); -} - static int shell_strcmp(const char *str1, const char *str2) { while (*str1 && (*str1 == *str2)) { str1++; diff --git a/shell.h b/shell.h index dbce648..40e7999 100644 --- a/shell.h +++ b/shell.h @@ -8,14 +8,4 @@ void shell_init(void); void shell_handle_input(char ch); void shell_print_prompt(void); -static inline uint8_t inb(uint16_t port) { - uint8_t ret; - asm volatile("inb %1, %0" : "=a"(ret) : "Nd"(port)); - return ret; -} - -static inline void outb(uint16_t port, uint8_t val) { - asm volatile("outb %0, %1" : : "a"(val), "Nd"(port)); -} - #endif \ No newline at end of file diff --git a/shell.o b/shell.o new file mode 100644 index 0000000..c9fbb94 Binary files /dev/null and b/shell.o differ diff --git a/spinlock.c b/spinlock.c new file mode 100644 index 0000000..4336825 --- /dev/null +++ b/spinlock.c @@ -0,0 +1,34 @@ +#include "spinlock.h" +void spinlock_init(spinlock_t* lock) { + *lock = 0; // Initialize the lock to unlocked state +} +unsigned long spinlock_acquire_irqsave(spinlock_t* lock) { + unsigned long flags; + asm volatile( + "pushf\n" // Save EFLAGS to stack + "pop %0\n" // Pop into flags variable + "cli\n" // Disable interrupts + : "=r"(flags) // Output operand + : // No input operands + : "memory" // Clobber memory to prevent reordering + ); + + while (__atomic_test_and_set(lock, __ATOMIC_ACQUIRE)) { + // Spin-wait (busy wait) + while (*lock) { + asm volatile("pause"); // Hint to CPU for better power management + } + } + return flags; +} +void spinlock_release_irqrestore(spinlock_t* lock, unsigned long flags) { + __atomic_clear(lock, __ATOMIC_RELEASE); // Release the lock + + asm volatile( + "push %0\n" // Push saved flags onto stack + "popf\n" // Restore EFLAGS from stack + : // No output operands + : "r"(flags) // Input operand + : "memory" // Clobber memory to prevent reordering + ); +} \ No newline at end of file diff --git a/spinlock.h b/spinlock.h new file mode 100644 index 0000000..bb1e7fb --- /dev/null +++ b/spinlock.h @@ -0,0 +1,4 @@ +#ifndef SPINLOCK_H +#define SPINLOCK_H +#include "sync.h" +#endif \ No newline at end of file diff --git a/spinlock.o b/spinlock.o new file mode 100644 index 0000000..587cbbd Binary files /dev/null and b/spinlock.o differ diff --git a/sync.h b/sync.h new file mode 100644 index 0000000..55a6c20 --- /dev/null +++ b/sync.h @@ -0,0 +1,57 @@ +#ifndef SYNC_H +#define SYNC_H + +#include + +typedef struct { + volatile bool locked; +} spinlock_t; + +/** + * @brief Initializes a spinlock to the unlocked state. + * @param lock Pointer to the spinlock + */ +static __inline__ void spinlock_init(spinlock_t* lock) { + lock->locked = 0; +} + +/** + * @brief Acquires the spinlock, spinning until it is free. + * This uses an atomic test-and-set operation. + * @param lock Pointer to the spinlock. + */ +static __inline__ void spinlock_acquire(spinlock_t* lock) { + while (__atomic_test_and_set(&lock->locked, __ATOMIC_ACQUIRE)); +} + +/** + * @brief Releases the spinlock. + * @param lock Pointer to the spinlock. + */ +static __inline__ void spinlock_release(spinlock_t* lock) { + __atomic_clear(&lock->locked, __ATOMIC_RELEASE); +} + +/** + * @brief Acquires the spinlock and disables interrupts. + * @param lock Pointer to the spinlock. + * @return The flags register before interrupts were disabled. + */ +static __inline__ unsigned long spinlock_acquire_irqsave(spinlock_t* lock) { + unsigned long flags; + __asm__ __volatile__("pushf; pop %0; cli" : "=r"(flags)); + spinlock_acquire(lock); + return flags; +} + +/** + * @brief Releases the spinlock and restores interrupts. + * @param lock Pointer to the spinlock. + * @param flags The flags register to restore. + */ +static __inline__ void spinlock_release_irqrestore(spinlock_t* lock, unsigned long flags) { + spinlock_release(lock); + __asm__ __volatile__("push %0; popf" :: "r"(flags)); +} + +#endif // SYNC_H \ No newline at end of file diff --git a/syscall.c b/syscall.c new file mode 100644 index 0000000..00aff34 --- /dev/null +++ b/syscall.c @@ -0,0 +1,9 @@ +#include "syscall.h" +#include "vga.h" +void syscall_install(void){ + vga_print_string("Syscall Interface Installed, Simple OS WORKING\n");} +void syscall_handler(registers_t *r){ + if (r->eax==0){ + vga_print_string("SYSTEM CALL RECEIVED!, SIMPLE OS WORKING\n"); + } +} \ No newline at end of file diff --git a/syscall.h b/syscall.h new file mode 100644 index 0000000..79ff222 --- /dev/null +++ b/syscall.h @@ -0,0 +1,9 @@ +#ifndef SYSCALL_H +#define SYSCALL_H + +#include "idt.h" + +void syscalls_install(void); +void syscall_handler(registers_t *r); + +#endif \ No newline at end of file diff --git a/syscall.o b/syscall.o new file mode 100644 index 0000000..4b34310 Binary files /dev/null and b/syscall.o differ diff --git a/task.c b/task.c new file mode 100644 index 0000000..9af4774 --- /dev/null +++ b/task.c @@ -0,0 +1,85 @@ +#include "task.h" +#include "pmm.h" +#include "vga.h" +#include "timer.h" +#include "idt.h" +#include +static task_t* current_task; +static task_t* ready_queue; +static int next_pid = 1; + +void idle_task_func(void){ + while(1){ + __asm__ __volatile__("hlt"); + } +} +task_t* get_current_task(void) { + return current_task; +} +void tasking_install(void) { + vga_print_string("Initializing multitasking... "); + current_task = (task_t*)pmm_alloc_page(); + memset(current_task, 0, sizeof(task_t)); + current_task->id = next_pid++; + current_task->state = TASK_RUNNING; + current_task->kernel_stack = NULL; + current_task->next = NULL; + ready_queue = current_task; // This will be our idle task + + vga_print_string("[OK]\n"); +} +void schedule_from_yield(void){ + __asm__ __volatile__("int $0x20"); +} +void create_task(char* name, void (*entry_point)(void)) { + (void)name; // Name is for debugging, unused for now + __asm__ __volatile__("cli"); + task_t* new_task = (task_t*)pmm_alloc_page(); + memset(new_task, 0, sizeof(task_t)); + + new_task->id = next_pid++; + new_task->state = TASK_READY; + new_task->kernel_stack = (void*)((uint32_t)pmm_alloc_page() + PAGE_SIZE); + uint32_t stack_top = (uint32_t)new_task->kernel_stack; + registers_t* initial_regs = (registers_t*)(stack_top - sizeof(registers_t)); + memset(initial_regs, 0, sizeof(registers_t)); + initial_regs->eip = (uint32_t)entry_point; + initial_regs->eflags = 0x202; // Enable interrupts + new_task->regs.esp = (uint32_t)initial_regs; + initial_regs->cs = 0x08; // Kernel code segment + initial_regs->ds = 0x10; // Kernel data segment + // Add to the end of the ready queue + task_t* temp = ready_queue; + while (temp->next != NULL) { + temp = temp->next; + } + temp->next = new_task; + new_task->next = ready_queue; + __asm__ __volatile__("sti"); +} + + + +void schedule(registers_t* r) { + if (!current_task) return; + + // Save the state of the curreint task + current_task->regs = *r; + task_t* next_task = current_task->next; + while (next_task && next_task->state != TASK_READY) { + next_task = next_task->next; + if (next_task == current_task) { + // No other ready tasks found + next_task = current_task; + break; + } + } + current_task = next_task; + current_task->state = TASK_RUNNING; + *r = current_task->regs; +} + +void schedule_and_release_lock(spinlock_t* lock, unsigned long flags) { + spinlock_release_irqrestore(lock, flags); + schedule_from_yield(); +} \ No newline at end of file diff --git a/task.h b/task.h new file mode 100644 index 0000000..a7e03af --- /dev/null +++ b/task.h @@ -0,0 +1,29 @@ +#ifndef TASK_H +#define TASK_H +#include +#include "idt.h" +#include "spinlock.h" +typedef enum { + TASK_RUNNING, + TASK_READY, + TASK_SLEEPING, + TASK_DEAD, + TASK_BLOCKED, + TASK_WAITING, + TASK_KILLED, + TASK_ZOMBIE +} task_state_t; +typedef struct task { + int id; + registers_t regs; + void* kernel_stack; + task_state_t state; + struct task* next; +} task_t; +void tasking_install(void); +void create_task(char* name, void (*entry_point)(void)); +void schedule(registers_t* r); +void schedule_and_release_lock(spinlock_t* lock, unsigned long flags); +task_t* get_current_task(void); + +#endif \ No newline at end of file diff --git a/task.o b/task.o new file mode 100644 index 0000000..1b5cefd Binary files /dev/null and b/task.o differ diff --git a/timer.c b/timer.c index 5492af1..a6a7d0e 100644 --- a/timer.c +++ b/timer.c @@ -1,24 +1,21 @@ #include "timer.h" -#include "idt.h" -#include "vga.h" +#include "task.h" +#include "io.h" volatile uint32_t ticks = 0; void timer_handler(registers_t *r) { - (void)r; ticks++; + schedule(r); } uint32_t get_ticks() { return ticks; } void timer_install() { - vga_print_string("Installing timer... "); - int frequency = 500; + int frequency = 100; uint32_t divisor = 1193180 / frequency; outb(0x43, 0x36); uint8_t l = (uint8_t)(divisor & 0xFF); uint8_t h = (uint8_t)((divisor >> 8) & 0xFF); outb(0x40, l); outb(0x40, h); - irq_install_handler(0, timer_handler); - - vga_print_string("[OK]\n"); + irq_install_handler(0, timer_handler); } \ No newline at end of file diff --git a/timer.o b/timer.o new file mode 100644 index 0000000..3706871 Binary files /dev/null and b/timer.o differ diff --git a/vga.o b/vga.o new file mode 100644 index 0000000..7cdd03b Binary files /dev/null and b/vga.o differ diff --git a/widget.c b/widget.c new file mode 100644 index 0000000..0d70502 --- /dev/null +++ b/widget.c @@ -0,0 +1,305 @@ +#include "widget.h" +#include +#include +#include "graphics.h" +#include "font.h" +#include "keyboard.h" +#include "timer.h" +#include "heap.h" +#include "shell.h" +#include "pci.h" +Font* g_widget_font=NULL; +void widget_set_font(Font* font){ + g_widget_font=font; +} +void draw_label(Widget* self,FrameBuffer* fb){ + if(!g_widget_font)return; + LabelData* data=(LabelData*)self->data; + if(!data||!data->text)return; + draw_string(fb, g_widget_font, data->text, self->x, self->y, data->color); +} +void update_label(Widget* self,FrameBuffer* fb){ + (void)self; (void)fb; +} +void draw_button(Widget* self,FrameBuffer* fb){ + if(!g_widget_font)return; + ButtonData* data=(ButtonData*)self->data; + if(!data||!data->text)return; + // Draw button background + fill_rectangle(fb, self->x, self->y, self->width, self->height, data->bg_color); + // Draw button border + for(int i=0;iborder_width;i++){ + for(int y=i;yheight-i;y++){ + for(int x=i;xwidth-i;x++){ + uint32_t color=data->border_color; + if(x==i||x==self->width-i-1||y==i||y==self->height-i-1){ + put_pixel(fb,self->x+x,self->y+y,color); + } + } + } + } + // Draw button text (centered) + int text_width=strlen(data->text)*g_widget_font->char_width; + int text_height=g_widget_font->char_height; + int text_x=self->x+self->width/2-text_width/2; + int text_y=self->y+self->height/2-text_height/2; + draw_string(fb, g_widget_font, data->text, text_x, text_y, data->text_color); +} +void update_button(Widget* self,FrameBuffer* fb){ + (void)self; (void)fb; +} +void draw_textbox(Widget* self,FrameBuffer* fb){ + (void)self; (void)fb; + if(!g_widget_font)return; +} +void update_textbox(Widget* self,FrameBuffer* fb){ + (void)self; (void)fb; +} +void draw_scrollbar(Widget* self,FrameBuffer* fb){ + (void)self; (void)fb; +} +void update_scrollbar(Widget* self,FrameBuffer* fb){ + (void)self; (void)fb; +} +void handle_button_click(Widget* self,int mouse_x,int mouse_y,int button){ + (void)mouse_x; (void)mouse_y; + ButtonData* data=(ButtonData*)self->data; + if(!data)return; + // Change button color on click + if(button==1){ // Left click + data->bg_color=data->press_color; + data->border_color=data->press_border; + } +} +void handle_button_release(Widget* self,int mouse_x,int mouse_y,int button){ + (void)mouse_x; (void)mouse_y; + ButtonData* data=(ButtonData*)self->data; + if(!data)return; + if(button==1){ // Left click + data->bg_color=data->base_color; + data->border_color=data->base_color; + } +} +void handle_button_hover(Widget* self,int mouse_x,int mouse_y){ + (void)mouse_x; (void)mouse_y; + ButtonData* data=(ButtonData*)self->data; + if(!data)return; + // Change button color on hover + data->bg_color=data->hover_color; + data->border_color=data->hover_border; +} +void handle_button_leave(Widget* self,int mouse_x,int mouse_y){ + (void)mouse_x; (void)mouse_y; + ButtonData* data=(ButtonData*)self->data; + if(!data)return; + // Revert button color when not hovering + data->bg_color=data->base_color; + data->border_color=data->base_color; +} + +typedef struct { + char* placeholder; + char* text; + uint32_t bg_color; + uint32_t text_color; +} TextboxData; +void widget_draw(Widget* widget,FrameBuffer* fb){ + if(widget&&widget->draw){ + widget->draw(widget,fb); + } +} +void widget_update(Widget* widget,FrameBuffer* fb){ + if(widget&&widget->update){ + widget->update(widget,fb); + } +} +void widget_handle_event(Widget* widget,int mouse_x,int mouse_y,int event){ + if (!widget) return; + if (mouse_x >= widget->x && mouse_x < widget->x + widget->width && + mouse_y >= widget->y && mouse_y < widget->y + widget->height) { + + if (event == EVENT_MOUSE_CLICK && widget->onClick) { + widget->onClick(widget, mouse_x, mouse_y, 1); // Assuming left button for now + } else if (event == EVENT_MOUSE_RELEASE && widget->onRelease) { + widget->onRelease(widget, mouse_x, mouse_y, 1); // Assuming left button for now + } else if (event == EVENT_MOUSE_HOVER && widget->onHover) { + widget->onHover(widget, mouse_x, mouse_y); + } else if (event == EVENT_MOUSE_MOVE && widget->onMove) { + widget->onMove(widget, mouse_x, mouse_y); + } + } +} +void widget_add(Widget** head,Widget* new_widget){ + if(!head||!new_widget)return; + new_widget->next=*head; + *head=new_widget; +} +void widget_remove(Widget** head,Widget* widget){ + if(!head||!widget)return; + if(*head==widget){ + *head=widget->next; + return; + } + Widget* current=*head; + while(current&¤t->next!=widget){ + current=current->next; + } + if(current){ + current->next=widget->next; + } +} +void widget_free(Widget* widget){ + if(!widget)return; + if(widget->data)free(widget->data); + free(widget); +} +void widget_free_all(Widget** head){ + if(!head)return; + Widget* current=*head; + while(current){ + Widget* next=current->next; + widget_free(current); + current=next; + } + *head=NULL; +} +void widget_draw_all(Widget* head,FrameBuffer* fb){ + Widget* current=head; + while(current){ + widget_draw(current,fb); + current=current->next; + } +} +void widget_update_all(Widget* head,FrameBuffer* fb){ + Widget* current=head; + while(current){ + widget_update(current,fb); + current=current->next; + } +} +void widget_handle_event_all(Widget* head,int mouse_x,int mouse_y,int event){ + Widget* current=head; + while(current){ + widget_handle_event(current,mouse_x,mouse_y,event); + current=current->next; + } +} +Widget* create_label(int x,int y,int width,int height,char* text,uint32_t color){ + LabelData* data=(LabelData*)malloc(sizeof(LabelData)); + if(!data)return NULL; + data->text=text; + data->color=color; + Widget* widget=(Widget*)malloc(sizeof(Widget)); + if(!widget){ + free(data); + return NULL; + } + widget->x=x; + widget->y=y; + widget->width=width; + widget->height=height; + widget->data=data; + widget->draw=draw_label; + widget->update=update_label; + return widget; +} +Widget* create_button(int x,int y,int width,int height,char* text,uint32_t base_color,uint32_t hover_color,uint32_t press_color,uint32_t border_color,int border_width,uint32_t text_color,uint32_t press_border,uint32_t hover_border){ + ButtonData* data=(ButtonData*)malloc(sizeof(ButtonData)); + if(!data)return NULL; + data->text=text; + data->base_color=base_color; + data->hover_color=hover_color; + data->press_color=press_color; + data->border_color=border_color; + data->border_width=border_width; + data->text_color=text_color; + data->press_border=press_border; + data->hover_border=hover_border; + Widget* widget=(Widget*)malloc(sizeof(Widget)); + if(!widget){ + free(data); + return NULL; + } + widget->x=x; + widget->y=y; + widget->width=width; + widget->height=height; + widget->data=data; + widget->draw=draw_button; + widget->update=update_button; + widget->onClick=handle_button_click; + widget->onRelease=handle_button_release; + widget->onHover=handle_button_hover; + widget->onMove=NULL; + return widget; +} +Widget* create_textbox(int x,int y,int width,int height,char* placeholder,uint32_t bg_color,uint32_t text_color){ + TextboxData* data=(TextboxData*)malloc(sizeof(TextboxData)); + if(!data)return NULL; + data->placeholder=placeholder; + data->bg_color=bg_color; + data->text_color=text_color; + data->text=(char*)malloc(256); // Fixed size for simplicity + if(!data->text){ + free(data); + return NULL; + } + data->text[0]='\0'; + Widget* widget=(Widget*)malloc(sizeof(Widget)); + if(!widget){ + free(data->text); + free(data); + return NULL; + } + widget->x=x; + widget->y=y; + widget->width=width; + widget->height=height; + widget->data=data; + widget->draw=draw_textbox; + widget->update=update_textbox; + return widget; +} + +typedef struct { + uint32_t bg_color; + uint32_t thumb_color; + int thumb_pos; + int thumb_size; +} ScrollbarData; +Widget* create_scrollbar(int x,int y,int width,int height,uint32_t bg_color,uint32_t thumb_color){ + ScrollbarData* data=(ScrollbarData*)malloc(sizeof(ScrollbarData)); + if(!data)return NULL; + data->bg_color=bg_color; + data->thumb_color=thumb_color; + data->thumb_pos=0; + data->thumb_size=height/4; // Example size + Widget* widget=(Widget*)malloc(sizeof(Widget)); + if(!widget){ + free(data); + return NULL; + } + widget->x=x; + widget->y=y; + widget->width=width; + widget->height=height; + widget->data=data; + widget->draw=draw_scrollbar; + widget->update=update_scrollbar; + return widget; +} +void init_widget_system(){ + // Initialize default font + // g_widget_font=load_font("default_font_path"); // Placeholder path + + // if(!g_widget_font){ + // Fallback to built-in font + // g_widget_font=get_builtin_font(); + // } + if(!g_widget_font){ + // If still no font, log error + vga_print_string("Failed to load widget font\n"); + } + // Initialize other widget system components if needed +} + \ No newline at end of file diff --git a/widget.h b/widget.h new file mode 100644 index 0000000..71c2c75 --- /dev/null +++ b/widget.h @@ -0,0 +1,94 @@ +#ifndef WIDGET_H +#define WIDGET_H +#include "graphics.h" +#include "font.h" +#include +struct Widget; +typedef enum { + WIDGET_LABEL, + WIDGET_BUTTON, + WIDGET_CHECKBOX, + WIDGET_RADIOBUTTON, + WIDGET_SCROLLBAR, + WIDGET_LISTBOX, + WIDGET_PANEL, + WIDGET_TEXTBOX, + WIDGET_TEXTAREA, + WIDGET_COMBOBOX, + WIDGET_TABLE, + WIDGET_TREE, + WIDGET_GRAPH, + WIDGET_DIALOG, + WIDGET_SPINNER, + WIDGET_CANVAS, + WIDGET_PROGRESSBAR, + WIDGET_FILECHOOSER, + WIDGET_COLORCHOOSER, + WIDGET_FONTCHOOSER, + WIDGET_SLIDER, + WIDGET_MENU, + WIDGET_TOGGLEBUTTON, + WIDGET_RADIOGROUP, + WIDGET_VOICEINPUT, + WIDGET_WINDOW +}WidgetType; + +typedef enum { + EVENT_MOUSE_CLICK = 1, + EVENT_MOUSE_RELEASE = 2, + EVENT_MOUSE_HOVER = 3, + EVENT_MOUSE_MOVE = 4, +} event_type_t; + +typedef struct Widget{ + WidgetType type; + int x,y,width,height; + void (*draw)(struct Widget* self,FrameBuffer* fb); + void (*update)(struct Widget* self,FrameBuffer* fb); + void (*onClick)(struct Widget* self,int mouse_x,int mouse_y,int button); + void (*onHover)(struct Widget* self,int mouse_x,int mouse_y); + void (*onRelease)(struct Widget* self,int mouse_x,int mouse_y,int button); + void (*onMove)(struct Widget* self,int mouse_x,int mouse_y); + void* data; + struct Widget* next; + +}Widget; +typedef struct{ + char* text; + uint32_t color; +} LabelData; +typedef struct{ + char* text; + uint32_t color; + uint32_t bg_color; + uint32_t border_color; + int border_width; + uint32_t base_color; + int base_width; + uint32_t text_color; + uint32_t press_color; + uint32_t press_border; + uint32_t hover_color; + uint32_t hover_border; +} ButtonData; +void init_widget_system(void); +void widget_set_font(Font* font); +void widget_draw_all(Widget* head,FrameBuffer* fb); +void widget_update_all(Widget* head,FrameBuffer* fb); +void widget_handle_event_all(Widget* head,int mouse_x,int mouse_y,int event); +void widget_add(Widget** head,Widget* new_widget); +void widget_remove(Widget** head,Widget* widget); +void widget_free(Widget* widget); +void widget_free_all(Widget** head); +void widget_update(Widget* widget,FrameBuffer* fb); +void widget_handle_event(Widget* widget,int mouse_x,int mouse_y,int event); + +Widget* create_label(int x,int y,int width,int height,char* text,uint32_t color); +Widget* create_textbox(int x,int y,int width,int height,char* placeholder,uint32_t bg_color,uint32_t text_color); +Widget* create_scrollbar(int x,int y,int width,int height,uint32_t bg_color,uint32_t thumb_color); +Widget* create_button(int x,int y,int width,int height,char* text,uint32_t base_color,uint32_t hover_color,uint32_t press_color,uint32_t border_color,int border_width,uint32_t text_color,uint32_t press_border,uint32_t hover_border); + +void widget_draw(Widget* widget, FrameBuffer* fb); +//Widget* create_checkbox(int x,int y,int width,int height,char* text,uint32_t color,uint32_t bg_color,uint32_t border_color,int border_width); + +#endif \ No newline at end of file diff --git a/widget.o b/widget.o new file mode 100644 index 0000000..95c96fd Binary files /dev/null and b/widget.o differ diff --git a/window.c b/window.c new file mode 100644 index 0000000..69748d0 --- /dev/null +++ b/window.c @@ -0,0 +1,310 @@ +#include "window.h" +#include +#include +#include "sync.h" +#include "dirty_rect.h" +#define WINDOW_BG_COLOR 0xECECEC +#define TITLE_BAR_COLOR 0x2C2C2C +#define TITLE_TEXT_COLOR 0xFFFFFF +#define TITLE_BAR_HEIGHT 25 +#define CLOSE_BUTTON_WIDTH 18 +#define CLOSE_BUTTON_HEIGHT 18 +#define CLOSE_BUTTON_MARGIN 4 +#define CLOSE_BUTTON_BG_COLOR 0xFF0000 // Red +#define CLOSE_BUTTON_HOVER_BG_COLOR 0xFF4444 // Brighter Red for hover +#define CLOSE_BUTTON_X_COLOR 0xFFFFFF // White +extern Font* g_widget_font; +extern Window* window_list_head; +extern Window* window_list_tail; +static spinlock_t wm_lock; +static Window* focused_window = NULL; +Window* create_window(int x,int y,int width,int height,const char* title,bool has_title_bar){ + Window* window=(Window*)malloc(sizeof(Window)); + if(!window)return NULL; + window->x=x; + window->y=y; + window->width=width; + window->height=height; + window->title=title; + window->has_title_bar=has_title_bar; + window->child_widgets_head=NULL; + window->child_widgets_tail=NULL; + window->next=NULL; + window->prev=NULL; + window->close_button_hovered = false; + return window; +} +void window_add_widget(Window* window,Widget* widget){ + if(!window||!widget)return; + if(!window->child_widgets_head){ + window->child_widgets_head=widget; + window->child_widgets_tail=widget; + }else{ + window->child_widgets_tail->next=widget; + window->child_widgets_tail=widget; + } + widget->next=NULL; // Ensure the new widget's next is NULL +} +void window_remove_widget(Window* window,Widget* widget){ + if(!window||!widget||!window->child_widgets_head)return; + if(window->child_widgets_head==widget){ + window->child_widgets_head=widget->next; + if(window->child_widgets_tail==widget){ + window->child_widgets_tail=NULL; + } + return; + } + Widget* current=window->child_widgets_head; + while(current&¤t->next!=widget){ + current=current->next; + } + if(current){ + current->next=widget->next; + if(window->child_widgets_tail==widget){ + window->child_widgets_tail=current; + } + } +} +void window_free_widgets(Window* window){ + if(!window)return; + Widget* current=window->child_widgets_head; + while(current){ + Widget* next=current->next; + if(current->data)free(current->data); + free(current); + current=next; + } + window->child_widgets_head=NULL; + window->child_widgets_tail=NULL; +} +void window_free(Window* window){ + if(!window)return; + window_free_widgets(window); + free(window); +} +void window_draw(Window* window,FrameBuffer* fb){ + if(!window)return; + // Draw window background + fill_rectangle(fb, window->x, window->y, window->width, window->height, WINDOW_BG_COLOR); + + // Draw title bar if present + if(window->has_title_bar&&window->title){ + fill_rectangle(fb, window->x, window->y, window->width, TITLE_BAR_HEIGHT, TITLE_BAR_COLOR); + + // Draw title text (centered) + if(g_widget_font){ + int text_width=strlen(window->title)*g_widget_font->char_width; + int text_height=g_widget_font->char_height; + int text_x=window->x+window->width/2-text_width/2; + int text_y=window->y+(TITLE_BAR_HEIGHT-text_height)/2; + draw_string(fb,g_widget_font,window->title,text_x,text_y,TITLE_TEXT_COLOR); + } + + // Draw close button + int btn_x = window->x + window->width - CLOSE_BUTTON_WIDTH - CLOSE_BUTTON_MARGIN; + int btn_y = window->y + (TITLE_BAR_HEIGHT - CLOSE_BUTTON_HEIGHT) / 2; + uint32_t btn_color = window->close_button_hovered ? CLOSE_BUTTON_HOVER_BG_COLOR : CLOSE_BUTTON_BG_COLOR; + fill_rectangle(fb, btn_x, btn_y, CLOSE_BUTTON_WIDTH, CLOSE_BUTTON_HEIGHT, btn_color); + + // Draw 'X' on the button + int x_margin = 4; + draw_line(fb, btn_x + x_margin, btn_y + x_margin, + btn_x + CLOSE_BUTTON_WIDTH - x_margin - 1, btn_y + CLOSE_BUTTON_HEIGHT - x_margin - 1, + CLOSE_BUTTON_X_COLOR); + draw_line(fb, btn_x + x_margin, btn_y + CLOSE_BUTTON_HEIGHT - x_margin - 1, + btn_x + CLOSE_BUTTON_WIDTH - x_margin - 1, btn_y + x_margin, + CLOSE_BUTTON_X_COLOR); + } + // Draw child widgets + widget_draw_all(window->child_widgets_head,fb); +} +void window_update(Window* window,FrameBuffer* fb){ + if(!window)return; + widget_update_all(window->child_widgets_head,fb); +} +void window_handle_event(Window* window,int mouse_x,int mouse_y,int event){ + if(!window)return; + widget_handle_event_all(window->child_widgets_head,mouse_x,mouse_y,event); +} +void window_on_click(Window* window,int mouse_x,int mouse_y,int button){ + (void)button; + if(!window)return; + widget_handle_event_all(window->child_widgets_head,mouse_x,mouse_y,EVENT_MOUSE_CLICK); +} +void window_on_release(Window* window,int mouse_x,int mouse_y,int button){ + (void)button; + if(!window)return; + widget_handle_event_all(window->child_widgets_head,mouse_x,mouse_y,EVENT_MOUSE_RELEASE); +} +void window_on_hover(Window* window,int mouse_x,int mouse_y){ + if(!window)return; + widget_handle_event_all(window->child_widgets_head,mouse_x,mouse_y,EVENT_MOUSE_HOVER); +} +void window_on_move(Window* window,int mouse_x,int mouse_y){ + if(!window)return; + widget_handle_event_all(window->child_widgets_head,mouse_x,mouse_y,EVENT_MOUSE_MOVE); +} + +void window_manager_init() { + spinlock_init(&wm_lock); +} + +void window_destroy(Window** head, Window** tail, Window* win_to_destroy) { + if (!win_to_destroy) return; + + spinlock_acquire(&wm_lock); + + // Unlink from the list + if (win_to_destroy->prev) { + win_to_destroy->prev->next = win_to_destroy->next; + } else { // It's the head + *head = win_to_destroy->next; + } + if (win_to_destroy->next) { + win_to_destroy->next->prev = win_to_destroy->prev; + } else { // It's the tail + *tail = win_to_destroy->prev; + } + + // Free associated widgets and the window itself + spinlock_release(&wm_lock); + + window_free_widgets(win_to_destroy); + free(win_to_destroy); +} + + +void window_bring_to_front(Window** head, Window** tail, Window* win) { + if (!win || *tail == win) { + return; // Already at the front or invalid window + } + + spinlock_acquire(&wm_lock); + + // Unlink from current position + if (win->prev) { + win->prev->next = win->next; + } else { // It's the head + *head = win->next; + } + + if (win->next) { + win->next->prev = win->prev; + } else { // It's the tail - this case should not happen if *tail != win + *tail = win->prev; + } + + // Add to the tail (front of the drawing order) + (*tail)->next = win; + win->prev = *tail; + win->next = NULL; + *tail = win; + + spinlock_release(&wm_lock); +} + +// State for window dragging, kept static within this file +static Window* dragged_window = NULL; +static int32_t drag_offset_x = 0; +static int32_t drag_offset_y = 0; + +void window_manager_handle_mouse(Window** head, Window** tail, int32_t mouse_x, int32_t mouse_y, uint8_t mouse_buttons, uint8_t last_buttons) { + + spinlock_acquire(&wm_lock); + + Window* top_win = *tail; + if (top_win) { + int btn_x = top_win->x + top_win->width - CLOSE_BUTTON_WIDTH - CLOSE_BUTTON_MARGIN; + int btn_y = top_win->y + (TITLE_BAR_HEIGHT - CLOSE_BUTTON_HEIGHT) / 2; + + if (mouse_x >= btn_x && mouse_x < btn_x + CLOSE_BUTTON_WIDTH && + mouse_y >= btn_y && mouse_y < btn_y + CLOSE_BUTTON_HEIGHT) { + top_win->close_button_hovered = true; + } else { + top_win->close_button_hovered = false; + } + } + + + // 1. Mouse button pressed + if ((mouse_buttons & 1) && !(last_buttons & 1)) { + // Iterate from top window (tail) to bottom to find which one was clicked + Window* win = *tail; + if (win) { // Only proceed if there is at least one window + // Check for close button click first + int btn_x = win->x + win->width - CLOSE_BUTTON_WIDTH - CLOSE_BUTTON_MARGIN; + int btn_y = win->y + (TITLE_BAR_HEIGHT - CLOSE_BUTTON_HEIGHT) / 2; + if (mouse_x >= btn_x && mouse_x < btn_x + CLOSE_BUTTON_WIDTH && + mouse_y >= btn_y && mouse_y < btn_y + CLOSE_BUTTON_HEIGHT) { + + window_destroy(head, tail, win); // This function handles its own locking + spinlock_release(&wm_lock); // Release lock before returning + return; // Exit immediately after destroying window + + } else if (mouse_x >= win->x && mouse_x < win->x + win->width && + mouse_y >= win->y && mouse_y < win->y + TITLE_BAR_HEIGHT) { + // It's a drag operation + dragged_window = win; + drag_offset_x = mouse_x - win->x; + drag_offset_y = mouse_y - win->y; + + window_bring_to_front(head, tail, win); + } else { + // Click was outside the top window's title bar, maybe handle widget clicks here in the future + } + } + } + + // 2. Mouse button released + if (!(mouse_buttons & 1) && (last_buttons & 1)) { + dragged_window = NULL; + } + + // 3. Mouse moved while dragging + if (dragged_window != NULL) { + // Invalidate the old position of the window before moving it + dirty_rect_add(dragged_window->x, dragged_window->y, dragged_window->width, dragged_window->height); + + dragged_window->x = mouse_x - drag_offset_x; + dragged_window->y = mouse_y - drag_offset_y; + } + + spinlock_release(&wm_lock); +} +void wm_process_mouse(int mouse_x,int mouse_y,uint8_t mouse_buttons,uint8_t last_buttons){ + window_manager_handle_mouse(&window_list_head,&window_list_tail,mouse_x,mouse_y,mouse_buttons,last_buttons); +} +void window_handle_key(char key){ + (void)key; + if(!window_list_tail)return; + // For now, just a placeholder to show where key handling would go. + // In a real implementation, you'd route this to the focused window's widgets. +} +void window_draw_all(Window* head,FrameBuffer* fb){ + spinlock_acquire(&wm_lock); + Window* current=head; + while(current){ + window_draw(current,fb); + current=current->next; + } + spinlock_release(&wm_lock); +} +void window_set_focus(Window* window){ + if(!window)return; + spinlock_acquire(&wm_lock); + window_bring_to_front(&window_list_head,&window_list_tail,window); + spinlock_release(&wm_lock); + focused_window=window; +} +Window* wm_get_focused_window(){ + return focused_window; +} +void window_update_all(Window* head,FrameBuffer* fb){ + spinlock_acquire(&wm_lock); + Window* current=head; + while(current){ + window_update(current,fb); + current=current->next; + } + spinlock_release(&wm_lock); +} \ No newline at end of file diff --git a/window.h b/window.h new file mode 100644 index 0000000..092dd33 --- /dev/null +++ b/window.h @@ -0,0 +1,35 @@ +#ifndef WINDOW_H +#define WINDOW_H +#include "graphics.h" +#include "widget.h" +#include +typedef struct Window { + int x,y,width,height; + const char* title; // Use const char* for simple, static titles + bool has_title_bar; + Widget* child_widgets_head; + Widget* child_widgets_tail; + struct Window* next; + struct Window* prev; + bool close_button_hovered; + +}Window; +void window_manager_init(void); +Window* create_window(int x,int y,int width,int height,const char* title,bool has_title_bar); +void window_add_widget(Window* window,Widget* widget); +void window_remove_widget(Window* window,Widget* widget); +void window_draw(Window* window,FrameBuffer* fb); +void window_update(Window* window,FrameBuffer* fb); +void window_on_click(Window* window,int mouse_x,int mouse_y,int button); +void window_on_hover(Window* window,int mouse_x,int mouse_y); +void window_on_release(Window* window,int mouse_x,int mouse_y,int button); +void window_on_move(Window* window,int mouse_x,int mouse_y); +void wm_process_mouse(int mouse_x,int mouse_y,uint8_t mouse_buttons,uint8_t last_buttons); +void window_destroy(Window** head, Window** tail, Window* win_to_destroy); +void window_bring_to_front(Window** head, Window** tail, Window* win); +void window_manager_handle_mouse(Window** head, Window** tail, int32_t mouse_x, int32_t mouse_y, uint8_t mouse_buttons, uint8_t last_buttons); +void wm_set_focus(Window* window); +void window_free_widgets(Window* window); +void window_handle_key(char key); +void window_free(Window* window); +#endif \ No newline at end of file diff --git a/window.o b/window.o new file mode 100644 index 0000000..97b6f5a Binary files /dev/null and b/window.o differ