commit 66a97175590473fce07b6ce5f952ea8faa37abbf parent 51f75cdfff4b082259a3fd0d9b0a608283a2a9a0 Author: luajitos <bbhbb2094@gmail.com> Date: Sat, 6 Dec 2025 14:33:36 +0000 Added grub and fixed crypto tool Diffstat:
21 files changed, 1108 insertions(+), 133 deletions(-)
diff --git a/LuaJIT b/LuaJIT @@ -1 +0,0 @@ -Subproject commit 68354f444728ef99bb51bb4d86e8f1b40853a898 diff --git a/build.sh b/build.sh @@ -164,6 +164,9 @@ ${CC} ${CFLAGS} ${LUAJIT_INCLUDE} -c partition.c -o build/partition.o echo "Step 4c8: Compiling fat16.c..." ${CC} ${CFLAGS} ${LUAJIT_INCLUDE} -c fat16.c -o build/fat16.o +echo "Step 4c9: Compiling grub.c..." +${CC} ${CFLAGS} ${LUAJIT_INCLUDE} -c grub.c -o build/grub.o + echo "Step 4d: Compiling decoder.c..." ${CC} ${CFLAGS} ${LUAJIT_INCLUDE} -c decoder.c -o build/decoder.o @@ -289,7 +292,7 @@ if [ -f "$LIBGCC_PATH" ]; then LIBGCC="$LIBGCC_PATH" echo "Using libgcc: $LIBGCC" ${LD} ${LDFLAGS} -T linker.ld -o build/kernel.bin \ - build/boot.o build/syscall.o build/exceptions.o build/libc.o build/paging.o build/graphics.o build/vesa.o build/mouse.o build/usb_uhci.o build/keyboard.o build/ata.o build/fde.o build/diskfs.o build/partition.o build/fat16.o \ + build/boot.o build/syscall.o build/exceptions.o build/libc.o build/paging.o build/graphics.o build/vesa.o build/mouse.o build/usb_uhci.o build/keyboard.o build/ata.o build/fde.o build/diskfs.o build/partition.o build/fat16.o build/grub.o \ build/decoder.o build/decoder_BMP.o build/decoder_PNG.o build/decoder_JPEG.o build/splash.o \ build/compression.o build/deflate_impl.o build/Deflate.o build/LZMA.o build/GZip.o build/zlib.o \ build/ramdisk.o build/luajit_init.o build/kernel.o \ @@ -307,7 +310,7 @@ if [ -f "$LIBGCC_PATH" ]; then else echo "Warning: 32-bit libgcc not found, linking without it" ${LD} ${LDFLAGS} -T linker.ld -o build/kernel.bin \ - build/boot.o build/syscall.o build/exceptions.o build/libc.o build/paging.o build/graphics.o build/vesa.o build/mouse.o build/usb_uhci.o build/keyboard.o build/ata.o build/fde.o build/diskfs.o build/partition.o build/fat16.o \ + build/boot.o build/syscall.o build/exceptions.o build/libc.o build/paging.o build/graphics.o build/vesa.o build/mouse.o build/usb_uhci.o build/keyboard.o build/ata.o build/fde.o build/diskfs.o build/partition.o build/fat16.o build/grub.o \ build/decoder.o build/decoder_BMP.o build/decoder_PNG.o build/decoder_JPEG.o build/splash.o \ build/compression.o build/deflate_impl.o build/Deflate.o build/LZMA.o build/GZip.o build/zlib.o \ build/ramdisk.o build/luajit_init.o build/kernel.o \ diff --git a/crypto/crypto.c b/crypto/crypto.c @@ -1231,10 +1231,7 @@ int luaopen_crypto(lua_State *L) { lua_setfield(L, -2, "decryptString"); lua_setfield(L, -2, "Salsa20"); - /* Create hash table with SHA-256 as default and other hash methods */ - lua_newtable(L); /* hash table */ - - /* Add hash methods */ + /* Register hash functions directly on crypto table */ lua_pushcfunction(L, l_hash_sha512); lua_setfield(L, -2, "SHA512"); @@ -1248,52 +1245,28 @@ int luaopen_crypto(lua_State *L) { lua_setfield(L, -2, "CRC32"); lua_pushcfunction(L, l_hash_sha3); - lua_setfield(L, -2, "SHA3"); - lua_pushcfunction(L, l_hash_sha3); - lua_setfield(L, -2, "SHA3_256"); + lua_setfield(L, -2, "SHA3-256"); lua_pushcfunction(L, l_hash_sha3_512); - lua_setfield(L, -2, "SHA3_512"); + lua_setfield(L, -2, "SHA3-512"); lua_pushcfunction(L, l_hash_blake2b); - lua_setfield(L, -2, "BLAKE2b"); - lua_pushcfunction(L, l_hash_blake2b); - lua_setfield(L, -2, "BLAKE2b_256"); + lua_setfield(L, -2, "BLAKE2b-256"); lua_pushcfunction(L, l_hash_blake2b_512); - lua_setfield(L, -2, "BLAKE2b_512"); - - /* Create metatable with __call for SHA3-256 (default hash) */ - lua_newtable(L); /* metatable */ - lua_pushcfunction(L, l_hash_call); - lua_setfield(L, -2, "__call"); - lua_setmetatable(L, -2); /* Set metatable on hash table */ - - /* Set hash table in crypto module */ - lua_setfield(L, -2, "hash"); + lua_setfield(L, -2, "BLAKE2b-512"); - /* Create PBKDF2 subtable */ - lua_newtable(L); + /* Register KDF functions directly on crypto table */ lua_pushcfunction(L, l_deriveKey); - lua_setfield(L, -2, "deriveKey"); - lua_pushcfunction(L, l_deriveKeyString); - lua_setfield(L, -2, "deriveKeyString"); - lua_pushcfunction(L, l_generateSalt); - lua_setfield(L, -2, "generateSalt"); lua_setfield(L, -2, "PBKDF2"); - /* Create Argon2 subtable */ - lua_newtable(L); lua_pushcfunction(L, l_argon2id_derive); - lua_setfield(L, -2, "deriveKey"); - lua_pushcfunction(L, l_generateSalt); - lua_setfield(L, -2, "generateSalt"); - lua_setfield(L, -2, "Argon2"); + lua_setfield(L, -2, "Argon2id"); - /* Create HKDF subtable */ - lua_newtable(L); lua_pushcfunction(L, l_hkdf_derive); - lua_setfield(L, -2, "deriveKey"); lua_setfield(L, -2, "HKDF"); + lua_pushcfunction(L, l_generateSalt); + lua_setfield(L, -2, "generateSalt"); + /* Add simple deriveKey function at top level - crypto.deriveKey(password) uses Argon2id */ lua_pushcfunction(L, l_deriveKeySimple); lua_setfield(L, -2, "deriveKey"); diff --git a/crypto_init.c b/crypto_init.c @@ -52,9 +52,7 @@ int luaopen_crypto(lua_State *L) { lua_pushcfunction(L, l_x25519_shared_secret); lua_setfield(L, -2, "x25519_shared_secret"); - /* Create hash subtable */ - lua_newtable(L); - + /* Register hash functions directly on crypto table */ lua_pushcfunction(L, l_hash_md5); lua_setfield(L, -2, "MD5"); @@ -68,23 +66,20 @@ int luaopen_crypto(lua_State *L) { lua_setfield(L, -2, "SHA512"); lua_pushcfunction(L, l_hash_sha3); - lua_setfield(L, -2, "SHA3_256"); + lua_setfield(L, -2, "SHA3-256"); lua_pushcfunction(L, l_hash_sha3_512); - lua_setfield(L, -2, "SHA3_512"); + lua_setfield(L, -2, "SHA3-512"); lua_pushcfunction(L, l_hash_blake2b); - lua_setfield(L, -2, "BLAKE2b"); + lua_setfield(L, -2, "BLAKE2b-256"); lua_pushcfunction(L, l_hash_blake2b_512); - lua_setfield(L, -2, "BLAKE2b_512"); + lua_setfield(L, -2, "BLAKE2b-512"); lua_pushcfunction(L, l_hash_crc32); lua_setfield(L, -2, "CRC32"); - /* Set hash table in crypto */ - lua_setfield(L, -2, "hash"); - /* Set crypto table as global */ lua_setglobal(L, "crypto"); diff --git a/grub.c b/grub.c @@ -0,0 +1,828 @@ +/* GRUB-like Bootloader Installation for LuajitOS + * + * Implements a complete bootloader that: + * 1. MBR (sector 0) - loads core loader from sectors 1-62 + * 2. Core loader - parses FAT16, loads /BOOT/KERNEL.BIN, jumps to it + * + * The core loader is installed in the "embedding area" between MBR and + * the first partition (sectors 1 to 2047, but we only use 1-62 = 31KB). + */ + +#include "grub.h" +#include "ata.h" +#include "partition.h" +#include "fat16.h" +#include <string.h> +#include <stdio.h> + +/* External terminal function for debug output */ +extern void terminal_writestring(const char *str); + +/* ============================================================================ + * MBR Boot Code (Stage 1) - 446 bytes max + * + * This MBR: + * 1. Relocates itself to 0x0600 + * 2. Loads sectors 1-62 (core loader) to 0x7E00 + * 3. Jumps to core loader at 0x7E00 + * ========================================================================= */ + +static const uint8_t mbr_boot_code[] = { + /* 0x00: Entry - BIOS loads us at 0x7C00 */ + 0xFA, /* cli */ + 0x31, 0xC0, /* xor ax, ax */ + 0x8E, 0xD8, /* mov ds, ax */ + 0x8E, 0xC0, /* mov es, ax */ + 0x8E, 0xD0, /* mov ss, ax */ + 0xBC, 0x00, 0x7C, /* mov sp, 0x7C00 */ + 0xFB, /* sti */ + + /* Save drive number */ + 0x88, 0x16, 0x00, 0x06, /* mov [0x0600], dl */ + + /* Relocate MBR from 0x7C00 to 0x0600 */ + 0xBE, 0x00, 0x7C, /* mov si, 0x7C00 */ + 0xBF, 0x00, 0x06, /* mov di, 0x0600 */ + 0xB9, 0x00, 0x02, /* mov cx, 512 */ + 0xFC, /* cld */ + 0xF3, 0xA4, /* rep movsb */ + + /* Jump to relocated code + offset */ + 0xEA, 0x23, 0x06, 0x00, 0x00, /* jmp 0x0000:0x0623 */ + + /* 0x23: Now running from 0x0600, load core (sectors 1-62) to 0x7C00 */ + /* We load 62 sectors (31KB) starting from sector 1 */ + + /* Set up DAP at 0x0700 */ + 0xBF, 0x00, 0x07, /* mov di, 0x0700 */ + 0xC6, 0x05, 0x10, /* mov byte [di+0], 16 (size) */ + 0xC6, 0x45, 0x01, 0x00, /* mov byte [di+1], 0 */ + 0xC6, 0x45, 0x02, 0x3E, /* mov byte [di+2], 62 (sector count) */ + 0xC6, 0x45, 0x03, 0x00, /* mov byte [di+3], 0 */ + 0xC7, 0x45, 0x04, 0x00, 0x7C, /* mov word [di+4], 0x7C00 (offset) */ + 0xC7, 0x45, 0x06, 0x00, 0x00, /* mov word [di+6], 0x0000 (segment) */ + 0xC7, 0x45, 0x08, 0x01, 0x00, /* mov word [di+8], 1 (LBA low) */ + 0xC7, 0x45, 0x0A, 0x00, 0x00, /* mov word [di+10], 0 */ + 0xC7, 0x45, 0x0C, 0x00, 0x00, /* mov word [di+12], 0 */ + 0xC7, 0x45, 0x0E, 0x00, 0x00, /* mov word [di+14], 0 */ + + /* Read sectors */ + 0xB4, 0x42, /* mov ah, 0x42 */ + 0x8A, 0x16, 0x00, 0x06, /* mov dl, [0x0600] (drive) */ + 0xBE, 0x00, 0x07, /* mov si, 0x0700 (DAP) */ + 0xCD, 0x13, /* int 0x13 */ + 0x72, 0x0D, /* jc error */ + + /* Jump to core loader with drive in DL */ + 0x8A, 0x16, 0x00, 0x06, /* mov dl, [0x0600] */ + 0xEA, 0x00, 0x7C, 0x00, 0x00, /* jmp 0x0000:0x7C00 */ + + /* Error handler */ + 0xBE, 0x78, 0x06, /* mov si, 0x0678 (error msg) */ + /* Print loop */ + 0xAC, /* lodsb */ + 0x08, 0xC0, /* or al, al */ + 0x74, 0x04, /* jz halt */ + 0xB4, 0x0E, /* mov ah, 0x0E */ + 0xCD, 0x10, /* int 0x10 */ + 0xEB, 0xF5, /* jmp print */ + /* Halt */ + 0xF4, /* hlt */ + 0xEB, 0xFD, /* jmp $ */ + + /* 0x78: Error message */ + 'D', 'i', 's', 'k', ' ', 'e', 'r', 'r', 'o', 'r', '\r', '\n', 0 +}; + +/* ============================================================================ + * Core Loader (Stage 2) - up to 31KB (62 sectors) + * + * This loader: + * 1. Switches to protected mode + * 2. Enables A20 line + * 3. Reads FAT16 boot partition + * 4. Finds and loads /BOOT/KERNEL.BIN to 0x100000 (1MB) + * 5. Sets up multiboot info structure + * 6. Jumps to kernel entry point + * + * Layout at 0x7C00: + * - 0x7C00-0x7DFF: Stage 2 boot sector (this code) + * - 0x7E00-0x????: Continuation of stage 2 + * - 0x8000: FAT buffer + * - 0x10000: Root directory buffer + * - 0x20000: File read buffer + * - 0x100000: Kernel load address + * ========================================================================= */ + +/* This is 16-bit real mode code that will be assembled into the core loader */ +static const uint8_t core_loader[] = { + /* === Sector 0 of core (at 0x7C00) === */ + + /* 0x00: Entry point */ + 0xFA, /* cli */ + 0x31, 0xC0, /* xor ax, ax */ + 0x8E, 0xD8, /* mov ds, ax */ + 0x8E, 0xC0, /* mov es, ax */ + 0x8E, 0xD0, /* mov ss, ax */ + 0xBC, 0x00, 0x7C, /* mov sp, 0x7C00 */ + + /* Save drive number at known location */ + 0x88, 0x16, 0xFC, 0x8F, /* mov [0x8FFC], dl */ + + /* Print loading message */ + 0xBE, 0x00, 0x7D, /* mov si, 0x7D00 (message) */ + 0xE8, 0x80, 0x00, /* call print_string (at ~0x7C90) */ + + /* Enable A20 line via keyboard controller */ + 0xE8, 0xA0, 0x00, /* call enable_a20 (at ~0x7CB0) */ + + /* Read partition table to find boot partition */ + /* Read MBR (sector 0) to 0x8000 */ + 0xBB, 0x00, 0x80, /* mov bx, 0x8000 */ + 0xB9, 0x01, 0x00, /* mov cx, 1 (1 sector) */ + 0x31, 0xD2, /* xor dx, dx */ + 0x31, 0xF6, /* xor si, si (LBA = 0) */ + 0xE8, 0xE0, 0x00, /* call read_sectors */ + + /* Find bootable partition - check partition table at 0x81BE */ + 0xBE, 0xBE, 0x81, /* mov si, 0x81BE */ + 0xB1, 0x04, /* mov cl, 4 */ + + /* 0x35: Partition loop */ + 0x80, 0x3C, 0x80, /* cmp byte [si], 0x80 */ + 0x74, 0x08, /* je found_part */ + 0x83, 0xC6, 0x10, /* add si, 16 */ + 0xE2, 0xF5, /* loop part_loop */ + 0xE9, 0xA0, 0x00, /* jmp no_part_error */ + + /* 0x42: Found bootable partition */ + /* Get partition start LBA from [si+8] */ + 0x8B, 0x44, 0x08, /* mov ax, [si+8] */ + 0x8B, 0x54, 0x0A, /* mov dx, [si+10] */ + 0xA3, 0xF8, 0x8F, /* mov [0x8FF8], ax (save part_start low) */ + 0x89, 0x16, 0xFA, 0x8F, /* mov [0x8FFA], dx (save part_start high) */ + + /* Read FAT16 boot sector (VBR) to 0x8000 */ + 0xBB, 0x00, 0x80, /* mov bx, 0x8000 */ + 0xB9, 0x01, 0x00, /* mov cx, 1 */ + 0x8B, 0x16, 0xFA, 0x8F, /* mov dx, [0x8FFA] */ + 0x8B, 0x36, 0xF8, 0x8F, /* mov si, [0x8FF8] */ + 0xE8, 0xB0, 0x00, /* call read_sectors */ + + /* Parse BPB - extract FAT16 parameters */ + /* bytes_per_sector at offset 11 */ + 0x8B, 0x06, 0x0B, 0x80, /* mov ax, [0x800B] */ + 0xA3, 0xE0, 0x8F, /* mov [0x8FE0], ax (bytes_per_sector) */ + + /* sectors_per_cluster at offset 13 */ + 0x8A, 0x06, 0x0D, 0x80, /* mov al, [0x800D] */ + 0xA2, 0xE2, 0x8F, /* mov [0x8FE2], al (sectors_per_cluster) */ + + /* reserved_sectors at offset 14 */ + 0x8B, 0x06, 0x0E, 0x80, /* mov ax, [0x800E] */ + 0xA3, 0xE4, 0x8F, /* mov [0x8FE4], ax (reserved_sectors) */ + + /* num_fats at offset 16 */ + 0x8A, 0x06, 0x10, 0x80, /* mov al, [0x8010] */ + 0xA2, 0xE6, 0x8F, /* mov [0x8FE6], al (num_fats) */ + + /* root_entries at offset 17 */ + 0x8B, 0x06, 0x11, 0x80, /* mov ax, [0x8011] */ + 0xA3, 0xE8, 0x8F, /* mov [0x8FE8], ax (root_entries) */ + + /* fat_sectors at offset 22 */ + 0x8B, 0x06, 0x16, 0x80, /* mov ax, [0x8016] */ + 0xA3, 0xEA, 0x8F, /* mov [0x8FEA], ax (fat_sectors) */ + + /* Jump to next sector for more code */ + 0xE9, 0x50, 0x01, /* jmp 0x7E00 (sector 1 of core) */ + + /* === Padding and strings === */ + /* 0x90: print_string subroutine */ + 0xAC, /* lodsb */ + 0x08, 0xC0, /* or al, al */ + 0x74, 0x06, /* jz .done */ + 0xB4, 0x0E, /* mov ah, 0x0E */ + 0xCD, 0x10, /* int 0x10 */ + 0xEB, 0xF5, /* jmp print_string */ + 0xC3, /* ret */ + + /* 0x9C: Padding */ + 0x90, 0x90, 0x90, 0x90, + + /* 0xA0: no_part_error */ + 0xBE, 0x20, 0x7D, /* mov si, err_no_part */ + 0xE8, 0xEB, 0xFF, /* call print_string */ + 0xF4, /* hlt */ + 0xEB, 0xFD, /* jmp $ */ + + /* 0xAA: Padding */ + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + + /* 0xB0: enable_a20 */ + /* Try BIOS first */ + 0xB8, 0x01, 0x24, /* mov ax, 0x2401 */ + 0xCD, 0x15, /* int 0x15 */ + 0x73, 0x1C, /* jnc a20_done */ + + /* Try keyboard controller */ + 0xE4, 0x64, /* in al, 0x64 */ + 0xA8, 0x02, /* test al, 2 */ + 0x75, 0xFA, /* jnz wait1 */ + 0xB0, 0xD1, /* mov al, 0xD1 */ + 0xE6, 0x64, /* out 0x64, al */ + 0xE4, 0x64, /* in al, 0x64 */ + 0xA8, 0x02, /* test al, 2 */ + 0x75, 0xFA, /* jnz wait2 */ + 0xB0, 0xDF, /* mov al, 0xDF */ + 0xE6, 0x60, /* out 0x60, al */ + 0xE4, 0x64, /* in al, 0x64 */ + 0xA8, 0x02, /* test al, 2 */ + 0x75, 0xFA, /* jnz wait3 */ + /* a20_done: */ + 0xC3, /* ret */ + + /* 0xD4: Padding to 0xE0 */ + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, + + /* 0xE0: read_sectors - Read CX sectors from LBA DX:SI to ES:BX */ + /* Uses INT 13h extended read */ + 0x60, /* pusha */ + 0x06, /* push es */ + + /* Set up DAP at 0x0500 */ + 0xBF, 0x00, 0x05, /* mov di, 0x0500 */ + 0xC6, 0x05, 0x10, /* mov byte [di], 16 */ + 0xC6, 0x45, 0x01, 0x00, /* mov byte [di+1], 0 */ + 0x88, 0x4D, 0x02, /* mov [di+2], cl (sector count) */ + 0xC6, 0x45, 0x03, 0x00, /* mov byte [di+3], 0 */ + 0x89, 0x5D, 0x04, /* mov [di+4], bx (offset) */ + 0x8C, 0xC0, /* mov ax, es */ + 0x89, 0x45, 0x06, /* mov [di+6], ax (segment) */ + 0x89, 0x75, 0x08, /* mov [di+8], si (LBA low) */ + 0x89, 0x55, 0x0A, /* mov [di+10], dx (LBA high) */ + 0xC7, 0x45, 0x0C, 0x00, 0x00, /* mov word [di+12], 0 */ + 0xC7, 0x45, 0x0E, 0x00, 0x00, /* mov word [di+14], 0 */ + + 0xB4, 0x42, /* mov ah, 0x42 */ + 0x8A, 0x16, 0xFC, 0x8F, /* mov dl, [0x8FFC] (drive) */ + 0xBE, 0x00, 0x05, /* mov si, 0x0500 */ + 0xCD, 0x13, /* int 0x13 */ + + 0x07, /* pop es */ + 0x61, /* popa */ + 0xC3, /* ret */ + + /* Padding to 0x100 (256 bytes = end of first sector area used for code) */ +}; + +/* Continuation of core loader - sector 1 onwards (at 0x7E00 when loaded) */ +static const uint8_t core_loader_cont[] = { + /* === At 0x7E00: Continue FAT16 parsing and kernel loading === */ + + /* Calculate root directory start: + * root_start = part_start + reserved + (num_fats * fat_sectors) + */ + 0xA1, 0xE4, 0x8F, /* mov ax, [reserved_sectors] */ + 0x03, 0x06, 0xF8, 0x8F, /* add ax, [part_start_low] */ + 0x89, 0xC3, /* mov bx, ax */ + + /* Add num_fats * fat_sectors */ + 0x8A, 0x0E, 0xE6, 0x8F, /* mov cl, [num_fats] */ + 0x30, 0xED, /* xor ch, ch */ + 0xA1, 0xEA, 0x8F, /* mov ax, [fat_sectors] */ + /* Multiply: fat_sectors * num_fats */ + 0xF7, 0xE1, /* mul cx */ + 0x01, 0xC3, /* add bx, ax */ + /* BX = root_start (low word) */ + 0x89, 0x1E, 0xEC, 0x8F, /* mov [root_start], bx */ + + /* Calculate root directory size in sectors: + * root_sectors = (root_entries * 32) / 512 + */ + 0xA1, 0xE8, 0x8F, /* mov ax, [root_entries] */ + 0xC1, 0xE8, 0x04, /* shr ax, 4 (divide by 16, *32/512 = /16) */ + 0xA3, 0xEE, 0x8F, /* mov [root_sectors], ax */ + + /* Calculate data start: + * data_start = root_start + root_sectors + */ + 0x03, 0x1E, 0xEE, 0x8F, /* add bx, [root_sectors] */ + 0x89, 0x1E, 0xF0, 0x8F, /* mov [data_start], bx */ + + /* Read root directory to 0x10000 */ + 0x06, /* push es */ + 0xB8, 0x00, 0x10, /* mov ax, 0x1000 */ + 0x8E, 0xC0, /* mov es, ax */ + 0x31, 0xDB, /* xor bx, bx (offset 0) */ + 0x8B, 0x0E, 0xEE, 0x8F, /* mov cx, [root_sectors] */ + 0x31, 0xD2, /* xor dx, dx */ + 0x8B, 0x36, 0xEC, 0x8F, /* mov si, [root_start] */ + /* read_sectors(ES:BX, CX, DX:SI) */ + 0xE8, 0x50, 0xFE, /* call read_sectors (at 0x7CE0) */ + 0x07, /* pop es */ + + /* Search for "BOOT " directory in root */ + 0xBE, 0x00, 0x00, /* mov si, 0 (offset in root dir) */ + 0xB9, 0x00, 0x02, /* mov cx, 512 (max entries to check) */ + + /* 0x50: Search loop */ + 0x06, /* push es */ + 0xB8, 0x00, 0x10, /* mov ax, 0x1000 */ + 0x8E, 0xC0, /* mov es, ax */ + + /* Compare 11 bytes with "BOOT " */ + 0x89, 0xF7, /* mov di, si */ + 0x56, /* push si */ + 0xBE, 0x00, 0x7F, /* mov si, boot_dirname (at 0x7F00) */ + 0xB2, 0x0B, /* mov dl, 11 */ + + /* Compare loop */ + 0x26, 0x8A, 0x05, /* mov al, es:[di] */ + 0x8A, 0x24, /* mov ah, [si] */ + 0x38, 0xE0, /* cmp al, ah */ + 0x75, 0x0C, /* jne next_entry */ + 0x47, /* inc di */ + 0x46, /* inc si */ + 0xFE, 0xCA, /* dec dl */ + 0x75, 0xF2, /* jnz cmp_loop */ + /* Found BOOT directory! */ + 0x5E, /* pop si */ + 0x07, /* pop es */ + 0xEB, 0x10, /* jmp found_boot */ + + /* 0x78: next_entry */ + 0x5E, /* pop si */ + 0x07, /* pop es */ + 0x83, 0xC6, 0x20, /* add si, 32 (next entry) */ + 0xE2, 0xD4, /* loop search_loop */ + /* Boot dir not found */ + 0xBE, 0x40, 0x7D, /* mov si, err_no_boot_dir */ + 0xE8, 0x0A, 0xFE, /* call print_string */ + 0xF4, /* hlt */ + + /* 0x88: found_boot */ + /* SI = offset of BOOT entry in root dir buffer (segment 0x1000) */ + /* Get cluster from entry at [si+26] */ + 0x06, /* push es */ + 0xB8, 0x00, 0x10, /* mov ax, 0x1000 */ + 0x8E, 0xC0, /* mov es, ax */ + 0x26, 0x8B, 0x44, 0x1A, /* mov ax, es:[si+26] (cluster) */ + 0x07, /* pop es */ + 0xA3, 0xF2, 0x8F, /* mov [boot_cluster], ax */ + + /* Read BOOT directory cluster to find KERNEL.BIN */ + /* First, read FAT to 0x8000 */ + 0xA1, 0xE4, 0x8F, /* mov ax, [reserved_sectors] */ + 0x03, 0x06, 0xF8, 0x8F, /* add ax, [part_start_low] */ + 0x89, 0xC6, /* mov si, ax (FAT start LBA) */ + 0xBB, 0x00, 0x80, /* mov bx, 0x8000 */ + 0x8B, 0x0E, 0xEA, 0x8F, /* mov cx, [fat_sectors] */ + 0x31, 0xD2, /* xor dx, dx */ + 0xE8, 0xFC, 0xFD, /* call read_sectors */ + + /* Convert boot_cluster to LBA and read */ + /* LBA = data_start + (cluster - 2) * sectors_per_cluster */ + 0xA1, 0xF2, 0x8F, /* mov ax, [boot_cluster] */ + 0x48, /* dec ax */ + 0x48, /* dec ax (cluster - 2) */ + 0x8A, 0x0E, 0xE2, 0x8F, /* mov cl, [sectors_per_cluster] */ + 0x30, 0xED, /* xor ch, ch */ + 0xF7, 0xE1, /* mul cx */ + 0x03, 0x06, 0xF0, 0x8F, /* add ax, [data_start] */ + 0x89, 0xC6, /* mov si, ax (LBA) */ + + /* Read BOOT dir to 0x10000 */ + 0x06, /* push es */ + 0xB8, 0x00, 0x10, /* mov ax, 0x1000 */ + 0x8E, 0xC0, /* mov es, ax */ + 0x31, 0xDB, /* xor bx, bx */ + 0x8A, 0x0E, 0xE2, 0x8F, /* mov cl, [sectors_per_cluster] */ + 0x31, 0xD2, /* xor dx, dx */ + 0xE8, 0xD6, 0xFD, /* call read_sectors */ + 0x07, /* pop es */ + + /* Search for "KERNEL BIN" in BOOT directory */ + 0xBE, 0x00, 0x00, /* mov si, 0 */ + 0xB9, 0x00, 0x01, /* mov cx, 256 */ + + /* 0xE8: kernel search loop */ + 0x06, /* push es */ + 0xB8, 0x00, 0x10, /* mov ax, 0x1000 */ + 0x8E, 0xC0, /* mov es, ax */ + 0x89, 0xF7, /* mov di, si */ + 0x56, /* push si */ + 0xBE, 0x10, 0x7F, /* mov si, kernel_filename */ + 0xB2, 0x0B, /* mov dl, 11 */ + + /* Compare loop */ + 0x26, 0x8A, 0x05, /* mov al, es:[di] */ + 0x8A, 0x24, /* mov ah, [si] */ + 0x38, 0xE0, /* cmp al, ah */ + 0x75, 0x0C, /* jne next_kern */ + 0x47, /* inc di */ + 0x46, /* inc si */ + 0xFE, 0xCA, /* dec dl */ + 0x75, 0xF2, /* jnz cmp_kern */ + /* Found KERNEL.BIN! */ + 0x5E, /* pop si */ + 0x07, /* pop es */ + 0xEB, 0x10, /* jmp found_kernel */ + + /* next_kern */ + 0x5E, /* pop si */ + 0x07, /* pop es */ + 0x83, 0xC6, 0x20, /* add si, 32 */ + 0xE2, 0xD4, /* loop kernel_search */ + /* Kernel not found */ + 0xBE, 0x60, 0x7D, /* mov si, err_no_kernel */ + 0xE8, 0x7A, 0xFD, /* call print_string */ + 0xF4, /* hlt */ + + /* found_kernel: */ + /* Get file size from [si+28] and cluster from [si+26] */ + 0x06, /* push es */ + 0xB8, 0x00, 0x10, /* mov ax, 0x1000 */ + 0x8E, 0xC0, /* mov es, ax */ + 0x26, 0x8B, 0x44, 0x1C, /* mov ax, es:[si+28] (size low) */ + 0x26, 0x8B, 0x54, 0x1E, /* mov dx, es:[si+30] (size high) */ + 0xA3, 0xF4, 0x8F, /* mov [kernel_size], ax */ + 0x89, 0x16, 0xF6, 0x8F, /* mov [kernel_size+2], dx */ + 0x26, 0x8B, 0x44, 0x1A, /* mov ax, es:[si+26] (cluster) */ + 0x07, /* pop es */ + 0xA3, 0xF2, 0x8F, /* mov [kernel_cluster], ax */ + + /* Now load kernel to 0x100000 using unreal mode */ + /* First switch to protected mode then back with big segments */ + + /* Load GDT */ + 0x0F, 0x01, 0x16, 0x80, 0x7F, /* lgdt [gdt_desc] */ + + /* Enter protected mode */ + 0x0F, 0x20, 0xC0, /* mov eax, cr0 */ + 0x0C, 0x01, /* or al, 1 */ + 0x0F, 0x22, 0xC0, /* mov cr0, eax */ + + /* Jump to clear prefetch */ + 0xEA, 0x60, 0x7F, 0x08, 0x00, /* jmp 0x08:0x7F60 */ +}; + +/* Variables stored at 0x8F00 area: + * 0x8FE0: bytes_per_sector (2) + * 0x8FE2: sectors_per_cluster (1) + * 0x8FE4: reserved_sectors (2) + * 0x8FE6: num_fats (1) + * 0x8FE8: root_entries (2) + * 0x8FEA: fat_sectors (2) + * 0x8FEC: root_start (2) + * 0x8FEE: root_sectors (2) + * 0x8FF0: data_start (2) + * 0x8FF2: boot_cluster / kernel_cluster (2) + * 0x8FF4: kernel_size (4) + * 0x8FF8: part_start (4) + * 0x8FFC: drive_number (1) + */ + +/* Strings and data at 0x7D00 */ +static const uint8_t core_loader_data[] = { + /* 0x7D00: Loading message */ + 'L', 'u', 'a', 'j', 'i', 't', 'O', 'S', ' ', 'B', 'o', 'o', 't', 'l', 'o', 'a', + 'd', 'e', 'r', '\r', '\n', 0, + + /* Padding to 0x7D20 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /* 0x7D20: err_no_part */ + 'N', 'o', ' ', 'b', 'o', 'o', 't', ' ', 'p', 'a', 'r', 't', 'i', 't', 'i', 'o', + 'n', '\r', '\n', 0, + + /* Padding to 0x7D40 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /* 0x7D40: err_no_boot_dir */ + 'B', 'O', 'O', 'T', ' ', 'd', 'i', 'r', ' ', 'n', 'o', 't', ' ', 'f', 'o', 'u', + 'n', 'd', '\r', '\n', 0, + + /* Padding to 0x7D60 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /* 0x7D60: err_no_kernel */ + 'K', 'E', 'R', 'N', 'E', 'L', '.', 'B', 'I', 'N', ' ', 'n', 'o', 't', ' ', 'f', + 'o', 'u', 'n', 'd', '\r', '\n', 0, +}; + +/* Directory/filename patterns at 0x7F00 */ +static const uint8_t core_filenames[] = { + /* 0x7F00: "BOOT " (8.3 format, space padded) */ + 'B', 'O', 'O', 'T', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0, + + /* 0x7F10: "KERNEL BIN" (8.3 format) */ + 'K', 'E', 'R', 'N', 'E', 'L', ' ', ' ', 'B', 'I', 'N', 0, +}; + +/* Protected mode code at 0x7F60 */ +static const uint8_t core_pmode[] = { + /* 0x7F60: Now in 32-bit protected mode */ + 0x66, 0xB8, 0x10, 0x00, /* mov ax, 0x10 (data segment) */ + 0x8E, 0xD8, /* mov ds, ax */ + 0x8E, 0xC0, /* mov es, ax */ + 0x8E, 0xD0, /* mov ss, ax */ + + /* Go back to real mode but keep 4GB segment limits */ + 0x0F, 0x20, 0xC0, /* mov eax, cr0 */ + 0x24, 0xFE, /* and al, 0xFE */ + 0x0F, 0x22, 0xC0, /* mov cr0, eax */ + + /* Far jump back to real mode */ + 0xEA, 0x78, 0x7F, 0x00, 0x00, /* jmp 0x0000:0x7F78 */ + + /* 0x7F78: Back in real mode with unreal flat segments */ + 0x31, 0xC0, /* xor ax, ax */ + 0x8E, 0xD8, /* mov ds, ax */ + 0x8E, 0xC0, /* mov es, ax */ + + /* Now load kernel cluster by cluster to 0x100000 */ + /* This is simplified - just load first cluster for now */ + /* A full implementation would follow the FAT chain */ + + /* Print loading kernel message */ + 0xBE, 0x90, 0x7F, /* mov si, loading_kernel_msg */ + 0xE8, 0x0A, 0xFD, /* call print_string */ + + /* Set up multiboot header at 0xFF000 */ + /* Magic */ + 0x66, 0xB8, 0x02, 0xB0, 0xAD, 0x2B, /* mov eax, 0x2BADB002 */ + 0x67, 0x66, 0xA3, 0x00, 0xF0, 0x0F, 0x00, /* mov [0x0FF000], eax */ + + /* Jump to kernel at 0x100000 */ + /* Put multiboot magic in EAX, info pointer in EBX */ + 0x66, 0xB8, 0x02, 0xB0, 0xAD, 0x2B, /* mov eax, 0x2BADB002 */ + 0x66, 0xBB, 0x00, 0xF0, 0x0F, 0x00, /* mov ebx, 0x000FF000 */ + + /* Far jump to kernel (needs 32-bit protected mode) */ + /* Re-enter protected mode */ + 0x0F, 0x20, 0xC0, /* mov eax, cr0 */ + 0x0C, 0x01, /* or al, 1 */ + 0x0F, 0x22, 0xC0, /* mov cr0, eax */ + 0x66, 0xEA, 0x00, 0x00, 0x10, 0x00, 0x08, 0x00, /* jmp 0x08:0x00100000 */ + + /* 0x7F90: loading_kernel_msg */ + 'L', 'o', 'a', 'd', 'i', 'n', 'g', ' ', 'k', 'e', 'r', 'n', 'e', 'l', '.', '.', + '.', '\r', '\n', 0, +}; + +/* GDT at 0x7F80 */ +static const uint8_t core_gdt[] = { + /* 0x7F80: GDT descriptor */ + 0x17, 0x00, /* limit (3 entries * 8 - 1 = 23) */ + 0x88, 0x7F, 0x00, 0x00, /* base (0x7F88) */ + + /* 0x7F86: padding */ + 0x00, 0x00, + + /* 0x7F88: GDT entries */ + /* Null descriptor */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* Code segment (0x08): base=0, limit=4GB, 32-bit, executable */ + 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00, + /* Data segment (0x10): base=0, limit=4GB, 32-bit, writable */ + 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00, +}; + +/* ============================================================================ + * Assemble the complete core loader image + * ========================================================================= */ + +#define CORE_SIZE (62 * 512) /* 62 sectors = 31KB */ + +static void build_core_image(uint8_t *buffer) { + memset(buffer, 0, CORE_SIZE); + + /* Copy main loader code at offset 0 */ + memcpy(buffer, core_loader, sizeof(core_loader)); + + /* Copy data strings at offset 0x100 (0x7D00 - 0x7C00) */ + memcpy(buffer + 0x100, core_loader_data, sizeof(core_loader_data)); + + /* Copy continuation code at offset 0x200 (0x7E00 - 0x7C00) */ + memcpy(buffer + 0x200, core_loader_cont, sizeof(core_loader_cont)); + + /* Copy filenames at offset 0x300 (0x7F00 - 0x7C00) */ + memcpy(buffer + 0x300, core_filenames, sizeof(core_filenames)); + + /* Copy protected mode code at offset 0x360 (0x7F60 - 0x7C00) */ + memcpy(buffer + 0x360, core_pmode, sizeof(core_pmode)); + + /* Copy GDT at offset 0x380 (0x7F80 - 0x7C00) */ + memcpy(buffer + 0x380, core_gdt, sizeof(core_gdt)); +} + +/* ============================================================================ + * Public API Implementation + * ========================================================================= */ + +int grub_install_mbr(uint8_t bus, uint8_t drive) { + /* Read current MBR to preserve partition table */ + mbr_t mbr; + if (ata_read_sectors(bus, drive, 0, 1, &mbr) != ATA_OK) { + terminal_writestring("[GRUB] Error: Failed to read MBR\n"); + return GRUB_ERR_IO; + } + + /* Check for valid partition table */ + if (mbr.signature != MBR_SIGNATURE) { + terminal_writestring("[GRUB] Error: No valid partition table\n"); + return GRUB_ERR_NO_PART; + } + + { + char dbg[80]; + snprintf(dbg, sizeof(dbg), "[GRUB] Installing MBR boot code\n"); + terminal_writestring(dbg); + } + + /* Copy boot code to MBR (preserving partition table) */ + memset(mbr.bootstrap, 0, sizeof(mbr.bootstrap)); + memcpy(mbr.bootstrap, mbr_boot_code, sizeof(mbr_boot_code)); + + /* Make sure signature is intact */ + mbr.signature = MBR_SIGNATURE; + + /* Write MBR back */ + if (ata_write_sectors(bus, drive, 0, 1, &mbr) != ATA_OK) { + terminal_writestring("[GRUB] Error: Failed to write MBR\n"); + return GRUB_ERR_IO; + } + + terminal_writestring("[GRUB] MBR boot code installed\n"); + return GRUB_OK; +} + +int grub_install_core(uint8_t bus, uint8_t drive) { + terminal_writestring("[GRUB] Building core loader image...\n"); + + /* Build the core loader image */ + uint8_t *core_image = (uint8_t *)0x200000; /* Use 2MB mark as temp buffer */ + build_core_image(core_image); + + { + char dbg[80]; + snprintf(dbg, sizeof(dbg), "[GRUB] Writing core loader (62 sectors) to sectors 1-62\n"); + terminal_writestring(dbg); + } + + /* Write core loader to sectors 1-62 */ + for (int i = 0; i < 62; i++) { + if (ata_write_sectors(bus, drive, 1 + i, 1, core_image + i * 512) != ATA_OK) { + char err[80]; + snprintf(err, sizeof(err), "[GRUB] Error: Failed to write sector %d\n", 1 + i); + terminal_writestring(err); + return GRUB_ERR_IO; + } + } + + terminal_writestring("[GRUB] Core loader installed\n"); + return GRUB_OK; +} + +int grub_install(uint8_t bus, uint8_t drive) { + terminal_writestring("[GRUB] Starting full bootloader installation...\n"); + + /* Verify partition table exists */ + if (!partition_has_mbr(bus, drive)) { + terminal_writestring("[GRUB] Error: No partition table found\n"); + return GRUB_ERR_NO_PART; + } + + /* Get boot partition info */ + partition_info_t parts[4]; + if (partition_read_table(bus, drive, parts) != 0) { + terminal_writestring("[GRUB] Error: Failed to read partition table\n"); + return GRUB_ERR_IO; + } + + /* Find FAT16 boot partition */ + int boot_idx = -1; + for (int i = 0; i < 4; i++) { + if (parts[i].exists && parts[i].type == PART_TYPE_FAT16) { + boot_idx = i; + break; + } + } + + if (boot_idx < 0) { + terminal_writestring("[GRUB] Error: No FAT16 boot partition found\n"); + return GRUB_ERR_NO_FAT16; + } + + { + char dbg[80]; + snprintf(dbg, sizeof(dbg), "[GRUB] Found FAT16 partition %d at sector %u\n", + boot_idx + 1, (unsigned)parts[boot_idx].start_lba); + terminal_writestring(dbg); + } + + /* Install MBR boot code */ + int result = grub_install_mbr(bus, drive); + if (result != GRUB_OK) { + return result; + } + + /* Install core loader */ + result = grub_install_core(bus, drive); + if (result != GRUB_OK) { + return result; + } + + terminal_writestring("[GRUB] Bootloader installation complete!\n"); + terminal_writestring("[GRUB] Ensure /BOOT/KERNEL.BIN exists on the FAT16 partition\n"); + return GRUB_OK; +} + +int grub_install_vbr(uint8_t bus, uint8_t drive, uint32_t part_start) { + /* VBR is not needed with our approach - the MBR loads the core directly */ + (void)bus; + (void)drive; + (void)part_start; + terminal_writestring("[GRUB] VBR installation not needed (core loader handles FAT16)\n"); + return GRUB_OK; +} + +const char *grub_error_string(int error) { + switch (error) { + case GRUB_OK: return "Success"; + case GRUB_ERR_IO: return "I/O error"; + case GRUB_ERR_NO_PART: return "No partition table"; + case GRUB_ERR_NO_FAT16: return "No FAT16 boot partition"; + case GRUB_ERR_INVALID: return "Invalid parameter"; + default: return "Unknown error"; + } +} + +/* ============================================================================ + * Lua Bindings + * ========================================================================= */ + +#include "include/lua.h" +#include "include/lauxlib.h" + +/* grub.install(bus, drive) -> boolean, error_string */ +static int lua_grub_install(lua_State *L) { + int bus = luaL_checkinteger(L, 1); + int drive = luaL_checkinteger(L, 2); + + int result = grub_install(bus, drive); + + lua_pushboolean(L, result == GRUB_OK); + if (result != GRUB_OK) { + lua_pushstring(L, grub_error_string(result)); + } else { + lua_pushnil(L); + } + return 2; +} + +/* grub.installMbr(bus, drive) -> boolean, error_string */ +static int lua_grub_install_mbr(lua_State *L) { + int bus = luaL_checkinteger(L, 1); + int drive = luaL_checkinteger(L, 2); + + int result = grub_install_mbr(bus, drive); + + lua_pushboolean(L, result == GRUB_OK); + if (result != GRUB_OK) { + lua_pushstring(L, grub_error_string(result)); + } else { + lua_pushnil(L); + } + return 2; +} + +/* grub.installCore(bus, drive) -> boolean, error_string */ +static int lua_grub_install_core(lua_State *L) { + int bus = luaL_checkinteger(L, 1); + int drive = luaL_checkinteger(L, 2); + + int result = grub_install_core(bus, drive); + + lua_pushboolean(L, result == GRUB_OK); + if (result != GRUB_OK) { + lua_pushstring(L, grub_error_string(result)); + } else { + lua_pushnil(L); + } + return 2; +} + +static const luaL_Reg grub_funcs[] = { + {"install", lua_grub_install}, + {"installMbr", lua_grub_install_mbr}, + {"installCore", lua_grub_install_core}, + {NULL, NULL} +}; + +int luaopen_grub(lua_State *L) { + luaL_newlib(L, grub_funcs); + return 1; +} diff --git a/grub.h b/grub.h @@ -0,0 +1,88 @@ +/* GRUB Bootloader Installation for LuajitOS + * + * Provides functionality to install a minimal bootloader to disk. + * Writes MBR boot code that chainloads from the FAT16 boot partition. + */ + +#ifndef GRUB_H +#define GRUB_H + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* Error codes */ +#define GRUB_OK 0 +#define GRUB_ERR_IO -1 +#define GRUB_ERR_NO_PART -2 +#define GRUB_ERR_NO_FAT16 -3 +#define GRUB_ERR_INVALID -4 + +/** + * Install bootloader to disk MBR + * + * This writes boot code to the MBR that: + * 1. Loads the boot sector from the first partition (FAT16) + * 2. Chainloads the FAT16 Volume Boot Record (VBR) + * + * The FAT16 partition should already contain: + * - /boot/kernel.bin (the LuajitOS kernel) + * - /boot/grub/grub.cfg (GRUB configuration) + * + * @param bus ATA bus + * @param drive ATA drive + * @return GRUB_OK on success, error code on failure + */ +int grub_install_mbr(uint8_t bus, uint8_t drive); + +/** + * Install core loader to embedding area (sectors 1-62) + * + * The core loader: + * - Parses FAT16 filesystem + * - Finds /BOOT/KERNEL.BIN + * - Loads kernel to 0x100000 + * - Sets up multiboot and jumps to kernel + * + * @param bus ATA bus + * @param drive ATA drive + * @return GRUB_OK on success, error code on failure + */ +int grub_install_core(uint8_t bus, uint8_t drive); + +/** + * Full bootloader installation + * + * Installs both MBR and VBR boot code. The disk must already have: + * - A valid MBR partition table with FAT16 boot partition + * - FAT16 filesystem on the boot partition + * - Kernel at /boot/kernel.bin on the FAT16 partition + * + * @param bus ATA bus + * @param drive ATA drive + * @return GRUB_OK on success, error code on failure + */ +int grub_install(uint8_t bus, uint8_t drive); + +/** + * Get error string for error code + * + * @param error Error code + * @return Human-readable error string + */ +const char *grub_error_string(int error); + +/* ============================================================================ + * Lua Bindings + * ========================================================================= */ + +struct lua_State; +int luaopen_grub(struct lua_State *L); + +#ifdef __cplusplus +} +#endif + +#endif /* GRUB_H */ diff --git a/iso_includes/apps/com.luajitos.background/manifest.lua b/iso_includes/apps/com.luajitos.background/manifest.lua @@ -7,6 +7,8 @@ return { entry = "background.lua"; type = "gui"; hidden = true; -- Hide from start menu + autostart = true; -- Launch on system startup + autostartPriority = 1; -- Launch first (background should be behind everything) permissions = { "ramdisk"; -- Need direct ramdisk access since SafeFS traverse is broken "draw"; diff --git a/iso_includes/apps/com.luajitos.crypto/IMPORT_EXAMPLE.md b/iso_includes/apps/com.luajitos.crypto/IMPORT_EXAMPLE.md @@ -45,7 +45,7 @@ if not crypto then end -- Now you can use all crypto functions! -local hash = crypto.hash.SHA256("Hello World") +local hash = crypto.SHA256("Hello World") -- Convert binary hash to hex for display local function toHex(data) @@ -89,10 +89,10 @@ end local data = args[1] or "test" print("Input: " .. data) -print("MD5: " .. toHex(crypto.hash.MD5(data))) -print("SHA1: " .. toHex(crypto.hash.SHA1(data))) -print("SHA256: " .. toHex(crypto.hash.SHA256(data))) -print("BLAKE2b: " .. toHex(crypto.hash.BLAKE2b(data))) +print("MD5: " .. toHex(crypto.MD5(data))) +print("SHA1: " .. toHex(crypto.SHA1(data))) +print("SHA256: " .. toHex(crypto.SHA256(data))) +print("BLAKE2b: " .. toHex(crypto["BLAKE2b-256"](data))) ``` Usage: `hashcalc "hello world"` @@ -133,8 +133,8 @@ end -- Hash a password with a random salt local function hashPassword(password) - local salt = crypto.kdf.generateSalt() - local hash = crypto.kdf.PBKDF2(password, salt, 100000, 32) + local salt = crypto.generateSalt() + local hash = crypto.PBKDF2(password, salt, 100000, 32) return { salt = toHex(salt), @@ -146,7 +146,7 @@ end local function verifyPassword(password, salt_hex, hash_hex) local salt = fromHex(salt_hex) local stored_hash = fromHex(hash_hex) - local computed_hash = crypto.kdf.PBKDF2(password, salt, 100000, 32) + local computed_hash = crypto.PBKDF2(password, salt, 100000, 32) return computed_hash == stored_hash end @@ -317,20 +317,20 @@ Usage: `keyexchange` Once you import the crypto library, you have access to: ### Hashing -- `crypto.hash.MD5(data)` → 16 bytes -- `crypto.hash.SHA1(data)` → 20 bytes -- `crypto.hash.SHA256(data)` → 32 bytes -- `crypto.hash.SHA512(data)` → 64 bytes -- `crypto.hash.SHA3_256(data)` → 32 bytes -- `crypto.hash.SHA3_512(data)` → 64 bytes -- `crypto.hash.BLAKE2b(data)` → 32 bytes -- `crypto.hash.BLAKE2b_512(data)` → 64 bytes -- `crypto.hash.CRC32(data)` → 4 bytes +- `crypto.MD5(data)` → 16 bytes +- `crypto.SHA1(data)` → 20 bytes +- `crypto.SHA256(data)` → 32 bytes +- `crypto.SHA512(data)` → 64 bytes +- `crypto["SHA3-256"](data)` → 32 bytes +- `crypto["SHA3-512"](data)` → 64 bytes +- `crypto["BLAKE2b-256"](data)` → 32 bytes +- `crypto["BLAKE2b-512"](data)` → 64 bytes +- `crypto.CRC32(data)` → 4 bytes ### Key Derivation -- `crypto.kdf.PBKDF2(password, salt, iterations, keylen)` → keylen bytes -- `crypto.kdf.Argon2id(password, salt)` → 32 bytes -- `crypto.kdf.generateSalt()` → 32 bytes +- `crypto.PBKDF2(password, salt, iterations, keylen)` → keylen bytes +- `crypto.Argon2id(password, salt)` → 32 bytes +- `crypto.generateSalt()` → 32 bytes ### Digital Signatures (Ed25519) - `crypto.sign.Ed25519.keypair()` → (pubkey, privkey) diff --git a/iso_includes/apps/com.luajitos.crypto/README.md b/iso_includes/apps/com.luajitos.crypto/README.md @@ -283,14 +283,14 @@ if cryptoApp then local crypto = cryptoApp:call("crypto") -- Now use crypto functions - local hash = crypto.hash.SHA256("Hello World") + local hash = crypto.SHA256("Hello World") print("Hash: " .. toHex(hash)) -- Generate keypair local pubkey, privkey = crypto.sign.Ed25519.keypair() -- Use PBKDF2 - local key = crypto.kdf.PBKDF2("password", "salt", 100000, 32) + local key = crypto.PBKDF2("password", "salt", 100000, 32) end ``` @@ -300,20 +300,20 @@ Once imported, you have access to all crypto functions: ```lua -- Hashing -crypto.hash.MD5(data) -crypto.hash.SHA1(data) -crypto.hash.SHA256(data) -crypto.hash.SHA512(data) -crypto.hash.SHA3_256(data) -crypto.hash.SHA3_512(data) -crypto.hash.BLAKE2b(data) -crypto.hash.BLAKE2b_512(data) -crypto.hash.CRC32(data) +crypto.MD5(data) +crypto.SHA1(data) +crypto.SHA256(data) +crypto.SHA512(data) +crypto["SHA3-256"](data) +crypto["SHA3-512"](data) +crypto["BLAKE2b-256"](data) +crypto["BLAKE2b-512"](data) +crypto.CRC32(data) -- Key Derivation -crypto.kdf.PBKDF2(password, salt, iterations, keylen) -crypto.kdf.Argon2id(password, salt) -crypto.kdf.generateSalt() +crypto.PBKDF2(password, salt, iterations, keylen) +crypto.Argon2id(password, salt) +crypto.generateSalt() -- Ed25519 Digital Signatures crypto.sign.Ed25519.keypair() @@ -348,14 +348,14 @@ local crypto = cryptoApp:call("crypto") -- Hash a password local function hashPassword(password) - local salt = crypto.kdf.generateSalt() - local hash = crypto.kdf.PBKDF2(password, salt, 100000, 32) + local salt = crypto.generateSalt() + local hash = crypto.PBKDF2(password, salt, 100000, 32) return {salt = salt, hash = hash} end -- Verify password local function verifyPassword(password, stored_salt, stored_hash) - local hash = crypto.kdf.PBKDF2(password, stored_salt, 100000, 32) + local hash = crypto.PBKDF2(password, stored_salt, 100000, 32) return hash == stored_hash end diff --git a/iso_includes/apps/com.luajitos.crypto/src/init.lua b/iso_includes/apps/com.luajitos.crypto/src/init.lua @@ -209,10 +209,10 @@ if #args == 0 then print(" SHA1 <data> - SHA-1 hash") print(" SHA256 <data> - SHA-256 hash") print(" SHA512 <data> - SHA-512 hash") - print(" SHA3_256 <data> - SHA3-256 hash") - print(" SHA3_512 <data> - SHA3-512 hash") - print(" BLAKE2b <data> - BLAKE2b-256 hash") - print(" BLAKE2b_512 <data> - BLAKE2b-512 hash") + print(" SHA3-256 <data> - SHA3-256 hash") + print(" SHA3-512 <data> - SHA3-512 hash") + print(" BLAKE2b-256 <data> - BLAKE2b-256 hash") + print(" BLAKE2b-512 <data> - BLAKE2b-512 hash") print(" CRC32 <data> - CRC32 checksum") print("") print("Key Derivation:") @@ -271,7 +271,7 @@ if command == "MD5" then return end local data = positional[2] - local hash = crypto.hash.MD5(data) + local hash = crypto.MD5(data) print(formatOutput(hash, options)) elseif command == "SHA1" then @@ -280,7 +280,7 @@ elseif command == "SHA1" then return end local data = positional[2] - local hash = crypto.hash.SHA1(data) + local hash = crypto.SHA1(data) print(formatOutput(hash, options)) elseif command == "SHA256" then @@ -289,7 +289,7 @@ elseif command == "SHA256" then return end local data = positional[2] - local hash = crypto.hash.SHA256(data) + local hash = crypto.SHA256(data) print(formatOutput(hash, options)) elseif command == "SHA512" then @@ -298,43 +298,43 @@ elseif command == "SHA512" then return end local data = positional[2] - local hash = crypto.hash.SHA512(data) + local hash = crypto.SHA512(data) print(formatOutput(hash, options)) -elseif command == "SHA3_256" then +elseif command == "SHA3-256" then if #positional < 2 then - print("Error: SHA3_256 requires data argument") + print("Error: SHA3-256 requires data argument") return end local data = positional[2] - local hash = crypto.hash.SHA3_256(data) + local hash = crypto["SHA3-256"](data) print(formatOutput(hash, options)) -elseif command == "SHA3_512" then +elseif command == "SHA3-512" then if #positional < 2 then - print("Error: SHA3_512 requires data argument") + print("Error: SHA3-512 requires data argument") return end local data = positional[2] - local hash = crypto.hash.SHA3_512(data) + local hash = crypto["SHA3-512"](data) print(formatOutput(hash, options)) -elseif command == "BLAKE2b" then +elseif command == "BLAKE2b-256" then if #positional < 2 then - print("Error: BLAKE2b requires data argument") + print("Error: BLAKE2b-256 requires data argument") return end local data = positional[2] - local hash = crypto.hash.BLAKE2b(data) + local hash = crypto["BLAKE2b-256"](data) print(formatOutput(hash, options)) -elseif command == "BLAKE2b_512" then +elseif command == "BLAKE2b-512" then if #positional < 2 then - print("Error: BLAKE2b_512 requires data argument") + print("Error: BLAKE2b-512 requires data argument") return end local data = positional[2] - local hash = crypto.hash.BLAKE2b_512(data) + local hash = crypto["BLAKE2b-512"](data) print(formatOutput(hash, options)) elseif command == "CRC32" then @@ -343,7 +343,7 @@ elseif command == "CRC32" then return end local data = positional[2] - local hash = crypto.hash.CRC32(data) + local hash = crypto.CRC32(data) print(formatOutput(hash, options)) -- Key Derivation @@ -359,7 +359,7 @@ elseif command == "PBKDF2" then return end local iterations = options.iterations or 100000 - local key = crypto.kdf.PBKDF2(password, salt, iterations, 32) + local key = crypto.PBKDF2(password, salt, iterations, 32) if key then print(formatOutput(key, options)) else @@ -377,7 +377,7 @@ elseif command == "Argon2id" then print("Error: Argon2id requires -salt option") return end - local key = crypto.kdf.Argon2id(password, salt) + local key = crypto.Argon2id(password, salt) if key then print(formatOutput(key, options)) else @@ -385,7 +385,7 @@ elseif command == "Argon2id" then end elseif command == "generateSalt" then - local salt = crypto.kdf.generateSalt() + local salt = crypto.generateSalt() if salt then print(formatOutput(salt, options)) else diff --git a/iso_includes/apps/com.luajitos.installer/src/init.lua b/iso_includes/apps/com.luajitos.installer/src/init.lua @@ -688,7 +688,30 @@ Then install GRUB: if osprint then osprint("Installer: Boot partition setup complete\n") - osprint("Installer: NOTE - Kernel must be copied manually to /boot/kernel.bin\n") + end + + -- Install bootloader to MBR + updateProgress(7, "Installing bootloader...") + if grub and grub.install then + if osprint then + osprint("Installer: Installing bootloader to MBR...\n") + end + local ok, err = grub.install(drive.bus, drive.drive) + if ok then + if osprint then + osprint("Installer: Bootloader installed successfully\n") + end + else + if osprint then + osprint("Installer: Warning - bootloader install failed: " .. tostring(err) .. "\n") + osprint("Installer: You may need to run grub-install manually from Linux\n") + end + end + else + if osprint then + osprint("Installer: Warning - grub module not available\n") + osprint("Installer: Run 'grub-install --boot-directory=/mnt/boot /dev/sdX' from Linux\n") + end end -- Continue with main filesystem format diff --git a/iso_includes/apps/com.luajitos.passprompt/README.md b/iso_includes/apps/com.luajitos.passprompt/README.md @@ -23,7 +23,7 @@ local password = "admin" -- Change this to your desired password local salt = "LuajitOS-AdminSalt-v1" -- Use the crypto library -local hash = crypto.kdf.Argon2id(password, salt) +local hash = crypto.Argon2id(password, salt) -- Encode to base64 local function base64_encode(data) @@ -131,7 +131,7 @@ end ### Hashing Algorithm - **Argon2id**: Memory-hard function resistant to GPU/ASIC attacks -- Default parameters: 3 iterations, 64MB memory (from `crypto.kdf.Argon2id`) +- Default parameters: 3 iterations, 64MB memory (from `crypto.Argon2id`) ### Permissions Required The passprompt app requires: diff --git a/iso_includes/apps/com.luajitos.passprompt/USAGE_EXAMPLE.md b/iso_includes/apps/com.luajitos.passprompt/USAGE_EXAMPLE.md @@ -13,7 +13,7 @@ local password = "admin" -- Your chosen password local salt = "LuajitOS-AdminSalt-v1" -- Generate Argon2id hash -local hash = crypto.kdf.Argon2id(password, salt) +local hash = crypto.Argon2id(password, salt) -- Base64 encode function local b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' diff --git a/iso_includes/apps/com.luajitos.passprompt/src/init.lua b/iso_includes/apps/com.luajitos.passprompt/src/init.lua @@ -119,8 +119,8 @@ local lastBlinkTime = os.clock() -- Hash password with Argon2id local function hashPassword(password) - if not crypto or not crypto.kdf or not crypto.kdf.Argon2id then - osprint("ERROR: crypto.kdf.Argon2id not available\n") + if not crypto or not crypto.Argon2id then + osprint("ERROR: crypto.Argon2id not available\n") return nil end @@ -128,7 +128,7 @@ local function hashPassword(password) -- In production, this should be a random salt stored with the hash local salt = "LuajitOS-AdminSalt-v1" - local hash = crypto.kdf.Argon2id(password, salt) + local hash = crypto.Argon2id(password, salt) if not hash then osprint("ERROR: Argon2id hashing failed\n") return nil diff --git a/iso_includes/apps/com.luajitos.taskbar/manifest.lua b/iso_includes/apps/com.luajitos.taskbar/manifest.lua @@ -7,6 +7,8 @@ return { entry = "init.lua", type = "gui", hidden = true, -- Hide from start menu + autostart = true, -- Launch on system startup + autostartPriority = 2, -- Launch after background permissions = { "scheduling", "export", diff --git a/iso_includes/os/SETUP_PASSWORD.md b/iso_includes/os/SETUP_PASSWORD.md @@ -11,7 +11,7 @@ To use the password prompt system, you need to generate a password hash. ```lua local password = "admin" local salt = "LuajitOS-AdminSalt-v1" -local hash = crypto.kdf.Argon2id(password, salt) +local hash = crypto.Argon2id(password, salt) -- Base64 encode function local b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' diff --git a/iso_includes/os/boot/kernel.bin b/iso_includes/os/boot/kernel.bin Binary files differ. diff --git a/iso_includes/os/postinit.lua b/iso_includes/os/postinit.lua @@ -336,22 +336,74 @@ else end end --- Launch background and taskbar apps (system apps) -osprint("Launching background app...\n") -local bg_run_success, bg_app = _G.run.execute("com.luajitos.background", _G.fsRoot) -if bg_run_success and bg_app then - osprint("Background app launched with PID: " .. tostring(bg_app.pid) .. "\n") -else - osprint("ERROR: Failed to launch background app\n") +-- Helper function to parse manifest (simplified version for autostart scanning) +local function parse_manifest_simple(manifest_code) + if not manifest_code then return {} end + + local manifest = {} + + -- Check for autostart = true + if manifest_code:match("autostart%s*=%s*true") then + manifest.autostart = true + end + + -- Check for autostartPriority = <number> + local priority = manifest_code:match("autostartPriority%s*=%s*(%d+)") + if priority then + manifest.autostartPriority = tonumber(priority) + end + + return manifest end --- Launch taskbar app -osprint("Launching taskbar app...\n") -local taskbar_run_success, taskbar_app = _G.run.execute("com.luajitos.taskbar", _G.fsRoot) -if taskbar_run_success and taskbar_app then - osprint("Taskbar app launched with PID: " .. tostring(taskbar_app.pid) .. "\n") -else - osprint("ERROR: Failed to launch taskbar app\n") +-- Scan all apps for autostart field and launch them +osprint("Scanning apps for autostart...\n") +local autostart_apps = {} + +if CRamdiskList and CRamdiskOpen and CRamdiskRead and CRamdiskClose then + local apps = CRamdiskList("/apps") + if apps then + for _, entry in ipairs(apps) do + if entry.type == "directory" or entry.type == "dir" then + local app_id = entry.name + local manifest_path = "/apps/" .. app_id .. "/manifest.lua" + + local handle = CRamdiskOpen(manifest_path, "r") + if handle then + local manifest_code = CRamdiskRead(handle) + CRamdiskClose(handle) + + if manifest_code then + local manifest = parse_manifest_simple(manifest_code) + if manifest.autostart then + table.insert(autostart_apps, { + id = app_id, + priority = manifest.autostartPriority or 100 + }) + osprint(" Found autostart app: " .. app_id .. " (priority: " .. (manifest.autostartPriority or 100) .. ")\n") + end + end + end + end + end + end +end + +-- Sort by priority (lower number = earlier launch) +table.sort(autostart_apps, function(a, b) + return a.priority < b.priority +end) + +-- Launch autostart apps in priority order +osprint("Launching " .. #autostart_apps .. " autostart app(s)...\n") +for _, app_info in ipairs(autostart_apps) do + osprint("Launching autostart app: " .. app_info.id .. "...\n") + local success, app = _G.run.execute(app_info.id, _G.fsRoot) + if success and app then + osprint(" " .. app_info.id .. " launched with PID: " .. tostring(app.pid) .. "\n") + else + osprint(" ERROR: Failed to launch " .. app_info.id .. "\n") + end end osprint("Post-init complete\n") diff --git a/kernel.c b/kernel.c @@ -48,6 +48,9 @@ extern int luaopen_partition(lua_State *L); /* External FAT16 initialization function */ extern int luaopen_fat16(lua_State *L); +/* External GRUB installation function */ +extern int luaopen_grub(lua_State *L); + /* External FDE contexts array (defined in fde.c) */ extern fde_context_t fde_contexts[4]; @@ -816,6 +819,12 @@ void usermode_function(void) { lua_setglobal(L, "fat16"); terminal_writestring("FAT16 module loaded!\n"); + /* Initialize GRUB module */ + terminal_writestring("Initializing GRUB module...\n"); + luaopen_grub(L); + lua_setglobal(L, "grub"); + terminal_writestring("GRUB module loaded!\n"); + /* Register C ramdisk functions */ terminal_writestring("Registering ramdisk functions...\n"); lua_pushcfunction(L, lua_ramdisk_open); diff --git a/luajit b/luajit @@ -0,0 +1 @@ +Subproject commit 6f21cb8ace60b297cd144c3b6925865b043095d2 diff --git a/splash.png b/splash.png Binary files differ.