Kernel V3.0.0

This commit is contained in:
boreddevnl
2026-02-25 22:59:50 +01:00
parent ca997072ce
commit 73a34edd0e
81 changed files with 272886 additions and 13685 deletions

View File

@@ -14,8 +14,8 @@ static void about_paint(Window *win) {
// Version info
draw_string(offset_x, offset_y + 105, "BoredOS 'Panda'", COLOR_WHITE);
draw_string(offset_x, offset_y + 120, "BoredOS Version 1.63", COLOR_WHITE);
draw_string(offset_x, offset_y + 135, "Kernel Version 2.5.3", COLOR_WHITE);
draw_string(offset_x, offset_y + 120, "BoredOS Version 1.64", COLOR_WHITE);
draw_string(offset_x, offset_y + 135, "Kernel Version 3.0.0", COLOR_WHITE);
// Copyright
draw_string(offset_x, offset_y + 150, "(C) 2026 boreddevnl.", COLOR_WHITE);

View File

@@ -1,10 +0,0 @@
#ifndef CALCULATOR_H
#define CALCULATOR_H
#include "wm.h"
extern Window win_calculator;
void calculator_init(void);
#endif

View File

@@ -2,6 +2,6 @@
void cli_cmd_boredver(char *args) {
(void)args;
cli_write("BoredOS v1.63\n");
cli_write("BoredOS Kernel V2.5.3\n");
cli_write("BoredOS v1.64\n");
cli_write("BoredOS Kernel V3.0.0\n");
}

View File

@@ -9,7 +9,6 @@ extern Window win_editor;
extern Window win_explorer;
extern Window win_cmd;
extern Window win_notepad;
extern Window win_calculator;
void cli_cmd_txtedit(char *args) {
// Parse the file path argument
@@ -52,7 +51,6 @@ void cli_cmd_txtedit(char *args) {
if (win_explorer.z_index > max_z) max_z = win_explorer.z_index;
if (win_cmd.z_index > max_z) max_z = win_cmd.z_index;
if (win_notepad.z_index > max_z) max_z = win_notepad.z_index;
if (win_calculator.z_index > max_z) max_z = win_calculator.z_index;
win_editor.z_index = max_z + 1;
cli_write("Opening: ");

View File

@@ -4,13 +4,13 @@
#include "io.h"
#include "rtc.h"
#include "notepad.h"
#include "calculator.h"
#include "fat32.h"
#include "disk.h"
#include "cli_apps/cli_apps.h"
#include "licensewr.h"
#include <stddef.h>
#include "memory_manager.h"
#include "process.h"
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
@@ -61,6 +61,9 @@ static char pager_wrapped_lines[2000][CMD_COLS + 1];
static int pager_total_lines = 0;
static int pager_top_line = 0;
// Process Execution State
bool cmd_is_waiting_for_process = false;
// Boot time for uptime
int boot_time_init = 0;
@@ -147,6 +150,13 @@ static void cmd_history_add(const char *cmd) {
}
static void cmd_print_prompt(void) {
// Clear the current line to prevent old output from corrupting the new command buffer
for (int i = 0; i < CMD_COLS; i++) {
screen_buffer[cursor_row][i].c = 0;
screen_buffer[cursor_row][i].color = current_color;
}
cursor_col = 0;
char buf[5];
buf[0] = cmd_state ? cmd_state->current_drive : 'A';
buf[1] = ':';
@@ -235,6 +245,10 @@ void cmd_putchar(char c) {
cmd_scroll_up();
cursor_row = CMD_ROWS - 1;
}
// Trigger repaint so output from syscalls is immediately visible
wm_mark_dirty(win_cmd.x, win_cmd.y, win_cmd.w, win_cmd.h);
wm_refresh();
}
// Public for CLI apps to use
@@ -265,6 +279,23 @@ void cmd_write_int(int n) {
cmd_write(buf);
}
void cmd_write_hex(uint64_t n) {
const char* digits = "0123456789ABCDEF";
char buf[19];
buf[0] = '0';
buf[1] = 'x';
buf[18] = '\0';
for (int i = 17; i >= 2; i--) {
buf[i] = digits[n & 0xF];
n >>= 4;
}
cmd_write(buf);
}
int cmd_get_cursor_col(void) {
return cursor_col;
}
// --- Pager Logic ---
// Public for CLI apps to use - clear the terminal screen
@@ -524,7 +555,6 @@ static void internal_cmd_txtedit(char *args) {
extern Window win_explorer;
extern Window win_cmd;
extern Window win_notepad;
extern Window win_calculator;
win_editor.visible = true;
win_editor.focused = true;
@@ -534,7 +564,6 @@ static void internal_cmd_txtedit(char *args) {
if (win_explorer.z_index > max_z) max_z = win_explorer.z_index;
if (win_cmd.z_index > max_z) max_z = win_cmd.z_index;
if (win_notepad.z_index > max_z) max_z = win_notepad.z_index;
if (win_calculator.z_index > max_z) max_z = win_calculator.z_index;
win_editor.z_index = max_z + 1;
cmd_write("Opening: ");
@@ -580,7 +609,59 @@ static void internal_cmd_ls(char *args) {
kfree(files);
}
// --- Commands (now delegated to cli_apps/) ---
void cmd_exec_elf(char *args) {
if (!args || args[0] == '\0') {
cmd_write("Usage: exec <filename>\n");
return;
}
char full_exec_path[512] = {0};
int i = 0;
if (args[0] && args[1] != ':') {
if (cmd_state) {
full_exec_path[i++] = cmd_state->current_drive;
full_exec_path[i++] = ':';
const char *dir = cmd_state->current_dir;
while (*dir && i < 509) {
full_exec_path[i++] = *dir++;
}
if (i > 2 && full_exec_path[i-1] != '/') {
full_exec_path[i++] = '/';
}
}
const char *p = args;
while (*p && i < 509) {
full_exec_path[i++] = *p++;
}
full_exec_path[i] = 0;
} else {
// Just copy what they provided
const char *p = args;
while (*p && i < 511) {
full_exec_path[i++] = *p++;
}
full_exec_path[i] = 0;
}
cmd_is_waiting_for_process = true;
process_create_elf(full_exec_path);
}
// Public API for syscall exit
void cmd_process_finished(void) {
if (cmd_is_waiting_for_process) {
cmd_is_waiting_for_process = false;
extern int cursor_col;
void cmd_putchar(char c);
if (cursor_col > 0) {
cmd_putchar('\n');
}
cmd_print_prompt();
}
}
// Command dispatch table
typedef struct {
@@ -589,6 +670,8 @@ typedef struct {
} CommandEntry;
static const CommandEntry commands[] = {
{"EXEC", cmd_exec_elf},
{"exec", cmd_exec_elf},
{"HELP", cli_cmd_help},
{"help", cli_cmd_help},
{"DATE", cli_cmd_date},
@@ -1060,44 +1143,66 @@ static void cmd_exec_single(char *cmd) {
}
}
// Check for executable in /Apps/
char app_path[256];
int app_idx = 0;
// Check for executable in Current Directory or A:/bin/
char search_path[512];
// Add drive letter if on different drive
if (cmd_state && cmd_state->current_drive != 'A') {
app_path[app_idx++] = cmd_state->current_drive;
app_path[app_idx++] = ':';
}
const char *prefix = "/Apps/";
while (*prefix) app_path[app_idx++] = *prefix++;
char *c = cmd;
while (*c && app_idx < 255) app_path[app_idx++] = *c++;
app_path[app_idx] = 0;
FAT32_FileHandle *app_fh = fat32_open(app_path, "r");
if (app_fh) {
uint8_t *app_buffer = (uint8_t*)kmalloc(VM_MEMORY_SIZE);
if (app_buffer) {
int size = fat32_read(app_fh, app_buffer, VM_MEMORY_SIZE);
fat32_close(app_fh);
if (size > 0) {
int res = vm_exec(app_buffer, size);
if (res != 0) {
cmd_write("Execution failed (invalid format or runtime error).\n");
}
} else {
cmd_write("Error: Empty file.\n");
}
kfree(app_buffer);
} else {
fat32_close(app_fh);
cmd_write("Error: Out of memory.\n");
// Check if the command already ends in .elf (case insensitive)
bool has_elf_ext = false;
int cmd_len = cmd_strlen(cmd);
if (cmd_len > 4) {
const char *ext = cmd + cmd_len - 4;
if ((ext[0] == '.' && (ext[1] == 'e' || ext[1] == 'E') &&
(ext[2] == 'l' || ext[2] == 'L') && (ext[3] == 'f' || ext[3] == 'F'))) {
has_elf_ext = true;
}
return;
}
// 1. Try Current Directory + .elf
if (cmd_state) {
int idx = 0;
search_path[idx++] = cmd_state->current_drive;
search_path[idx++] = ':';
const char *dir = cmd_state->current_dir;
while (*dir && idx < 500) search_path[idx++] = *dir++;
if (idx > 2 && search_path[idx-1] != '/') search_path[idx++] = '/';
const char *c = cmd;
while (*c && idx < 500) search_path[idx++] = *c++;
if (!has_elf_ext) {
search_path[idx++] = '.'; search_path[idx++] = 'e'; search_path[idx++] = 'l'; search_path[idx++] = 'f';
}
search_path[idx] = 0;
FAT32_FileHandle *fh = fat32_open(search_path, "r");
if (fh) {
fat32_close(fh);
cmd_is_waiting_for_process = true;
process_create_elf(search_path);
return;
}
}
// 2. Try A:/bin/ + .elf
{
int idx = 0;
const char *bin_prefix = "A:/bin/";
while (*bin_prefix) search_path[idx++] = *bin_prefix++;
const char *c = cmd;
while (*c && idx < 500) search_path[idx++] = *c++;
if (!has_elf_ext) {
search_path[idx++] = '.'; search_path[idx++] = 'e'; search_path[idx++] = 'l'; search_path[idx++] = 'f';
}
search_path[idx] = 0;
FAT32_FileHandle *fh = fat32_open(search_path, "r");
if (fh) {
fat32_close(fh);
cmd_is_waiting_for_process = true;
process_create_elf(search_path);
return;
}
}
cmd_write("Unknown command: ");
cmd_write(cmd);
@@ -1402,7 +1507,9 @@ static void cmd_key(Window *target, char c) {
cmd_exec(cmd_buf);
cmd_print_prompt();
if (!cmd_is_waiting_for_process) {
cmd_print_prompt();
}
} else if (c == 17) { // UP
if (history_len > 0) {
if (history_pos == -1) {
@@ -1476,6 +1583,8 @@ static void create_test_files(void) {
if (!fat32_exists("Apps")) fat32_mkdir("Apps");
if (!fat32_exists("Desktop")) fat32_mkdir("Desktop");
if (!fat32_exists("RecycleBin")) fat32_mkdir("RecycleBin");
if (!fat32_exists("bin")) fat32_mkdir("bin");
// Always try to write README to ensure content exists
@@ -1676,7 +1785,6 @@ static void create_test_files(void) {
void cmd_init(void) {
fat32_init(); // Init FAT32 filesystem
create_test_files();
win_cmd.title = "Command Prompt";

View File

@@ -12,6 +12,8 @@ void cmd_reset(void);
void cmd_write(const char *str);
void cmd_putchar(char c);
void cmd_write_int(int n);
void cmd_write_hex(uint64_t n);
int cmd_get_cursor_col(void);
void cmd_screen_clear(void);
void cmd_increment_msg_count(void);

143
src/kernel/elf.c Normal file
View File

@@ -0,0 +1,143 @@
#include "elf.h"
#include "fat32.h"
#include "memory_manager.h"
#include "paging.h"
#include "platform.h"
extern void serial_print(const char *s);
extern void serial_write(const char *str);
static void print_hex(uint64_t n) {
char buf[17];
char* x = "0123456789ABCDEF";
buf[16] = 0;
for (int i=15; i>=0; i--) { buf[i] = x[n & 0xF]; n >>= 4; }
serial_write(buf);
}
uint64_t elf_load(const char *path, uint64_t user_pml4) {
FAT32_FileHandle *file = fat32_open(path, "r");
if (!file || !file->valid) {
serial_write("[ELF] Error: Failed to open file ");
serial_write(path);
serial_write("\n");
return 0;
}
// Read the ELF Header
Elf64_Ehdr ehdr;
if (fat32_read(file, &ehdr, sizeof(Elf64_Ehdr)) != sizeof(Elf64_Ehdr)) {
serial_write("[ELF] Error: Could not read ELF Header\n");
fat32_close(file);
return 0;
}
// Validate Magic Number & Properties
if (ehdr.e_ident[0] != ELFMAG0 || ehdr.e_ident[1] != ELFMAG1 ||
ehdr.e_ident[2] != ELFMAG2 || ehdr.e_ident[3] != ELFMAG3) {
serial_write("[ELF] Error: Invalid ELF Magic Number\n");
fat32_close(file);
return 0;
}
if (ehdr.e_ident[4] != ELFCLASS64) {
serial_write("[ELF] Error: Not a 64-bit ELF\n");
fat32_close(file);
return 0;
}
if (ehdr.e_ident[5] != ELFDATA2LSB) {
serial_write("[ELF] Error: Not Little Endian\n");
fat32_close(file);
return 0;
}
if (ehdr.e_type != ET_EXEC && ehdr.e_type != ET_DYN) {
serial_write("[ELF] Error: Not an Executable\n");
fat32_close(file);
return 0;
}
if (ehdr.e_machine != EM_X86_64) {
serial_write("[ELF] Error: Not x86_64 Architecture\n");
fat32_close(file);
return 0;
}
serial_write("[ELF] Number of program headers: ");
print_hex(ehdr.e_phnum);
serial_write("\n");
// Iterate Over Program Headers
for (int i = 0; i < ehdr.e_phnum; i++) {
fat32_seek(file, ehdr.e_phoff + (i * ehdr.e_phentsize), 0);
Elf64_Phdr phdr;
if (fat32_read(file, &phdr, sizeof(Elf64_Phdr)) != sizeof(Elf64_Phdr)) {
serial_write("[ELF] Error: Failed to read Program Header\n");
continue;
}
serial_write("[ELF] Header type parsed: ");
print_hex(phdr.p_type);
serial_write("\n");
// Only load segments with type PT_LOAD
if (phdr.p_type == PT_LOAD) {
uint64_t p_vaddr = phdr.p_vaddr;
uint64_t p_memsz = phdr.p_memsz;
uint64_t p_filesz = phdr.p_filesz;
uint64_t p_offset = phdr.p_offset;
serial_write("[ELF] Loaded PT_LOAD segment vaddr=");
print_hex(p_vaddr);
serial_write("\n");
if (p_memsz == 0) continue;
// Calculate page-aligned boundaries
uint64_t align_offset = p_vaddr & 0xFFF;
uint64_t start_page = p_vaddr & ~0xFFF;
uint64_t num_pages = (p_memsz + align_offset + 0xFFF) / 4096;
// Allocate and Map Pages
for (uint64_t p = 0; p < num_pages; p++) {
uint64_t vaddr = start_page + (p * 4096);
void* phys = kmalloc_aligned(4096, 4096);
if (!phys) {
serial_write("[ELF] Error: Out of memory mapping PT_LOAD\n");
fat32_close(file);
return 0;
}
// Determine Flags
uint64_t flags = 0x07; // Present, RW, User
paging_map_page(user_pml4, vaddr, v2p((uint64_t)phys), flags);
// Initialize page memory
uint8_t* dest = (uint8_t*)phys;
for (int j=0; j<4096; j++) dest[j] = 0; // zero memory (handles BSS)
// If loading from file
if (p_filesz > 0) {
uint64_t copy_start_offset = 0;
uint64_t file_seek_pos = p_offset;
uint64_t bytes_to_copy = 4096;
if (p == 0) {
copy_start_offset = align_offset;
bytes_to_copy = 4096 - align_offset;
} else {
file_seek_pos += (p * 4096) - align_offset;
}
if (bytes_to_copy > p_filesz) {
bytes_to_copy = p_filesz;
}
if (bytes_to_copy > 0) {
fat32_seek(file, file_seek_pos, 0);
fat32_read(file, dest + copy_start_offset, bytes_to_copy);
p_filesz -= bytes_to_copy;
}
}
}
}
}
fat32_close(file);
return ehdr.e_entry;
}

74
src/kernel/elf.h Normal file
View File

@@ -0,0 +1,74 @@
#ifndef ELF_H
#define ELF_H
#include <stdint.h>
typedef uint16_t Elf64_Half;
typedef uint32_t Elf64_Word;
typedef int32_t Elf64_Sword;
typedef uint64_t Elf64_Xword;
typedef int64_t Elf64_Sxword;
typedef uint64_t Elf64_Addr;
typedef uint64_t Elf64_Off;
#define EI_NIDENT 16
typedef struct {
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
Elf64_Half e_type; /* Object file type */
Elf64_Half e_machine; /* Architecture */
Elf64_Word e_version; /* Object file version */
Elf64_Addr e_entry; /* Entry point virtual address */
Elf64_Off e_phoff; /* Program header table file offset */
Elf64_Off e_shoff; /* Section header table file offset */
Elf64_Word e_flags; /* Processor-specific flags */
Elf64_Half e_ehsize; /* ELF header size in bytes */
Elf64_Half e_phentsize; /* Program header table entry size */
Elf64_Half e_phnum; /* Program header table entry count */
Elf64_Half e_shentsize; /* Section header table entry size */
Elf64_Half e_shnum; /* Section header table entry count */
Elf64_Half e_shstrndx; /* Section header string table index */
} Elf64_Ehdr;
typedef struct {
Elf64_Word p_type; /* Segment type */
Elf64_Word p_flags; /* Segment flags */
Elf64_Off p_offset; /* Segment file offset */
Elf64_Addr p_vaddr; /* Segment virtual address */
Elf64_Addr p_paddr; /* Segment physical address */
Elf64_Xword p_filesz; /* Segment size in file */
Elf64_Xword p_memsz; /* Segment size in memory */
Elf64_Xword p_align; /* Segment alignment */
} Elf64_Phdr;
/* e_ident constants */
#define ELFMAG0 0x7f
#define ELFMAG1 'E'
#define ELFMAG2 'L'
#define ELFMAG3 'F'
#define ELFCLASS64 2
#define ELFDATA2LSB 1
#define EV_CURRENT 1
/* e_type constants */
#define ET_EXEC 2
#define ET_DYN 3
/* e_machine constants */
#define EM_X86_64 62
/* p_type constants */
#define PT_LOAD 1
/* p_flags constants */
#define PF_X 1
#define PF_W 2
#define PF_R 4
#include <stdbool.h>
// Loads the ELF executable at 'path' using fat32 into the pagemap given by user_pml4.
// Returns entry point address on success, or 0 on failure.
uint64_t elf_load(const char *path, uint64_t user_pml4);
#endif

View File

@@ -8,7 +8,7 @@
#include "markdown.h"
#include "cmd.h"
#include "notepad.h"
#include "calculator.h"
#include "process.h"
#include "minesweeper.h"
#include "viewer.h"
#include "control_panel.h"
@@ -816,7 +816,9 @@ static void explorer_open_target(const char *path) {
if (fat32_is_directory(path)) {
explorer_open_directory(path);
} else {
if (explorer_is_markdown_file(path)) {
if (explorer_str_ends_with(path, ".elf")) {
process_create_elf(path);
} else if (explorer_is_markdown_file(path)) {
wm_bring_to_front(&win_markdown);
markdown_open_file(path);
} else if (explorer_str_ends_with(path, ".pnt")) {
@@ -853,7 +855,7 @@ static void explorer_open_item(Window *win, int index) {
if (explorer_strcmp(state->items[index].name, "Notepad.shortcut") == 0) {
target = &win_notepad;
} else if (explorer_strcmp(state->items[index].name, "Calculator.shortcut") == 0) {
target = &win_calculator;
process_create_elf("/bin/calculator.elf"); return;
} else if (explorer_strcmp(state->items[index].name, "Terminal.shortcut") == 0) {
target = &win_cmd; cmd_reset();
} else if (explorer_strcmp(state->items[index].name, "Minesweeper.shortcut") == 0) {
@@ -916,6 +918,8 @@ static void explorer_draw_file_icon(int x, int y, bool is_dir, uint32_t color, c
if (full_path[explorer_strlen(full_path) - 1] != '/') explorer_strcat(full_path, "/");
explorer_strcat(full_path, filename);
draw_image_icon(x + 5, y + 5, full_path);
} else if (explorer_str_ends_with(filename, ".elf")) {
draw_elf_icon(x + 5, y + 5, "");
} else {
draw_document_icon(x + 5, y + 5, "");
}
@@ -1782,7 +1786,6 @@ static void explorer_handle_file_context_menu_click(Window *win, int x, int y) {
for (int i = 0; i < explorer_win_count; i++) if (explorer_wins[i]->z_index > max_z) max_z = explorer_wins[i]->z_index;
if (win_cmd.z_index > max_z) max_z = win_cmd.z_index;
if (win_notepad.z_index > max_z) max_z = win_notepad.z_index;
if (win_calculator.z_index > max_z) max_z = win_calculator.z_index;
if (win_editor.z_index > max_z) max_z = win_editor.z_index;
if (win_markdown.z_index > max_z) max_z = win_markdown.z_index;
if (win_control_panel.z_index > max_z) max_z = win_control_panel.z_index;

View File

@@ -9,7 +9,6 @@ extern Window win_explorer;
extern Window win_editor;
extern Window win_cmd;
extern Window win_notepad;
extern Window win_calculator;
extern Window win_markdown;
#define EXPLORER_MAX_FILES 64

View File

@@ -1301,9 +1301,17 @@ int fat32_seek(FAT32_FileHandle *handle, int offset, int whence) {
handle->position = new_position;
// For RealFS, we might need to walk cluster chain to update handle->cluster
// if we seeked far.
if (handle->drive != 'A') {
// Both RealFS and RAMFS must accurately re-walk their cluster chains
if (handle->drive == 'A') {
handle->cluster = handle->start_cluster;
uint32_t pos = 0;
while (pos + FAT32_CLUSTER_SIZE <= handle->position) {
uint32_t next = fat_table[handle->cluster];
if (next >= 0xFFFFFFF8) break;
handle->cluster = next;
pos += FAT32_CLUSTER_SIZE;
}
} else {
// Re-walk to find current cluster
int vol_idx = handle->drive - 'A';
FAT32_Volume *vol = &volumes[vol_idx];

View File

@@ -283,7 +283,7 @@ void draw_char(int x, int y, char c, uint32_t color) {
if (uc > 127) return;
// Fast rejection: if the character is entirely outside the clipping/dirty rect, skip it
if (g_clip_enabled) {
if (g_clip_enabled && !g_render_target) {
if (x + 8 <= g_clip_x || x >= g_clip_x + g_clip_w ||
y + 8 <= g_clip_y || y >= g_clip_y + g_clip_h) {
return;
@@ -460,3 +460,26 @@ void graphics_set_clipping(int x, int y, int w, int h) {
void graphics_clear_clipping(void) {
g_clip_enabled = false;
}
void graphics_blit_buffer(uint32_t *src, int dst_x, int dst_y, int w, int h) {
if (!g_fb || !src) return;
int sw = get_screen_width();
int sh = get_screen_height();
for (int y = 0; y < h; y++) {
int vy = dst_y + y;
if (vy < 0 || vy >= sh) continue;
for (int x = 0; x < w; x++) {
int vx = dst_x + x;
if (vx < 0 || vx >= sw) continue;
uint32_t pcol = src[y * w + x];
// Alpha blending support:
// If the alpha byte is 0, we treat it as transparent ONLY if the color is also 0.
// This handles common 0xRRGGBB as opaque.
if ((pcol & 0xFF000000) != 0 || (pcol & 0xFFFFFF) != 0) {
g_back_buffer[vy * sw + vx] = pcol;
}
}
}
}

View File

@@ -23,6 +23,7 @@ void graphics_set_bg_color(uint32_t color);
void graphics_set_bg_pattern(const uint32_t *pattern); // 128x128 pattern
void graphics_set_bg_image(uint32_t *pixels, int w, int h); // Full-screen wallpaper image
void graphics_set_render_target(uint32_t *buffer, int w, int h);
void graphics_blit_buffer(uint32_t *src, int dst_x, int dst_y, int w, int h);
void draw_boredos_logo(int x, int y, int scale);

23
src/kernel/gui_ipc.h Normal file
View File

@@ -0,0 +1,23 @@
#ifndef GUI_IPC_H
#define GUI_IPC_H
#define GUI_CMD_WINDOW_CREATE 1
#define GUI_CMD_DRAW_RECT 2
#define GUI_CMD_DRAW_STRING 3
#define GUI_CMD_MARK_DIRTY 4
#define GUI_CMD_GET_EVENT 5
#define GUI_CMD_DRAW_ROUNDED_RECT_FILLED 6
#define GUI_EVENT_NONE 0
#define GUI_EVENT_PAINT 1
#define GUI_EVENT_CLICK 2
#define GUI_EVENT_RIGHT_CLICK 3
#define GUI_EVENT_CLOSE 4
typedef struct {
int type;
int arg1; // For click: x
int arg2; // For click: y
} gui_event_t;
#endif

View File

@@ -16,17 +16,43 @@ static void print_hex(uint64_t val) {
serial_write(buf);
}
void exception_handler_c(uint64_t vector, uint64_t err_code, uint64_t rip, uint64_t cr2) {
#include "process.h"
#include "cmd.h"
uint64_t exception_handler_c(registers_t *regs) {
uint64_t vector = regs->int_no;
uint64_t rip = regs->rip;
uint64_t cr2;
asm volatile("mov %%cr2, %0" : "=r"(cr2));
serial_write("\n*** EXCEPTION ***\nVector: ");
print_hex(vector);
serial_write("\nError Code: ");
print_hex(err_code);
print_hex(regs->err_code);
serial_write("\nRIP: ");
print_hex(rip);
serial_write("\nCR2: ");
print_hex(cr2);
serial_write("\nCPU HALTED.\n");
// Mirror to shell
if (cmd_get_cursor_col() != 0) cmd_write("\n");
cmd_write("*** EXCEPTION ***\nVector: "); cmd_write_hex(vector);
cmd_write("\nError Code: "); cmd_write_hex(regs->err_code);
cmd_write("\nRIP: "); cmd_write_hex(rip);
cmd_write("\nCR2: "); cmd_write_hex(cr2);
cmd_write("\n");
// Filter by CS selector to check if we are in user mode (RPL=3)
if ((regs->cs & 0x3) != 0) {
serial_write("\nUSER MODE EXCEPTION - Terminating process.\n");
cmd_write("USER MODE EXCEPTION - Terminating process.\n");
return process_terminate_current();
}
serial_write("\nKERNEL PANIC - CPU HALTED.\n");
cmd_write("KERNEL PANIC - CPU HALTED.\n");
while(1) { asm volatile("cli; hlt"); }
return (uint64_t)regs; // Unreachable but for completeness
}
#define IDT_ENTRIES 256

View File

@@ -18,7 +18,10 @@ send_eoi:
pop rax
ret
%macro ISR_NOERRCODE 1
%macro ISR_NOERRCODE 2
isr%2_wrapper:
push 0 ; Dummy error code
push %2 ; Vector
push rax
push rbx
push rcx
@@ -35,7 +38,7 @@ send_eoi:
push r14
push r15
; Pass current RSP as 1st argument
; Pass current RSP as 1st argument (registers_t*)
mov rdi, rsp
call %1
@@ -58,17 +61,18 @@ send_eoi:
pop rcx
pop rbx
pop rax
add rsp, 16 ; drop dummy vector and error code
iretq
%endmacro
isr0_wrapper:
ISR_NOERRCODE timer_handler
ISR_NOERRCODE timer_handler, 32
isr1_wrapper:
ISR_NOERRCODE keyboard_handler
ISR_NOERRCODE keyboard_handler, 33
isr12_wrapper:
ISR_NOERRCODE mouse_handler
ISR_NOERRCODE mouse_handler, 44
; Common exception macro
%macro EXCEPTION_ERRCODE 1
@@ -101,16 +105,14 @@ exception_common:
push r14
push r15
; Call C handler: void exception_handler_c(uint64_t vector, uint64_t err_code, uint64_t rip, uint64_t cr2)
; Stack right now: 15 registers (15*8=120 bytes), then vector (8), then err_code (8), then RIP (8), CS (8), RFLAGS (8), RSP (8), SS (8)
mov rdi, [rsp + 120] ; vector
mov rsi, [rsp + 128] ; err_code
mov rdx, [rsp + 136] ; RIP
mov rcx, cr2 ; CR2
; Call C handler: uint64_t exception_handler_c(registers_t *regs)
mov rdi, rsp
call exception_handler_c
; Restore (in case we want to return, but usually we halt)
; Switch stack if needed (for process termination)
mov rsp, rax
; Restore (in case we want to return, but usually we halt if kernel)
pop r15
pop r14
pop r13

View File

@@ -11,6 +11,7 @@
#include "ps2.h"
#include "wm.h"
#include "io.h"
#include "fat32.h"
#include "memory_manager.h"
#include "platform.h"
#include "wallpaper.h"
@@ -32,10 +33,17 @@ static volatile struct limine_memmap_request memmap_request = {
.revision = 0
};
__attribute__((used, section(".requests")))
static volatile struct limine_module_request module_request = {
.id = LIMINE_MODULE_REQUEST,
.revision = 0
};
__attribute__((used, section(".requests_start")))
static volatile struct limine_request *const requests_start_marker[] = {
(struct limine_request *)&framebuffer_request,
(struct limine_request *)&memmap_request,
(struct limine_request *)&module_request,
NULL
};
@@ -107,22 +115,7 @@ void kmain(void) {
serial_write("[DEBUG] idt_init OK\n");
process_init();
int ENABLE_USER_TEST = 1; // Set to 1 to test User Mode ring 3 jump
if (ENABLE_USER_TEST) {
// Create an isolated PML4 table for this "process"
uint64_t user_pml4_phys = paging_create_user_pml4_phys();
serial_write("[DEBUG] user_pml4 created OK\n");
if (user_pml4_phys) {
// Debug verify we can allocate
void* code_page = kmalloc_aligned(4096, 4096);
if (code_page) {
extern void user_test_function(void);
process_create(user_test_function, true);
serial_write("[DEBUG] User Process 1 Created.\n");
}
}
}
serial_write("[DEBUG] Skipping user mode test, proceeding with normal boot.\n");
@@ -132,6 +125,7 @@ void kmain(void) {
for (uint64_t i = 0; i < memmap_request.response->entry_count; i++) {
struct limine_memmap_entry *entry = memmap_request.response->entries[i];
// Count usable memory regions
if (entry->type == LIMINE_MEMMAP_USABLE) {
total_usable_memory += entry->length;
@@ -149,6 +143,30 @@ void kmain(void) {
memory_manager_init_with_size(pool_size);
// Initialize FAT32 RAMFS and mount Limine modules
fat32_init();
if (module_request.response != NULL) {
for (uint64_t i = 0; i < module_request.response->module_count; i++) {
struct limine_file *mod = module_request.response->modules[i];
// mod->path typically starts with a '/' from Limine
FAT32_FileHandle *fh = fat32_open(mod->path, "w");
if (fh && fh->valid) {
fat32_write(fh, mod->address, mod->size);
fat32_close(fh);
serial_write("[DEBUG] Limine Module loaded into RAMFS: ");
serial_write(mod->path);
serial_write("\n");
}
}
}
int ENABLE_USER_TEST = 1; // Set to 1 to test User Mode ring 3 jump
#ifdef ENABLE_USER_TEST
process_init();
// The desktop is PID 0
#endif
// 3. PS/2 Init (Mouse/Keyboard)
asm("cli");
ps2_init();

View File

@@ -17,13 +17,21 @@ static bool initialized = false;
// --- Helper Functions ---
// Simple memset for internal use
static void mem_memset(void *dest, int val, size_t len) {
void mem_memset(void *dest, int val, size_t len) {
uint8_t *ptr = (uint8_t *)dest;
while (len-- > 0) {
*ptr++ = (uint8_t)val;
}
}
void mem_memcpy(void *dest, const void *src, size_t len) {
uint8_t *d = (uint8_t *)dest;
const uint8_t *s = (const uint8_t *)src;
while (len-- > 0) {
*d++ = *s++;
}
}
// Simple memmove
static void mem_memmove(void *dest, const void *src, size_t len) {
uint8_t *d = (uint8_t *)dest;

View File

@@ -55,4 +55,7 @@ size_t memory_get_peak_usage(void);
void memory_reset_peak(void);
bool memory_is_valid_ptr(void *ptr);
void mem_memset(void *dest, int val, size_t len);
void mem_memcpy(void *dest, const void *src, size_t len);
#endif // MEMORY_MANAGER_H

View File

@@ -5,6 +5,8 @@
#include "io.h"
#include "platform.h"
#include "memory_manager.h"
#include "elf.h"
#include "wm.h"
extern void cmd_write(const char *str);
extern void serial_write(const char *str);
@@ -48,7 +50,7 @@ void process_create(void* entry_point, bool is_user) {
// 2. Allocate aligned stack
void* stack = kmalloc_aligned(4096, 4096);
void* kernel_stack = kmalloc_aligned(4096, 4096); // Needed for when user interrupts to Ring 0
void* kernel_stack = kmalloc_aligned(16384, 16384); // Needed for when user interrupts to Ring 0
if (is_user) {
// Map user stack to 0x800000
@@ -62,18 +64,20 @@ void process_create(void* entry_point, bool is_user) {
// Build initial stack frame for iretq
// Stack grows down, start at top
uint64_t* stack_ptr = (uint64_t*)((uint64_t)kernel_stack + 4096);
uint64_t* stack_ptr = (uint64_t*)((uint64_t)kernel_stack + 16384);
*(--stack_ptr) = 0x1B; // SS (User Data)
*(--stack_ptr) = 0x800000 + 4096; // RSP
*(--stack_ptr) = 0x202; // RFLAGS (IF=1)
*(--stack_ptr) = 0x23; // CS (User Code)
*(--stack_ptr) = 0x400000; // RIP
*(--stack_ptr) = 0; // int_no
*(--stack_ptr) = 0; // err_code
// Push 15 zeros for general purpose registers (r15 -> rax)
for (int i = 0; i < 15; i++) *(--stack_ptr) = 0;
new_proc->kernel_stack = (uint64_t)kernel_stack + 4096;
new_proc->kernel_stack = (uint64_t)kernel_stack + 16384;
new_proc->rsp = (uint64_t)stack_ptr;
} else {
// Kernel thread
@@ -84,6 +88,8 @@ void process_create(void* entry_point, bool is_user) {
*(--stack_ptr) = 0x202; // RFLAGS
*(--stack_ptr) = 0x08; // CS (Kernel Code)
*(--stack_ptr) = (uint64_t)entry_point; // RIP
*(--stack_ptr) = 0; // int_no
*(--stack_ptr) = 0; // err_code
for (int i = 0; i < 15; i++) *(--stack_ptr) = 0;
@@ -96,6 +102,63 @@ void process_create(void* entry_point, bool is_user) {
current_process->next = new_proc;
}
void process_create_elf(const char* filepath) {
if (process_count >= MAX_PROCESSES) return;
process_t *new_proc = &processes[process_count];
new_proc->pid = next_pid++;
new_proc->is_user = true;
// 1. Setup Page Table
new_proc->pml4_phys = paging_create_user_pml4_phys();
if (!new_proc->pml4_phys) return;
// 2. Load ELF executable
uint64_t entry_point = elf_load(filepath, new_proc->pml4_phys);
if (entry_point == 0) {
serial_write("[PROCESS] Failed to load ELF: ");
serial_write(filepath);
serial_write("\n");
// We technically leak the page table here, but let's ignore cleanup for now
return;
}
// 3. Allocate generic User stack and Kernel stack for interrupts
void* stack = kmalloc_aligned(4096, 4096);
void* kernel_stack = kmalloc_aligned(16384, 16384);
// Map User stack to 0x800000 -> Note: ELFs might overwrite this if they load there!
// But our ELF loader defaults 0x400000 for standard code.
paging_map_page(new_proc->pml4_phys, 0x800000, v2p((uint64_t)stack), PT_PRESENT | PT_RW | PT_USER);
// 4. Build Stack Frame
uint64_t* stack_ptr = (uint64_t*)((uint64_t)kernel_stack + 16384);
*(--stack_ptr) = 0x1B; // SS (User Mode Data)
*(--stack_ptr) = 0x800000 + 4096; // RSP
*(--stack_ptr) = 0x202; // RFLAGS (Interrupts Enabled)
*(--stack_ptr) = 0x23; // CS (User Mode Code)
*(--stack_ptr) = entry_point; // RIP
*(--stack_ptr) = 0; // int_no
*(--stack_ptr) = 0; // err_code
// 15 General purpose registers
for (int i = 0; i < 15; i++) *(--stack_ptr) = 0;
new_proc->kernel_stack = (uint64_t)kernel_stack + 16384;
new_proc->rsp = (uint64_t)stack_ptr;
// We only increment process_count after success
process_count++;
// Add to linked list
new_proc->next = current_process->next;
current_process->next = new_proc;
serial_write("[PROCESS] Spawned ELF Executable: ");
serial_write(filepath);
serial_write("\n");
}
process_t* process_get_current(void) {
return current_process;
}
@@ -112,9 +175,11 @@ uint64_t process_schedule(uint64_t current_rsp) {
// Switch process
current_process = current_process->next;
// Update Kernel Stack for User Mode interrupts
// Update Kernel Stack for User Mode interrupts and System Calls
if (current_process->is_user && current_process->kernel_stack) {
tss_set_stack(current_process->kernel_stack);
extern uint64_t kernel_syscall_stack;
kernel_syscall_stack = current_process->kernel_stack;
}
// Switch page table
@@ -123,3 +188,58 @@ uint64_t process_schedule(uint64_t current_rsp) {
return current_process->rsp;
}
uint64_t process_terminate_current(void) {
if (!current_process) return 0;
// 1. Cleanup side effects
if (current_process->ui_window) {
wm_remove_window((Window *)current_process->ui_window);
current_process->ui_window = NULL;
}
extern void cmd_process_finished(void);
cmd_process_finished();
// 2. Find previous process in circular list
process_t *prev = current_process;
while (prev->next != current_process) {
prev = prev->next;
}
// 3. Remove current from list
process_t *to_delete = current_process;
if (prev == current_process) {
// Only one process (should be kernel), cannot terminate.
return to_delete->rsp;
}
prev->next = to_delete->next;
current_process = to_delete->next;
// Mark slot as freeish (simple version)
to_delete->pid = 0xFFFFFFFF;
// 4. Load context for the NEXT process
if (current_process->is_user && current_process->kernel_stack) {
tss_set_stack(current_process->kernel_stack);
extern uint64_t kernel_syscall_stack;
kernel_syscall_stack = current_process->kernel_stack;
}
paging_switch_directory(current_process->pml4_phys);
return current_process->rsp;
}
void process_push_gui_event(process_t *proc, gui_event_t *ev) {
if (!proc) return;
int next_tail = (proc->gui_event_tail + 1) % MAX_GUI_EVENTS;
// Drop event if queue is full
if (next_tail == proc->gui_event_head) {
return;
}
proc->gui_events[proc->gui_event_tail] = *ev;
proc->gui_event_tail = next_tail;
}

View File

@@ -3,6 +3,9 @@
#include <stdint.h>
#include <stdbool.h>
#include "gui_ipc.h"
#define MAX_GUI_EVENTS 32
// Registers saved on the stack by interrupts/exceptions
typedef struct {
@@ -18,13 +21,23 @@ typedef struct process {
uint64_t pml4_phys; // Physical address of the page table
uint64_t kernel_stack; // Ring 0 stack pointer for user mode switches
bool is_user;
gui_event_t gui_events[MAX_GUI_EVENTS];
int gui_event_head;
int gui_event_tail;
void *ui_window; // Pointer to the active Window
struct process *next;
} process_t;
void process_init(void);
void process_create(void* entry_point, bool is_user);
void process_create_elf(const char* filepath);
process_t* process_get_current(void);
uint64_t process_schedule(uint64_t current_rsp);
uint64_t process_terminate_current(void);
void process_push_gui_event(process_t *proc, gui_event_t *ev);
#endif

View File

@@ -8,14 +8,14 @@ extern void serial_print(const char *s);
extern void serial_print_hex(uint64_t n);
// --- Timer Handler ---
uint64_t timer_handler(uint64_t rsp) {
uint64_t timer_handler(registers_t *regs) {
wm_timer_tick();
network_process_frames();
extern uint64_t process_schedule(uint64_t current_rsp);
outb(0x20, 0x20); // EOI to Master PIC
rsp = process_schedule(rsp);
uint64_t rsp = process_schedule((uint64_t)regs);
return rsp;
}
@@ -41,13 +41,13 @@ static char scancode_map_shift[128] = {
0, ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
uint64_t keyboard_handler(uint64_t rsp) {
uint64_t keyboard_handler(registers_t *regs) {
uint8_t scancode = inb(0x60);
if (scancode == 0xE0) {
extended_scancode = true;
outb(0x20, 0x20);
return rsp;
return (uint64_t)regs;
}
if (scancode == 0x2A || scancode == 0x36) { // Shift Down
@@ -77,7 +77,7 @@ uint64_t keyboard_handler(uint64_t rsp) {
}
outb(0x20, 0x20); // EOI
return rsp;
return (uint64_t)regs;
}
// --- Mouse ---
@@ -135,12 +135,12 @@ void mouse_init(void) {
mouse_read();
}
uint64_t mouse_handler(uint64_t rsp) {
uint64_t mouse_handler(registers_t *regs) {
uint8_t status = inb(0x64);
if (!(status & 0x20)) {
outb(0x20, 0x20);
outb(0xA0, 0x20);
return rsp; // Return rsp here as well
return (uint64_t)regs;
}
uint8_t b = inb(0x60);
@@ -169,7 +169,7 @@ uint64_t mouse_handler(uint64_t rsp) {
outb(0x20, 0x20);
outb(0xA0, 0x20); // Slave EOI
return rsp;
return (uint64_t)regs;
}
void ps2_init(void) {

View File

@@ -4,8 +4,10 @@
#include <stdint.h>
void ps2_init(void);
uint64_t timer_handler(uint64_t rsp);
uint64_t keyboard_handler(uint64_t rsp);
uint64_t mouse_handler(uint64_t rsp);
#include "process.h"
uint64_t timer_handler(registers_t *regs);
uint64_t keyboard_handler(registers_t *regs);
uint64_t mouse_handler(registers_t *regs);
#endif

View File

@@ -1,6 +1,9 @@
#include "syscall.h"
#include "gdt.h"
#include "memory_manager.h"
#include "gui_ipc.h"
#include "process.h"
#include "wm.h"
// Read MSR
static inline uint64_t rdmsr(uint32_t msr) {
@@ -43,13 +46,232 @@ void syscall_init(void) {
wrmsr(MSR_FMASK, 0x200);
}
void syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5) {
static void user_window_close(Window *win) {
process_t *proc = (process_t *)win->data;
if (!proc) return;
gui_event_t ev = { .type = GUI_EVENT_CLOSE };
process_push_gui_event(proc, &ev);
}
static void user_window_paint(Window *win) {
process_t *proc = (process_t *)win->data;
if (!proc) return;
gui_event_t ev = { .type = GUI_EVENT_PAINT };
process_push_gui_event(proc, &ev);
}
static void user_window_click(Window *win, int x, int y) {
process_t *proc = (process_t *)win->data;
if (!proc) return;
gui_event_t ev = { .type = GUI_EVENT_CLICK, .arg1 = x, .arg2 = y };
process_push_gui_event(proc, &ev);
}
uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5) {
extern void cmd_write(const char *str);
extern void serial_write(const char *str);
extern void cmd_process_finished(void);
if (syscall_num == 1) { // SYS_WRITE
// arg2 is the buffer based on our user_test logic
cmd_write((const char*)arg2);
serial_write((const char*)arg2);
} else if (syscall_num == 0) { // SYS_EXIT
process_t *proc = process_get_current();
if (proc && proc->ui_window) {
wm_remove_window((Window *)proc->ui_window);
proc->ui_window = NULL;
}
cmd_process_finished();
// The actual process termination and scheduling will be handled later
// For now this just releases the CMD prompt lock.
// We will eventually need to mark the process_t as DEAD here.
} else if (syscall_num == 3) { // SYS_GUI
int cmd = (int)arg1;
process_t *proc = process_get_current();
if (cmd == GUI_CMD_WINDOW_CREATE) {
const char *title = (const char *)arg2;
uint64_t *params = (uint64_t *)arg3;
if (!params) return 0;
Window *win = kmalloc(sizeof(Window));
if (!win) return 0;
// Copy title from user space to kernel space so wm.c can access it safely
int title_len = 0;
while (title[title_len] && title_len < 255) title_len++;
char *kernel_title = kmalloc(title_len + 1);
if (kernel_title) {
for (int i = 0; i < title_len; i++) {
kernel_title[i] = title[i];
}
kernel_title[title_len] = '\0';
}
// Basic initialization
win->title = kernel_title ? kernel_title : "Unknown";
win->x = (int)params[0];
win->y = (int)params[1];
win->w = (int)params[2];
win->h = (int)params[3];
// Sanity checks for dimensions
if (win->w <= 0 || win->w > 4096) win->w = 400;
if (win->h <= 0 || win->h > 4096) win->h = 400;
win->visible = true;
win->focused = true;
win->z_index = 0;
win->buf_len = 0;
win->buffer[0] = 0;
win->data = proc;
// Safe allocation
size_t pixel_size = (size_t)win->w * win->h * 4;
win->pixels = kmalloc(pixel_size);
win->comp_pixels = kmalloc(pixel_size);
if (win->pixels) {
extern void mem_memset(void *dest, int val, size_t len);
mem_memset(win->pixels, 0, pixel_size);
}
if (win->comp_pixels) {
extern void mem_memset(void *dest, int val, size_t len);
mem_memset(win->comp_pixels, 0, pixel_size);
}
win->paint = user_window_paint;
win->handle_click = user_window_click;
win->handle_close = user_window_close;
win->handle_key = NULL;
win->handle_right_click = NULL;
proc->ui_window = win;
wm_add_window(win);
return (uint64_t)win;
} else if (cmd == GUI_CMD_DRAW_RECT) {
Window *win = (Window *)arg2;
uint64_t *p = (uint64_t *)arg3;
uint32_t color = (uint32_t)arg4;
if (win && p) {
extern void draw_rect(int x, int y, int w, int h, uint32_t color);
extern void graphics_set_render_target(uint32_t *buffer, int w, int h);
uint64_t rflags;
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
if (win->pixels) {
// Strict user-to-window relative clamping
int rx = (int)p[0]; int ry = (int)p[1];
int rw = (int)p[2]; int rh = (int)p[3];
if (rx < 0) { rw += rx; rx = 0; }
if (ry < 0) { rh += ry; ry = 0; }
if (rx + rw > win->w) rw = win->w - rx;
if (ry + rh > win->h) rh = win->h - ry;
if (rw > 0 && rh > 0) {
graphics_set_render_target(win->pixels, win->w, win->h);
draw_rect(rx, ry, rw, rh, color);
graphics_set_render_target(NULL, 0, 0);
}
} else {
draw_rect(win->x + p[0], win->y + p[1], p[2], p[3], color);
}
asm volatile("push %0; popfq" : : "r"(rflags));
}
} else if (cmd == GUI_CMD_DRAW_ROUNDED_RECT_FILLED) {
Window *win = (Window *)arg2;
uint64_t *p = (uint64_t *)arg3;
uint32_t color = (uint32_t)arg4;
if (win && p) {
extern void draw_rounded_rect_filled(int x, int y, int w, int h, int radius, uint32_t color);
extern void graphics_set_render_target(uint32_t *buffer, int w, int h);
uint64_t rflags;
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
if (win->pixels) {
int rx = (int)p[0]; int ry = (int)p[1];
int rw = (int)p[2]; int rh = (int)p[3];
int rr = (int)p[4];
if (rx < 0) { rw += rx; rx = 0; }
if (ry < 0) { rh += ry; ry = 0; }
if (rx + rw > win->w) rw = win->w - rx;
if (ry + rh > win->h) rh = win->h - ry;
if (rw > 0 && rh > 0) {
graphics_set_render_target(win->pixels, win->w, win->h);
draw_rounded_rect_filled(rx, ry, rw, rh, rr, color);
graphics_set_render_target(NULL, 0, 0);
}
} else {
draw_rounded_rect_filled(win->x + p[0], win->y + p[1], p[2], p[3], p[4], color);
}
asm volatile("push %0; popfq" : : "r"(rflags));
}
} else if (cmd == GUI_CMD_DRAW_STRING) {
Window *win = (Window *)arg2;
uint64_t coords = arg3;
int ux = coords & 0xFFFFFFFF;
int uy = coords >> 32;
const char *user_str = (const char *)arg4;
uint32_t color = (uint32_t)arg5;
if (win && user_str) {
extern void draw_string(int x, int y, const char *str, uint32_t color);
extern void graphics_set_render_target(uint32_t *buffer, int w, int h);
// Copy string safely to kernel stack buffer
char kernel_str[256];
int i = 0;
while (i < 255 && user_str[i]) {
kernel_str[i] = user_str[i];
i++;
}
kernel_str[i] = 0;
uint64_t rflags;
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
if (win->pixels) {
// String clipping is handled by draw_char -> put_pixel,
// but we ensure coordinate sanity here
if (ux >= -100 && ux < win->w && uy >= -100 && uy < win->h) {
graphics_set_render_target(win->pixels, win->w, win->h);
draw_string(ux, uy, kernel_str, color);
graphics_set_render_target(NULL, 0, 0);
}
} else {
draw_string(win->x + ux, win->y + uy, kernel_str, color);
}
asm volatile("push %0; popfq" : : "r"(rflags));
}
} else if (cmd == GUI_CMD_MARK_DIRTY) {
Window *win = (Window *)arg2;
uint64_t *p = (uint64_t *)arg3;
if (win && p) {
// Dual-buffer commit: copy pixels to comp_pixels
if (win->pixels && win->comp_pixels) {
extern void mem_memcpy(void *dest, const void *src, size_t len);
mem_memcpy(win->comp_pixels, win->pixels, (size_t)win->w * win->h * 4);
}
wm_mark_dirty(win->x + p[0], win->y + p[1], p[2], p[3]);
}
} else if (cmd == GUI_CMD_GET_EVENT) {
Window *win = (Window *)arg2;
gui_event_t *ev_out = (gui_event_t *)arg3;
if (!win || !ev_out) return 0;
if (proc->gui_event_head != proc->gui_event_tail) {
*ev_out = proc->gui_events[proc->gui_event_head];
proc->gui_event_head = (proc->gui_event_head + 1) % MAX_GUI_EVENTS;
return 1;
}
return 0;
}
}
return 0;
}

View File

@@ -15,6 +15,6 @@
#define SYS_EXIT 60
void syscall_init(void);
void syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5);
uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5);
#endif // SYSCALL_H

View File

@@ -12,19 +12,14 @@ section .text
; R9 = arg5
syscall_entry:
; We arrived here from Ring 3 via `syscall`.
; RAX = syscall_num
; RDI, RSI, RDX, R10, R8, R9 = args
; RCX = User RIP
; R11 = User RFLAGS
; Current RSP = User RSP
; 1. Save User RSP
; 1. Switch to Kernel Stack
; Use scratch temporarily to pivot (Risk: Task switch here is rare but possible)
mov [rel user_rsp_scratch], rsp
; 2. Switch to Kernel Stack
mov rsp, [rel kernel_syscall_stack]
; 2. Save User RSP on per-process kernel stack
push qword [rel user_rsp_scratch]
; 3. Save preserved registers (System V ABI)
push rbx
push rbp
@@ -33,32 +28,18 @@ syscall_entry:
push r14
push r15
; We also need to save RCX (RIP) and R11 (RFLAGS) because C functions might clobber them
; 4. Save RCX (RIP) and R11 (RFLAGS)
push rcx
push r11
; Syscall convention: argument 4 is passed in R10, but C expects it in RCX
mov rcx, r10
; The syscall number is in RAX, let's put it in RDI (arg 0 for C)
; But wait, the ABI expects arg1 in RDI!
; Let's change our C handler signature or adapt here.
; C handler: void syscall_handler_c(uint64_t syscall_num, uint64_t arg1, ...)
; So:
; syscall_num -> RDI
; arg1 (was RDI) -> RSI
; arg2 (was RSI) -> RDX
; arg3 (was RDX) -> RCX
; arg4 (was R10) -> R8
; arg5 (was R8) -> R9
; arg6 (was R9) -> stack (if needed, but we have 6 regs)
; This shuffling is messy. Let's just push everything and call a struct-based handler,
; or carefully shuffle.
; For now, let's just make sure RAX goes to RDI, RDI to RSI, RSI to RDX, RDX to RCX, R10 to R8.
; Shuffling for SYS V C ABI:
; R9 is arg6 -> no room in registers, need to push to stack (but our handler takes 6 args total)
; arg5: R9 (remains R9 as 6th arg in C)
; arg4: R8 (was R9)
; arg3: RCX (was R10)
; arg2: RDX (was RSI)
; arg1: RSI (was RDI)
; num: RDI (was RAX)
mov r9, r8 ; arg5
mov r8, r10 ; arg4
mov rcx, rdx ; arg3
@@ -66,14 +47,14 @@ syscall_entry:
mov rsi, rdi ; arg1
mov rdi, rax ; syscall_num
; 4. Call C handler
; 5. Call C handler
call syscall_handler_c
; 5. Restore RCX and R11
; 6. Restore RCX and R11
pop r11
pop rcx
; 6. Restore preserved registers
; 7. Restore preserved registers
pop r15
pop r14
pop r13
@@ -81,14 +62,11 @@ syscall_entry:
pop rbp
pop rbx
; 7. Restore User RSP
mov rsp, [rel user_rsp_scratch]
; 8. Restore User RSP from kernel stack
pop rsp
; 8. Return to User Mode
; NASM syntax for 64-bit sysret requires the o64 prefix
; Force IF=1 (bit 9) in R11 (restored to RFLAGS) to ensure interrupts stay enabled!
or r11, 0x200
; 9. Return to User Mode (sysret)
or r11, 0x200 ; Force Interrupts enabled
o64 sysret
section .bss

View File

@@ -0,0 +1,30 @@
CC = x86_64-elf-gcc
AS = nasm
LD = x86_64-elf-ld
CFLAGS = -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc
LDFLAGS = -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start
LIBC_SOURCES = $(wildcard libc/*.c)
LIBC_OBJS = $(LIBC_SOURCES:.c=.o) crt0.o
APP_SOURCES = $(wildcard *.c)
APP_OBJS = $(APP_SOURCES:.c=.o)
APP_ELFS = $(APP_SOURCES:.c=.elf)
all: $(APP_ELFS)
crt0.o: crt0.asm
$(AS) -f elf64 $< -o $@
libc/%.o: libc/%.c
$(CC) $(CFLAGS) -c $< -o $@
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
%.elf: $(LIBC_OBJS) %.o
$(LD) $(LDFLAGS) $^ -o $@
clean:
rm -f *.o libc/*.o *.elf

View File

@@ -1,13 +1,17 @@
#include "calculator.h"
#include "graphics.h"
#include "wm.h"
#include "syscall.h"
#include "libui.h"
#include <stdbool.h>
#include <stddef.h>
Window win_calculator;
#define SCALE 1000000LL
// Dark Mode Colors mapping to libui
#define COLOR_DARK_BG 0xFF1E1E1E
#define COLOR_DARK_PANEL 0xFF2D2D2D
#define COLOR_DARK_TEXT 0xFFF0F0F0
#define COLOR_DARK_BORDER 0xFF3A3A3A
static ui_window_t win_calculator;
static long long calc_acc = 0;
static long long calc_curr = 0;
static char calc_op = 0;
@@ -15,8 +19,9 @@ static bool calc_new_entry = true;
static bool calc_error = false;
static bool calc_decimal_mode = false;
static long long calc_decimal_divisor = 10;
static char display_buffer[1024];
static int display_buf_len = 0;
// Simple integer square root
static long long isqrt(long long n) {
if (n < 0) return -1;
if (n == 0) return 0;
@@ -29,45 +34,31 @@ static long long isqrt(long long n) {
return x;
}
// Convert fixed point to string
static void fixed_to_str(long long n, char *buf) {
if (n == 0) {
buf[0] = '0'; buf[1] = 0; return;
}
char temp[64];
int pos = 0;
bool neg = n < 0;
if (neg) n = -n;
long long int_part = n / SCALE;
long long frac_part = n % SCALE;
// Fraction part
char frac_buf[16];
int f_idx = 0;
// Fill exactly 6 digits
for(int k=0; k<6; k++) {
long long div = 100000;
for(int m=0; m<k; m++) div /= 10;
frac_buf[f_idx++] = '0' + ((frac_part / div) % 10);
}
frac_buf[f_idx] = 0;
// Trim trailing zeros
while (f_idx > 0 && frac_buf[f_idx-1] == '0') {
f_idx--;
}
while (f_idx > 0 && frac_buf[f_idx-1] == '0') f_idx--;
frac_buf[f_idx] = 0;
if (f_idx > 0) {
for (int i = f_idx - 1; i >= 0; i--) {
temp[pos++] = frac_buf[i];
}
for (int i = f_idx - 1; i >= 0; i--) temp[pos++] = frac_buf[i];
temp[pos++] = '.';
}
// Integer part
if (int_part == 0) {
temp[pos++] = '0';
} else {
@@ -76,40 +67,33 @@ static void fixed_to_str(long long n, char *buf) {
int_part /= 10;
}
}
if (neg) temp[pos++] = '-';
// Reverse into buf
int j = 0;
while (pos > 0) {
buf[j++] = temp[--pos];
}
while (pos > 0) buf[j++] = temp[--pos];
buf[j] = 0;
}
static void update_display(Window *win) {
static void update_display(void) {
if (calc_error) {
char *err = "Error";
int i = 0; while(err[i]) { win->buffer[i] = err[i]; i++; }
win->buffer[i] = 0;
int i = 0; while(err[i]) { display_buffer[i] = err[i]; i++; }
display_buffer[i] = 0;
} else {
fixed_to_str(calc_curr, win->buffer);
fixed_to_str(calc_curr, display_buffer);
}
win->buf_len = 0; while(win->buffer[win->buf_len]) win->buf_len++;
display_buf_len = 0; while(display_buffer[display_buf_len]) display_buf_len++;
}
static void calculator_paint(Window *win) {
// Background
draw_rect(win->x + 4, win->y + 30, win->w - 8, win->h - 34, COLOR_DARK_BG);
static void calculator_paint(void) {
int w = 180;
int h = 230;
ui_draw_rect(win_calculator, 4, 30, w - 8, h - 34, COLOR_DARK_BG);
ui_draw_rounded_rect_filled(win_calculator, 10, 36, w - 20, 25, 6, COLOR_DARK_PANEL);
// Display Area with dark mode styling
draw_rounded_rect_filled(win->x + 10, win->y + 36, win->w - 20, 25, 6, COLOR_DARK_PANEL);
// Right align text
int text_w = win->buf_len * 8;
int text_x = win->x + win->w - 15 - text_w;
draw_string(text_x, win->y + 44, win->buffer, COLOR_DARK_TEXT);
int text_w = display_buf_len * 8;
int text_x = w - 15 - text_w;
ui_draw_string(win_calculator, text_x, 44, display_buffer, COLOR_DARK_TEXT);
// Buttons - macOS style squircle buttons
const char *labels[] = {
"C", "sqr", "rt", "/",
"7", "8", "9", "*",
@@ -121,19 +105,16 @@ static void calculator_paint(Window *win) {
int bw = 35;
int bh = 25;
int gap = 5;
int start_x = win->x + 10;
int start_y = win->y + 70;
int start_x = 10;
int start_y = 70;
for (int i = 0; i < 20; i++) {
int r = i / 4;
int c = i % 4;
// Draw rounded button backgrounds
draw_rounded_rect_filled(start_x + c*(bw+gap), start_y + r*(bh+gap), bw, bh, 4, COLOR_DARK_BORDER);
// Draw button text
ui_draw_rounded_rect_filled(win_calculator, start_x + c*(bw+gap), start_y + r*(bh+gap), bw, bh, 4, COLOR_DARK_BORDER);
int label_x = start_x + c*(bw+gap) + 5;
int label_y = start_y + r*(bh+gap) + 9;
draw_string(label_x, label_y, labels[i], COLOR_DARK_TEXT);
ui_draw_string(win_calculator, label_x, label_y, labels[i], COLOR_DARK_TEXT);
}
}
@@ -145,20 +126,18 @@ static void do_op(void) {
}
else if (calc_op == '/') {
if (calc_curr == 0) calc_error = true;
else {
calc_acc = (calc_acc * SCALE) / calc_curr;
}
else calc_acc = (calc_acc * SCALE) / calc_curr;
} else {
calc_acc = calc_curr;
}
}
static void calculator_click(Window *win, int x, int y) {
static void calculator_click(int x, int y) {
int bw = 35;
int bh = 25;
int gap = 5;
int start_x = 10;
int start_y = 65;
int start_y = 65; // Matches the hitboxes
for (int i = 0; i < 20; i++) {
int r = i / 4;
@@ -168,14 +147,13 @@ static void calculator_click(Window *win, int x, int y) {
if (x >= bx && x < bx + bw && y >= by && y < by + bh) {
const char *labels[] = {
"C", "sqr", "rt", "/",
"C", "s", "r", "/",
"7", "8", "9", "*",
"4", "5", "6", "-",
"1", "2", "3", "+",
"0", ".", "BS", "="
"0", ".", "B", "="
};
const char *lbl_str = labels[i];
char lbl = lbl_str[0];
char lbl = labels[i][0];
if (lbl >= '0' && lbl <= '9') {
if (calc_new_entry || calc_error) {
@@ -184,7 +162,6 @@ static void calculator_click(Window *win, int x, int y) {
calc_decimal_mode = false;
} else {
if (calc_decimal_mode) {
// Add digit to fraction
if (calc_decimal_divisor <= SCALE) {
long long digit_val = ((long long)(lbl - '0') * SCALE) / calc_decimal_divisor;
if (calc_curr >= 0) calc_curr += digit_val;
@@ -192,7 +169,6 @@ static void calculator_click(Window *win, int x, int y) {
calc_decimal_divisor *= 10;
}
} else {
// Integer shift
if (calc_curr >= 0) calc_curr = calc_curr * 10 + (lbl - '0') * SCALE;
else calc_curr = calc_curr * 10 - (lbl - '0') * SCALE;
}
@@ -208,69 +184,81 @@ static void calculator_click(Window *win, int x, int y) {
calc_decimal_divisor = 10;
}
} else if (lbl == 'C') {
calc_curr = 0;
calc_acc = 0;
calc_op = 0;
calc_new_entry = true;
calc_error = false;
calc_decimal_mode = false;
} else if (lbl == 'B') { // BS (Backspace)
calc_curr = 0; calc_acc = 0; calc_op = 0;
calc_new_entry = true; calc_error = false; calc_decimal_mode = false;
} else if (lbl == 'B') {
if (!calc_new_entry && !calc_error) {
if (calc_decimal_mode) {
calc_curr = 0;
calc_new_entry = true;
if (calc_decimal_divisor > 10) {
calc_decimal_divisor /= 10;
long long unit = SCALE / calc_decimal_divisor;
// This removes the last decimal digit
calc_curr = (calc_curr / (unit * 10)) * (unit * 10);
} else {
// Backspace on the dot itself or first decimal
calc_decimal_mode = false;
calc_decimal_divisor = 10;
// Ensure the fractional part is cleared
calc_curr = (calc_curr / SCALE) * SCALE;
}
} else {
calc_curr /= 10;
// Integer backspace: remove last digit of integer part
calc_curr = (calc_curr / SCALE / 10) * SCALE;
}
}
} else if (lbl == 's') { // sqr
calc_curr = (calc_curr * calc_curr) / SCALE;
calc_new_entry = true;
} else if (lbl == 'r') { // rt (sqrt)
calc_curr = (calc_curr * calc_curr) / SCALE; calc_new_entry = true;
} else if (lbl == 'r') { // rt
long long s = isqrt(calc_curr);
if (s == -1) calc_error = true;
else calc_curr = s * 1000;
calc_new_entry = true;
} else if (lbl == '=') {
do_op();
calc_curr = calc_acc;
calc_op = 0;
calc_new_entry = true;
calc_decimal_mode = false;
calc_curr = calc_acc; calc_op = 0; calc_new_entry = true; calc_decimal_mode = false;
} else {
// Operator
if (!calc_new_entry) {
if (calc_op) do_op();
else calc_acc = calc_curr;
}
calc_op = lbl;
calc_new_entry = true;
calc_decimal_mode = false;
calc_op = lbl; calc_new_entry = true; calc_decimal_mode = false;
}
update_display(win);
wm_mark_dirty(win->x, win->y, win->w, win->h);
update_display();
calculator_paint();
ui_mark_dirty(win_calculator, 0, 0, 180, 230);
return;
}
}
}
void calculator_init(void) {
win_calculator.title = "Calculator";
win_calculator.x = 200;
win_calculator.y = 200;
win_calculator.w = 180; // Slightly wider for 4 cols with gaps
win_calculator.h = 230; // Taller for 5 rows
win_calculator.visible = false;
win_calculator.focused = false;
win_calculator.z_index = 0;
win_calculator.paint = calculator_paint;
win_calculator.handle_click = calculator_click;
win_calculator.handle_right_click = NULL;
int main(void) {
win_calculator = ui_window_create("Calculator", 200, 200, 180, 230);
calc_curr = 0;
calc_acc = 0;
calc_op = 0;
calc_new_entry = true;
update_display(&win_calculator);
}
update_display();
// First paint
calculator_paint();
ui_mark_dirty(win_calculator, 0, 0, 180, 230);
// Check events from Kernel User Interface queue
gui_event_t ev;
while (1) {
if (ui_get_event(win_calculator, &ev)) {
if (ev.type == GUI_EVENT_PAINT) {
calculator_paint();
ui_mark_dirty(win_calculator, 0, 0, 180, 230);
} else if (ev.type == GUI_EVENT_CLICK) {
calculator_click(ev.arg1, ev.arg2);
} else if (ev.type == GUI_EVENT_CLOSE) {
sys_exit(0);
}
}
}
return 0;
}

Binary file not shown.

View File

@@ -0,0 +1,12 @@
#include "syscall.h"
int main() {
const char* msg = "Attempting to crash via null dereference...\n";
sys_write(1, msg, 45);
// Null pointer dereference
volatile int* p = (int*)0;
*p = 123;
return 0;
}

BIN
src/kernel/userland/crash.elf Executable file

Binary file not shown.

View File

@@ -0,0 +1,26 @@
; userland/crt0.asm
global _start
extern main
extern sys_exit
section .text
_start:
; The kernel loads the ELF and jumps here.
; RSP should point to the 0x800000 stack.
; Align the stack to 16 bytes for C functions (System V ABI)
and rsp, -16
; Call main(argc, argv)
; We don't have argc or argv yet, pass 0
xor rdi, rdi
xor rsi, rsi
call main
; If main returns, call exit(status)
mov rdi, rax ; Pass main's return value to exit syscall
call sys_exit
; Fallback halt if exit miraculously returns
.hang:
jmp .hang

BIN
src/kernel/userland/crt0.o Normal file

Binary file not shown.

View File

@@ -0,0 +1,7 @@
#include "syscall.h"
int main() {
const char* msg = "Hello from Userland ELF!\n";
sys_write(1, msg, 25);
return 0;
}

BIN
src/kernel/userland/hello.elf Executable file

Binary file not shown.

BIN
src/kernel/userland/hello.o Normal file

Binary file not shown.

View File

@@ -0,0 +1,40 @@
#include "libui.h"
#include "syscall.h"
#include <stddef.h>
extern uint64_t syscall3(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_t arg3);
extern uint64_t syscall4(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4);
extern uint64_t syscall5(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5);
// sys_gui uses syscall #3
#define SYS_GUI 3
ui_window_t ui_window_create(const char *title, int x, int y, int w, int h) {
uint64_t params[4] = { (uint64_t)x, (uint64_t)y, (uint64_t)w, (uint64_t)h };
return (ui_window_t)syscall3(SYS_GUI, GUI_CMD_WINDOW_CREATE, (uint64_t)title, (uint64_t)params);
}
bool ui_get_event(ui_window_t win, gui_event_t *ev) {
int res = (int)syscall3(SYS_GUI, GUI_CMD_GET_EVENT, (uint64_t)win, (uint64_t)ev);
return res != 0;
}
void ui_draw_rect(ui_window_t win, int x, int y, int w, int h, uint32_t color) {
uint64_t params[4] = { (uint64_t)x, (uint64_t)y, (uint64_t)w, (uint64_t)h };
syscall4(SYS_GUI, GUI_CMD_DRAW_RECT, (uint64_t)win, (uint64_t)params, (uint64_t)color);
}
void ui_draw_rounded_rect_filled(ui_window_t win, int x, int y, int w, int h, int radius, uint32_t color) {
uint64_t params[5] = { (uint64_t)x, (uint64_t)y, (uint64_t)w, (uint64_t)h, (uint64_t)radius };
syscall4(SYS_GUI, GUI_CMD_DRAW_ROUNDED_RECT_FILLED, (uint64_t)win, (uint64_t)params, (uint64_t)color);
}
void ui_draw_string(ui_window_t win, int x, int y, const char *str, uint32_t color) {
uint64_t coords = ((uint64_t)x & 0xFFFFFFFF) | ((uint64_t)y << 32);
syscall5(SYS_GUI, GUI_CMD_DRAW_STRING, (uint64_t)win, coords, (uint64_t)str, (uint64_t)color);
}
void ui_mark_dirty(ui_window_t win, int x, int y, int w, int h) {
uint64_t params[4] = { (uint64_t)x, (uint64_t)y, (uint64_t)w, (uint64_t)h };
syscall3(SYS_GUI, GUI_CMD_MARK_DIRTY, (uint64_t)win, (uint64_t)params);
}

View File

@@ -0,0 +1,40 @@
#ifndef LIBUI_H
#define LIBUI_H
#include <stdint.h>
#include <stdbool.h>
// GUI Command IDs
#define GUI_CMD_WINDOW_CREATE 1
#define GUI_CMD_DRAW_RECT 2
#define GUI_CMD_DRAW_STRING 3
#define GUI_CMD_MARK_DIRTY 4
#define GUI_CMD_GET_EVENT 5
#define GUI_CMD_DRAW_ROUNDED_RECT_FILLED 6
// Event Types
#define GUI_EVENT_NONE 0
#define GUI_EVENT_PAINT 1
#define GUI_EVENT_CLICK 2
#define GUI_EVENT_RIGHT_CLICK 3
#define GUI_EVENT_CLOSE 4
typedef struct {
int type;
int arg1; // For click: x
int arg2; // For click: y
} gui_event_t;
// Window Handle
typedef int ui_window_t;
// libui API
ui_window_t ui_window_create(const char *title, int x, int y, int w, int h);
bool ui_get_event(ui_window_t win, gui_event_t *ev);
void ui_draw_rect(ui_window_t win, int x, int y, int w, int h, uint32_t color);
void ui_draw_rounded_rect_filled(ui_window_t win, int x, int y, int w, int h, int radius, uint32_t color);
void ui_draw_string(ui_window_t win, int x, int y, const char *str, uint32_t color);
void ui_mark_dirty(ui_window_t win, int x, int y, int w, int h);
#endif

View File

@@ -0,0 +1,71 @@
#include "syscall.h"
uint64_t syscall0(uint64_t sys_num) {
uint64_t ret;
asm volatile("syscall"
: "=a"(ret)
: "a"(sys_num)
: "rcx", "r11", "memory");
return ret;
}
uint64_t syscall1(uint64_t sys_num, uint64_t arg1) {
uint64_t ret;
asm volatile("syscall"
: "=a"(ret)
: "a"(sys_num), "D"(arg1)
: "rcx", "r11", "memory");
return ret;
}
uint64_t syscall2(uint64_t sys_num, uint64_t arg1, uint64_t arg2) {
uint64_t ret;
asm volatile("syscall"
: "=a"(ret)
: "a"(sys_num), "D"(arg1), "S"(arg2)
: "rcx", "r11", "memory");
return ret;
}
uint64_t syscall3(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_t arg3) {
uint64_t ret;
asm volatile("syscall"
: "=a"(ret)
: "a"(sys_num), "D"(arg1), "S"(arg2), "d"(arg3)
: "rcx", "r11", "memory", "r10", "r8", "r9");
return ret;
}
uint64_t syscall4(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4) {
uint64_t ret;
register uint64_t r10 asm("r10") = arg4;
asm volatile("syscall"
: "=a"(ret)
: "a"(sys_num), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10)
: "rcx", "r11", "memory", "r8", "r9");
return ret;
}
uint64_t syscall5(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5) {
uint64_t ret;
register uint64_t r10 asm("r10") = arg4;
register uint64_t r8 asm("r8") = arg5;
asm volatile("syscall"
: "=a"(ret)
: "a"(sys_num), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), "r"(r8)
: "rcx", "r11", "memory", "r9");
return ret;
}
// C-Friendly Wrappers
void sys_exit(int status) {
syscall1(SYS_EXIT, (uint64_t)status);
while (1); // Halt
}
int sys_write(int fd, const char *buf, int len) {
return (int)syscall3(SYS_WRITE, (uint64_t)fd, (uint64_t)buf, (uint64_t)len);
}

View File

@@ -0,0 +1,22 @@
#ifndef SYSCALL_H
#define SYSCALL_H
#include <stdint.h>
// Standard syscalls available from Kernel mode
#define SYS_EXIT 0
#define SYS_WRITE 1
// Internal assembly entry into Ring 0
extern uint64_t syscall0(uint64_t sys_num);
extern uint64_t syscall1(uint64_t sys_num, uint64_t arg1);
extern uint64_t syscall2(uint64_t sys_num, uint64_t arg1, uint64_t arg2);
extern uint64_t syscall3(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_t arg3);
extern uint64_t syscall4(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4);
extern uint64_t syscall5(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5);
// Public API
void sys_exit(int status);
int sys_write(int fd, const char *buf, int len);
#endif

Binary file not shown.

View File

@@ -2,7 +2,7 @@
#include "graphics.h"
#include "io.h"
#include "cmd.h"
#include "calculator.h"
#include "process.h"
#include "cli_apps/cli_utils.h"
#include "explorer.h"
#include "editor.h"
@@ -475,6 +475,40 @@ void draw_document_icon(int x, int y, const char *label) {
draw_icon_label(x, y, label);
}
void draw_elf_icon(int x, int y, const char *label) {
uint32_t icon_buf[48 * 48];
for (int i = 0; i < 48 * 48; i++) icon_buf[i] = 0xFFFF00FF;
graphics_set_render_target(icon_buf, 48, 48);
// Grey squircle (macOS detailed style)
draw_rounded_rect_filled(2, 2, 44, 44, 12, 0xFF353535); // Subtle shadow border
draw_rounded_rect_filled(4, 4, 40, 40, 10, 0xFF4A4A4A); // Main grey body
// Glossy top highlight
draw_rect(10, 5, 28, 1, 0xFF5A5A5A);
// Green "exec" text (fixed font 8x12)
draw_string(8, 12, "exec", 0xFF00FF00);
// Minor details to look "premium"
draw_rect(10, 28, 28, 1, 0xFF3D3D3D);
draw_rect(10, 34, 20, 1, 0xFF3D3D3D);
graphics_set_render_target(NULL, 0, 0);
int dx = x + 24, dy = y + 12;
for (int ty = 0; ty < 32; ty++) {
for (int tx = 0; tx < 32; tx++) {
int src_x = tx * 48 / 32;
int src_y = ty * 48 / 32;
uint32_t c1 = icon_buf[src_y * 48 + src_x];
if (c1 != 0xFFFF00FF) put_pixel(dx + tx, dy + ty, c1);
}
}
draw_icon_label(x, y, label);
}
// === Dynamic thumbnail cache for JPG explorer icons ===
#define THUMB_CACHE_SIZE 8
#define THUMB_PIXELS (48 * 48)
@@ -967,6 +1001,12 @@ void draw_window(Window *win) {
draw_rounded_rect_filled(win->x, win->y + 20, win->w, win->h - 20, 8, COLOR_DARK_BG);
draw_rect(win->x, win->y + 20, win->w, 8, COLOR_DARK_BG);
if (win->comp_pixels) {
graphics_blit_buffer(win->comp_pixels, win->x, win->y, win->w, win->h);
} else if (win->pixels) {
graphics_blit_buffer(win->pixels, win->x, win->y, win->w, win->h);
}
if (win->paint) {
win->paint(win);
}
@@ -1101,7 +1141,8 @@ void wm_paint(void) {
else if (str_starts_with(icon->name, "Paint")) draw_paint_icon(icon->x, icon->y, label);
else draw_icon(icon->x, icon->y, label);
} else {
if (str_ends_with(icon->name, ".pnt")) draw_paint_icon(icon->x, icon->y, icon->name);
if (str_ends_with(icon->name, ".elf")) draw_elf_icon(icon->x, icon->y, icon->name);
else if (str_ends_with(icon->name, ".pnt")) draw_paint_icon(icon->x, icon->y, icon->name);
else if (str_ends_with(icon->name, ".jpg") || str_ends_with(icon->name, ".JPG")) {
draw_image_icon(icon->x, icon->y, icon->name);
draw_icon_label(icon->x, icon->y, icon->name);
@@ -1299,6 +1340,41 @@ void wm_bring_to_front(Window *win) {
void wm_add_window(Window *win) {
if (window_count < 32) {
all_windows[window_count++] = win;
wm_bring_to_front(win); // Ensure newly added windows are on top
}
}
void wm_remove_window(Window *win) {
if (!win) return;
int index = -1;
for (int i = 0; i < window_count; i++) {
if (all_windows[i] == win) {
index = i;
break;
}
}
if (index != -1) {
// Shift remaining windows
for (int i = index; i < window_count - 1; i++) {
all_windows[i] = all_windows[i + 1];
}
window_count--;
// Free resources
if (win->pixels) kfree(win->pixels);
if (win->comp_pixels) kfree(win->comp_pixels);
// If the title was allocated in syscall.c, we should free it,
// but currently we don't know for sure if it was kmalloc'd or a literal.
// In syscall.c it is kmalloc'd. Let's assume we should free it if it's not a known literal.
// Safer to just free it since userland windows always have kmalloc'd titles.
if (win->title && win->handle_close) { // Heuristic: user windows have handle_close set in syscall.c
kfree(win->title);
}
kfree(win);
force_redraw = true;
}
}
@@ -1499,7 +1575,12 @@ void wm_handle_click(int x, int y) {
// Check traffic light close button (now at top-left)
if (rect_contains(topmost->x + 8, topmost->y + 2, 12, 12, x, y)) {
topmost->visible = false;
if (topmost->handle_close) {
topmost->handle_close(topmost);
} else {
topmost->visible = false;
}
// Reset window state on close
if (topmost == &win_explorer) {
explorer_reset();
@@ -1749,7 +1830,7 @@ void wm_handle_right_click(int x, int y) {
} else if (str_starts_with(start_menu_pending_app, "Terminal")) {
cmd_reset(); wm_bring_to_front(&win_cmd);
} else if (str_starts_with(start_menu_pending_app, "Calculator")) {
wm_bring_to_front(&win_calculator);
process_create_elf("/bin/calculator.elf");
} else if (str_starts_with(start_menu_pending_app, "Minesweeper")) {
wm_bring_to_front(&win_minesweeper);
} else if (str_starts_with(start_menu_pending_app, "Settings")) {
@@ -1779,7 +1860,7 @@ void wm_handle_right_click(int x, int y) {
if (str_ends_with(icon->name, "Notepad.shortcut")) {
wm_bring_to_front(&win_notepad); handled = true;
} else if (str_ends_with(icon->name, "Calculator.shortcut")) {
wm_bring_to_front(&win_calculator); handled = true;
process_create_elf("/bin/calculator.elf"); handled = true;
} else if (str_ends_with(icon->name, "Minesweeper.shortcut")) {
wm_bring_to_front(&win_minesweeper); handled = true;
} else if (str_ends_with(icon->name, "Settings.shortcut")) {
@@ -1830,7 +1911,9 @@ void wm_handle_right_click(int x, int y) {
char path[128] = "/Desktop/";
int p=9; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
if (str_ends_with(icon->name, ".pnt")) {
if (str_ends_with(icon->name, ".elf")) {
process_create_elf(path);
} else if (str_ends_with(icon->name, ".pnt")) {
paint_load(path);
wm_bring_to_front(&win_paint);
} else if (str_ends_with(icon->name, ".md")) {
@@ -2173,7 +2256,6 @@ void wm_init(void) {
notepad_init();
cmd_init();
calculator_init();
explorer_init();
editor_init();
markdown_init();
@@ -2189,27 +2271,25 @@ void wm_init(void) {
// Initialize z-indices
win_notepad.z_index = 0;
win_cmd.z_index = 1;
win_calculator.z_index = 2;
win_explorer.z_index = 3;
win_editor.z_index = 4;
win_markdown.z_index = 5;
win_control_panel.z_index = 6;
win_about.z_index = 7;
win_minesweeper.z_index = 8;
win_paint.z_index = 9;
win_explorer.z_index = 2;
win_editor.z_index = 3;
win_markdown.z_index = 4;
win_control_panel.z_index = 5;
win_about.z_index = 6;
win_minesweeper.z_index = 7;
win_paint.z_index = 8;
all_windows[0] = &win_notepad;
all_windows[1] = &win_cmd;
all_windows[2] = &win_calculator;
all_windows[3] = &win_explorer;
all_windows[4] = &win_editor;
all_windows[5] = &win_markdown;
all_windows[6] = &win_control_panel;
all_windows[7] = &win_about;
all_windows[8] = &win_minesweeper;
all_windows[9] = &win_paint;
all_windows[10] = &win_viewer;
window_count = 11;
all_windows[2] = &win_explorer;
all_windows[3] = &win_editor;
all_windows[4] = &win_markdown;
all_windows[5] = &win_control_panel;
all_windows[6] = &win_about;
all_windows[7] = &win_minesweeper;
all_windows[8] = &win_paint;
all_windows[9] = &win_viewer;
window_count = 10;
// Only show Explorer and Notepad on desktop (Explorer on top)
win_explorer.visible = false;
@@ -2222,7 +2302,6 @@ void wm_init(void) {
// Rest are hidden initially
win_cmd.visible = false;
win_calculator.visible = false;
win_editor.visible = false;
win_markdown.visible = false;
win_control_panel.visible = false;

View File

@@ -48,12 +48,15 @@ struct Window {
bool focused;
int z_index; // Layering depth (higher = on top)
void *data; // Per-window private data
uint32_t *pixels; // Pointer to backing buffer for UI events (Back Buffer)
uint32_t *comp_pixels; // Pointer to composition buffer (Front Buffer)
// Callbacks
void (*paint)(Window *win);
void (*handle_key)(Window *win, char c);
void (*handle_click)(Window *win, int x, int y);
void (*handle_right_click)(Window *win, int x, int y);
void (*handle_close)(Window *win);
};
void wm_init(void);
@@ -63,6 +66,7 @@ void wm_handle_click(int x, int y);
void wm_handle_right_click(int x, int y);
void wm_process_input(void);
void wm_add_window(Window *win);
void wm_remove_window(Window *win);
void wm_bring_to_front(Window *win);
// Redraw system
@@ -87,6 +91,7 @@ void draw_traffic_light(int x, int y); // Red close button only
void draw_icon(int x, int y, const char *label);
void draw_folder_icon(int x, int y, const char *label);
void draw_document_icon(int x, int y, const char *label);
void draw_elf_icon(int x, int y, const char *label);
void draw_image_icon(int x, int y, const char *label);
void draw_notepad_icon(int x, int y, const char *label);
void draw_calculator_icon(int x, int y, const char *label);