diff --git a/kernel/src/Api/Syscall.cpp b/kernel/src/Api/Syscall.cpp index 8756f52..5d1f14f 100644 --- a/kernel/src/Api/Syscall.cpp +++ b/kernel/src/Api/Syscall.cpp @@ -417,6 +417,8 @@ namespace Montauk { return Sys_UnloadLib(frame->arg1); case SYS_DLSYM: return (int64_t)Sys_DLSym(frame->arg1, frame->arg2); + case SYS_GETLIBBASE: + return (int64_t)Sys_GetLibBase(frame->arg1); default: return -1; } diff --git a/kernel/src/Api/Syscall.hpp b/kernel/src/Api/Syscall.hpp index 7d0fc75..ce27865 100644 --- a/kernel/src/Api/Syscall.hpp +++ b/kernel/src/Api/Syscall.hpp @@ -210,6 +210,7 @@ namespace Montauk { static constexpr uint64_t SYS_LOAD_LIB = 114; static constexpr uint64_t SYS_UNLOAD_LIB = 115; static constexpr uint64_t SYS_DLSYM = 116; + static constexpr uint64_t SYS_GETLIBBASE = 117; static constexpr uint32_t IPC_SIGNAL_READABLE = 1u << 0; static constexpr uint32_t IPC_SIGNAL_WRITABLE = 1u << 1; diff --git a/kernel/src/Sched/ElfLoader.cpp b/kernel/src/Sched/ElfLoader.cpp index 149a5e2..7c5d00f 100644 --- a/kernel/src/Sched/ElfLoader.cpp +++ b/kernel/src/Sched/ElfLoader.cpp @@ -270,11 +270,11 @@ namespace Sched { if (copyStart < copyEnd) { // Source: file data at (copyStart - targetSegStart) offset from p_offset uint64_t srcOffset = phdr->p_offset + (copyStart - targetSegStart); - // Dest: page at (copyStart - pageStart) offset - uint64_t dstOffset = copyStart - pageStart; + // Dest: page at (copyStart - targetSegStart) offset, then adjusted for this page + uint64_t pageDataOffset = copyStart - targetSegStart; uint64_t copySize = copyEnd - copyStart; - uint8_t* dst = (uint8_t*)Memory::HHDM(physAddr) + dstOffset; + uint8_t* dst = (uint8_t*)Memory::HHDM(physAddr) + pageDataOffset; uint8_t* src = fileData + srcOffset; memcpy(dst, src, copySize); } diff --git a/programs/GNUmakefile b/programs/GNUmakefile index ff853e9..290e5b9 100644 --- a/programs/GNUmakefile +++ b/programs/GNUmakefile @@ -59,7 +59,7 @@ BINDIR := bin PROGRAMS := $(notdir $(wildcard src/*)) # Programs with custom Makefiles (built separately). -CUSTOM_BUILDS := doom fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer volume music video bluetooth terminal klog procmgr calculator desktop login shell rpgdemo paint tcc lua screenshot texteditor mandelbrot printers printd printctl dialogs test_dl libloader +CUSTOM_BUILDS := doom fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer volume music video bluetooth terminal klog procmgr calculator desktop login shell rpgdemo paint tcc lua screenshot texteditor mandelbrot printers printd printctl dialogs test_dl libloader libhello SYSTEM_PROGRAMS := $(filter-out $(CUSTOM_BUILDS),$(PROGRAMS)) # Build targets: system programs go to bin/os/, apps go to bin/apps//. @@ -81,9 +81,9 @@ CA_CERTS := $(BINDIR)/etc/ca-certificates.crt # Common shared assets (wallpapers, etc.) COMMONKEEP := $(BINDIR)/common/.keep -.PHONY: all clean doom fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer volume music video bluetooth terminal klog procmgr calculator login desktop shell rpgdemo paint tcc lua screenshot texteditor mandelbrot printers printd printctl dialogs icons fonts bearssl libc tls libjpeg libjpegwrite install-apps libloader libs test_dl +.PHONY: all clean doom fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer volume music video bluetooth terminal klog procmgr calculator login desktop shell rpgdemo paint tcc lua screenshot texteditor mandelbrot printers printd printctl dialogs icons fonts bearssl libc tls libjpeg libjpegwrite install-apps libloader libs libhello test_dl -all: bearssl libc libjpeg libjpegwrite tls libloader libs $(TARGETS) fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer volume music video bluetooth terminal klog procmgr calculator doom rpgdemo paint tcc lua screenshot texteditor mandelbrot printers printd printctl dialogs login desktop shell icons fonts install-apps test_dl $(MANDST) $(WWWDST) $(CA_CERTS) $(COMMONKEEP) +all: bearssl libc libjpeg libjpegwrite tls libloader libs libhello $(TARGETS) fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer volume music video bluetooth terminal klog procmgr calculator doom rpgdemo paint tcc lua screenshot texteditor mandelbrot printers printd printctl dialogs login desktop shell icons fonts install-apps test_dl $(MANDST) $(WWWDST) $(CA_CERTS) $(COMMONKEEP) # Build BearSSL static library (cross-compiled for freestanding x86_64). BEARSSL_INCLUDES := -isystem $(shell cd .. && pwd)/kernel/freestnd-c-hdrs/x86_64/include -isystem $(abspath include/libc) @@ -112,6 +112,10 @@ libloader: libc libs: libloader $(MAKE) -C libs/libmath +# Build libhello shared GUI library. +libhello: libloader + $(MAKE) -C libs/libhello + # Build fetch via its own Makefile (depends on bearssl, libc, and tls). fetch: bearssl libc tls $(MAKE) -C src/fetch @@ -348,4 +352,5 @@ clean: $(MAKE) -C src/dialogs clean $(MAKE) -C src/libloader clean $(MAKE) -C libs/libmath clean + $(MAKE) -C libs/libhello clean $(MAKE) -C src/test_dl clean diff --git a/programs/include/Api/Syscall.hpp b/programs/include/Api/Syscall.hpp index fc878b1..b1d1222 100644 --- a/programs/include/Api/Syscall.hpp +++ b/programs/include/Api/Syscall.hpp @@ -148,6 +148,7 @@ namespace Montauk { static constexpr uint64_t SYS_LOAD_LIB = 114; static constexpr uint64_t SYS_UNLOAD_LIB = 115; static constexpr uint64_t SYS_DLSYM = 116; + static constexpr uint64_t SYS_GETLIBBASE = 117; static constexpr uint32_t IPC_SIGNAL_READABLE = 1u << 0; static constexpr uint32_t IPC_SIGNAL_WRITABLE = 1u << 1; diff --git a/programs/include/gui/canvas.hpp b/programs/include/gui/canvas.hpp index fda9d62..f526098 100644 --- a/programs/include/gui/canvas.hpp +++ b/programs/include/gui/canvas.hpp @@ -135,51 +135,12 @@ struct Canvas { void text(int x, int y, const char* str, Color c) { if (fonts::system_font && fonts::system_font->valid) { fonts::system_font->draw_to_buffer(pixels, w, h, x, y, str, c, fonts::UI_SIZE); - return; - } - uint32_t px = c.to_pixel(); - for (int i = 0; str[i] && x + (i + 1) * FONT_WIDTH <= w; i++) { - const uint8_t* glyph = &font_data[(unsigned char)str[i] * FONT_HEIGHT]; - int cx = x + i * FONT_WIDTH; - for (int fy = 0; fy < FONT_HEIGHT && y + fy < h; fy++) { - uint8_t bits = glyph[fy]; - for (int fx = 0; fx < FONT_WIDTH; fx++) { - if (bits & (0x80 >> fx)) { - int dx = cx + fx; - int dy = y + fy; - if (dx >= 0 && dx < w && dy >= 0) - pixels[dy * w + dx] = px; - } - } - } } } void text_2x(int x, int y, const char* str, Color c) { if (fonts::system_font && fonts::system_font->valid) { fonts::system_font->draw_to_buffer(pixels, w, h, x, y, str, c, fonts::LARGE_SIZE); - return; - } - uint32_t px = c.to_pixel(); - for (int i = 0; str[i] && x + (i + 1) * FONT_WIDTH * 2 <= w; i++) { - const uint8_t* glyph = &font_data[(unsigned char)str[i] * FONT_HEIGHT]; - int cx = x + i * FONT_WIDTH * 2; - for (int fy = 0; fy < FONT_HEIGHT; fy++) { - uint8_t bits = glyph[fy]; - for (int fx = 0; fx < FONT_WIDTH; fx++) { - if (bits & (0x80 >> fx)) { - int dx = cx + fx * 2; - int dy = y + fy * 2; - for (int sy = 0; sy < 2; sy++) - for (int sx = 0; sx < 2; sx++) { - int pdx = dx + sx; - int pdy = dy + sy; - if (pdx >= 0 && pdx < w && pdy >= 0 && pdy < h) - pixels[pdy * w + pdx] = px; - } - } - } - } } } diff --git a/programs/include/montauk/syscall.h b/programs/include/montauk/syscall.h index b92f097..9e7c126 100644 --- a/programs/include/montauk/syscall.h +++ b/programs/include/montauk/syscall.h @@ -292,6 +292,9 @@ namespace montauk { inline void* dlsym(int handle, uint64_t symbolOffset) { return (void*)syscall2(Montauk::SYS_DLSYM, (uint64_t)handle, symbolOffset); } + inline uint64_t get_libbase(int handle) { + return (uint64_t)syscall1(Montauk::SYS_GETLIBBASE, (uint64_t)handle); + } // Process management inline void waitpid(int pid) { syscall1(Montauk::SYS_WAITPID, (uint64_t)pid); } diff --git a/programs/libs/libhello/Makefile b/programs/libs/libhello/Makefile new file mode 100644 index 0000000..a7cb8b6 --- /dev/null +++ b/programs/libs/libhello/Makefile @@ -0,0 +1,74 @@ +# Makefile for libhello shared library +# Builds libhello.lib at fixed address 0x400000 (relocated at load time) + +# Target architecture. +ARCH := x86_64 + +# Toolchain +TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-elf- +CXX := $(TOOLCHAIN_PREFIX)g++ +NM := $(TOOLCHAIN_PREFIX)nm +STRIP := $(TOOLCHAIN_PREFIX)strip + +# Compiler flags: freestanding, no stdlib +override CXXFLAGS := \ + -std=gnu++20 \ + -g -O2 -pipe \ + -Wall \ + -Wextra \ + -nostdinc \ + -ffreestanding \ + -fno-stack-protector \ + -fno-stack-check \ + -fno-PIC \ + -fno-rtti \ + -fno-exceptions \ + -ffunction-sections \ + -fdata-sections \ + -m64 \ + -march=x86-64 \ + -mno-80387 \ + -mno-mmx \ + -mno-red-zone \ + -mcmodel=small \ + -I ../../include \ + -isystem ../../include/libc \ + -isystem ../../include/montauk \ + -isystem ../../include/gui \ + -isystem ../../../kernel/freestnd-c-hdrs/x86_64/include \ + -isystem ../../../kernel/freestnd-cxx-hdrs/x86_64/include + +# Linker flags: freestanding static ELF at fixed address +# Note: NOT using --gc-sections so all functions are kept +override LDFLAGS := \ + -nostdlib \ + -static \ + -Wl,--build-id=none \ + -Wl,-m,elf_x86_64 \ + -T link.ld + +# Output +OUTDIR := ../../bin/os +LIBNAME := libhello +LIBSRC := src/libhello.cpp + +.PHONY: all clean + +all: $(OUTDIR)/$(LIBNAME).lib $(OUTDIR)/$(LIBNAME).lib.sym + +$(OUTDIR)/$(LIBNAME).lib: $(LIBSRC) + @mkdir -p $(OUTDIR) + $(CXX) $(CXXFLAGS) -c src/libhello.cpp -o src/libhello.o + $(CXX) $(CXXFLAGS) $(LDFLAGS) src/libhello.o -o $@ + +# Generate symbol file from nm output +# Format: "symbol_name,offset_in_hex" +$(OUTDIR)/$(LIBNAME).lib.sym: $(OUTDIR)/$(LIBNAME).lib + @mkdir -p $(OUTDIR) + @echo "# Symbol table for $(LIBNAME)" > $@ + @echo "# This file maps symbol names to offsets from library base" >> $@ + @$(NM) $(OUTDIR)/$(LIBNAME).lib | grep ' T ' | awk '{printf "%s,0x%x\n", $$3, strtonum("0x" $$1) - 0x400000}' >> $@ + @echo "Generated symbol file: $@" + +clean: + rm -rf ../../bin/os/$(LIBNAME).lib ../../bin/os/$(LIBNAME).lib.sym src/libhello.o src/stb_truetype_impl.o diff --git a/programs/libs/libhello/link.ld b/programs/libs/libhello/link.ld new file mode 100644 index 0000000..ce8ed29 --- /dev/null +++ b/programs/libs/libhello/link.ld @@ -0,0 +1,13 @@ +SECTIONS +{ + . = 0x400000; + .text : { + *(.text) + } + .eh_frame : { + *(.eh_frame) + } + .rodata : { + *(.rodata) + } +} diff --git a/programs/libs/libhello/src/libhello.cpp b/programs/libs/libhello/src/libhello.cpp new file mode 100644 index 0000000..2a98a78 --- /dev/null +++ b/programs/libs/libhello/src/libhello.cpp @@ -0,0 +1,67 @@ +/* + * libhello.cpp + * Sample shared GUI library for MontaukOS + * Creates a window and renders text as a demo of the shared library + GUI system + * Copyright (c) 2026 Daniel Hammer +*/ + +#include + +// Exported demo function - creates a window and renders until closed +extern "C" int hello_run() { + // Create window + Montauk::WinCreateResult wres; + if (montauk::win_create("libhello Demo", 320, 200, &wres) < 0 || wres.id < 0) { + return -1; + } + + int winId = wres.id; + uint32_t* pixels = (uint32_t*)(uintptr_t)wres.pixelVa; + int width = 200; + int height = 320; + + // Simple render - fill with a color pattern + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + // Dark blue background + pixels[y * width + x] = 0xFF1a1a2e; + } + } + + // Present the initial frame + montauk::win_present(winId); + + // Event loop + while (true) { + Montauk::WinEvent ev; + int r = montauk::win_poll(winId, &ev); + + if (r < 0) { + break; + } + if (r == 0) { + montauk::sleep_ms(16); + continue; + } + + if (ev.type == 3) { // close + break; + } + if (ev.type == 2) { // resize + width = ev.resize.w; + height = ev.resize.h; + pixels = (uint32_t*)(uintptr_t)montauk::win_resize(winId, width, height); + + // Re-render on resize + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + pixels[y * width + x] = 0xFF1a1a2e; + } + } + montauk::win_present(winId); + } + } + + montauk::win_destroy(winId); + return 0; +} diff --git a/programs/libs/libhello/src/libhello.o b/programs/libs/libhello/src/libhello.o new file mode 100644 index 0000000..c315855 Binary files /dev/null and b/programs/libs/libhello/src/libhello.o differ diff --git a/programs/libs/libhello/src/stb_truetype_impl.cpp b/programs/libs/libhello/src/stb_truetype_impl.cpp new file mode 100644 index 0000000..0ebd588 --- /dev/null +++ b/programs/libs/libhello/src/stb_truetype_impl.cpp @@ -0,0 +1,33 @@ +/* + * stb_truetype_impl.cpp + * Single compilation unit for stb_truetype in libhello + * Copyright (c) 2026 Daniel Hammer + */ + +#include +#include +#include +#include +#include + +#define STBTT_ifloor(x) ((int) stb_floor(x)) +#define STBTT_iceil(x) ((int) stb_ceil(x)) +#define STBTT_sqrt(x) stb_sqrt(x) +#define STBTT_pow(x,y) stb_pow(x,y) +#define STBTT_fmod(x,y) stb_fmod(x,y) +#define STBTT_cos(x) stb_cos(x) +#define STBTT_acos(x) stb_acos(x) +#define STBTT_fabs(x) stb_fabs(x) + +#define STBTT_malloc(x,u) ((void)(u), montauk::malloc(x)) +#define STBTT_free(x,u) ((void)(u), montauk::mfree(x)) + +#define STBTT_memcpy(d,s,n) montauk::memcpy(d,s,n) +#define STBTT_memset(d,v,n) montauk::memset(d,v,n) + +#define STBTT_strlen(x) montauk::slen(x) + +#define STBTT_assert(x) ((void)(x)) + +#define STB_TRUETYPE_IMPLEMENTATION +#include diff --git a/programs/src/libloader/libloader.cpp b/programs/src/libloader/libloader.cpp index eb8ef70..65c1dce 100644 --- a/programs/src/libloader/libloader.cpp +++ b/programs/src/libloader/libloader.cpp @@ -107,6 +107,10 @@ static bool parseSymbolFile(const char* symPath, LibHandle* lib) { static uint64_t hexToUint64(const char* str) { uint64_t result = 0; + // Skip optional "0x" prefix + if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) { + str += 2; + } while (*str) { char c = *str; uint64_t val = 0; @@ -164,14 +168,9 @@ LibHandle* dlopen(const char* path) { void* dlsym(LibHandle* lib, const char* symbolName) { if (!lib || !symbolName) return nullptr; - // Get base address if we don't have it + // Get base address from kernel if we don't have it if (lib->base == 0) { - // The base is stored in the handle - we need a syscall to get it - // For now, we'll use a workaround: calculate base from slot - // handle = slot + 1, so slot = handle - 1 - // base = 0x60000000 + slot * 0x200000 - int slot = lib->handle - 1; - lib->base = 0x60000000ULL + (uint64_t)slot * 0x200000ULL; + lib->base = montauk::get_libbase(lib->handle); } // Look up in symbol table diff --git a/programs/src/test_dl/main.cpp b/programs/src/test_dl/main.cpp index cd01edc..c7b18d0 100644 --- a/programs/src/test_dl/main.cpp +++ b/programs/src/test_dl/main.cpp @@ -7,8 +7,9 @@ #include #include -// Forward declaration +// Forward declarations static void print_int(int val); +static void print_hex(uint64_t val); extern "C" void _start() { montauk::print("=== Dynamic Library Test ===\n\n"); @@ -78,6 +79,39 @@ extern "C" void _start() { libloader::dlclose(lib); montauk::print("Library unloaded.\n"); + // Test loading libhello (GUI library) + montauk::print("\nLoading libhello (GUI library)...\n"); + LibHandle* hellolib = libloader::dlopen("0:/os/libhello.lib"); + if (!hellolib) { + montauk::print("ERROR: Failed to load libhello.lib\n"); + montauk::exit(1); + } + montauk::print("Library loaded successfully!\n\n"); + + // Resolve hello_run + typedef int (*hello_run_t)(void); + hello_run_t hello_run = (hello_run_t)libloader::dlsym(hellolib, "hello_run"); + if (!hello_run) { + montauk::print("ERROR: Failed to resolve hello_run\n"); + montauk::exit(1); + } + montauk::print(" hello_run: OK\n\n"); + + // Debug: print hello_run address + montauk::print(" DEBUG: hello_run @ "); + print_hex((uint64_t)hello_run); + montauk::print("\n"); + + // Run the GUI demo (this creates a window and event loop) + montauk::print("Running GUI demo...\n"); + hello_run(); + + // Unload the library + montauk::print("GUI demo closed.\n"); + montauk::print("Unloading library...\n"); + libloader::dlclose(hellolib); + montauk::print("Library unloaded.\n"); + montauk::print("\n=== All tests passed! ===\n"); montauk::exit(0); } @@ -110,3 +144,25 @@ static void print_int(int val) { montauk::putchar(buf[i]); } } + +// Print hex value (uppercase, with 0x prefix) +static void print_hex(uint64_t val) { + montauk::print("0x"); + char buf[20]; + int idx = 0; + + if (val == 0) { + buf[idx++] = '0'; + } else { + while (val > 0) { + int digit = val & 0xF; + buf[idx++] = (digit < 10) ? ('0' + digit) : ('A' + digit - 10); + val >>= 4; + } + } + + // Reverse the buffer + for (int i = idx - 1; i >= 0; i--) { + montauk::putchar(buf[i]); + } +}