diff --git a/Makefile b/Makefile index ce20bb0..d770a1d 100644 --- a/Makefile +++ b/Makefile @@ -43,14 +43,14 @@ disk: run: iso disk @if [ -n "$$DISPLAY" ] || [ -n "$$WAYLAND_DISPLAY" ]; then \ - qemu-system-i386 -cdrom $(ISO) -drive file=$(DATA_DISK),format=raw,if=ide,index=0,media=disk; \ + qemu-system-i386 -cdrom $(ISO) -drive file=$(DATA_DISK),format=raw,if=ide,index=0,media=disk -m 512M; \ else \ echo "No GUI display detected, falling back to nographic mode."; \ - qemu-system-i386 -cdrom $(ISO) -drive file=$(DATA_DISK),format=raw,if=ide,index=0,media=disk -nographic -serial mon:stdio; \ + qemu-system-i386 -cdrom $(ISO) -drive file=$(DATA_DISK),format=raw,if=ide,index=0,media=disk -nographic -serial mon:stdio -m 512M; \ fi run-nographic: iso disk - qemu-system-i386 -cdrom $(ISO) -drive file=$(DATA_DISK),format=raw,if=ide,index=0,media=disk -nographic -serial mon:stdio + qemu-system-i386 -cdrom $(ISO) -drive file=$(DATA_DISK),format=raw,if=ide,index=0,media=disk -nographic -serial mon:stdio -m 512M clean: rm -rf build diff --git a/src/ata.c b/src/ata.c index b0118bf..0daf19d 100644 --- a/src/ata.c +++ b/src/ata.c @@ -99,6 +99,11 @@ int ata_write_sector(uint32_t lba, const void *buffer) { return ata_wait_not_busy(); } +int ata_zero_sector(uint32_t lba) { + uint8_t sector[512] = {0}; + return ata_write_sector(lba, sector); +} + uint32_t ata_get_sector_count() { uint16_t buf[256]; ata_wait_not_busy(); diff --git a/src/fs/main.c b/src/fs/main.c new file mode 100644 index 0000000..03ca453 --- /dev/null +++ b/src/fs/main.c @@ -0,0 +1,690 @@ +#include "main.h" +#include "../kernel.h" +#include "../libc/main.h" +#include + +super_blockt_t mounted_superblock; +int disk_mounted = 0; + +void tfs_format() { + int total_blocks = ata_get_sector_count(); + + for (int i = 0; i < total_blocks; i++) { + ata_zero_sector(i); + } + + super_blockt_t new_superblock; + + new_superblock.total_blocks = total_blocks; + strncpy(new_superblock.magic, "TurtleFS", 8); + + new_superblock.bitmap_start = 1; + + // 1 Byte = 1 Block + new_superblock.bitmap_end = + new_superblock.bitmap_start + + ((total_blocks + 511) / 512) - 1; + + new_superblock.entries_start = + new_superblock.bitmap_end + 1; + + new_superblock.entries_end = + new_superblock.entries_start + + (total_blocks / 80); + + new_superblock.data_start = + new_superblock.entries_end + 1; + + new_superblock.version = 1; + + // write superblock + uint8_t superblock_sector[512] = {0}; + memcpy(superblock_sector, + &new_superblock, + sizeof(super_blockt_t)); + + ata_write_sector(0, superblock_sector); + + // ---- reserve metadata ---- + uint8_t bitmap_sector[512]; + + for (int i = new_superblock.bitmap_start; + i <= new_superblock.bitmap_end; + i++) { + + memset(bitmap_sector, 0, 512); + ata_read_sector(i, bitmap_sector); + + for (int j = 0; j < 512; j++) { + + int block = + ((i - new_superblock.bitmap_start) * 512) + + j; + + if (block <= new_superblock.entries_end) { + bitmap_sector[j] = 1; + } + } + + ata_write_sector(i, bitmap_sector); + } + tfs_mount(); + make_dir("/", -1); +} + +int tfs_mount() { + uint8_t sector[512]; + ata_read_sector(0, sector); + memcpy(&mounted_superblock, sector, sizeof(super_blockt_t)); + int is_turtle = strncmp(mounted_superblock.magic, "TurtleFS", 8); + if (is_turtle == 0) { // This is Turtle + disk_mounted = 1; + return 1; + } else { + return 0; + } +} + +int alloc_bitmap() { + uint8_t sector[512]; + + if (!disk_mounted) + return -1; + + for (int i = mounted_superblock.bitmap_start; + i <= mounted_superblock.bitmap_end; + i++) { + + ata_read_sector(i, sector); + + for (int j = 0; j < 512; j++) { + if (sector[j] == 0) { + sector[j] = 1; + ata_write_sector(i, sector); + + int block = + ((i - mounted_superblock.bitmap_start) + * 512) + j; + + return block; + } + } + } + + return -1; +} + +int get_entry_by_id(int id, fs_entry_t* out, + int* out_sector, + int* out_index) { + + uint8_t sector_buf[512]; + + for (int sector = mounted_superblock.entries_start; + sector <= mounted_superblock.entries_end; + sector++) { + + ata_read_sector(sector, sector_buf); + + fs_entry_t* entries = + (fs_entry_t*)sector_buf; + + for (int i = 0; i < 2; i++) { + + if (entries[i].name[0] == '\0') + continue; + + if (entries[i].id == id) { + + if (out) + memcpy(out, + &entries[i], + sizeof(fs_entry_t)); + + if (out_sector) + *out_sector = sector; + + if (out_index) + *out_index = i; + + return 0; + } + } + } + + return -1; +} + +int make_file(char* name, int parent, int size) { + if (strnlen(name, 64) == 64) + return -4; + fs_entry_t file; + memset(&file, 0, sizeof(fs_entry_t)); + int sectors = (size + 511) / 512; + int last_sector = -1; + file.type = 1; + file.extent_count = 1; + file.parent = parent; + file.size = size; + strncpy(file.name, name, 63); + file.name[63] = '\0'; + + for (int i = 0; i < sectors; i++) { + int sector = alloc_bitmap(); + + if (sector < 0) { + return -1; + } + + if (last_sector == -1) { + file.extents[0].start = sector; + file.extents[0].end = sector; + } else if (sector == last_sector + 1) { + file.extents[ + file.extent_count - 1 + ].end = sector; + } else { + + if (file.extent_count >= MAX_EXTENTS) { + return -2; + } + + file.extent_count++; + + file.extents[ + file.extent_count - 1 + ].start = sector; + + file.extents[ + file.extent_count - 1 + ].end = sector; + } + + last_sector = sector; + } + + // ---- search free entry block ---- + + uint8_t sector_buf[512]; + + for (int sector = + mounted_superblock.entries_start; + sector <= mounted_superblock.entries_end; + sector++) { + ata_read_sector(sector, sector_buf); + fs_entry_t* entries = + (fs_entry_t*)sector_buf; + + // 2 entries per sector + for (int i = 0; i < 2; i++) { + // empty = name[0] == 0 + if (entries[i].name[0] == '\0') { + file.id = ((sector - mounted_superblock.entries_start) * 2) + i; + memcpy( + &entries[i], + &file, + sizeof(fs_entry_t) + ); + + ata_write_sector( + sector, + sector_buf + ); + + return 0; + } + } + } + + return -3; // entry table full +} + +int make_dir(char* name, int parent_id) { + fs_entry_t dir; + memset(&dir, 0, sizeof(fs_entry_t)); + dir.type = 2; // folder + dir.extent_count = 0; + dir.parent = parent_id; + strncpy(dir.name, name, 63); + dir.name[63] = '\0'; + uint8_t sector_buf[512]; + + int is_root = (parent_id == -1); + + // search for free entry + for (int sector = + mounted_superblock.entries_start; + sector <= mounted_superblock.entries_end; + sector++) { + + ata_read_sector(sector, sector_buf); + fs_entry_t* entries = + (fs_entry_t*)sector_buf; + + // 2 entries per sector + for (int i = 0; i < 2; i++) { + // empty entry + if (entries[i].name[0] == '\0') { + // set id + if (is_root) { + dir.id = 0; + } else { + dir.id = ((sector - mounted_superblock.entries_start) * 2) + i; + } + + memcpy( + &entries[i], + &dir, + sizeof(fs_entry_t) + ); + + ata_write_sector( + sector, + sector_buf + ); + + return dir.id; + } + } + } + + return -1; +} + +int file_get_size(int id) { + fs_entry_t file; + + if (get_entry_by_id(id, &file, NULL, NULL) < 0) + return -1; + + if (file.type != 1) + return -1; + + return file.size; +} + +int file_read(int id, void* buffer) { + fs_entry_t file; + + if (get_entry_by_id(id, &file, NULL, NULL) < 0) + return -1; + + if (file.type != 1) + return -1; + + uint8_t* dst = (uint8_t*)buffer; + + for (int e = 0; e < file.extent_count; e++) { + + for (int sector = + file.extents[e].start; + sector <= file.extents[e].end; + sector++) { + + ata_read_sector( + sector, + dst + ); + + dst += 512; + } + } + + return 0; +} + +int file_delete(int id) { + fs_entry_t file; + int entry_sector; + int entry_index; + + if (get_entry_by_id( + id, + &file, + &entry_sector, + &entry_index) < 0) + return -1; + + if (file.type != 1) + return -1; + + uint8_t bitmap[512]; + + for (int e = 0; e < file.extent_count; e++) { + + for (int block = + file.extents[e].start; + block <= file.extents[e].end; + block++) { + + int bitmap_sector = + mounted_superblock.bitmap_start + + (block / 512); + + int bitmap_index = + block % 512; + + ata_read_sector( + bitmap_sector, + bitmap + ); + + bitmap[bitmap_index] = 0; + + ata_write_sector( + bitmap_sector, + bitmap + ); + } + } + + uint8_t sector_buf[512]; + + ata_read_sector( + entry_sector, + sector_buf + ); + + fs_entry_t* entries = + (fs_entry_t*)sector_buf; + + memset( + &entries[entry_index], + 0, + sizeof(fs_entry_t) + ); + + ata_write_sector( + entry_sector, + sector_buf + ); + + return 0; +} + +//You may ask why i don't use this function else? i'm too lazy just quickly slapped it together + +int remove_entry(int id) { + uint8_t sector_buf[512]; + + for (int sector = mounted_superblock.entries_start; + sector <= mounted_superblock.entries_end; + sector++) { + + ata_read_sector(sector, sector_buf); + fs_entry_t* entries = (fs_entry_t*)sector_buf; + + for (int i = 0; i < 2; i++) { + + if (entries[i].name[0] == '\0') + continue; + + if (entries[i].id != id) + continue; + + memset(&entries[i], 0, sizeof(fs_entry_t)); + ata_write_sector(sector, sector_buf); + return 0; + } + } + + return -1; +} + +int dir_delete(int id) { + if (id == 0) return -1; + uint8_t sector_buf[512]; + for (int sector = mounted_superblock.entries_start; + sector <= mounted_superblock.entries_end; + sector++) { + ata_read_sector(sector, sector_buf); + fs_entry_t* entries = (fs_entry_t*)sector_buf; + for (int i = 0; i < 2; i++) { + if (entries[i].name[0] == '\0') continue; + if (entries[i].parent != id) continue; + int child_id = entries[i].id; + int child_type = entries[i].type; + if (child_type == 1) + file_delete(child_id); + else if (child_type == 2) + dir_delete(child_id); + ata_read_sector(sector, sector_buf); + } + } + return remove_entry(id); +} + +int file_write(int id, const void* buffer, int size) { + fs_entry_t file; + int entry_sector; + int entry_index; + + if (file.size < size) { + int success = file_resize(id, size); + if (success != 0) { + return -1; + } + } + + if (get_entry_by_id( + id, + &file, + &entry_sector, + &entry_index) < 0) + return -1; + + if (file.type != 1) + return -1; + + const uint8_t* src = buffer; + int remaining = size; + + uint8_t sector_buf[512]; + + for (int e = 0; + e < file.extent_count && remaining > 0; + e++) { + + for (int sector = + file.extents[e].start; + sector <= file.extents[e].end && + remaining > 0; + sector++) { + + memset(sector_buf, 0, 512); + + int bytes = + remaining > 512 + ? 512 + : remaining; + + memcpy( + sector_buf, + src, + bytes + ); + + ata_write_sector( + sector, + sector_buf + ); + + src += bytes; + remaining -= bytes; + } + } + + file.size = size; + + ata_read_sector( + entry_sector, + sector_buf + ); + + fs_entry_t* entries = + (fs_entry_t*)sector_buf; + + memcpy( + &entries[entry_index], + &file, + sizeof(fs_entry_t) + ); + + ata_write_sector( + entry_sector, + sector_buf + ); + + return 0; +} + +int find_entry(char* name, int parent) { + uint8_t sector_buf[512]; + + for (int sector = + mounted_superblock.entries_start; + sector <= mounted_superblock.entries_end; + sector++) { + + ata_read_sector(sector, sector_buf); + + fs_entry_t* entries = + (fs_entry_t*)sector_buf; + + for (int i = 0; i < 2; i++) { + + if (entries[i].name[0] == '\0') + continue; + + if (entries[i].parent != parent) + continue; + + if (strncmp(entries[i].name, name, strlen(name)) == 0) + return entries[i].id; + } + } + + return -1; +} + +int list_dir(int parent, + fs_entry_t* out, + int max_entries) { + + uint8_t sector_buf[512]; + int count = 0; + + for (int sector = + mounted_superblock.entries_start; + sector <= mounted_superblock.entries_end; + sector++) { + + ata_read_sector(sector, sector_buf); + + fs_entry_t* entries = + (fs_entry_t*)sector_buf; + + for (int i = 0; i < 2; i++) { + + if (entries[i].name[0] == '\0') + continue; + + if (entries[i].parent != parent) + continue; + + if (count >= max_entries) + return count; + + memcpy( + &out[count], + &entries[i], + sizeof(fs_entry_t) + ); + + count++; + } + } + + return count; +} + +int file_resize(int id, int new_size) { + fs_entry_t file; + int entry_sector; + int entry_index; + + if (get_entry_by_id(id, &file, &entry_sector, &entry_index) < 0) + return -1; + + if (file.type != 1) + return -1; + + int old_sectors = 0; + for (int e = 0; e < file.extent_count; e++) + old_sectors += file.extents[e].end - file.extents[e].start + 1; + + int new_sectors = (new_size + 511) / 512; + + if (new_sectors < old_sectors) { + int to_free = old_sectors - new_sectors; + uint8_t bitmap[512]; + + for (int e = file.extent_count - 1; e >= 0 && to_free > 0; e--) { + while (file.extents[e].end >= file.extents[e].start && to_free > 0) { + int block = file.extents[e].end; + + int bitmap_sector = mounted_superblock.bitmap_start + (block / 512); + int bitmap_index = block % 512; + + ata_read_sector(bitmap_sector, bitmap); + bitmap[bitmap_index] = 0; + ata_write_sector(bitmap_sector, bitmap); + + file.extents[e].end--; + to_free--; + } + + if (file.extents[e].end < file.extents[e].start) { + file.extent_count--; + } + } + + } else if (new_sectors > old_sectors) { + int to_alloc = new_sectors - old_sectors; + + for (int i = 0; i < to_alloc; i++) { + int block = alloc_bitmap(); + if (block < 0) + return -2; + + int last_extent = file.extent_count - 1; + + if (block == file.extents[last_extent].end + 1) { + file.extents[last_extent].end++; + } else { + if (file.extent_count >= MAX_EXTENTS) + return -3; + file.extent_count++; + file.extents[file.extent_count - 1].start = block; + file.extents[file.extent_count - 1].end = block; + } + } + } + + file.size = new_size; + + uint8_t sector_buf[512]; + ata_read_sector(entry_sector, sector_buf); + fs_entry_t* entries = (fs_entry_t*)sector_buf; + memcpy(&entries[entry_index], &file, sizeof(fs_entry_t)); + ata_write_sector(entry_sector, sector_buf); + + return 0; +} + +int total_sectors_mounted() { + if (disk_mounted) { + return mounted_superblock.total_blocks; + } + return -1; +} diff --git a/src/fs/main.h b/src/fs/main.h new file mode 100644 index 0000000..e695396 --- /dev/null +++ b/src/fs/main.h @@ -0,0 +1,44 @@ +#include + +#define MAX_EXTENTS 16 + +typedef struct { + char magic[8]; // TurtleFS + uint32_t version; // version of the filesystem + uint32_t bitmap_start; // start of the bitmap + uint32_t bitmap_end; // end of the bitmap + uint32_t entries_start; + uint32_t entries_end; + uint32_t total_blocks; // total blocks of device + uint32_t data_start; // start of data +} super_blockt_t; + +typedef struct { + uint32_t start; // start of the extent + uint32_t end; // end of the extent +} fs_extent_t; + +typedef struct { + char name[64]; + int type; // 1 means it's a file, 2 means it's a folder + int size; + fs_extent_t extents[MAX_EXTENTS]; + int extent_count; + int parent; // parent folder + int id; // own id +} fs_entry_t; + +void tfs_format(); +int total_sectors_mounted(); +int make_dir(char* name, int parent_id); +int make_file(char* name, int parent, int size); +int file_get_size(int id); +int file_read(int id, void* buffer); +int file_write(int id, const void* buffer, int size); +int file_delete(int id); +int dir_delete(int id); +int find_entry(char* name, int parent); +int list_dir(int parent, fs_entry_t* out, int max_entries); +int get_entry_by_id(int id, fs_entry_t* out, int* out_sector, int* out_index); +int file_resize(int id, int new_size); +int tfs_mount(); diff --git a/src/kernel.h b/src/kernel.h index c21322e..e640029 100644 --- a/src/kernel.h +++ b/src/kernel.h @@ -55,6 +55,7 @@ void outb(uint16_t port, uint8_t value); // ---------------- ATA ---------------- int ata_read_sector(uint32_t lba, void *buffer); int ata_write_sector(uint32_t lba, const void *buffer); +int ata_zero_sector(uint32_t lba); uint32_t ata_get_sector_count(); // ---------------- SYSTEM ---------------- diff --git a/src/libc/main.c b/src/libc/main.c index 2b09087..c8bb1e1 100644 --- a/src/libc/main.c +++ b/src/libc/main.c @@ -1,4 +1,5 @@ #include +#include void* memcpy(void* dest, const void* src, unsigned int n) { uint32_t* d32 = (uint32_t*)dest; @@ -19,6 +20,21 @@ void* memcpy(void* dest, const void* src, unsigned int n) { return dest; } +char *strchr(const char *str, int c) { + while (*str) + { + if (*str == (char)c) + return (char *)str; + + str++; + } + + if (c == '\0') + return (char *)str; + + return NULL; +} + int strncmp(const char *a, const char *b, uint32_t n) { for (uint32_t i = 0; i < n; i++) { if (a[i] != b[i]) @@ -55,6 +71,22 @@ char *strncpy(char *dst, const char *src, uint32_t n) { return dst; } +int strlen(char* str) { + int len = 0; + for (int i = 0; str[i] != '\0'; i++) { + len++; + } + return len; +} + +int strnlen(char* str, int maxlen) { + int len = 0; + for (int i = 0; str[i] != '\0' && len < maxlen; i++) { + len++; + } + return len; +} + uint32_t string_to_hex(const char *str) { uint32_t result = 0; if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) { diff --git a/src/libc/main.h b/src/libc/main.h index c5b0820..c7f21b3 100644 --- a/src/libc/main.h +++ b/src/libc/main.h @@ -2,7 +2,10 @@ uint32_t string_to_hex(const char *str); int memcmp(const void *a, const void *b, uint32_t n); +char *strchr(const char *str, int c); char *strncpy(char *dst, const char *src, uint32_t n); void *memset(void *dst, int val, uint32_t n); int strncmp(const char *a, const char *b, uint32_t n); +int strlen(char* str); +int strnlen(char* str, int len); void* memcpy(void* dest, const void* src, unsigned int n); diff --git a/src/mouse/mouse.c b/src/mouse/mouse.c index 1c710f9..99fe866 100644 --- a/src/mouse/mouse.c +++ b/src/mouse/mouse.c @@ -36,12 +36,14 @@ void mouse_irq_handler() { int dx = (int8_t)mouse_packet[1]; int dy = (int8_t)mouse_packet[2]; + mouse.last_x = mouse.x; + mouse.last_y = mouse.y; mouse.x += dx; mouse.y -= dy; mouse.left = mouse_packet[0] & 1; mouse.right = mouse_packet[0] & 2; mouse.middle = mouse_packet[0] & 4; - update_cursor(mouse.x + dx, mouse.y - dy); + //update_cursor(mouse.x + dx, mouse.y - dy); } static void ps2mouse_write(uint8_t data) { diff --git a/src/mouse/mouse.h b/src/mouse/mouse.h index eaed5b3..d33e460 100644 --- a/src/mouse/mouse.h +++ b/src/mouse/mouse.h @@ -9,6 +9,8 @@ extern uint8_t mouse_cycle; typedef struct { int x; int y; + int last_x; + int last_y; uint8_t left; uint8_t right; uint8_t middle; diff --git a/src/mouse/render.h b/src/mouse/render.h index b33629e..6334227 100644 --- a/src/mouse/render.h +++ b/src/mouse/render.h @@ -1 +1,2 @@ +void save_cursor_bg(int x, int y); void update_cursor(int new_x, int new_y); diff --git a/src/multitasking/assembly.asm b/src/multitasking/assembly.asm index 45aa6d5..47eea31 100644 --- a/src/multitasking/assembly.asm +++ b/src/multitasking/assembly.asm @@ -2,9 +2,11 @@ global timer_stub extern schedule extern current_task extern tasks +extern pit_ticks timer_stub: cli + inc dword [pit_ticks] pusha mov eax, [current_task] imul eax, 44 diff --git a/src/multitasking/task.c b/src/multitasking/task.c index a880fb0..f5b9186 100644 --- a/src/multitasking/task.c +++ b/src/multitasking/task.c @@ -18,6 +18,7 @@ const int TASK_SIZE = sizeof(task_t); int current_task = -1; int tasks_count = 0; +volatile uint32_t pit_ticks = 0; task_t tasks[MAX_TASKS]; diff --git a/src/multitasking/task.h b/src/multitasking/task.h index 2388ce0..8e800db 100644 --- a/src/multitasking/task.h +++ b/src/multitasking/task.h @@ -10,4 +10,5 @@ void tasks_get_info(task_info_t* input, int max_tasks); int add_task(void (*func), char* name, int stack_size); int disable_task(int id); int enable_task(int id); +extern volatile uint32_t pit_ticks; int get_task_count(); diff --git a/src/shell.c b/src/shell.c index 304d3e8..abb0099 100644 --- a/src/shell.c +++ b/src/shell.c @@ -5,7 +5,9 @@ #include "multitasking/task.h" #include "arch/idt.h" #include "arch/gdt.h" +#include "wm/main.h" #include "keyboard/keyboard.h" +#include "fs/main.h" #include "display.h" #include "pci/pci.h" #include "pit/pit.h" @@ -31,6 +33,8 @@ static user_db_sector_t g_user_db; static int g_logged_in = 0; static char g_current_user[USERNAME_MAX + 1]; +int current_dir_id = 0; + static int streq(const char *a, const char *b) { while (*a && *b) { if (*a != *b) { @@ -757,6 +761,214 @@ static void run_command(const char *cmd) { return; } + if (starts_with(cmd, "wm ")) { + const char* color_str = cmd + 3; + uint32_t color_int = string_to_hex(color_str); + wm_background_color = color_int; + int window = create_window("Test", 100, 100); + window_pixel_chessboard(window); + add_task(wm_render, "Window Manager", 8096); + return; + } + + if (streq(cmd, "ls")) { + + fs_entry_t entries[64]; + + int count = list_dir( + current_dir_id, + entries, + 64 + ); + + for (int i = 0; i < count; i++) { + char* entry = entries[i].name; + + + console_writefln( + "%s %s", + entries[i].type == 2 + ? "" + : "", + entries[i].name + ); + } + + return; + } + + if (starts_with(cmd, "cd ")) { + const char* name = cmd + 3; + + if (name[0] == '-') { + fs_entry_t entry; + get_entry_by_id(current_dir_id, &entry, NULL, NULL); + current_dir_id = entry.parent; + return; + } + + int id = find_entry( + (char*)name, + current_dir_id + ); + + if (id < 0) { + console_writefln("Directory not found", true, 0, 0); + return; + } + + fs_entry_t entry; + + if (get_entry_by_id( + id, + &entry, + NULL, + NULL + ) < 0) { + return; + } + + if (entry.type != 2) { + console_writefln("Not a directory", true, 0, 0); + return; + } + + current_dir_id = id; + return; + } + + if (starts_with(cmd, "mkdir ")) { + + const char* name = cmd + 6; + + int id = make_dir( + (char*)name, + current_dir_id + ); + + console_writefln( + "Directory created (%d)", + id + ); + + return; + } + + if (starts_with(cmd, "touch ")) { + + const char* name = cmd + 6; + + int id = make_file( + (char*)name, + current_dir_id, + 1024 + ); + + console_writefln( + "File created (%d)", + id + ); + + return; + } + + if (starts_with(cmd, "cat ")) { + + const char* name = cmd + 4; + + int id = find_entry( + (char*)name, + current_dir_id + ); + + if (id < 0) { + console_writefln("File not found"); + return; + } + + int size = file_get_size(id); + + char* buffer = malloc(size + 1); + + file_read(id, buffer); + + buffer[size] = '\0'; + + console_writefln("%s", buffer); + + free(buffer); + + return; + } + + if (starts_with(cmd, "write ")) { + + char* filename = cmd + 6; + + char* text = strchr(filename, ' '); + + if (!text) { + console_writefln("Usage: write "); + return; + } + + *text = '\0'; + text++; + + int id = find_entry( + filename, + current_dir_id + ); + + if (id < 0) { + console_writefln("File not found"); + return; + } + + file_write( + id, + text, + strlen(text) + ); + + console_writefln("Written"); + + return; + } + + if (starts_with(cmd, "rm ")) { + const char* name = cmd + 3; + + int id = find_entry( + (char*)name, + current_dir_id + ); + + if (id < 0) { + console_writefln("Not found"); + return; + } + + fs_entry_t entry; + + get_entry_by_id( + id, + &entry, + NULL, + NULL + ); + + if (entry.type == 1) { + file_delete(id); + } else { + dir_delete(id); + } + + console_writefln("Deleted"); + + return; + } + if (streq(cmd, "whoami")) { if (g_logged_in) { console_writeln(g_current_user); @@ -846,6 +1058,15 @@ void shell() { console_writeln(" "); set_console_fg_color(0xFFFFFF); pci_enumerate(&g_pci_bus); + if (!tfs_mount()) { + console_writeln("Seems like you're not formated to TFS!"); + tfs_format(); + tfs_mount(); + } + int disk_size_bytes = ata_get_sector_count() * 512; + console_writefln("Disk size(sectors): %d", ata_get_sector_count()); + console_writefln("Disk size(KiB): %d", disk_size_bytes / 1024); + console_writefln("Disk size(MiB): %d", disk_size_bytes / (1024 * 1024)); auth_boot_flow(); //console_writeln(" "); int new_prompt = 1; diff --git a/src/wm/main.c b/src/wm/main.c new file mode 100644 index 0000000..fd55919 --- /dev/null +++ b/src/wm/main.c @@ -0,0 +1,557 @@ +// ---- includes ---- + +#include "windows.h" +#include "../libc/main.h" +#include +#include +#include +#include "../memory/main.h" +#include "../mouse/mouse.h" +#include "../mouse/render.h" +#include "../keyboard/keyboard.h" +#include "../multitasking/task.h" +#include "../display.h" +#include "../pit/pit.h" + +window_t windows[MAX_WINDOWS]; +int window_count = 0; +int highest_z = 0; +static int last_mouse_left = 0; +uint32_t wm_background_color; +uint32_t* backbuffer; +uint32_t* framebuffer; +#define TASKBAR_HEIGHT 28 + +// ---- backbuffer primitives ---- + +void bf_draw_pixel(int x, int y, uint32_t c) { + if (x < 0 || y < 0 || x >= screen.width || y >= screen.height) return; + backbuffer[screen.width * y + x] = c; +} + +void bf_draw_rect(int x, int y, int w, int h, uint32_t c) { + for (int yy = 0; yy < h; yy++) { + for (int xx = 0; xx < w; xx++) { + bf_draw_pixel(x + xx, y + yy, c); + } + } +} + +void clear(uint32_t* buf, uint32_t color) { + int size = screen.width * screen.height; + for (int i = 0; i < size; i++) { + buf[i] = color; + } +} +// Window rendering API +int window_draw_pixel(int window, int x, int y, uint32_t color) { + if (window <= 0 || window > window_count) + return -1; + window_t* w = &windows[window]; + w->framebuffer[y * w->x + x] = color; + return 0; +} + +int window_draw_rect(int window, int x, int y, int w, int h, uint32_t color) { + if (window <= 0 || window > window_count) + return -1; + + window_t* w2 = &windows[window]; + + for (int yy = y; yy < (y + h); yy++) { + for (int xx = x; xx < (x + w); xx++) { + w2->framebuffer[yy * w2->x + xx] = color; + } + } + return 0; +} + +int window_draw_char(int window, int x, int y, char c, int size, uint32_t fg, uint32_t bg) { + if (window <- 0 || window > window_count) + return -1; + window_t* w = &windows[window]; + for (int row = 0; row < 16; row++) { + uint8_t line = font_bin[(uint8_t)c * 16 + row]; + for (int col = 0; col < 8; col++) { + uint32_t pixel_color = (line & (1 << (7 - col))) ? fg : bg; + for (int dy = 0; dy < size; dy++) { + for (int dx = 0; dx < size; dx++) { + int px = x + col * size + dx; + int py = y + row * size + dy; + w->framebuffer[py * w->x + px] = pixel_color; + } + } + } + } + return 0; +} + +int window_printf(int window, int x, int y, int size, uint32_t fg, uint32_t bg, const char* fmt, ...) { + if (window <= 0 || window > window_count) + return -1; + va_list args; + va_start(args, fmt); + char buffer[32]; + int cx = x; + + for (int i = 0; fmt[i] != '\0'; i++) { + if (fmt[i] == '%') { + i++; + + if (fmt[i] == 's') { + char* s = va_arg(args, char*); + for (int j = 0; s[j] != '\0'; j++) { + window_draw_char(window, cx, y, s[j], size, fg, bg); + cx += FONT_SIZE * size; + } + } + else if (fmt[i] == 'd') { + itoa(va_arg(args, int), buffer, 10); + for (int j = 0; buffer[j] != '\0'; j++) { + window_draw_char(window, cx, y, buffer[j], size, fg, bg); + cx += FONT_SIZE * size; + } + } + else if (fmt[i] == 'x') { + itoa(va_arg(args, int), buffer, 16); + for (int j = 0; buffer[j] != '\0'; j++) { + window_draw_char(window, cx, y, buffer[j], size, fg, bg); + cx += FONT_SIZE * size; + } + } + else if (fmt[i] == 'c') { + char c = (char)va_arg(args, int); + window_draw_char(window, cx, y, c, size, fg, bg); + cx += FONT_SIZE * size; + } + else if (fmt[i] == '%') { + window_draw_char(window, cx, y, '%', size, fg, bg); + cx += FONT_SIZE * size; + } + } else { + window_draw_char(window, cx, y, fmt[i], size, fg, bg); + cx += FONT_SIZE * size; + } + } + + va_end(args); + return 0; +} + +// ---- Checks ---- +int window_pixel_chessboard(int window) { + if (window < 0 || window >= window_count) return -1; + + window_t* w = &windows[window]; + + for (int y = 0; y < w->h; y++) { + for (int x = 0; x < w->w; x++) { + + uint32_t color = ((x + y) & 1) ? 0x000000 : 0xFFFFFF; + + w->framebuffer[y * w->w + x] = color; + } + } + + return 0; +} + +// ---- text rendering ---- + +void bf_draw_char(int x, int y, char c, int size, uint32_t fg, uint32_t bg) { + for (int row = 0; row < 16; row++) { + uint8_t line = font_bin[(uint8_t)c * 16 + row]; + + for (int col = 0; col < 8; col++) { + uint32_t color = (line & (1 << (7 - col))) ? fg : bg; + + for (int dy = 0; dy < size; dy++) { + for (int dx = 0; dx < size; dx++) { + bf_draw_pixel( + x + col * size + dx, + y + row * size + dy, + color + ); + } + } + } + } +} + +void bf_printf(int x, int y, int size, uint32_t fg, uint32_t bg, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + + char buffer[64]; + int cx = x; + + for (int i = 0; fmt[i] != '\0'; i++) { + + if (fmt[i] == '%') { + i++; + + if (fmt[i] == 's') { + char* s = va_arg(args, char*); + + if (!s) s = "(null)"; + + for (int j = 0; s[j] != '\0'; j++) { + bf_draw_char(cx, y, s[j], size, fg, bg); + cx += 8 * size; + } + } + + else if (fmt[i] == 'd') { + itoa(va_arg(args, int), buffer, 10); + + for (int j = 0; buffer[j] != '\0'; j++) { + bf_draw_char(cx, y, buffer[j], size, fg, bg); + cx += 8 * size; + } + } + + else if (fmt[i] == 'x') { + itoa(va_arg(args, int), buffer, 16); + + for (int j = 0; buffer[j] != '\0'; j++) { + bf_draw_char(cx, y, buffer[j], size, fg, bg); + cx += 8 * size; + } + } + + else if (fmt[i] == 'c') { + char c = (char)va_arg(args, int); + bf_draw_char(cx, y, c, size, fg, bg); + cx += 8 * size; + } + + else if (fmt[i] == '%') { + bf_draw_char(cx, y, '%', size, fg, bg); + cx += 8 * size; + } + } + + else { + bf_draw_char(cx, y, fmt[i], size, fg, bg); + cx += 8 * size; + } + } + + va_end(args); +} + + +// ---- input drag ---- + +static int drag_window = -1; +static int last_mouse_x = 0; +static int last_mouse_y = 0; + +// ---- z-order helper ---- + +void bring_window_to_front(int id) { + if (windows[id].z == highest_z) return; + if (id < 0 || id >= window_count) return; + + highest_z++; + windows[id].z = highest_z; + drag_window = -1; +} + +// ---- window clear ---- +int clear_window(int window) { + if (window <= 0 || window > window_count) + return -1; + + window_t* w = &windows[window]; + for (int x = 0; x < w->x; x++) { + for (int y = 0; y < w->y; y++) { + w->framebuffer[y * w->w + x] = 0x000000; + } + } + return 0; +} + + +// ---- window creation ---- + +int create_window(char* name, int width, int height) { + if (window_count >= MAX_WINDOWS) return -1; + + window_t* w = &windows[window_count]; + + w->framebuffer = malloc(width * height * sizeof(uint32_t)); + if (!w->framebuffer) return -1; + + strncpy(w->title, name, sizeof(w->title) - 1); + w->title[sizeof(w->title) - 1] = '\0'; + + w->w = width; + w->h = height; + + int sw, sh; + get_screen_res(&sw, &sh); + + w->x = sw / 2 - width / 2; + w->y = sh / 2 - height / 2; + + highest_z++; + w->z = highest_z; + + window_count++; + //clear_window((window_count - 1)); + return window_count - 1; +} + +// ---- window rendering ---- + +void draw_window(int id) { + window_t* w = &windows[id]; + + int x0 = w->x; + int y0 = w->y; + + // ---- titlebar ---- + bf_draw_rect(x0, y0 - 20, w->w, 20, 0x444444); + + // ---- title text ---- + bf_printf(x0 + 4, y0 - 16, 1, 0xFFFFFF, 0x444444, w->title); + + // ---- window content ---- + for (int y = 0; y < w->h; y++) { + for (int x = 0; x < w->w; x++) { + bf_draw_pixel( + x0 + x, + y0 + y, + w->framebuffer[y * w->w + x] + ); + } + } +} + +// ---- taskbar ---- +void draw_taskbar() { + int sw, sh; + get_screen_res(&sw, &sh); + + int y = sh - TASKBAR_HEIGHT; + + // ---- background ---- + bf_draw_rect(0, y, sw, TASKBAR_HEIGHT, 0x222222); + + // ---- top border ---- + bf_draw_rect(0, y, sw, 1, 0x555555); + + int offset_x = 4; + + for (int i = 0; i < window_count; i++) { + window_t* w = &windows[i]; + + int btn_w = 90; + int btn_h = 20; + int btn_x = offset_x; + int btn_y = y + 4; + + if (btn_x + btn_w > sw) + break; + + // ---- hover ---- + int hovered = + mouse.x >= btn_x && + mouse.x < btn_x + btn_w && + mouse.y >= btn_y && + mouse.y < btn_y + btn_h; + + uint32_t color = hovered ? 0x555555 : 0x444444; + + // ---- active window ---- + if (w->z == highest_z) + color = 0x666666; + + // ---- button ---- + bf_draw_rect( + btn_x, + btn_y, + btn_w, + btn_h, + color + ); + + // ---- title ---- + bf_printf( + btn_x + 4, + btn_y + 4, + 1, + 0xFFFFFF, + color, + w->title + ); + + // ---- click --- + int clicked = mouse.left && !last_mouse_left; + if (hovered && clicked) { + bring_window_to_front(i); + } + + offset_x += btn_w + 4; + } +} + +// ---- cursor ---- + +// ---- cursor shape ---- + +static const uint16_t cursor_shape[16] = { + 0b1000000000000000, + 0b1100000000000000, + 0b1110000000000000, + 0b1111000000000000, + 0b1111100000000000, + 0b1111110000000000, + 0b1111111000000000, + 0b1111111100000000, + 0b1111111110000000, + 0b1111111111000000, + 0b1111100000000000, + 0b1101100000000000, + 0b1000110000000000, + 0b0000110000000000, + 0b0000011000000000, + 0b0000011000000000, +}; + +// ---- cursor draw ---- + +void bf_draw_cursor(int mx, int my) { + for (int y = 0; y < 16; y++) { + uint16_t row = cursor_shape[y]; + + for (int x = 0; x < 16; x++) { + if (row & (1 << (15 - x))) { + bf_draw_pixel(mx + x, my + y, 0xFFFFFF); + } + } + } +} + +// ---- drag update ---- + +void wm_update_drag(int mouse_btn) { + if (!mouse_btn) { + drag_window = -1; + return; + } + + if (drag_window != -1) { + bring_window_to_front(drag_window); + + if (drag_window < 0 || drag_window >= window_count) { + drag_window = -1; + return; + } + + window_t* w = &windows[drag_window]; + int dx = mouse.x - last_mouse_x; + int dy = mouse.y - last_mouse_y; + w->x += dx; + w->y += dy; + } + + else { + for (int i = window_count - 1; i >= 0; i--) { + + window_t* w = &windows[i]; + + if (mouse.x >= w->x && + mouse.x < w->x + w->w && + mouse.y >= w->y - 20 && + mouse.y < w->y) { + + drag_window = i; + break; + } + } + } + + last_mouse_x = mouse.x; + last_mouse_y = mouse.y; +} + +// ---- framebuffer flip ---- + +void screen_flip() { + int size = screen.width * screen.height * sizeof(uint32_t); + memcpy(framebuffer, backbuffer, size); +} + +// ---- draw all windows sort by z ---- + +void draw_all_windows() { + for (int i = 0; i < window_count; i++) { + for (int j = i + 1; j < window_count; j++) { + + if (windows[j].z < windows[i].z) { + window_t tmp = windows[i]; + windows[i] = windows[j]; + windows[j] = tmp; + } + } + } + + for (int i = 0; i < window_count; i++) { + draw_window(i); + } +} + +// test window +int test_window_id; + +void test_window_task() { + while (1) { + int x = (100 - (8 / 2)); + int y = (100 - (16 / 2)); + char c = getchar(); + window_printf(test_window_id, x, y, 1, 0xFFFFFF, 0x000000, "%s", c); + } +} + +void test_window() { + test_window_id = create_window("Key", 100, 100); + add_task(test_window_task, "Test Window Task", 4096); +} + + +// ---- render loop ---- + +int wm_running; + +void wm_render() { + uint32_t last_tick = 0; + const uint32_t TICKS_PER_FRAME = 2; + disable_task(0); + clear_screen(); + int sw, sh; + get_screen_res(&sw, &sh); + backbuffer = malloc(sw * sh * sizeof(uint32_t)); + framebuffer = (uint32_t*)screen.buffer; + wm_running = 1; + //test_window(); + + while (wm_running) { + if (pit_ticks - last_tick >= TICKS_PER_FRAME) { + last_tick = pit_ticks; + clear(backbuffer, wm_background_color); + draw_all_windows(); + draw_taskbar(); + wm_update_drag(mouse.left); + bf_draw_cursor(mouse.x, mouse.y); + screen_flip(); + last_mouse_left = mouse.left; + } + + __asm__ volatile("hlt"); + } + free(backbuffer); + enable_task(0); + clear_screen(); +} diff --git a/src/wm/main.h b/src/wm/main.h new file mode 100644 index 0000000..22b7329 --- /dev/null +++ b/src/wm/main.h @@ -0,0 +1,10 @@ +#include + +extern uint32_t wm_background_color; +int create_window(char* name, int width, int height); +int window_draw_rect(int window, int x, int y, int w, int h, uint32_t color); +int window_draw_pixel(int window, int x, int y, uint32_t color); +int window_draw_char(int window, int x, int y, char c, int size, uint32_t fg, uint32_t bg); +int window_printf(int window, int x, int y, int size, uint32_t fg, uint32_t bg, const char* fmt, ...); +int window_pixel_chessboard(int window); +void wm_render(); diff --git a/src/wm/windows.h b/src/wm/windows.h new file mode 100644 index 0000000..da77092 --- /dev/null +++ b/src/wm/windows.h @@ -0,0 +1,15 @@ +#include +#include + +#define MAX_WINDOWS 32 + +typedef struct window { + int x, y, w, h; + int old_x, old_y; + int z; + bool focused; + bool dragging; + uint32_t* framebuffer; + int fb_changed; + char title[64]; +} window_t;