luajit_init.c (38620B)
1 #include <stdint.h> 2 #include <stddef.h> 3 #include <stdlib.h> 4 #include <string.h> 5 #include <ctype.h> 6 7 /* LuaJIT headers */ 8 #include <lua.h> 9 #include <lualib.h> 10 #include <lauxlib.h> 11 12 /* Graphics functions */ 13 #include "graphics.h" 14 #include "vesa.h" 15 16 /* Image decoder functions */ 17 #include "decoder.h" 18 #include "decoder_BMP.h" 19 #include "decoder_PNG.h" 20 #include "decoder_JPEG.h" 21 #include "compression/compression.h" 22 #include "ramdisk.h" 23 24 /* External functions and data from boot.s */ 25 extern void enter_usermode(void (*entry_point)(void)); 26 extern void syscall_handler(void); 27 extern uint8_t tss[104]; 28 extern uint32_t kernel_stack_top; 29 extern uint64_t gdt_start[]; 30 31 /* External exception handlers from exceptions.s */ 32 extern void double_fault_handler(void); 33 extern void gpf_handler(void); 34 extern void page_fault_handler(void); 35 extern void irq12_handler(void); 36 extern void irq1_handler(void); 37 38 /* Serial port (COM1) */ 39 #define SERIAL_PORT 0x3F8 40 41 /* VGA text mode buffer */ 42 static uint16_t* const VGA_MEMORY = (uint16_t*)0xB8000; 43 static const size_t VGA_TEXT_WIDTH = 80; 44 static const size_t VGA_TEXT_HEIGHT = 25; 45 static size_t terminal_row = 0; 46 static size_t terminal_column = 0; 47 static uint8_t terminal_color = 0x0F; 48 49 /* IDT entry structure */ 50 struct idt_entry { 51 uint16_t offset_low; 52 uint16_t selector; 53 uint8_t zero; 54 uint8_t type_attr; 55 uint16_t offset_high; 56 } __attribute__((packed)); 57 58 struct idt_ptr { 59 uint16_t limit; 60 uint32_t base; 61 } __attribute__((packed)); 62 63 static struct idt_entry idt[256]; 64 static struct idt_ptr idtp; 65 66 /* Serial port functions */ 67 static inline void serial_write(uint8_t data) { 68 __asm__ volatile ("outb %0, %1" : : "a"(data), "Nd"(SERIAL_PORT)); 69 } 70 71 static void serial_init(void) { 72 __asm__ volatile ("outb %0, %1" : : "a"((uint8_t)0x00), "Nd"(SERIAL_PORT + 1)); // Disable interrupts 73 __asm__ volatile ("outb %0, %1" : : "a"((uint8_t)0x80), "Nd"(SERIAL_PORT + 3)); // Enable DLAB 74 __asm__ volatile ("outb %0, %1" : : "a"((uint8_t)0x03), "Nd"(SERIAL_PORT + 0)); // Set divisor low byte (38400 baud) 75 __asm__ volatile ("outb %0, %1" : : "a"((uint8_t)0x00), "Nd"(SERIAL_PORT + 1)); // Set divisor high byte 76 __asm__ volatile ("outb %0, %1" : : "a"((uint8_t)0x03), "Nd"(SERIAL_PORT + 3)); // 8 bits, no parity, one stop bit 77 __asm__ volatile ("outb %0, %1" : : "a"((uint8_t)0xC7), "Nd"(SERIAL_PORT + 2)); // Enable FIFO 78 __asm__ volatile ("outb %0, %1" : : "a"((uint8_t)0x0B), "Nd"(SERIAL_PORT + 4)); // IRQs enabled, RTS/DSR set 79 } 80 81 /* VGA functions */ 82 static inline uint16_t vga_entry(unsigned char uc, uint8_t color) { 83 return (uint16_t)uc | (uint16_t)color << 8; 84 } 85 86 void terminal_initialize(void) { 87 serial_init(); 88 for (size_t y = 0; y < VGA_TEXT_HEIGHT; y++) { 89 for (size_t x = 0; x < VGA_TEXT_WIDTH; x++) { 90 VGA_MEMORY[y * VGA_TEXT_WIDTH + x] = vga_entry(' ', terminal_color); 91 } 92 } 93 } 94 95 void terminal_putchar(char c) { 96 /* Write to serial port */ 97 serial_write((uint8_t)c); 98 99 /* Write to VGA */ 100 if (c == '\n') { 101 terminal_column = 0; 102 if (++terminal_row == VGA_TEXT_HEIGHT) { 103 terminal_row = VGA_TEXT_HEIGHT - 1; 104 for (size_t y = 0; y < VGA_TEXT_HEIGHT - 1; y++) { 105 for (size_t x = 0; x < VGA_TEXT_WIDTH; x++) { 106 VGA_MEMORY[y * VGA_TEXT_WIDTH + x] = VGA_MEMORY[(y + 1) * VGA_TEXT_WIDTH + x]; 107 } 108 } 109 for (size_t x = 0; x < VGA_TEXT_WIDTH; x++) { 110 VGA_MEMORY[(VGA_TEXT_HEIGHT - 1) * VGA_TEXT_WIDTH + x] = vga_entry(' ', terminal_color); 111 } 112 } 113 return; 114 } 115 116 VGA_MEMORY[terminal_row * VGA_TEXT_WIDTH + terminal_column] = vga_entry(c, terminal_color); 117 if (++terminal_column == VGA_TEXT_WIDTH) { 118 terminal_column = 0; 119 if (++terminal_row == VGA_TEXT_HEIGHT) { 120 terminal_row = VGA_TEXT_HEIGHT - 1; 121 } 122 } 123 } 124 125 void terminal_writestring(const char* data) { 126 while (*data) terminal_putchar(*data++); 127 } 128 129 void terminal_writeint(int value) { 130 if (value < 0) { 131 terminal_putchar('-'); 132 value = -value; 133 } 134 135 char buffer[16]; 136 int i = 0; 137 138 if (value == 0) { 139 terminal_putchar('0'); 140 return; 141 } 142 143 while (value > 0) { 144 buffer[i++] = '0' + (value % 10); 145 value /= 10; 146 } 147 148 while (i > 0) { 149 terminal_putchar(buffer[--i]); 150 } 151 } 152 153 /* Simple delay function */ 154 static void delay(void) { 155 for (volatile int i = 0; i < 10000000; i++); 156 } 157 158 /* System calls */ 159 #define SYSCALL_OSPRINT 1 160 #define SYSCALL_GETRANDOM 2 161 #define SYSCALL_READ_FILE 3 162 163 /* ===== CSPRNG Implementation ===== */ 164 165 /* ChaCha20 state for CSPRNG */ 166 static uint32_t chacha_state[16]; 167 static int rng_initialized = 0; 168 169 /* ChaCha20 quarter round */ 170 #define ROTL32(v, n) (((v) << (n)) | ((v) >> (32 - (n)))) 171 #define QR(a, b, c, d) \ 172 a += b; d ^= a; d = ROTL32(d, 16); \ 173 c += d; b ^= c; b = ROTL32(b, 12); \ 174 a += b; d ^= a; d = ROTL32(d, 8); \ 175 c += d; b ^= c; b = ROTL32(b, 7); 176 177 /* Try to get random number from CPU (RDRAND instruction) */ 178 static inline int rdrand32(uint32_t* value) { 179 unsigned char ok; 180 __asm__ volatile ( 181 "rdrand %0; setc %1" 182 : "=r"(*value), "=qm"(ok) 183 ); 184 return ok; 185 } 186 187 /* Try to get random seed from CPU (RDSEED instruction - better for seeding) */ 188 static inline int rdseed32(uint32_t* value) { 189 unsigned char ok; 190 __asm__ volatile ( 191 "rdseed %0; setc %1" 192 : "=r"(*value), "=qm"(ok) 193 ); 194 return ok; 195 } 196 197 /* Get CPU timestamp counter for entropy */ 198 static inline uint64_t rdtsc(void) { 199 uint32_t lo, hi; 200 __asm__ volatile ("rdtsc" : "=a"(lo), "=d"(hi)); 201 return ((uint64_t)hi << 32) | lo; 202 } 203 204 /* Check if RDRAND is supported */ 205 static int cpu_has_rdrand(void) { 206 uint32_t eax, ebx, ecx, edx; 207 __asm__ volatile ( 208 "cpuid" 209 : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) 210 : "a"(1), "c"(0) 211 ); 212 return (ecx & (1 << 30)) != 0; /* RDRAND is bit 30 of ECX */ 213 } 214 215 /* Read CPU temperature from thermal MSR (if available) */ 216 static uint32_t try_read_cpu_temp(void) { 217 uint32_t eax, ebx, ecx, edx; 218 219 /* Check if Digital Thermal Sensor is available (CPUID.06H) */ 220 __asm__ volatile ( 221 "cpuid" 222 : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) 223 : "a"(6), "c"(0) 224 ); 225 226 if (eax & 1) { /* Digital temperature sensor supported */ 227 uint32_t lo, hi; 228 /* Read IA32_THERM_STATUS MSR (0x19C) */ 229 __asm__ volatile ( 230 "rdmsr" 231 : "=a"(lo), "=d"(hi) 232 : "c"(0x19C) 233 ); 234 return lo; /* Lower 32 bits contain temperature reading */ 235 } 236 return 0; 237 } 238 239 /* Read CMOS RTC for additional entropy */ 240 static uint32_t read_rtc_entropy(void) { 241 uint32_t entropy = 0; 242 243 /* Read various CMOS RTC registers for entropy */ 244 /* Port 0x70 = CMOS address, Port 0x71 = CMOS data */ 245 for (int reg = 0; reg < 10; reg++) { 246 __asm__ volatile ("outb %0, $0x70" : : "a"((uint8_t)reg)); 247 uint8_t val; 248 __asm__ volatile ("inb $0x71, %0" : "=a"(val)); 249 entropy = (entropy << 3) ^ val; 250 } 251 252 return entropy; 253 } 254 255 /* Keyboard functions for entropy collection */ 256 #define KBD_DATA_PORT 0x60 257 #define KBD_STATUS_PORT 0x64 258 259 static inline uint8_t kbd_read_data(void) { 260 uint8_t data; 261 __asm__ volatile ("inb %1, %0" : "=a"(data) : "Nd"((uint16_t)KBD_DATA_PORT)); 262 return data; 263 } 264 265 static inline uint8_t kbd_read_status(void) { 266 uint8_t status; 267 __asm__ volatile ("inb %1, %0" : "=a"(status) : "Nd"((uint16_t)KBD_STATUS_PORT)); 268 return status; 269 } 270 271 static inline int kbd_has_data(void) { 272 return (kbd_read_status() & 0x01) != 0; 273 } 274 275 /* Collect entropy from keyboard timing */ 276 static uint32_t collect_keyboard_entropy(int num_keys) { 277 uint32_t entropy = 0; 278 int keys_collected = 0; 279 280 /* Clear any pending keyboard data */ 281 while (kbd_has_data()) { 282 kbd_read_data(); 283 } 284 285 terminal_writestring("\n=== ENTROPY COLLECTION ===\n"); 286 terminal_writestring("Please press "); 287 288 /* Print number */ 289 char num_str[4]; 290 int idx = 0; 291 int n = num_keys; 292 if (n >= 10) { 293 num_str[idx++] = '0' + (n / 10); 294 n %= 10; 295 } 296 num_str[idx++] = '0' + n; 297 num_str[idx] = '\0'; 298 terminal_writestring(num_str); 299 300 terminal_writestring(" random keys...\n"); 301 302 uint64_t last_tsc = rdtsc(); 303 304 while (keys_collected < num_keys) { 305 if (kbd_has_data()) { 306 uint8_t scancode = kbd_read_data(); 307 308 /* Only count key presses (bit 7 clear), ignore releases */ 309 if ((scancode & 0x80) == 0) { 310 uint64_t current_tsc = rdtsc(); 311 uint64_t delta = current_tsc - last_tsc; 312 313 /* Mix in scancode, timing delta, and current TSC */ 314 entropy ^= scancode; 315 entropy = (entropy << 7) | (entropy >> 25); /* Rotate */ 316 entropy ^= (uint32_t)delta; 317 entropy = (entropy << 13) | (entropy >> 19); /* Rotate */ 318 entropy ^= (uint32_t)(current_tsc ^ (current_tsc >> 32)); 319 320 last_tsc = current_tsc; 321 keys_collected++; 322 323 /* Visual feedback */ 324 terminal_putchar('.'); 325 } 326 } 327 } 328 329 terminal_writestring(" done!\n"); 330 return entropy; 331 } 332 333 /* Initialize ChaCha20 state with entropy */ 334 static void init_chacha_rng(void) { 335 int has_rdrand = cpu_has_rdrand(); 336 337 /* ChaCha20 constants ("expand 32-byte k") */ 338 chacha_state[0] = 0x61707865; 339 chacha_state[1] = 0x3320646e; 340 chacha_state[2] = 0x79622d32; 341 chacha_state[3] = 0x6b206574; 342 343 /* Gather entropy from multiple sources for mixing */ 344 uint32_t cpu_temp = try_read_cpu_temp(); 345 uint32_t rtc_entropy = read_rtc_entropy(); 346 uint64_t initial_tsc = rdtsc(); 347 348 /* Collect keyboard timing entropy from user */ 349 /* DISABLED: uint32_t kbd_entropy = collect_keyboard_entropy(10); */ 350 uint32_t kbd_entropy = (uint32_t)(rdtsc() ^ (rdtsc() >> 32)); /* Use TSC instead for now */ 351 352 /* Seed state with hardware RNG or fallback to multiple entropy sources */ 353 for (int i = 4; i < 16; i++) { 354 if (has_rdrand && rdseed32(&chacha_state[i])) { 355 /* Got hardware random seed - most secure */ 356 /* Still mix in other entropy for defense in depth */ 357 chacha_state[i] ^= kbd_entropy; 358 chacha_state[i] ^= cpu_temp; 359 chacha_state[i] ^= rtc_entropy; 360 continue; 361 } 362 363 /* Fallback: mix ALL entropy sources */ 364 uint64_t tsc = rdtsc(); 365 chacha_state[i] = (uint32_t)(tsc ^ (tsc >> 32)); 366 chacha_state[i] ^= cpu_temp; 367 chacha_state[i] ^= rtc_entropy; 368 chacha_state[i] ^= (uint32_t)initial_tsc; 369 chacha_state[i] ^= kbd_entropy; 370 371 /* Add timing jitter by doing variable work */ 372 for (volatile int j = 0; j < (i * 100); j++) { 373 tsc = rdtsc(); 374 chacha_state[i] ^= (uint32_t)tsc; 375 } 376 377 /* Mix in CPU temp again (might have changed) */ 378 chacha_state[i] ^= try_read_cpu_temp(); 379 380 /* Mix in keyboard entropy rotated by position */ 381 chacha_state[i] ^= (kbd_entropy << i) | (kbd_entropy >> (32 - i)); 382 } 383 384 rng_initialized = 1; 385 } 386 387 /* ChaCha20 block function */ 388 static void chacha20_block(uint32_t out[16]) { 389 uint32_t x[16]; 390 391 /* Copy state */ 392 for (int i = 0; i < 16; i++) { 393 x[i] = chacha_state[i]; 394 } 395 396 /* 20 rounds */ 397 for (int i = 0; i < 10; i++) { 398 /* Column rounds */ 399 QR(x[0], x[4], x[8], x[12]); 400 QR(x[1], x[5], x[9], x[13]); 401 QR(x[2], x[6], x[10], x[14]); 402 QR(x[3], x[7], x[11], x[15]); 403 /* Diagonal rounds */ 404 QR(x[0], x[5], x[10], x[15]); 405 QR(x[1], x[6], x[11], x[12]); 406 QR(x[2], x[7], x[8], x[13]); 407 QR(x[3], x[4], x[9], x[14]); 408 } 409 410 /* Add original state */ 411 for (int i = 0; i < 16; i++) { 412 out[i] = x[i] + chacha_state[i]; 413 } 414 415 /* Increment counter */ 416 chacha_state[12]++; 417 if (chacha_state[12] == 0) { 418 chacha_state[13]++; 419 } 420 } 421 422 /* Get random bytes (CSPRNG) */ 423 static void get_random_bytes(void* buf, size_t len) { 424 uint8_t* bytes = (uint8_t*)buf; 425 int has_rdrand = cpu_has_rdrand(); 426 427 /* RNG should already be initialized in kernel mode */ 428 if (!rng_initialized) { 429 /* Shouldn't happen, but handle gracefully */ 430 return; 431 } 432 433 while (len > 0) { 434 /* Try RDRAND first for direct hardware randomness */ 435 if (has_rdrand && len >= 4) { 436 uint32_t val; 437 if (rdrand32(&val)) { 438 for (int i = 0; i < 4 && len > 0; i++, len--) { 439 *bytes++ = (val >> (i * 8)) & 0xFF; 440 } 441 continue; 442 } 443 } 444 445 /* Fallback to ChaCha20 */ 446 uint32_t block[16]; 447 chacha20_block(block); 448 449 size_t to_copy = len < 64 ? len : 64; 450 for (size_t i = 0; i < to_copy; i++) { 451 bytes[i] = ((uint8_t*)block)[i]; 452 } 453 bytes += to_copy; 454 len -= to_copy; 455 } 456 } 457 458 /* ===== End CSPRNG Implementation ===== */ 459 460 /* Syscall handler (called from syscall.s) */ 461 int handle_syscall(int syscall_num, uint32_t param1, uint32_t param2, uint32_t param3) { 462 if (syscall_num == SYSCALL_OSPRINT) { 463 terminal_writestring((const char*)param1); 464 465 /* 250ms delay */ 466 unsigned long long start, end; 467 __asm__ volatile ("rdtsc" : "=A"(start)); 468 do { 469 __asm__ volatile ("rdtsc" : "=A"(end)); 470 } while ((end - start) < 500000000ULL); /* ~250ms at 2GHz CPU */ 471 472 return 0; 473 } 474 if (syscall_num == SYSCALL_GETRANDOM) { 475 /* getrandom(void *buf, size_t buflen, unsigned int flags) */ 476 void* buf = (void*)param1; 477 size_t buflen = (size_t)param2; 478 /* unsigned int flags = param3; */ /* We ignore flags for now */ 479 (void)param3; 480 481 /* Debug output */ 482 terminal_writestring("KERNEL: getrandom called, buflen="); 483 char num[16]; 484 int i = 0, n = buflen; 485 do { num[i++] = '0' + (n % 10); n /= 10; } while (n > 0); 486 while (i > 0) { char c = num[--i]; terminal_putchar(c); } 487 terminal_putchar('\n'); 488 489 if (!buf || buflen == 0) { 490 terminal_writestring("KERNEL: getrandom returning -1 (EINVAL)\n"); 491 return -1; /* EINVAL */ 492 } 493 494 get_random_bytes(buf, buflen); 495 terminal_writestring("KERNEL: getrandom returning "); 496 i = 0; n = buflen; 497 do { num[i++] = '0' + (n % 10); n /= 10; } while (n > 0); 498 while (i > 0) { char c = num[--i]; terminal_putchar(c); } 499 terminal_putchar('\n'); 500 return (int)buflen; /* Return number of bytes written */ 501 } 502 return -1; 503 } 504 505 /* TSS setup */ 506 void tss_install(void) { 507 /* Zero out TSS */ 508 for (int i = 0; i < 104; i++) { 509 tss[i] = 0; 510 } 511 512 /* Set kernel stack in TSS (used when transitioning from ring 3 to ring 0) */ 513 uint32_t *tss_ptr = (uint32_t*)tss; 514 tss_ptr[1] = (uint32_t)&kernel_stack_top; /* ESP0 */ 515 tss_ptr[2] = 0x10; /* SS0 (kernel data segment) */ 516 517 /* Write TSS descriptor to GDT at index 5 (offset 0x28) */ 518 uint32_t base = (uint32_t)tss; 519 uint32_t limit = 104 - 1; 520 521 /* TSS descriptor format */ 522 uint64_t tss_desc = limit & 0xFFFF; /* Limit low */ 523 tss_desc |= ((uint64_t)(base & 0xFFFF)) << 16; /* Base low */ 524 tss_desc |= ((uint64_t)((base >> 16) & 0xFF)) << 32; /* Base mid */ 525 tss_desc |= ((uint64_t)0x89) << 40; /* Type: available 32-bit TSS, present */ 526 tss_desc |= ((uint64_t)((limit >> 16) & 0xF)) << 48; /* Limit high + flags */ 527 tss_desc |= ((uint64_t)((base >> 24) & 0xFF)) << 56; /* Base high */ 528 529 gdt_start[5] = tss_desc; 530 531 /* Load TSS */ 532 __asm__ volatile ("ltr %%ax" : : "a"(0x28)); /* TSS selector = 0x28 */ 533 } 534 535 /* IDT setup */ 536 void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags) { 537 idt[num].offset_low = base & 0xFFFF; 538 idt[num].offset_high = (base >> 16) & 0xFFFF; 539 idt[num].selector = sel; 540 idt[num].zero = 0; 541 idt[num].type_attr = flags; 542 } 543 544 void idt_install(void) { 545 idtp.limit = sizeof(idt) - 1; 546 idtp.base = (uint32_t)&idt; 547 548 /* Set up exception handlers (DPL=0, present, 32-bit interrupt gate) */ 549 idt_set_gate(0x08, (uint32_t)double_fault_handler, 0x08, 0x8E); /* Double Fault */ 550 idt_set_gate(0x0d, (uint32_t)gpf_handler, 0x08, 0x8E); /* General Protection Fault */ 551 idt_set_gate(0x0e, (uint32_t)page_fault_handler, 0x08, 0x8E); /* Page Fault */ 552 553 /* Set up IRQ handlers */ 554 idt_set_gate(0x21, (uint32_t)irq1_handler, 0x08, 0x8E); /* IRQ1 (Keyboard) */ 555 idt_set_gate(0x2C, (uint32_t)irq12_handler, 0x08, 0x8E); /* IRQ12 (PS/2 Mouse) */ 556 557 /* Set up syscall gate (int 0x80) */ 558 idt_set_gate(0x80, (uint32_t)syscall_handler, 0x08, 0xEE); /* DPL=3, present, 32-bit interrupt gate */ 559 560 /* Load IDT */ 561 __asm__ volatile ("lidt %0" : : "m"(idtp)); 562 } 563 564 /* Debug counter for allocations */ 565 static int alloc_count = 0; 566 567 /* Lua allocator */ 568 static void* lua_allocator(void* ud, void* ptr, size_t osize, size_t nsize) { 569 (void)ud; (void)osize; 570 571 if (nsize == 0) { 572 free(ptr); 573 return NULL; 574 } 575 576 if (ptr == NULL) { 577 void* result = malloc(nsize); 578 if (!result) { 579 terminal_writestring("ERROR: Memory allocation failed\n"); 580 } 581 return result; 582 } else { 583 void* result = realloc(ptr, nsize); 584 if (!result) { 585 terminal_writestring("ERROR: Memory reallocation failed\n"); 586 } 587 return result; 588 } 589 } 590 591 /* Test function - copy EXACT structure of os print */ 592 static int lua_test_dummy(lua_State* L) { 593 const char* str = luaL_checkstring(L, 1); 594 terminal_writestring("DEBUG: dummy got string: "); 595 terminal_writestring(str); 596 terminal_writestring("\n"); 597 return 0; 598 } 599 600 /* Lua binding for osprint (uses syscall in user mode) */ 601 static int lua_osprint(lua_State* L) { 602 const char* str = luaL_checkstring(L, 1); 603 terminal_writestring(str); 604 return 0; 605 } 606 607 /* Note: All graphics functions are now in graphics.c */ 608 609 /* Custom string.sub implementation in C - rewritten based on working string.char */ 610 static int lua_string_sub(lua_State* L) { 611 size_t len; 612 const char* s = luaL_checklstring(L, 1, &len); 613 int start = luaL_checkint(L, 2); 614 int end = luaL_optint(L, 3, -1); 615 616 /* Lua uses 1-based indexing */ 617 if (start < 0) start = len + start + 1; 618 if (end < 0) end = len + end + 1; 619 if (start < 1) start = 1; 620 if (end > (int)len) end = len; 621 622 /* Handle empty or invalid range */ 623 if (start > end) { 624 lua_pushlstring(L, "", 0); 625 return 1; 626 } 627 628 /* Calculate substring length */ 629 size_t sub_len = (size_t)(end - start + 1); 630 631 /* Allocate buffer for substring */ 632 char* buffer = (char*)malloc(sub_len); 633 if (!buffer) { 634 lua_pushstring(L, "out of memory"); 635 lua_error(L); 636 return 0; 637 } 638 639 /* Copy substring to buffer using memcpy */ 640 memcpy(buffer, s + start - 1, sub_len); 641 642 /* Push the substring */ 643 lua_pushlstring(L, buffer, sub_len); 644 645 /* Free buffer */ 646 free(buffer); 647 648 return 1; 649 } 650 651 /* string.replace(str, pattern, replacement) */ 652 static int lua_string_replace(lua_State* L) { 653 size_t str_len, pat_len, rep_len; 654 const char* str = luaL_checklstring(L, 1, &str_len); 655 const char* pattern = luaL_checklstring(L, 2, &pat_len); 656 const char* replacement = luaL_checklstring(L, 3, &rep_len); 657 658 if (pat_len == 0) { 659 lua_pushvalue(L, 1); /* Return original string */ 660 return 1; 661 } 662 663 /* Count occurrences */ 664 int count = 0; 665 const char* p = str; 666 while ((p = strstr(p, pattern)) != NULL) { 667 count++; 668 p += pat_len; 669 } 670 671 if (count == 0) { 672 lua_pushvalue(L, 1); /* Return original string */ 673 return 1; 674 } 675 676 /* Allocate result buffer */ 677 size_t new_len = str_len - (count * pat_len) + (count * rep_len); 678 char* result = malloc(new_len + 1); 679 if (!result) { 680 lua_pushstring(L, "out of memory"); 681 lua_error(L); 682 return 0; 683 } 684 685 /* Build result string */ 686 char* dst = result; 687 const char* src = str; 688 while (*src) { 689 const char* match = strstr(src, pattern); 690 if (match == NULL) { 691 /* Copy remaining */ 692 while (*src) *dst++ = *src++; 693 break; 694 } 695 /* Copy before match */ 696 while (src < match) *dst++ = *src++; 697 /* Copy replacement */ 698 for (size_t i = 0; i < rep_len; i++) *dst++ = replacement[i]; 699 /* Skip pattern */ 700 src += pat_len; 701 } 702 *dst = '\0'; 703 704 lua_pushlstring(L, result, new_len); 705 free(result); 706 return 1; 707 } 708 709 /* string.trimr(str, char) - trim from right */ 710 static int lua_string_trimr(lua_State* L) { 711 size_t len; 712 const char* str = luaL_checklstring(L, 1, &len); 713 size_t char_len; 714 const char* trim_char = luaL_optlstring(L, 2, " ", &char_len); 715 char c = trim_char[0]; 716 717 int end = len; 718 while (end > 0 && str[end - 1] == c) { 719 end--; 720 } 721 722 lua_pushlstring(L, str, end); 723 return 1; 724 } 725 726 /* string.triml(str, char) - trim from left */ 727 static int lua_string_triml(lua_State* L) { 728 size_t len; 729 const char* str = luaL_checklstring(L, 1, &len); 730 size_t char_len; 731 const char* trim_char = luaL_optlstring(L, 2, " ", &char_len); 732 char c = trim_char[0]; 733 734 int start = 0; 735 while (start < (int)len && str[start] == c) { 736 start++; 737 } 738 739 lua_pushlstring(L, str + start, len - start); 740 return 1; 741 } 742 743 /* string.trim(str, char) - trim from both sides */ 744 static int lua_string_trim(lua_State* L) { 745 size_t len; 746 const char* str = luaL_checklstring(L, 1, &len); 747 size_t char_len; 748 const char* trim_char = luaL_optlstring(L, 2, " ", &char_len); 749 char c = trim_char[0]; 750 751 int start = 0; 752 while (start < (int)len && str[start] == c) { 753 start++; 754 } 755 756 int end = len; 757 while (end > start && str[end - 1] == c) { 758 end--; 759 } 760 761 lua_pushlstring(L, str + start, end - start); 762 return 1; 763 } 764 765 /* string.charAt(s, i) - fast single character access, returns single-char string */ 766 static int lua_string_charat(lua_State* L) { 767 size_t len; 768 const char* s = luaL_checklstring(L, 1, &len); 769 int pos = luaL_checkint(L, 2); 770 771 /* Lua uses 1-based indexing */ 772 if (pos < 0) pos = len + pos + 1; 773 774 /* Check bounds */ 775 if (pos < 1 || pos > (int)len) { 776 lua_pushlstring(L, "", 0); /* Return empty string for out of bounds */ 777 return 1; 778 } 779 780 /* Allocate a buffer and copy the character - don't use pointer into Lua string! */ 781 char* buffer = (char*)malloc(1); 782 if (!buffer) { 783 lua_pushstring(L, "out of memory"); 784 lua_error(L); 785 return 0; 786 } 787 788 buffer[0] = s[pos - 1]; 789 lua_pushlstring(L, buffer, 1); 790 free(buffer); 791 792 return 1; 793 } 794 795 /* string.byte(s, i, j) - returns byte values */ 796 static int lua_string_byte(lua_State* L) { 797 size_t len; 798 const char* s = luaL_checklstring(L, 1, &len); 799 int start = luaL_optint(L, 2, 1); 800 int end = luaL_optint(L, 3, start); 801 802 /* Lua uses 1-based indexing */ 803 if (start < 0) start = len + start + 1; 804 if (end < 0) end = len + end + 1; 805 if (start < 1) start = 1; 806 if (end > (int)len) end = len; 807 808 if (start > end) return 0; /* Empty range */ 809 810 int n = end - start + 1; 811 if (n > (int)(len - start + 1)) n = len - start + 1; 812 813 /* Push each byte value */ 814 for (int i = 0; i < n; i++) { 815 lua_pushinteger(L, (unsigned char)s[start - 1 + i]); 816 } 817 818 return n; /* Return number of values pushed */ 819 } 820 821 /* string.char(...) - converts byte values to string */ 822 static int __attribute__((cdecl)) lua_string_char(lua_State* L) { 823 int n = lua_gettop(L); /* Number of arguments */ 824 825 if (n == 0) { 826 lua_pushlstring(L, "", 0); 827 return 1; 828 } 829 830 char* buffer = malloc(n + 1); 831 if (!buffer) { 832 lua_pushstring(L, "out of memory"); 833 lua_error(L); 834 return 0; 835 } 836 837 for (int i = 0; i < n; i++) { 838 int c = luaL_checkint(L, i + 1); 839 if (c < 0 || c > 255) { 840 free(buffer); 841 lua_pushstring(L, "invalid byte value"); 842 lua_error(L); 843 return 0; 844 } 845 buffer[i] = (char)c; 846 } 847 848 lua_pushlstring(L, buffer, n); 849 free(buffer); 850 return 1; 851 } 852 853 /* string.dump(function) - serialize function to bytecode */ 854 static int lua_string_dump(lua_State* L) { 855 luaL_checktype(L, 1, LUA_TFUNCTION); 856 lua_settop(L, 1); 857 858 /* Use lua_dump to serialize the function */ 859 /* Note: We'd need a writer function for this, but for now return an error */ 860 lua_pushstring(L, "string.dump not fully implemented in bare metal mode"); 861 lua_error(L); 862 return 0; 863 } 864 865 /* debug_funcaddr(func) - print the address of a function (for debugging) */ 866 static int lua_debug_funcaddr(lua_State* L) { 867 if (lua_iscfunction(L, 1)) { 868 lua_CFunction f = lua_tocfunction(L, 1); 869 char buffer[64]; 870 /* Print address in hex */ 871 char* p = buffer; 872 uintptr_t addr = (uintptr_t)f; 873 874 *p++ = '0'; 875 *p++ = 'x'; 876 877 for (int i = 28; i >= 0; i -= 4) { 878 int digit = (addr >> i) & 0xF; 879 *p++ = digit < 10 ? '0' + digit : 'a' + digit - 10; 880 } 881 *p = '\0'; 882 883 lua_pushstring(L, buffer); 884 return 1; 885 } else if (lua_isfunction(L, 1)) { 886 lua_pushstring(L, "<lua function>"); 887 return 1; 888 } else { 889 lua_pushstring(L, "<not a function>"); 890 return 1; 891 } 892 } 893 894 /* string.reverse(s) - reverses a string */ 895 static int lua_string_reverse(lua_State* L) { 896 size_t len; 897 const char* s = luaL_checklstring(L, 1, &len); 898 899 char* buffer = malloc(len); 900 if (!buffer) { 901 lua_pushstring(L, "out of memory"); 902 lua_error(L); 903 return 0; 904 } 905 906 for (size_t i = 0; i < len; i++) { 907 buffer[i] = s[len - 1 - i]; 908 } 909 910 lua_pushlstring(L, buffer, len); 911 free(buffer); 912 return 1; 913 } 914 915 /* string.lower(s) - converts to lowercase */ 916 static int lua_string_lower(lua_State* L) { 917 size_t len; 918 const char* s = luaL_checklstring(L, 1, &len); 919 920 char* buffer = malloc(len); 921 if (!buffer) { 922 lua_pushstring(L, "out of memory"); 923 lua_error(L); 924 return 0; 925 } 926 927 for (size_t i = 0; i < len; i++) { 928 buffer[i] = tolower((unsigned char)s[i]); 929 } 930 931 lua_pushlstring(L, buffer, len); 932 free(buffer); 933 return 1; 934 } 935 936 /* string.upper(s) - converts to uppercase */ 937 static int lua_string_upper(lua_State* L) { 938 size_t len; 939 const char* s = luaL_checklstring(L, 1, &len); 940 941 char* buffer = malloc(len); 942 if (!buffer) { 943 lua_pushstring(L, "out of memory"); 944 lua_error(L); 945 return 0; 946 } 947 948 for (size_t i = 0; i < len; i++) { 949 buffer[i] = toupper((unsigned char)s[i]); 950 } 951 952 lua_pushlstring(L, buffer, len); 953 free(buffer); 954 return 1; 955 } 956 957 /* CompileString(code, [name]) - compiles Lua code and returns a function or nil, error */ 958 static int lua_compilestring(lua_State* L) { 959 const char* code = luaL_checkstring(L, 1); 960 const char* name = luaL_optstring(L, 2, "compiled"); 961 962 if (luaL_loadstring(L, code) != 0) { 963 /* Return nil, error_message */ 964 lua_pushnil(L); 965 lua_insert(L, -2); 966 return 2; 967 } 968 969 /* Return compiled function */ 970 return 1; 971 } 972 973 /* RunString(code, [name]) - compiles and executes Lua code, returns success status */ 974 static int lua_runstring(lua_State* L) { 975 const char* code = luaL_checkstring(L, 1); 976 const char* name = luaL_optstring(L, 2, "runstring"); 977 978 if (luaL_loadstring(L, code) != 0) { 979 /* Pop error message and return false */ 980 lua_pop(L, 1); 981 lua_pushboolean(L, 0); 982 return 1; 983 } 984 985 if (lua_pcall(L, 0, 0, 0) != 0) { 986 /* Pop error message and return false */ 987 lua_pop(L, 1); 988 lua_pushboolean(L, 0); 989 return 1; 990 } 991 992 /* Return true on success */ 993 lua_pushboolean(L, 1); 994 return 1; 995 } 996 997 /* Embedded packed ramdisk */ 998 extern char _binary_packed_bin_start[]; 999 extern char _binary_packed_bin_end[]; 1000 1001 /* Debug message for inline asm */ 1002 static const char msg_returned[] = "INLINE ASM: returned from lua_newstate\n"; 1003 1004 /* Convert unsigned int to string */ 1005 static void uint_to_str(uint32_t num, char* str) { 1006 if (num == 0) { 1007 str[0] = '0'; 1008 str[1] = '\0'; 1009 return; 1010 } 1011 1012 char temp[16]; 1013 int i = 0; 1014 1015 while (num > 0) { 1016 temp[i++] = '0' + (num % 10); 1017 num /= 10; 1018 } 1019 1020 /* Reverse */ 1021 for (int j = 0; j < i; j++) { 1022 str[j] = temp[i - 1 - j]; 1023 } 1024 str[i] = '\0'; 1025 } 1026 1027 /* User mode entry point - this runs in ring 3 */ 1028 __attribute__((naked)) void usermode_main(void) { 1029 /* Ensure stack is 16-byte aligned for proper function calls */ 1030 /* Using naked attribute since we're manually managing the stack frame */ 1031 __asm__ volatile ( 1032 "and $-16, %%esp\n" 1033 "sub $12, %%esp\n" 1034 "push %%ebp\n" 1035 "mov %%esp, %%ebp\n" 1036 ::: "memory" 1037 ); 1038 1039 /* Set up user mode data segments */ 1040 __asm__ volatile ( 1041 "mov $0x23, %%ax\n" 1042 "mov %%ax, %%ds\n" 1043 "mov %%ax, %%es\n" 1044 "mov %%ax, %%fs\n" 1045 "mov %%ax, %%gs\n" 1046 : : : "ax" 1047 ); 1048 1049 /* Enable SSE/SSE2 instructions - REQUIRED for LuaJIT */ 1050 /* Enable FPU by clearing CR0.EM (bit 2) and setting CR0.MP (bit 1) */ 1051 __asm__ volatile ( 1052 "mov %%cr0, %%eax\n" 1053 "and $0xFFFFFFFB, %%eax\n" /* Clear EM bit (bit 2) */ 1054 "or $0x00000002, %%eax\n" /* Set MP bit (bit 1) */ 1055 "mov %%eax, %%cr0\n" 1056 : : : "eax" 1057 ); 1058 1059 /* Enable SSE by setting CR4.OSFXSR (bit 9) and CR4.OSXMMEXCPT (bit 10) */ 1060 __asm__ volatile ( 1061 "mov %%cr4, %%eax\n" 1062 "or $0x00000600, %%eax\n" /* Set bits 9 and 10 */ 1063 "mov %%eax, %%cr4\n" 1064 : : : "eax" 1065 ); 1066 1067 /* Create Lua state */ 1068 lua_State* L = lua_newstate(lua_allocator, NULL); 1069 1070 if (!L) { 1071 terminal_writestring("ERROR: Failed to create Lua state\n"); 1072 while(1) __asm__ volatile ("hlt"); 1073 } 1074 1075 /* Load standard libraries */ 1076 luaL_openlibs(L); 1077 1078 /* Disable JIT compiler - run in interpreter mode only */ 1079 lua_getglobal(L, "jit"); 1080 if (lua_istable(L, -1)) { 1081 lua_getfield(L, -1, "off"); 1082 if (lua_isfunction(L, -1)) { 1083 lua_call(L, 0, 0); 1084 } else { 1085 lua_pop(L, 1); 1086 } 1087 lua_pop(L, 1); 1088 } else { 1089 lua_pop(L, 1); 1090 } 1091 1092 /* Register core functions */ 1093 lua_pushcfunction(L, lua_osprint); 1094 lua_setglobal(L, "osprint"); 1095 1096 lua_pushcfunction(L, lua_runstring); 1097 lua_setglobal(L, "RunString"); 1098 1099 /* Register graphics functions */ 1100 lua_pushcfunction(L, lua_enter_graphics_mode); 1101 lua_setglobal(L, "EnterGraphicsMode"); 1102 1103 lua_pushcfunction(L, lua_exit_graphics_mode); 1104 lua_setglobal(L, "ExitGraphicsMode"); 1105 1106 lua_pushcfunction(L, lua_set_pixel); 1107 lua_setglobal(L, "SetPixel"); 1108 1109 lua_pushcfunction(L, lua_draw_rect); 1110 lua_setglobal(L, "DrawRect"); 1111 1112 lua_pushcfunction(L, lua_clear_screen); 1113 lua_setglobal(L, "ClearScreen"); 1114 1115 lua_pushcfunction(L, lua_process_buffered_draw_ops); 1116 lua_setglobal(L, "ProcessBufferedDrawOps"); 1117 1118 /* Register VESA functions */ 1119 lua_pushcfunction(L, lua_vesa_init); 1120 lua_setglobal(L, "VESAInit"); 1121 1122 lua_pushcfunction(L, lua_vesa_set_mode); 1123 lua_setglobal(L, "VESASetMode"); 1124 1125 lua_pushcfunction(L, lua_vesa_get_mode_info); 1126 lua_setglobal(L, "VESAGetModeInfo"); 1127 1128 lua_pushcfunction(L, lua_vesa_list_modes); 1129 lua_setglobal(L, "VESAListModes"); 1130 1131 lua_pushcfunction(L, lua_vesa_set_pixel); 1132 lua_setglobal(L, "VESASetPixel"); 1133 1134 lua_pushcfunction(L, lua_vesa_draw_rect); 1135 lua_setglobal(L, "VESADrawRect"); 1136 1137 lua_pushcfunction(L, lua_vesa_clear_screen); 1138 lua_setglobal(L, "VESAClearScreen"); 1139 1140 lua_pushcfunction(L, lua_vesa_process_buffered_draw_ops); 1141 lua_setglobal(L, "VESAProcessBufferedDrawOps"); 1142 1143 /* Register image decoder functions */ 1144 lua_pushcfunction(L, lua_bmp_load); 1145 lua_setglobal(L, "BMPLoad"); 1146 terminal_writestring("Registered BMPLoad function\n"); 1147 1148 /* Verify BMPLoad is in global */ 1149 lua_getglobal(L, "BMPLoad"); 1150 if (lua_isfunction(L, -1)) { 1151 terminal_writestring("BMPLoad verification: SUCCESS\n"); 1152 } else { 1153 terminal_writestring("BMPLoad verification: FAILED\n"); 1154 } 1155 lua_pop(L, 1); 1156 1157 /* lua_bmp_save and lua_png_save are commented out in decoder files */ 1158 // lua_pushcfunction(L, lua_bmp_save); 1159 // lua_setglobal(L, "BMPSave"); 1160 1161 lua_pushcfunction(L, lua_png_load); 1162 lua_setglobal(L, "PNGLoad"); 1163 1164 lua_pushcfunction(L, lua_jpeg_load); 1165 lua_setglobal(L, "JPEGLoad"); 1166 terminal_writestring("Registered JPEGLoad function\n"); 1167 1168 /* Verify JPEGLoad is in global */ 1169 lua_getglobal(L, "JPEGLoad"); 1170 if (lua_isfunction(L, -1)) { 1171 terminal_writestring("JPEGLoad verification: SUCCESS\n"); 1172 } else { 1173 terminal_writestring("JPEGLoad verification: FAILED\n"); 1174 } 1175 lua_pop(L, 1); 1176 1177 // lua_pushcfunction(L, lua_png_save); 1178 // lua_setglobal(L, "PNGSave"); 1179 1180 lua_pushcfunction(L, lua_image_draw); 1181 lua_setglobal(L, "ImageDraw"); 1182 1183 lua_pushcfunction(L, lua_image_draw_scaled); 1184 lua_setglobal(L, "ImageDrawScaled"); 1185 1186 lua_pushcfunction(L, lua_image_get_info); 1187 lua_setglobal(L, "ImageGetInfo"); 1188 1189 lua_pushcfunction(L, lua_image_destroy); 1190 lua_setglobal(L, "ImageDestroy"); 1191 1192 lua_pushcfunction(L, lua_image_rotate); 1193 lua_setglobal(L, "ImageRotate"); 1194 1195 lua_pushcfunction(L, lua_image_get_width); 1196 lua_setglobal(L, "ImageGetWidth"); 1197 1198 lua_pushcfunction(L, lua_image_get_height); 1199 lua_setglobal(L, "ImageGetHeight"); 1200 1201 lua_pushcfunction(L, lua_image_get_pixel); 1202 lua_setglobal(L, "ImageGetPixel"); 1203 1204 extern int lua_image_get_buffer_bgra(lua_State* L); 1205 lua_pushcfunction(L, lua_image_get_buffer_bgra); 1206 lua_setglobal(L, "ImageGetBufferBGRA"); 1207 1208 /* Register compression functions */ 1209 lua_pushcfunction(L, lua_deflate_compress); 1210 lua_setglobal(L, "DeflateCompress"); 1211 1212 lua_pushcfunction(L, lua_deflate_decompress); 1213 lua_setglobal(L, "DeflateDecompress"); 1214 1215 lua_pushcfunction(L, lua_lzma_compress); 1216 lua_setglobal(L, "LZMACompress"); 1217 1218 lua_pushcfunction(L, lua_lzma_decompress); 1219 lua_setglobal(L, "LZMADecompress"); 1220 1221 lua_pushcfunction(L, lua_gzip_compress); 1222 lua_setglobal(L, "GZipCompress"); 1223 1224 lua_pushcfunction(L, lua_gzip_decompress); 1225 lua_setglobal(L, "GZipDecompress"); 1226 1227 lua_pushcfunction(L, lua_adler32); 1228 lua_setglobal(L, "Adler32"); 1229 1230 lua_pushcfunction(L, lua_crc32); 1231 lua_setglobal(L, "CRC32"); 1232 1233 /* Register C ramdisk functions */ 1234 lua_pushcfunction(L, lua_ramdisk_create); 1235 lua_setglobal(L, "CRamdiskCreate"); 1236 1237 lua_pushcfunction(L, lua_ramdisk_open); 1238 lua_setglobal(L, "CRamdiskOpen"); 1239 1240 lua_pushcfunction(L, lua_ramdisk_read); 1241 lua_setglobal(L, "CRamdiskRead"); 1242 1243 lua_pushcfunction(L, lua_ramdisk_write); 1244 lua_setglobal(L, "CRamdiskWrite"); 1245 1246 lua_pushcfunction(L, lua_ramdisk_close); 1247 lua_setglobal(L, "CRamdiskClose"); 1248 1249 lua_pushcfunction(L, lua_ramdisk_seek); 1250 lua_setglobal(L, "CRamdiskSeek"); 1251 1252 lua_pushcfunction(L, lua_ramdisk_mkdir); 1253 lua_setglobal(L, "CRamdiskMkdir"); 1254 1255 lua_pushcfunction(L, lua_ramdisk_exists); 1256 lua_setglobal(L, "CRamdiskExists"); 1257 1258 lua_pushcfunction(L, lua_ramdisk_list); 1259 lua_setglobal(L, "CRamdiskList"); 1260 1261 lua_pushcfunction(L, lua_ramdisk_remove); 1262 lua_setglobal(L, "CRamdiskRemove"); 1263 1264 lua_pushcfunction(L, lua_ramdisk_find); 1265 lua_setglobal(L, "CRamdiskFind"); 1266 1267 /* Initialize C ramdisk and load packed data */ 1268 terminal_writestring("Loading C ramdisk from packed data...\n"); 1269 c_ramdisk_root = ramdisk_create_root(); 1270 if (!c_ramdisk_root) { 1271 terminal_writestring("ERROR: Failed to create C ramdisk root\n"); 1272 lua_close(L); 1273 while(1) __asm__ volatile ("hlt"); 1274 } 1275 1276 /* Load packed ramdisk data */ 1277 size_t packed_size = _binary_packed_bin_end - _binary_packed_bin_start; 1278 terminal_writestring("Packed ramdisk size: "); 1279 char size_str[16]; 1280 uint_to_str(packed_size, size_str); 1281 terminal_writestring(size_str); 1282 terminal_writestring(" bytes\n"); 1283 1284 int entries_loaded = ramdisk_load_packed(c_ramdisk_root, (uint8_t*)_binary_packed_bin_start, packed_size); 1285 if (entries_loaded < 0) { 1286 terminal_writestring("ERROR: Failed to load packed ramdisk\n"); 1287 lua_close(L); 1288 while(1) __asm__ volatile ("hlt"); 1289 } 1290 1291 terminal_writestring("Loaded "); 1292 uint_to_str(entries_loaded, size_str); 1293 terminal_writestring(size_str); 1294 terminal_writestring(" entries from packed ramdisk\n"); 1295 1296 /* Expose C ramdisk root to Lua */ 1297 lua_pushlightuserdata(L, c_ramdisk_root); 1298 lua_setglobal(L, "c_ramdisk_root"); 1299 1300 /* NOTE: init.lua is now loaded from ramdisk in kernel.c, not embedded */ 1301 /* This code is kept for reference but commented out */ 1302 /* 1303 size_t script_size = _binary_build_init_with_ramdisk_lua_end - _binary_build_init_with_ramdisk_lua_start; 1304 1305 if (luaL_loadbuffer(L, _binary_build_init_with_ramdisk_lua_start, script_size, "init.lua") != 0) { 1306 terminal_writestring("ERROR: Failed to load init.lua: "); 1307 terminal_writestring(lua_tostring(L, -1)); 1308 terminal_writestring("\n"); 1309 lua_close(L); 1310 while(1) __asm__ volatile ("hlt"); 1311 } 1312 1313 int result = lua_pcall(L, 0, 0, 0); 1314 1315 if (result != 0) { 1316 terminal_writestring("ERROR: Failed to execute init.lua: "); 1317 const char* err = lua_tostring(L, -1); 1318 if (err) { 1319 terminal_writestring(err); 1320 } else { 1321 terminal_writestring("(no error message)"); 1322 } 1323 terminal_writestring("\n"); 1324 lua_close(L); 1325 while(1) __asm__ volatile ("hlt"); 1326 } 1327 */ 1328 1329 /* Sleep for 10 seconds after running init.lua */ 1330 unsigned long long start, end; 1331 __asm__ volatile ("rdtsc" : "=A"(start)); 1332 do { 1333 __asm__ volatile ("rdtsc" : "=A"(end)); 1334 } while ((end - start) < 20000000000ULL); /* ~10 seconds at 2GHz CPU */ 1335 1336 terminal_writestring("System halted\n"); 1337 lua_close(L); 1338 1339 while(1) __asm__ volatile ("hlt"); 1340 }