Compare commits

...

28 Commits

Author SHA1 Message Date
f6b4039348 Add dynamic heap size allocation 2025-12-04 20:59:26 +01:00
8761d6867c Add dev env setup 2025-12-04 20:55:27 +01:00
Martin Petr
f2b5e17856 Merge pull request #1 from MartinGamesCZ/dev-efi-port
Switch to EFI version
2025-12-04 19:07:03 +01:00
c289ac6f38 Add readme and license 2025-12-04 19:04:29 +01:00
868b5700cd Remove unused lib 2025-12-04 17:11:24 +01:00
092781ba57 Extend PCI driver 2025-12-03 21:31:39 +01:00
7defc557b2 Add PCI driver 2025-12-03 21:17:23 +01:00
e4b18fc8d7 Implement sysfs 2025-12-03 20:41:52 +01:00
19e034a982 Add console module 2025-12-03 20:05:06 +01:00
4b4c3022eb Change entrypoint function 2025-12-03 18:56:16 +01:00
e3dce14c64 Add TS code embedding 2025-12-03 18:32:35 +01:00
35b16bfc49 Add basic print program 2025-12-02 22:38:22 +01:00
3f0b94d2fc Add failed try 2025-12-02 19:17:05 +01:00
f483a34d3c Add PCI driver 2025-11-30 10:47:59 +01:00
af5d8c709b Add typescript kernel loader 2025-11-29 23:14:51 +01:00
b7f619b8c3 Remove gitea action 2025-11-29 22:31:30 +01:00
12c109a120 Add gitea build action
Some checks failed
Build ISO and Upload Artifact / build-and-upload (push) Failing after 27s
2025-11-29 20:06:04 +01:00
c222cae16f Make EFI port primary 2025-11-29 20:00:51 +01:00
e2184bdc27 Somewhat working 2025-11-29 13:34:21 +01:00
5b8804621c Add source 2025-11-28 22:50:05 +01:00
aea99102cc Start EFI port 2025-11-28 22:42:14 +01:00
1775af99b0 Add process manager 2025-11-23 18:52:51 +01:00
6f303bf656 Implement system env and app resolver 2025-11-23 11:54:05 +01:00
4bf79e358a Add shell and echo app 2025-11-22 23:43:42 +01:00
29a5cacdea Add app launcher and oskrnl 2025-11-22 22:22:28 +01:00
34fc6e8d3a Update readme 2025-11-22 20:24:43 +01:00
304dda0adf Add disk driver 2025-11-21 22:57:51 +01:00
18092face9 Add interrupts and keyboard driver 2025-11-20 21:13:50 +01:00
93 changed files with 2556 additions and 1374 deletions

11
.gitignore vendored
View File

@@ -1,5 +1,6 @@
_o/
build/
picolibc/
picolibc-install/
/lib/
old/
out/
node_modules/
*.iso
*.img
.clangd

View File

@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
SOFTWARE.

View File

@@ -2,7 +2,7 @@
## What the hell is this?
Lints is an experimental operating system kernel written almost entirely in TypeScript. This is not some in-browser system emulator or WebAssembly hack; Lints actually runs on real hardware (or a hardware emulator like QEMU) by leveraging a JavaScript engine with a small C kernel (just some basic memory management needed by the JS engine) and JS-to-C bindings for purposes like writting data to pointers, etc.
Lints is an experimental operating system kernel written almost entirely in TypeScript. This is not some in-browser system emulator or WebAssembly hack; Lints actually runs on real hardware (or a virtual machine) by leveraging a JavaScript engine with a small C kernel (just some basic memory management needed by the JS engine) and JS-to-C bindings for purposes like writting data to pointers, etc.
## Why?
@@ -16,10 +16,30 @@ Lints is an experimental operating system kernel written almost entirely in Type
Please don't.
If you really want to, make sure you have Docker installed, then run:
If you really want to, make sure you have VirtualBox and Bun installed, then run:
```bash
./scripts/run-kernel.sh
bun install
```
To run in VirtualBox:
```bash
st run vbox
```
To get bootable ISO:
```bash
st run build
```
The built ISO can be found in `out/` directory.
## How to setup development environment?
```bash
./src/scripts/setup_dev.sh
```
## If you are an employer looking at this...

17
bun.lock Normal file
View File

@@ -0,0 +1,17 @@
{
"lockfileVersion": 1,
"workspaces": {
"": {
"dependencies": {
"sailet": "^0.1.1",
},
},
},
"packages": {
"chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
"sailet": ["sailet@0.1.1", "", { "dependencies": { "chalk": "^5.6.2" }, "peerDependencies": { "typescript": "^5" }, "bin": { "sailet": "dist/cli/index.js", "st": "dist/cli/index.js" } }, "sha512-zKcCvANgxqB2YY/XbLtgLomHJvOvcYHDg0qpZ831XxORUm45oVFNWeBItaZzxFGZDfoXNXr6VqzDuRIoukMXaA=="],
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
}
}

View File

@@ -1,21 +0,0 @@
FROM fedora:41
RUN dnf install -y \
gcc \
gcc-c++ \
make \
nasm \
python3 \
git \
qemu-system-x86 \
wget \
meson \
unzip \
&& dnf clean all
RUN curl -fsSL https://bun.sh/install | bash
ENV PATH="/root/.bun/bin:${PATH}"
WORKDIR /workspace
CMD ["bash", "-c", "/workspace/scripts/build-picolibc.sh && /workspace/scripts/build-kernel.sh"]

5
package.json Normal file
View File

@@ -0,0 +1,5 @@
{
"dependencies": {
"sailet": "^0.1.1"
}
}

View File

@@ -1,18 +0,0 @@
# Meson cross-compilation file for i686-elf with picolibc
[binaries]
c = 'gcc'
ar = 'ar'
as = 'as'
ld = 'ld'
strip = 'strip'
[host_machine]
system = 'none'
cpu_family = 'x86'
cpu = 'i686'
endian = 'little'
[properties]
c_args = ['-m32', '-march=i686']
c_link_args = ['-m32']
skip_sanity_check = true

18
sailet.config.ts Normal file
View File

@@ -0,0 +1,18 @@
// sailet.config.ts
import { script, step, cmd, $ } from "sailet";
script("build", () => [
step("Prepare", () => [cmd($`./src/scripts/prepare_build.sh`)]),
step("Build EFI", () => [
cmd($`./src/scripts/build_system.sh`),
cmd($`./src/scripts/embed_system.sh`),
cmd($`./src/scripts/build_core.sh`),
]),
step("Build ISO", () => [cmd($`./src/scripts/build_iso.sh`)]),
]);
script("vbox", () => [
step("Build", () => [cmd($`st run build`)]),
step("Run", () => [cmd($`./src/scripts/run_vbox.sh`)]),
]);

View File

@@ -1,85 +0,0 @@
#!/bin/bash
# Build and run kernel with picolibc
set -e
mkdir -p lib
./scripts/get_duktape.sh
# Paths
PICOLIBC_INSTALL="$(pwd)/picolibc-install"
BUILD_DIR="build"
OUT_DIR="$BUILD_DIR/out"
# Check if picolibc is installed
if [ ! -d "$PICOLIBC_INSTALL" ]; then
echo "Error: Picolibc not found at $PICOLIBC_INSTALL"
echo "Please run: make picolibc"
exit 1
fi
# Create build directories
mkdir -p "$BUILD_DIR"
mkdir -p "$OUT_DIR"
# Build TypeScript to JavaScript
cd src/os
echo "Compiling TypeScript to JavaScript..."
bun build --outdir ../../build --target node --bundle src/index.ts
cd ../../
# Generate embedded JavaScript header
echo "Generating embedded JavaScript..."
bun scripts/build_js.js
python3 scripts/embed_js.py build/index.js > "$BUILD_DIR/embedded_js.h"
# Compiler flags
CFLAGS="-m32 -march=i686 -ffreestanding -nostdlib -fno-builtin"
CFLAGS="$CFLAGS -I$PICOLIBC_INSTALL/include"
CFLAGS="$CFLAGS -I./lib/duktape/src"
CFLAGS="$CFLAGS -I./src/lib"
CFLAGS="$CFLAGS -I./src"
CFLAGS="$CFLAGS -I$BUILD_DIR"
CFLAGS="$CFLAGS -Wall -Wextra"
LDFLAGS="-m elf_i386 -nostdlib"
LDFLAGS="$LDFLAGS -L$PICOLIBC_INSTALL/lib"
# Get libgcc path
LIBGCC=$(gcc -m32 -print-libgcc-file-name)
echo "=== Building kernel with picolibc ==="
# Build boot assembly
echo "Assembling boot code..."
nasm -f elf32 src/boot/kernel.asm -o "$BUILD_DIR/kasm.o"
# Build duktape
echo "Building Duktape..."
gcc $CFLAGS -c lib/duktape/src/duktape.c -o "$BUILD_DIR/duktape.o"
# Build kernel
echo "Building kernel..."
gcc $CFLAGS -c src/kernel/kernel.c -o "$BUILD_DIR/kc.o"
# Build syscalls
echo "Building syscalls..."
gcc $CFLAGS -c src/lib/syscalls.c -o "$BUILD_DIR/syscalls.o"
# Link everything together
echo "Linking kernel..."
ld $LDFLAGS -T src/link.ld -o "$OUT_DIR/kernel" \
"$BUILD_DIR/kasm.o" \
"$BUILD_DIR/kc.o" \
"$BUILD_DIR/duktape.o" \
"$BUILD_DIR/syscalls.o" \
-lc "$LIBGCC"
echo ""
echo "=== Build complete! ==="
echo ""
echo "Running kernel in QEMU..."
echo "(Press Ctrl+A then X to exit)"
echo ""

View File

@@ -1,55 +0,0 @@
#!/bin/bash
# Script to build picolibc for i686 freestanding environment
set -e
PICOLIBC_DIR="picolibc"
BUILD_DIR="build/picolibc"
INSTALL_DIR="$(pwd)/picolibc-install"
echo "=== Building Picolibc for i686 freestanding ==="
# Check if picolibc exists
if [ ! -d "$PICOLIBC_DIR" ]; then
echo "Error: Picolibc source not found at $PICOLIBC_DIR"
echo "Cloning..."
git clone --branch 1.8.10 https://github.com/picolibc/picolibc.git "$PICOLIBC_DIR"
fi
# Get current version
cd "$PICOLIBC_DIR"
CURRENT_VERSION=$(git describe --tags 2>/dev/null || echo "unknown")
echo "Using picolibc version: $CURRENT_VERSION"
cd ..
# Create build directory
mkdir -p "$BUILD_DIR"
echo "Configuring picolibc with meson..."
meson setup "$BUILD_DIR" "$PICOLIBC_DIR" \
--cross-file picolibc-i686.txt \
--prefix="$INSTALL_DIR" \
--wipe \
-Dmultilib=false \
-Dpicocrt=false \
-Dsemihost=false \
-Dspecsdir=none \
-Dtinystdio=true \
-Dio-long-long=true \
-Dformat-default=double \
-Dtests=false
echo "Building picolibc..."
meson compile -C "$BUILD_DIR"
echo "Installing picolibc..."
meson install -C "$BUILD_DIR"
echo ""
echo "=== Picolibc build complete! ==="
echo "Installation directory: $INSTALL_DIR"
echo ""
echo "To use picolibc in your kernel:"
echo " Include path: -I$INSTALL_DIR/include"
echo " Library path: -L$INSTALL_DIR/lib"
echo " Link with: -lc"

View File

@@ -1,2 +0,0 @@
docker build -t lints-dev -f docker/Dockerfile .
docker run -it --rm -v "$(pwd)":/workspace -w /workspace lints-dev

View File

@@ -1,11 +0,0 @@
#! /usr/bin/env bun
import { readFileSync, writeFileSync } from "fs";
writeFileSync(
"build/index.js",
readFileSync("build/index.js", "utf-8")
.replaceAll("let ", "var ")
.replaceAll("const ", "var ")
.replaceAll("\n`", "\\n`")
.replaceAll("`", "'")
);

View File

@@ -1,58 +0,0 @@
#!/usr/bin/env python3
"""
Embed JavaScript file as a C string constant
"""
import sys
def escape_c_string(s):
"""Escape a string for use in C source code"""
result = []
for char in s:
if char == "\n":
result.append("\\n")
elif char == "\r":
result.append("\\r")
elif char == "\t":
result.append("\\t")
elif char == "\\":
result.append("\\\\")
elif char == '"':
result.append('\\"')
elif ord(char) < 32 or ord(char) > 126:
result.append(f"\\x{ord(char):02x}")
else:
result.append(char)
return "".join(result)
def main():
if len(sys.argv) != 2:
print("Usage: embed_js.py <input.js>", file=sys.stderr)
sys.exit(1)
input_file = sys.argv[1]
try:
with open(input_file, "r") as f:
js_code = f.read()
except FileNotFoundError:
print(f"Error: File not found: {input_file}", file=sys.stderr)
sys.exit(1)
# Generate C header file
print("/* Auto-generated file - do not edit */")
print("#ifndef EMBEDDED_JS_H")
print("#define EMBEDDED_JS_H")
print()
escaped = escape_c_string(js_code)
print(f'const char *embedded_js_code = "{escaped}";')
print()
print("#endif /* EMBEDDED_JS_H */")
if __name__ == "__main__":
main()

View File

@@ -1,28 +0,0 @@
#!/bin/bash
# Script to download Duktape library if not present
set -e
DUKTAPE_DIR="lib/duktape"
DUKTAPE_REPO="https://github.com/joeqread/arduino-duktape.git"
TEMP_DIR="lib/temp_duktape"
echo "=== Checking for Duktape library ==="
if [ -d "$DUKTAPE_DIR" ]; then
echo "Duktape already exists at $DUKTAPE_DIR"
else
echo "Duktape not found. Cloning from $DUKTAPE_REPO..."
git clone "$DUKTAPE_REPO" "$TEMP_DIR"
echo "Extracting src folder..."
mkdir -p "$DUKTAPE_DIR"
mv "$TEMP_DIR/src" "$DUKTAPE_DIR/"
echo "Cleaning up temporary directory..."
rm -rf "$TEMP_DIR"
echo "Duktape cloned successfully!"
fi
echo "Done."

View File

@@ -1,3 +0,0 @@
./scripts/build.sh
qemu-system-i386 -serial stdio -kernel "build/out/kernel"

View File

@@ -1,17 +0,0 @@
bits 32 ;nasm directive
section .text
;multiboot spec
align 4
dd 0x1BADB002 ;magic
dd 0x00 ;flags
dd - (0x1BADB002 + 0x00) ;checksum. m+f+c should be zero
global start
extern kmain ;kmain is defined in the kernel.c file
start:
cli ; stop interrupts
call kmain
hlt ; halt the CPU

9
src/core/compat/assert.h Normal file
View File

@@ -0,0 +1,9 @@
//---------------------------------------------------------------
//
// !!! AI GENERATE SLOP, PLEASE FIX !!!
//
//---------------------------------------------------------------
#pragma once
#define assert(x) ((void)0)
#define NDEBUG 1

0
src/core/compat/ctype.h Normal file
View File

0
src/core/compat/fenv.h Normal file
View File

View File

@@ -0,0 +1,27 @@
//---------------------------------------------------------------
//
// !!! AI GENERATE SLOP, PLEASE FIX !!!
//
//---------------------------------------------------------------
#ifndef _INTTYPES_H
#define _INTTYPES_H
#include <stdint.h>
#define PRId64 "lld"
#define PRIu64 "llu"
#define PRIx64 "llx"
#define PRIX64 "llX"
#define PRId32 "d"
#define PRIu32 "u"
#define PRIx32 "x"
#define PRIX32 "X"
#define PRIdPTR "ld"
#define PRIuPTR "lu"
#define PRIxPTR "lx"
#define PRIXPTR "lX"
#endif

195
src/core/compat/main.c Normal file
View File

@@ -0,0 +1,195 @@
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdarg.h>
#include "stdio.h"
#include "quickjs.h"
#define NULL ((void*)0)
// EFI definitions
typedef uint64_t EFI_STATUS;
typedef void* EFI_HANDLE;
#define EFI_SUCCESS 0
typedef struct {
uint64_t signature;
uint32_t revision;
uint32_t headerSize;
uint32_t crc32;
uint32_t reserved;
} EFI_TABLE_HEADER;
struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL;
typedef EFI_STATUS (*EFI_TEXT_STRING)(
struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
uint16_t *String
);
typedef EFI_STATUS (*EFI_TEXT_CLEAR_SCREEN)(
struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
);
typedef struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL {
void *reset;
EFI_TEXT_STRING OutputString;
void *testString;
void *queryMode;
void *setMode;
void *setAttribute;
EFI_TEXT_CLEAR_SCREEN ClearScreen;
void *setCursorPosition;
void *enableCursor;
void *mode;
} EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL;
typedef struct EFI_SYSTEM_TABLE {
EFI_TABLE_HEADER hdr;
uint16_t *firmwareVendor;
uint32_t firmwareRevision;
void *consoleInHandle;
void *conIn;
void *consoleOutHandle;
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
void *standardErrorHandle;
void *stdErr;
void *runtimeServices;
void *bootServices;
uint64_t numberOfTableEntries;
void *configurationTable;
} EFI_SYSTEM_TABLE;
static EFI_SYSTEM_TABLE *gST = NULL;
static void Print(uint16_t *str) {
if (gST && gST->ConOut)
gST->ConOut->OutputString(gST->ConOut, str);
}
static uint16_t *AsciiToUnicode(const char *ascii) {
static uint16_t buffer[1024];
int i;
for (i = 0; ascii[i] && i < 1023; i++) {
buffer[i] = (uint16_t)ascii[i];
}
buffer[i] = 0;
return buffer;
}
// stdio implementation
int printf(const char *format, ...) {
char buf[1024];
va_list ap;
va_start(ap, format);
int ret = vsnprintf(buf, sizeof(buf), format, ap);
va_end(ap);
Print(AsciiToUnicode(buf));
return ret;
}
int fprintf(FILE *stream, const char *format, ...) {
if (stream != stdout && stream != stderr) return 0;
char buf[1024];
va_list ap;
va_start(ap, format);
int ret = vsnprintf(buf, sizeof(buf), format, ap);
va_end(ap);
Print(AsciiToUnicode(buf));
return ret;
}
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) {
if (stream != stdout && stream != stderr) return 0;
const char *p = ptr;
size_t total = size * nmemb;
char buf[1025];
size_t i = 0;
while (i < total) {
size_t chunk = total - i;
if (chunk > 1024) chunk = 1024;
memcpy(buf, p + i, chunk);
buf[chunk] = 0;
Print(AsciiToUnicode(buf));
i += chunk;
}
return nmemb;
}
int fputc(int c, FILE *stream) {
if (stream != stdout && stream != stderr) return c;
char buf[2] = { (char)c, 0 };
Print(AsciiToUnicode(buf));
return c;
}
int putchar(int c) {
return fputc(c, stdout);
}
EFI_STATUS efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
(void)ImageHandle;
gST = SystemTable;
gST->ConOut->ClearScreen(gST->ConOut);
Print(L"UEFI QuickJS\r\n");
Print(L"============\r\n\r\n");
JSRuntime *rt = JS_NewRuntime();
if (!rt) {
Print(L"Failed to create runtime\r\n");
return EFI_SUCCESS;
}
JSContext *ctx = JS_NewContext(rt);
if (!ctx) {
Print(L"Failed to create context\r\n");
JS_FreeRuntime(rt);
return EFI_SUCCESS;
}
Print(L"QuickJS initialized!\r\n\r\n");
// Test Classes
const char *code =
"class Test { "
" constructor(val) { this.val = val; } "
" getVal() { return this.val; } "
"} "
"let t = new Test(42); "
"t.getVal();";
Print(L"Evaluating code...\r\n");
JSValue val = JS_Eval(ctx, code, strlen(code), "<input>", JS_EVAL_TYPE_GLOBAL);
if (JS_IsException(val)) {
JSValue ex = JS_GetException(ctx);
const char *str = JS_ToCString(ctx, ex);
if (str) {
printf("Exception: %s\n", str);
JS_FreeCString(ctx, str);
} else {
printf("Exception: [unknown]\n");
}
JS_FreeValue(ctx, ex);
} else {
const char *str = JS_ToCString(ctx, val);
if (str) {
printf("Result: %s\n", str);
JS_FreeCString(ctx, str);
} else {
printf("Result: [unknown]\n");
}
JS_FreeValue(ctx, val);
}
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
Print(L"\r\nSuccess!\r\n");
Print(L"\r\nPress Ctrl+C...\r\n");
for(;;);
return EFI_SUCCESS;
}

51
src/core/compat/math.h Normal file
View File

@@ -0,0 +1,51 @@
//---------------------------------------------------------------
//
// !!! AI GENERATE SLOP, PLEASE FIX !!!
//
//---------------------------------------------------------------
#ifndef _MATH_H
#define _MATH_H
#define NAN (__builtin_nan(""))
#define INFINITY (__builtin_inf())
#define signbit(x) __builtin_signbit(x)
double floor(double x);
double ceil(double x);
double fabs(double x);
double modf(double x, double *iptr);
double fmod(double x, double y);
double sqrt(double x);
double pow(double x, double y);
double log(double x);
double exp(double x);
double sin(double x);
double cos(double x);
double tan(double x);
int isnan(double x);
int isinf(double x);
int isfinite(double x);
double trunc(double x);
double fmin(double x, double y);
double fmax(double x, double y);
double hypot(double x, double y);
double acos(double x);
double asin(double x);
double atan(double x);
double atan2(double y, double x);
double cbrt(double x);
double cosh(double x);
double expm1(double x);
double log1p(double x);
double log2(double x);
double log10(double x);
double sinh(double x);
double tanh(double x);
double asinh(double x);
double acosh(double x);
double atanh(double x);
double round(double x);
long int lrint(double x);
#endif

768
src/core/compat/minilibc.c Normal file
View File

@@ -0,0 +1,768 @@
//---------------------------------------------------------------
//
// !!! AI GENERATE SLOP, PLEASE FIX !!!
//
//---------------------------------------------------------------
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
extern int printf(const char *format, ...);
// Basic libc stub implementations for Elk
// String functions
void *memset(void *s, int c, size_t n) {
unsigned char *p = s;
while (n--) *p++ = (unsigned char)c;
return s;
}
void *memcpy(void *dest, const void *src, size_t n) {
unsigned char *d = dest;
const unsigned char *s = src;
while (n--) *d++ = *s++;
return dest;
}
void *memmove(void *dest, const void *src, size_t n) {
unsigned char *d = dest;
const unsigned char *s = src;
if (d < s) {
while (n--) *d++ = *s++;
} else {
d += n;
s += n;
while (n--) *--d = *--s;
}
return dest;
}
int memcmp(const void *s1, const void *s2, size_t n) {
const unsigned char *p1 = s1, *p2 = s2;
while (n--) {
if (*p1 != *p2) return *p1 - *p2;
p1++;
p2++;
}
return 0;
}
size_t strlen(const char *s) {
size_t len = 0;
while (s[len]) len++;
return len;
}
int strcmp(const char *s1, const char *s2) {
while (*s1 && (*s1 == *s2)) {
s1++;
s2++;
}
return *(unsigned char *)s1 - *(unsigned char *)s2;
}
int strncmp(const char *s1, const char *s2, size_t n) {
while (n && *s1 && (*s1 == *s2)) {
s1++;
s2++;
n--;
}
if (n == 0) return 0;
return *(unsigned char *)s1 - *(unsigned char *)s2;
}
char *strcpy(char *dest, const char *src) {
char *d = dest;
while ((*d++ = *src++));
return dest;
}
char *strncpy(char *dest, const char *src, size_t n) {
size_t i;
for (i = 0; i < n && src[i]; i++)
dest[i] = src[i];
for (; i < n; i++)
dest[i] = '\0';
return dest;
}
// Math functions - basic implementations
double floor(double x) {
if (x >= 0) {
return (double)(int64_t)x;
} else {
int64_t i = (int64_t)x;
return (i == x) ? x : (double)(i - 1);
}
}
double ceil(double x) {
if (x >= 0) {
int64_t i = (int64_t)x;
return (i == x) ? x : (double)(i + 1);
} else {
return (double)(int64_t)x;
}
}
double fabs(double x) {
return x < 0 ? -x : x;
}
double modf(double x, double *iptr) {
*iptr = (double)(int64_t)x;
return x - *iptr;
}
double fmod(double x, double y) {
if (y == 0.0) return 0.0;
return x - floor(x / y) * y;
}
// Simple sqrt using Newton's method
double sqrt(double x) {
if (x < 0) return 0.0;
if (x == 0) return 0.0;
double guess = x / 2.0;
double prev;
int iterations = 10;
while (iterations--) {
prev = guess;
guess = (guess + x / guess) / 2.0;
if (fabs(guess - prev) < 0.0001) break;
}
return guess;
}
double pow(double x, double y) {
// Very basic pow - only handles integer exponents
if (y == 0.0) return 1.0;
if (y < 0.0) return 1.0 / pow(x, -y);
double result = 1.0;
int64_t exp = (int64_t)y;
while (exp--) result *= x;
return result;
}
double log(double x) {
// Simplified log (not accurate, just enough for Elk)
if (x <= 0) return 0.0;
return 0.0; // Stub
}
double exp(double x) {
// Simplified exp
(void)x;
return 1.0; // Stub
}
double sin(double x) {
(void)x;
return 0.0; // Stub
}
double cos(double x) {
(void)x;
return 1.0; // Stub
}
double tan(double x) {
(void)x;
return 0.0; // Stub
}
int isnan(double x) {
return x != x;
}
int isinf(double x) {
return x == __builtin_inf() || x == -__builtin_inf();
}
int isfinite(double x) {
return !isnan(x) && !isinf(x);
}
// Stdlib functions
double strtod(const char *str, char **endptr) {
double result = 0.0;
double sign = 1.0;
double scale = 0.1;
int decimal = 0;
while (*str == ' ' || *str == '\t') str++;
if (*str == '-') {
sign = -1.0;
str++;
} else if (*str == '+') {
str++;
}
while (*str) {
if (*str >= '0' && *str <= '9') {
if (decimal) {
result += (*str - '0') * scale;
scale *= 0.1;
} else {
result = result * 10.0 + (*str - '0');
}
} else if (*str == '.' && !decimal) {
decimal = 1;
} else {
break;
}
str++;
}
if (endptr) *endptr = (char *)str;
return result * sign;
}
long strtol(const char *str, char **endptr, int base) {
long result = 0;
int sign = 1;
while (*str == ' ') str++;
if (*str == '-') {
sign = -1;
str++;
}
while (*str >= '0' && *str <= '9') {
result = result * base + (*str - '0');
str++;
}
if (endptr) *endptr = (char *)str;
return result * sign;
}
// Dynamic heap - will be initialized based on available RAM
static unsigned char *heap = NULL;
static size_t heap_size = 0;
static size_t heap_pos = 0;
// Forward declare EFI types we need
typedef uint64_t EFI_STATUS;
typedef void* EFI_HANDLE;
typedef uint64_t UINT64;
typedef uint32_t UINT32;
typedef uintptr_t UINTN;
typedef struct {
UINT32 Type;
UINT64 PhysicalStart;
UINT64 VirtualStart;
UINT64 NumberOfPages;
UINT64 Attribute;
} EFI_MEMORY_DESCRIPTOR;
typedef struct EFI_BOOT_SERVICES_PARTIAL {
// EFI_TABLE_HEADER (24 bytes) + 5 pointers (RaiseTPL, RestoreTPL, AllocatePages, FreePages, GetMemoryMap)
char padding[64]; // 24 + 5*8 = 64 bytes to reach AllocatePool
EFI_STATUS (*AllocatePool)(UINT32 PoolType, UINTN Size, void **Buffer);
} EFI_BOOT_SERVICES_PARTIAL;
typedef struct {
char hdr[24]; // EFI_TABLE_HEADER
void *firmwareVendor;
UINT32 firmwareRevision;
void *consoleInHandle;
void *conIn;
void *consoleOutHandle;
void *ConOut;
void *standardErrorHandle;
void *stdErr;
void *runtimeServices;
EFI_BOOT_SERVICES_PARTIAL *BootServices;
} EFI_SYSTEM_TABLE_PARTIAL;
#define EfiConventionalMemory 7
// Initialize heap with maximum available memory
void init_heap(void *system_table) {
// Static fallback heap in case EFI allocation fails
static unsigned char static_heap[64 * 1024 * 1024]; // 64 MB fallback
EFI_SYSTEM_TABLE_PARTIAL *st = (EFI_SYSTEM_TABLE_PARTIAL*)system_table;
// Safety check
if (!st || !st->BootServices || !st->BootServices->AllocatePool) {
printf("WARNING: EFI Boot Services not available, using static heap\n");
heap = static_heap;
heap_size = sizeof(static_heap);
heap_pos = 0;
printf("Heap initialized: %zu MB (static fallback)\n", heap_size / (1024 * 1024));
return;
}
// Try to allocate a very large heap - start with 16 GB and work down if needed
size_t sizes[] = {
16ULL * 1024 * 1024 * 1024, // 16 GB
8ULL * 1024 * 1024 * 1024, // 8 GB
4ULL * 1024 * 1024 * 1024, // 4 GB
2ULL * 1024 * 1024 * 1024, // 2 GB
1ULL * 1024 * 1024 * 1024, // 1 GB
512ULL * 1024 * 1024, // 512 MB
256ULL * 1024 * 1024, // 256 MB
128ULL * 1024 * 1024, // 128 MB
64ULL * 1024 * 1024, // 64 MB
32ULL * 1024 * 1024, // 32 MB
16ULL * 1024 * 1024, // 16 MB
8ULL * 1024 * 1024 // 8 MB (fallback)
};
for (int i = 0; i < 12; i++) {
EFI_STATUS status = st->BootServices->AllocatePool(
EfiConventionalMemory,
sizes[i],
(void**)&heap
);
if (status == 0) { // EFI_SUCCESS
heap_size = sizes[i];
heap_pos = 0;
if (heap_size >= 1024ULL * 1024 * 1024) {
printf("Heap initialized: %zu GB (%zu bytes)\n",
heap_size / (1024ULL * 1024 * 1024), heap_size);
} else {
printf("Heap initialized: %zu MB (%zu bytes)\n",
heap_size / (1024 * 1024), heap_size);
}
return;
}
}
// If all EFI allocations failed, use static heap
printf("WARNING: EFI allocation failed, using static heap\n");
heap = static_heap;
heap_size = sizeof(static_heap);
heap_pos = 0;
printf("Heap initialized: %zu MB (static fallback)\n", heap_size / (1024 * 1024));
}
void *malloc(size_t size) {
if (!heap) {
printf("malloc failed: heap not initialized\n");
return (void*)0;
}
size = (size + 7) & ~7;
size_t total = size + 8;
if (heap_pos + total > heap_size) {
printf("malloc failed: OOM (requested %zu, available %zu)\n", total, heap_size - heap_pos);
return (void*)0;
}
*(size_t*)&heap[heap_pos] = size;
void *ptr = &heap[heap_pos + 8];
heap_pos += total;
return ptr;
}
void free(void *ptr) {
(void)ptr;
}
void *realloc(void *ptr, size_t size) {
if (!ptr) return malloc(size);
size_t *p_size = (size_t*)((char*)ptr - 8);
size_t old_size = *p_size;
if (size <= old_size) return ptr;
void *new_ptr = malloc(size);
if (!new_ptr) return (void*)0;
memcpy(new_ptr, ptr, old_size);
return new_ptr;
}
void *calloc(size_t nmemb, size_t size) {
size_t total = nmemb * size;
void *ptr = malloc(total);
if (ptr) memset(ptr, 0, total);
return ptr;
}
void abort(void) {
printf("ABORT called!\n");
while(1);
}
// stdio functions
int vsnprintf(char *str, size_t size, const char *format, __builtin_va_list ap) {
size_t i = 0;
const char *p = format;
while (*p && i < size - 1) {
if (*p != '%') {
str[i++] = *p++;
continue;
}
p++; // Skip '%'
// Parse flags, width, precision, length modifiers
int precision = -1;
// Flags (ignored for now)
while (*p == '-' || *p == '+' || *p == ' ' || *p == '#' || *p == '0') p++;
// Width
if (*p == '*') {
__builtin_va_arg(ap, int); // Consume width
p++;
} else {
while (*p >= '0' && *p <= '9') p++;
}
// Precision
if (*p == '.') {
p++;
if (*p == '*') {
precision = __builtin_va_arg(ap, int);
p++;
} else {
int val = 0;
while (*p >= '0' && *p <= '9') {
val = val * 10 + (*p - '0');
p++;
}
precision = val;
}
}
// Length modifiers (ignored)
while (*p == 'h' || *p == 'l' || *p == 'L' || *p == 'z' || *p == 't') p++;
if (*p == 'd' || *p == 'i') {
int val = __builtin_va_arg(ap, int);
char buf[32];
int pos = 0;
int neg = 0;
if (val < 0) { neg = 1; val = -val; }
if (val == 0) buf[pos++] = '0';
while (val) {
buf[pos++] = '0' + (val % 10);
val /= 10;
}
if (neg) buf[pos++] = '-';
while (pos > 0 && i < size - 1) str[i++] = buf[--pos];
} else if (*p == 'u') {
unsigned int val = __builtin_va_arg(ap, unsigned int);
char buf[32];
int pos = 0;
if (val == 0) buf[pos++] = '0';
while (val) {
buf[pos++] = '0' + (val % 10);
val /= 10;
}
while (pos > 0 && i < size - 1) str[i++] = buf[--pos];
} else if (*p == 's') {
const char *s = __builtin_va_arg(ap, const char *);
if (!s) s = "(null)";
size_t len = 0;
const char *tmp = s;
while (*tmp++) len++;
if (precision >= 0 && len > (size_t)precision) len = (size_t)precision;
size_t k = 0;
while (k < len && i < size - 1) str[i++] = s[k++];
} else if (*p == 'c') {
char c = (char)__builtin_va_arg(ap, int);
if (i < size - 1) str[i++] = c;
} else if (*p == 'g' || *p == 'f') {
// Basic double support
double val = __builtin_va_arg(ap, double);
int ival = (int)val;
// Print integer part
char buf[32];
int pos = 0;
int neg = 0;
if (val < 0) { neg = 1; val = -val; ival = -ival; }
if (ival == 0) buf[pos++] = '0';
int temp = ival;
while (temp) {
buf[pos++] = '0' + (temp % 10);
temp /= 10;
}
if (neg) buf[pos++] = '-';
while (pos > 0 && i < size - 1) str[i++] = buf[--pos];
// Simple decimal part (up to 4 digits)
val -= (int)val;
if (val > 0.0001) {
if (i < size - 1) str[i++] = '.';
for (int k=0; k<4 && val > 0.0001 && i < size-1; k++) {
val *= 10;
int digit = (int)val;
str[i++] = '0' + digit;
val -= digit;
}
}
} else {
if (i < size - 1) str[i++] = *p;
}
p++;
}
str[i] = '\0';
return i;
}
int snprintf(char *str, size_t size, const char *format, ...) {
__builtin_va_list ap;
__builtin_va_start(ap, format);
int ret = vsnprintf(str, size, format, ap);
__builtin_va_end(ap);
return ret;
}
// Compiler intrinsics for Windows target
void __chkstk(void) {
// Stack checking - not needed for UEFI
}
int _fltused = 0; // Floating point used marker
char *strchr(const char *s, int c) {
while (*s != (char)c) {
if (!*s++) {
return (void*)0;
}
}
return (char *)s;
}
double trunc(double x) {
return (x > 0) ? floor(x) : ceil(x);
}
double fmin(double x, double y) {
return (x < y) ? x : y;
}
double fmax(double x, double y) {
return (x > y) ? x : y;
}
double hypot(double x, double y) {
return sqrt(x*x + y*y);
}
double acos(double x) { (void)x; return 0.0; }
double asin(double x) { (void)x; return 0.0; }
double atan(double x) { (void)x; return 0.0; }
double atan2(double y, double x) { (void)y; (void)x; return 0.0; }
double cbrt(double x) { (void)x; return 0.0; }
double cosh(double x) { (void)x; return 0.0; }
double expm1(double x) { (void)x; return 0.0; }
double log1p(double x) { (void)x; return 0.0; }
double log2(double x) { (void)x; return 0.0; }
double log10(double x) { (void)x; return 0.0; }
double sinh(double x) { (void)x; return 0.0; }
double tanh(double x) { (void)x; return 0.0; }
double asinh(double x) { (void)x; return 0.0; }
double acosh(double x) { (void)x; return 0.0; }
double atanh(double x) { (void)x; return 0.0; }
double round(double x) {
return (x >= 0.0) ? floor(x + 0.5) : ceil(x - 0.5);
}
long int lrint(double x) {
return (long int)round(x);
}
size_t _msize(void *ptr) {
if (!ptr) return 0;
return *(size_t*)((char*)ptr - 8);
}
int fesetround(int round) { (void)round; return 0; }
int fegetround(void) { return 0; }
int errno = 0;
#include "time.h"
#include "sys/time.h"
time_t time(time_t *t) {
if (t) *t = 0;
return 0;
}
static struct tm tm_buf;
struct tm *gmtime(const time_t *timep) {
(void)timep;
// Stub: return 1970-01-01
tm_buf.tm_year = 70;
tm_buf.tm_mon = 0;
tm_buf.tm_mday = 1;
return &tm_buf;
}
struct tm *localtime(const time_t *timep) {
return gmtime(timep);
}
time_t mktime(struct tm *tm) {
(void)tm;
return 0;
}
int gettimeofday(struct timeval *tv, struct timezone *tz) {
if (tv) {
tv->tv_sec = 0;
tv->tv_usec = 0;
}
return 0;
}
void *memchr(const void *s, int c, size_t n) {
const unsigned char *p = s;
while (n--) {
if (*p == (unsigned char)c) return (void *)p;
p++;
}
return (void*)0;
}
char *strcat(char *dest, const char *src) {
char *d = dest;
while (*d) d++;
while ((*d++ = *src++));
return dest;
}
char *strncat(char *dest, const char *src, size_t n) {
char *d = dest;
while (*d) d++;
while (n-- && *src) *d++ = *src++;
*d = 0;
return dest;
}
char *strstr(const char *haystack, const char *needle) {
size_t len = strlen(needle);
if (len == 0) return (char *)haystack;
while (*haystack) {
if (!memcmp(haystack, needle, len)) return (char *)haystack;
haystack++;
}
return (void*)0;
}
char *strdup(const char *s) {
size_t len = strlen(s) + 1;
char *new = malloc(len);
if (new) memcpy(new, s, len);
return new;
}
char *strrchr(const char *s, int c) {
const char *found = (void*)0;
while (*s) {
if (*s == (char)c) found = s;
s++;
}
if (*s == (char)c) found = s;
return (char *)found;
}
int abs(int j) {
return (j < 0) ? -j : j;
}
int isdigit(int c) {
return (c >= '0' && c <= '9');
}
int isspace(int c) {
return (c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r');
}
int isupper(int c) {
return (c >= 'A' && c <= 'Z');
}
int islower(int c) {
return (c >= 'a' && c <= 'z');
}
int isalpha(int c) {
return isupper(c) || islower(c);
}
int isalnum(int c) {
return isalpha(c) || isdigit(c);
}
int tolower(int c) {
return isupper(c) ? c + 32 : c;
}
int toupper(int c) {
return islower(c) ? c - 32 : c;
}
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) {
// Simple bubble sort for now
if (nmemb < 2 || size == 0) return;
char *b = (char *)base;
// Byte-by-byte swap to avoid malloc
for (size_t i = 0; i < nmemb - 1; i++) {
for (size_t j = 0; j < nmemb - i - 1; j++) {
if (compar(b + j * size, b + (j + 1) * size) > 0) {
char *p1 = b + j * size;
char *p2 = b + (j + 1) * size;
for (size_t k = 0; k < size; k++) {
char t = p1[k];
p1[k] = p2[k];
p2[k] = t;
}
}
}
}
}
#include "setjmp.h"
int setjmp(jmp_buf env) {
(void)env;
return 0;
}
void longjmp(jmp_buf env, int val) {
(void)env; (void)val;
printf("longjmp called!\n");
abort();
}

18
src/core/compat/setjmp.h Normal file
View File

@@ -0,0 +1,18 @@
//---------------------------------------------------------------
//
// !!! AI GENERATE SLOP, PLEASE FIX !!!
//
//---------------------------------------------------------------
#ifndef _SETJMP_H
#define _SETJMP_H
#include <stdint.h>
// x86_64 jmp_buf: rbx, rbp, r12, r13, r14, r15, rsp, rip
typedef uint64_t jmp_buf[8];
int setjmp(jmp_buf env);
void longjmp(jmp_buf env, int val);
#endif

12
src/core/compat/stdarg.h Normal file
View File

@@ -0,0 +1,12 @@
//---------------------------------------------------------------
//
// !!! AI GENERATE SLOP, PLEASE FIX !!!
//
//---------------------------------------------------------------
#pragma once
typedef __builtin_va_list va_list;
#define va_start(ap, last) __builtin_va_start(ap, last)
#define va_end(ap) __builtin_va_end(ap)
#define va_arg(ap, type) __builtin_va_arg(ap, type)

23
src/core/compat/stdio.h Normal file
View File

@@ -0,0 +1,23 @@
//---------------------------------------------------------------
//
// !!! AI GENERATE SLOP, PLEASE FIX !!!
//
//---------------------------------------------------------------
#pragma once
#include <stdarg.h>
#include <stddef.h>
typedef struct FILE FILE;
#define stdout ((FILE*)1)
#define stderr ((FILE*)2)
#define stdin ((FILE*)0)
int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
int snprintf(char *str, size_t size, const char *format, ...);
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
int fputc(int c, FILE *stream);
int putchar(int c);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

20
src/core/compat/stdlib.h Normal file
View File

@@ -0,0 +1,20 @@
//---------------------------------------------------------------
//
// !!! AI GENERATE SLOP, PLEASE FIX !!!
//
//---------------------------------------------------------------
#pragma once
#include <stddef.h>
void *malloc(size_t size);
void free(void *ptr);
void *realloc(void *ptr, size_t size);
void *calloc(size_t nmemb, size_t size);
double strtod(const char *str, char **endptr);
long strtol(const char *str, char **endptr, int base);
void abort(void);
#define alloca __builtin_alloca
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
int abs(int j);
size_t _msize(void *ptr);

29
src/core/compat/string.h Normal file
View File

@@ -0,0 +1,29 @@
//---------------------------------------------------------------
//
// !!! AI GENERATE SLOP, PLEASE FIX !!!
//
//---------------------------------------------------------------
#ifndef _STRING_H
#define _STRING_H
#include <stddef.h>
void *memset(void *s, int c, size_t n);
void *memcpy(void *dest, const void *src, size_t n);
void *memmove(void *dest, const void *src, size_t n);
int memcmp(const void *s1, const void *s2, size_t n);
size_t strlen(const char *s);
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);
char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);
char *strcat(char *dest, const char *src);
char *strncat(char *dest, const char *src, size_t n);
char *strchr(const char *s, int c);
char *strrchr(const char *s, int c);
char *strstr(const char *haystack, const char *needle);
char *strdup(const char *s);
void *memchr(const void *s, int c, size_t n);
#endif

View File

@@ -0,0 +1,24 @@
//---------------------------------------------------------------
//
// !!! AI GENERATE SLOP, PLEASE FIX !!!
//
//---------------------------------------------------------------
#ifndef _SYS_TIME_H
#define _SYS_TIME_H
#include "time.h"
struct timeval {
long tv_sec;
long tv_usec;
};
struct timezone {
int tz_minuteswest;
int tz_dsttime;
};
int gettimeofday(struct timeval *tv, struct timezone *tz);
#endif

31
src/core/compat/time.h Normal file
View File

@@ -0,0 +1,31 @@
//---------------------------------------------------------------
//
// !!! AI GENERATE SLOP, PLEASE FIX !!!
//
//---------------------------------------------------------------
#ifndef _TIME_H
#define _TIME_H
#include <stddef.h>
typedef long time_t;
struct tm {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
};
time_t time(time_t *t);
struct tm *gmtime(const time_t *timep);
struct tm *localtime(const time_t *timep);
time_t mktime(struct tm *tm);
#endif

184
src/core/efi.h Normal file
View File

@@ -0,0 +1,184 @@
#ifndef EFI_H
#define EFI_H
#include <stdint.h>
#define NULL ((void*)0)
// Basic Types
typedef uint64_t UINT64;
typedef uint32_t UINT32;
typedef uint16_t UINT16;
typedef uint8_t UINT8;
typedef uintptr_t UINTN;
typedef intptr_t INTN;
typedef void VOID;
typedef uint64_t EFI_STATUS;
typedef void* EFI_HANDLE;
#define EFI_SUCCESS 0
#define EFI_ERROR(status) (((INTN)(status)) < 0)
typedef struct {
UINT32 Data1;
UINT16 Data2;
UINT16 Data3;
UINT8 Data4[8];
} EFI_GUID;
typedef struct {
uint64_t signature;
uint32_t revision;
uint32_t headerSize;
uint32_t crc32;
uint32_t reserved;
} EFI_TABLE_HEADER;
// Simple Text Output Protocol
struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL;
typedef EFI_STATUS (*EFI_TEXT_STRING)(
struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
uint16_t *String
);
typedef EFI_STATUS (*EFI_TEXT_CLEAR_SCREEN)(
struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
);
typedef struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL {
void *reset;
EFI_TEXT_STRING OutputString;
void *testString;
void *queryMode;
void *setMode;
void *setAttribute;
EFI_TEXT_CLEAR_SCREEN ClearScreen;
void *setCursorPosition;
void *enableCursor;
void *mode;
} EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL;
// Boot Services
typedef struct {
EFI_TABLE_HEADER Hdr;
void *RaiseTPL;
void *RestoreTPL;
void *AllocatePages;
void *FreePages;
void *GetMemoryMap;
void *AllocatePool;
void *FreePool;
void *CreateEvent;
void *SetTimer;
void *WaitForEvent;
void *SignalEvent;
void *CloseEvent;
void *CheckEvent;
void *InstallProtocolInterface;
void *ReinstallProtocolInterface;
void *UninstallProtocolInterface;
void *HandleProtocol;
void *Reserved;
void *RegisterProtocolNotify;
void *LocateHandle;
void *LocateDevicePath;
void *InstallConfigurationTable;
void *LoadImage;
void *StartImage;
void *Exit;
void *UnloadImage;
void *ExitBootServices;
void *GetNextMonotonicCount;
void *Stall;
void *SetWatchdogTimer;
void *ConnectController;
void *DisconnectController;
void *OpenProtocol;
void *CloseProtocol;
void *OpenProtocolInformation;
void *ProtocolsPerHandle;
void *LocateHandleBuffer;
EFI_STATUS (*LocateProtocol)(EFI_GUID *Protocol, void *Registration, void **Interface);
void *InstallMultipleProtocolInterfaces;
void *UninstallMultipleProtocolInterfaces;
void *CalculateCrc32;
void *CopyMem;
void *SetMem;
void *CreateEventEx;
} EFI_BOOT_SERVICES;
// PCI Root Bridge IO Protocol
#define EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID \
{ 0x2f707ebb, 0x4a1a, 0x11d4, {0x9a, 0x38, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} }
typedef enum {
EfiPciWidthUint8,
EfiPciWidthUint16,
EfiPciWidthUint32,
EfiPciWidthUint64,
EfiPciWidthFifoUint8,
EfiPciWidthFifoUint16,
EfiPciWidthFifoUint32,
EfiPciWidthFifoUint64,
EfiPciWidthFillUint8,
EfiPciWidthFillUint16,
EfiPciWidthFillUint32,
EfiPciWidthFillUint64,
EfiPciWidthMaximum
} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH;
typedef struct _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL;
typedef
EFI_STATUS
(*EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM) (
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
UINT64 Address,
UINTN Count,
VOID *Buffer
);
typedef struct {
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM Read;
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM Write;
} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS;
struct _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL {
void *ParentHandle;
void *PollMem;
void *PollIo;
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Mem;
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Io;
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Pci;
void *CopyMem;
void *Map;
void *Unmap;
void *AllocateBuffer;
void *FreeBuffer;
void *Flush;
void *GetAttributes;
void *SetAttributes;
void *Configuration;
UINT32 SegmentNumber;
};
// System Table
typedef struct EFI_SYSTEM_TABLE {
EFI_TABLE_HEADER hdr;
uint16_t *firmwareVendor;
uint32_t firmwareRevision;
void *consoleInHandle;
void *conIn;
void *consoleOutHandle;
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
void *standardErrorHandle;
void *stdErr;
void *runtimeServices;
EFI_BOOT_SERVICES *BootServices;
uint64_t numberOfTableEntries;
void *configurationTable;
} EFI_SYSTEM_TABLE;
#endif

231
src/core/main.c Normal file
View File

@@ -0,0 +1,231 @@
#include "efi.h"
#include "quickjs.h"
#include "stdio.h"
#include "system_prog.h"
#include "util.h"
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
static EFI_SYSTEM_TABLE *gST = NULL;
// Declare heap initialization function from minilibc.c
extern void init_heap(void *system_table);
void print(uint16_t *str) {
if (gST && gST->ConOut)
gST->ConOut->OutputString(gST->ConOut, str);
}
int printf(const char *format, ...) {
char buf[1024];
va_list ap;
va_start(ap, format);
int ret = vsnprintf(buf, sizeof(buf), format, ap);
va_end(ap);
print(AsciiToUnicode(buf));
return ret;
}
int fprintf(FILE *stream, const char *format, ...) {
if (stream != stdout && stream != stderr)
return 0;
char buf[1024];
va_list ap;
va_start(ap, format);
int ret = vsnprintf(buf, sizeof(buf), format, ap);
va_end(ap);
print(AsciiToUnicode(buf));
return ret;
}
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) {
if (stream != stdout && stream != stderr)
return 0;
const char *p = ptr;
size_t total = size * nmemb;
char buf[1025];
size_t i = 0;
while (i < total) {
size_t chunk = total - i;
if (chunk > 1024)
chunk = 1024;
memcpy(buf, p + i, chunk);
buf[chunk] = 0;
print(AsciiToUnicode(buf));
i += chunk;
}
return nmemb;
}
int fputc(int c, FILE *stream) {
if (stream != stdout && stream != stderr)
return c;
char buf[2] = {(char)c, 0};
print(AsciiToUnicode(buf));
return c;
}
int putchar(int c) { return fputc(c, stdout); }
// ------------------------------- Kernel C TS bindings
// -------------------------------
JSValue jsKCPrintln(JSContext *ctx, JSValueConst jsThis, int argc,
JSValueConst *argv) {
if (argc < 1)
return JS_ThrowSyntaxError(ctx, "Missing argument");
const char *str = JS_ToCString(ctx, argv[0]);
if (!str)
return JS_EXCEPTION;
print(AsciiToUnicode(str));
print(L"\r\n");
JS_FreeCString(ctx, str);
return JS_UNDEFINED;
}
JSValue jsKCClearScreen(JSContext *ctx, JSValueConst jsThis, int argc,
JSValueConst *argv) {
gST->ConOut->ClearScreen(gST->ConOut);
return JS_UNDEFINED;
}
JSValue jsKCPCIReadDword(JSContext *ctx, JSValueConst jsThis, int argc,
JSValueConst *argv) {
if (argc < 1)
return JS_ThrowSyntaxError(ctx, "Missing argument");
uint32_t addr_u32;
JS_ToUint32(ctx, &addr_u32, argv[0]);
UINT64 addr = (UINT64)
addr_u32; // Ensure type matches EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_RW's
// Address parameter
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *pci;
EFI_GUID pciGuid = EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID;
EFI_STATUS status =
gST->BootServices->LocateProtocol(&pciGuid, NULL, (void **)&pci);
if (EFI_ERROR(status)) {
return JS_ThrowInternalError(
ctx, "Failed to locate PCI Root Bridge IO Protocol: %d", status);
}
UINT32 data = 0;
status = pci->Pci.Read(pci, EfiPciWidthUint32, addr, 1, &data);
return JS_NewUint32(ctx, data);
}
void initKC(JSContext *ctx) {
JSValue global = JS_GetGlobalObject(ctx);
JSValue kc = JS_NewObject(ctx);
JS_SetPropertyStr(ctx, global, "kc", kc);
JS_SetPropertyStr(ctx, kc, "println", JS_NewCFunction(ctx, jsKCPrintln, "println", 1));
JS_SetPropertyStr(ctx, kc, "clearScreen", JS_NewCFunction(ctx, jsKCClearScreen, "clearScreen", 0));
JS_SetPropertyStr(ctx, kc, "pciReadDword", JS_NewCFunction(ctx, jsKCPCIReadDword, "pciReadDword", 1));
JS_FreeValue(ctx, global);
}
// ------------------------------------- EFI main
// -------------------------------------
EFI_STATUS efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
(void)ImageHandle;
gST = SystemTable;
gST->ConOut->ClearScreen(gST->ConOut);
print(L"Booting LintsOS...\r\n");
// Initialize heap with maximum available memory
init_heap(SystemTable);
JSRuntime *rt = JS_NewRuntime();
if (!rt) {
print(L"!!! Kernel panic: Failed to create runtime !!!\r\n");
return EFI_SUCCESS;
}
JSContext *ctx = JS_NewContext(rt);
if (!ctx) {
print(L"!!! Kernel panic: Failed to create context !!!\r\n");
JS_FreeRuntime(rt);
return EFI_SUCCESS;
}
initKC(ctx);
JSValue val;
JSValue eval_result = JS_Eval(ctx, SYSTEM_PROG_JS, strlen(SYSTEM_PROG_JS),
"<input>", JS_EVAL_TYPE_GLOBAL);
if (JS_IsException(eval_result))
val = eval_result;
else {
JS_FreeValue(ctx, eval_result);
JSValue global_obj = JS_GetGlobalObject(ctx);
JSValue kentry_func = JS_GetPropertyStr(ctx, global_obj, "KEntry");
if (JS_IsFunction(ctx, kentry_func))
val = JS_Call(ctx, kentry_func, JS_UNDEFINED, 0, NULL);
else
val = JS_ThrowReferenceError(ctx,
"KEntry function not found or not callable");
JS_FreeValue(ctx, kentry_func);
JS_FreeValue(ctx, global_obj);
}
if (JS_IsException(val)) {
JSValue ex = JS_GetException(ctx);
const char *str = JS_ToCString(ctx, ex);
if (str) {
printf("!!! Kernel panic: %s !!!\n", str);
JS_FreeCString(ctx, str);
} else
printf("!!! Kernel panic: [unknown] !!!\n");
JS_FreeValue(ctx, ex);
} else {
const char *str = JS_ToCString(ctx, val);
if (str) {
printf("!!! Kernel panic: %s !!!\n", str);
JS_FreeCString(ctx, str);
} else
printf("!!! Kernel panic: [unknown] !!!\n");
JS_FreeValue(ctx, val);
}
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
for (;;)
;
return EFI_SUCCESS;
}

32
src/core/util.c Normal file
View File

@@ -0,0 +1,32 @@
#include "util.h"
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdarg.h>
#include "stdio.h"
#include "quickjs.h"
#include "efi.h"
void halt() {
for(;;);
}
//---------------------------------------------------------------
//
// !!! AI GENERATE SLOP, PLEASE FIX !!!
//
//---------------------------------------------------------------
uint16_t *AsciiToUnicode(const char *ascii) {
static uint16_t buffer[1024];
int i;
for (i = 0; ascii[i] && i < 1023; i++) {
buffer[i] = (uint16_t)ascii[i];
}
buffer[i] = 0;
return buffer;
}

13
src/core/util.h Normal file
View File

@@ -0,0 +1,13 @@
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdarg.h>
#include "stdio.h"
#ifndef UTIL_H
#define UTIL_H
void halt();
uint16_t *AsciiToUnicode(const char *ascii);
#endif

View File

@@ -1,153 +0,0 @@
#include <string.h>
#include <stdint.h>
#include <duktape.h>
#include "embedded_js.h"
#define WHITE_TXT 0x0F
// Forward declaration
unsigned int k_printf(char *message, unsigned int line);
duk_context *ctx;
duk_ret_t native_addrw(duk_context *ctx)
{
// Get the address (first argument)
uint32_t address = (uint32_t)duk_to_uint32(ctx, 0);
// Get the value to write (second argument)
uint8_t value = (uint8_t)duk_to_uint32(ctx, 1);
// Write the value to the address
uint8_t *ptr = (uint8_t *)address;
*ptr = value;
return 0;
}
// Port byte in
duk_ret_t native_ptin(duk_context *ctx)
{
// Get the port (first argument)
uint16_t port = (uint16_t)duk_to_uint32(ctx, 0);
uint8_t result;
__asm__ volatile("inb %1, %0"
: "=a"(result)
: "Nd"(port));
duk_push_uint(ctx, (duk_uint_t)result);
return 1;
}
// Port byte out
duk_ret_t native_ptout(duk_context *ctx)
{
// Get the port (first argument)
uint16_t port = (uint16_t)duk_to_uint32(ctx, 0);
// Get the value to write (second argument)
uint8_t value = (uint8_t)duk_to_uint32(ctx, 1);
__asm__ volatile("outb %0, %1"
:
: "a"(value), "Nd"(port));
return 0;
}
duk_ret_t native_dword_in(duk_context *ctx)
{
// Get the port (first argument)
uint16_t port = (uint16_t)duk_to_uint32(ctx, 0);
uint32_t result;
__asm__ volatile("inl %1, %0"
: "=a"(result)
: "Nd"(port));
duk_push_uint(ctx, (duk_uint_t)result);
return 1;
}
duk_ret_t native_dword_out(duk_context *ctx)
{
// Get the port (first argument)
uint16_t port = (uint16_t)duk_to_uint32(ctx, 0);
// Get the value to write (second argument)
uint32_t value = (uint32_t)duk_to_uint32(ctx, 1);
__asm__ volatile("outl %0, %1"
:
: "a"(value), "Nd"(port));
return 0;
}
void kmain()
{
// Initialize Duktape heap
ctx = duk_create_heap_default();
// Register native memory write function
duk_push_c_function(ctx, native_addrw, 2);
duk_put_global_string(ctx, "$addrw");
// Register native port in function
duk_push_c_function(ctx, native_ptin, 1);
duk_put_global_string(ctx, "$ptin");
// Register native port out function
duk_push_c_function(ctx, native_ptout, 2);
duk_put_global_string(ctx, "$ptout");
// Register native dword in function
duk_push_c_function(ctx, native_dword_in, 1);
duk_put_global_string(ctx, "$dwordin");
// Register native dword out function
duk_push_c_function(ctx, native_dword_out, 2);
duk_put_global_string(ctx, "$dwordout");
// Execute embedded JavaScript code from build/index.js
duk_push_string(ctx, embedded_js_code);
duk_int_t returnCode = duk_peval(ctx);
if (returnCode != 0)
{
// Error occurred - display stack trace
duk_safe_to_stacktrace(ctx, -1);
k_printf((char *)duk_safe_to_string(ctx, -1), 1);
}
duk_pop(ctx);
}
unsigned int k_printf(char *message, unsigned int line)
{
char *vidmem = (char *)0xb8000;
unsigned int i = 0;
i = (line * 80 * 2);
while (*message != 0)
{
if (*message == '\n') // check for a new line
{
line++;
i = (line * 80 * 2);
*message++;
}
else
{
vidmem[i] = *message;
*message++;
i++;
vidmem[i] = WHITE_TXT;
i++;
};
};
return (1);
}

1
src/lib/quickjs Submodule

Submodule src/lib/quickjs added at 177e1b32a4

View File

@@ -1,33 +0,0 @@
/*
* Minimal system stubs for freestanding picolibc
*/
#include <sys/types.h>
#include <sys/time.h>
#include <errno.h>
/* Exit function - halt the system */
void _exit(int status)
{
(void)status;
/* Halt the CPU */
while (1)
{
__asm__ volatile("hlt");
}
}
/* Get time of day - not supported in freestanding */
int gettimeofday(struct timeval *tv, void *tz)
{
(void)tz;
if (tv)
{
tv->tv_sec = 0;
tv->tv_usec = 0;
}
return 0;
}
/* Sbrk - memory allocation (picolibc uses __heap_start and __heap_end from linker script) */
/* No need to implement sbrk as picolibc uses the linker symbols directly */

View File

@@ -1,40 +0,0 @@
/*
* link.ld
*/
OUTPUT_FORMAT(elf32-i386)
ENTRY(start)
SECTIONS
{
. = 0x100000;
.text : {
*(.text)
*(.text.*)
*(.rodata)
*(.rodata.*)
}
.data : {
*(.data)
*(.data.*)
}
.bss : {
*(.bss)
*(.bss.*)
*(COMMON)
}
/* Heap for malloc */
. = ALIGN(4096);
__heap_start = .;
. = . + 0x100000; /* 1MB heap */
__heap_end = .;
/* Stack grows downward from high memory */
. = ALIGN(4096);
__stack_bottom = .;
. = . + 0x10000; /* 64KB stack */
__stack_top = .;
}

View File

@@ -1,8 +0,0 @@
import { kmain } from "./kernel";
import { kpanic } from "./kernel/panic";
try {
kmain();
} catch (e) {
kpanic(e instanceof Error ? e.message : String(e));
}

View File

@@ -1,130 +0,0 @@
import { dwordin, dwordout } from "../../../lib/libts/dword";
import { portin, portout } from "../../../lib/libts/port";
import { Logger } from "../../../lib/libstd/logger/logger.kmod";
import { sysfs_mkdir, sysfs_writeFile } from "../../filesystem/sysfs";
import { Path } from "../../../lib/libstd/path";
const KDRIVER_PCI_CONFIG_ADDR = 0xcf8;
const KDRIVER_PCI_CONFIG_DATA = 0xcfc;
export function kdriver_dev_pci_init() {}
export function kdriver_dev_pci_detectDevices() {
Logger.log("[PCI] Scanning...");
for (let bus = 0; bus < 256; bus++) {
for (let device = 0; device < 32; device++) {
kdriver_dev_pci_checkDevice(bus, device, 0);
const headerType = kdriver_dev_pci_getHeaderType(bus, device, 0);
if ((headerType & 0x80) !== 0) {
for (let func = 1; func < 8; func++) {
kdriver_dev_pci_checkDevice(bus, device, func);
}
}
}
}
}
export function kdriver_dev_pci_checkDevice(
bus: number,
device: number,
func: number
) {
const vendorId = kdriver_dev_pci_getVendorId(bus, device, func);
if (vendorId === 0xffff) return;
const deviceId = kdriver_dev_pci_getDeviceId(bus, device, func);
const classCode = kdriver_dev_pci_getClassCode(bus, device, func);
const subclass = kdriver_dev_pci_getSubclass(bus, device, func);
const filename = bus + ":" + device + ":" + func;
Logger.log(
"[PCI] Found device pci:" +
filename +
" (vendor:" +
vendorId.toString(16) +
", device:" +
deviceId.toString(16) +
", class:" +
classCode.toString(16) +
", subclass:" +
subclass.toString(16) +
")"
);
const dirname = Path.join("/pci", filename);
sysfs_mkdir(dirname);
sysfs_writeFile(Path.join(dirname, "vendor"), vendorId);
sysfs_writeFile(Path.join(dirname, "device"), deviceId);
sysfs_writeFile(Path.join(dirname, "class"), classCode);
sysfs_writeFile(Path.join(dirname, "subclass"), subclass);
}
export function kdriver_dev_pci_getDeviceId(
bus: number,
device: number,
func: number
) {
const data = kdriver_dev_pci_readConfigDword(bus, device, func, 0);
return data >> 16;
}
export function kdriver_dev_pci_getVendorId(
bus: number,
device: number,
func: number
) {
const data = kdriver_dev_pci_readConfigDword(bus, device, func, 0);
return data & 0xffff;
}
export function kdriver_dev_pci_getClassCode(
bus: number,
device: number,
func: number
) {
const data = kdriver_dev_pci_readConfigDword(bus, device, func, 8);
return (data >> 24) & 0xff;
}
export function kdriver_dev_pci_getSubclass(
bus: number,
device: number,
func: number
) {
const data = kdriver_dev_pci_readConfigDword(bus, device, func, 8);
return (data >> 16) & 0xff;
}
export function kdriver_dev_pci_getHeaderType(
bus: number,
device: number,
func: number
) {
const data = kdriver_dev_pci_readConfigDword(bus, device, func, 12);
return (data >> 16) & 0xff;
}
export function kdriver_dev_pci_readConfigDword(
bus: number,
device: number,
func: number,
offset: number
) {
const address =
(1 << 31) | (bus << 16) | (device << 11) | (func << 8) | (offset & 0xfc);
dwordout(KDRIVER_PCI_CONFIG_ADDR, address);
const data = dwordin(KDRIVER_PCI_CONFIG_DATA);
return data;
}

View File

@@ -1,27 +0,0 @@
import { portin, portout } from "../../../lib/libts/port";
const SERIAL_PORT_COM1 = 0x3f8;
export function kdriver_etc_serial_init() {
portout(SERIAL_PORT_COM1 + 1, 0x00); // Disable all interrupts
portout(SERIAL_PORT_COM1 + 3, 0x80); // Enable DLAB
portout(SERIAL_PORT_COM1 + 0, 0x03); // 38400 baud
portout(SERIAL_PORT_COM1 + 1, 0x00);
portout(SERIAL_PORT_COM1 + 3, 0x03); // 8 bits, no parity, one stop bit
portout(SERIAL_PORT_COM1 + 2, 0xc7); // Enable FIFO, clear them, with 14-byte threshold
portout(SERIAL_PORT_COM1 + 4, 0x0b);
}
export function kdriver_etc_serial_isTransmitBufferEmpty(): boolean {
return (portin(SERIAL_PORT_COM1 + 5) & 0x20) !== 0;
}
export function kdriver_etc_serial_transmit(byte: number): void {
while (!kdriver_etc_serial_isTransmitBufferEmpty()) {}
portout(SERIAL_PORT_COM1, byte);
}
export function kdriver_etc_serial_read(): number {
return portin(SERIAL_PORT_COM1);
}

View File

@@ -1,138 +0,0 @@
import { Logger } from "../../lib/libstd/logger/logger.kmod";
import { Path } from "../../lib/libstd/path";
import type {
KFilesystemDriver,
KFilesystemEntity,
KFilesystemMemdata,
KFilesystemStat,
} from "../../types/filesystem/fs";
const sysfs_data: KFilesystemMemdata = [];
export function sysfs_driver(): KFilesystemDriver {
return {
id: "sysfs",
init: sysfs_init,
listDir(path: string): KFilesystemEntity[] | null {
return sysfs_listDir(path);
},
readFile(path: string): unknown {
return sysfs_readFile(path);
},
writeFile(path: string, content: unknown): void {
throw new Error("Cannot write to sysfs files.");
},
createFile(path: string, content: unknown): void {
throw new Error("Cannot create files in sysfs.");
},
mkdir(path: string): void {
throw new Error("Cannot create directories in sysfs.");
},
stat(path: string): KFilesystemStat | null {
return sysfs_statEntity(path);
},
};
}
export function sysfs_init(): void {
sysfs_data.push({
name: "root",
path: "/",
type: "folder",
size: 0,
contents: null,
});
sysfs_mkdir("/pci");
}
export function sysfs_getEntity(path: string): KFilesystemEntity | null {
for (let i = 0; i < sysfs_data.length; i++) {
const entity = sysfs_data[i]!;
if (entity.path === path) return entity;
}
return null;
}
export function sysfs_statEntity(path: string): KFilesystemStat | null {
const entity = sysfs_getEntity(path);
if (!entity) return null;
return {
name: entity.name,
type: entity.type,
size: entity.size,
};
}
export function sysfs_mkdir(path: string): void {
if (sysfs_getEntity(path)) return;
const parent = Path.dirname(path);
if (!sysfs_getEntity(parent)) return;
sysfs_data.push({
name: Path.filename(path),
path,
type: "folder",
size: 0,
contents: null,
});
}
export function sysfs_createFile(path: string, content: unknown): void {
if (sysfs_getEntity(path)) return;
const parent = Path.dirname(path);
if (!sysfs_getEntity(parent)) return;
const size = String(content).length;
sysfs_data.push({
name: Path.filename(path),
path,
type: "file",
size,
contents: content,
});
}
export function sysfs_writeFile(path: string, content: unknown): void {
const entity = sysfs_getEntity(path);
if (!entity) return sysfs_createFile(path, content);
if (entity.type !== "file") return;
entity.contents = content;
entity.size = String(content).length;
}
export function sysfs_readFile(path: string): unknown {
const entity = sysfs_getEntity(path);
if (!entity) return null;
if (entity.type !== "file") return null;
return entity.contents;
}
export function sysfs_listDir(path: string): KFilesystemEntity[] | null {
const entity = sysfs_getEntity(path);
if (!entity) return null;
if (entity.type !== "folder") return null;
const contents: KFilesystemEntity[] = [];
for (let i = 0; i < sysfs_data.length; i++) {
const e = sysfs_data[i]!;
if (Path.dirname(e.path) === path) {
contents.push(e);
}
}
return contents;
}

View File

@@ -1,46 +0,0 @@
import { Logger } from "../lib/libstd/logger/logger.kmod";
import { charc } from "../lib/libts/byte";
import { padStart } from "../lib/libts/string";
import { getDate } from "../lib/sys/date";
import { kdriver_dev_pci_detectDevices } from "./drivers/dev/pci";
import {
kdriver_etc_serial_read,
kdriver_etc_serial_transmit,
} from "./drivers/etc/serial";
import { sysfs_driver, sysfs_readFile } from "./filesystem/sysfs";
import {
kmod_drivers_init,
kmod_drivers_register,
} from "./modules/drivers/drivers.kmod";
import {
kmod_filesystem_init,
kmod_filesystem_mount,
kmod_filesystem_readFile,
} from "./modules/filesystem/filesystem.kmod";
import {
kmod_graphics_vga_clear,
kmod_graphics_vga_init,
kmod_graphics_vga_pushLine,
} from "./modules/graphics/graphics.kmod";
export function kmain() {
kmod_drivers_init();
kmod_drivers_register();
Logger.log("[Kernel] Drivers initialized.");
Logger.log("[Kernel] Initializing filesystem module...");
kmod_filesystem_init();
kmod_filesystem_mount("/sys", sysfs_driver);
Logger.log("[Kernel] Initializing PCI devices...");
kdriver_dev_pci_detectDevices();
Logger.log("[Kernel] Initializing VGA module...");
kmod_graphics_vga_init();
kmod_graphics_vga_pushLine("[Kernel] Kernel initialized successfully.");
kmod_graphics_vga_pushLine("Current date: " + getDate().toDateString());
kmod_graphics_vga_pushLine(
Number(kmod_filesystem_readFile("/sys/pci/0:1:0/vendor")).toString(16)
);
}

View File

@@ -1 +0,0 @@
export * from "./time"

View File

@@ -1,2 +0,0 @@
export const CFG_KMOD_BIOS_TIME_CMOS_ADDR = 0x70;
export const CFG_KMOD_BIOS_TIME_CMOS_DATA_ADDR = 0x71;

View File

@@ -1,96 +0,0 @@
import { portin, portout } from "../../../lib/libts/port";
import { padStart } from "../../../lib/libts/string";
import {
CFG_KMOD_BIOS_TIME_CMOS_ADDR,
CFG_KMOD_BIOS_TIME_CMOS_DATA_ADDR,
} from "./config";
export function kmod_bios_time_getCentury(): number {
const val = 0x32;
portout(CFG_KMOD_BIOS_TIME_CMOS_ADDR, val);
const data = portin(CFG_KMOD_BIOS_TIME_CMOS_DATA_ADDR);
return (data & 0x0f) + ((data >> 4) & 0x0f) * 10;
}
export function kmod_bios_time_getYear(): number {
const val = 0x09;
portout(CFG_KMOD_BIOS_TIME_CMOS_ADDR, val);
const data = portin(CFG_KMOD_BIOS_TIME_CMOS_DATA_ADDR);
return (data & 0x0f) + ((data >> 4) & 0x0f) * 10;
}
export function kmod_bios_time_getMonth(): number {
const val = 0x08;
portout(CFG_KMOD_BIOS_TIME_CMOS_ADDR, val);
const data = portin(CFG_KMOD_BIOS_TIME_CMOS_DATA_ADDR);
return (data & 0x0f) + ((data >> 4) & 0x0f) * 10;
}
export function kmod_bios_time_getDay(): number {
const val = 0x07;
portout(CFG_KMOD_BIOS_TIME_CMOS_ADDR, val);
const data = portin(CFG_KMOD_BIOS_TIME_CMOS_DATA_ADDR);
return (data & 0x0f) + ((data >> 4) & 0x0f) * 10;
}
export function kmod_bios_time_getHours(): number {
const val = 0x04;
portout(CFG_KMOD_BIOS_TIME_CMOS_ADDR, val);
const data = portin(CFG_KMOD_BIOS_TIME_CMOS_DATA_ADDR);
return (data & 0x0f) + ((data >> 4) & 0x0f) * 10;
}
export function kmod_bios_time_getMinutes(): number {
const val = 0x02;
portout(CFG_KMOD_BIOS_TIME_CMOS_ADDR, val);
const data = portin(CFG_KMOD_BIOS_TIME_CMOS_DATA_ADDR);
return (data & 0x0f) + ((data >> 4) & 0x0f) * 10;
}
export function kmod_bios_time_getSeconds(): number {
const val = 0x00;
portout(CFG_KMOD_BIOS_TIME_CMOS_ADDR, val);
const data = portin(CFG_KMOD_BIOS_TIME_CMOS_DATA_ADDR);
return (data & 0x0f) + ((data >> 4) & 0x0f) * 10;
}
export function kmod_bios_time_getTimestamp(): string {
const century = kmod_bios_time_getCentury();
const year = kmod_bios_time_getYear();
const month = kmod_bios_time_getMonth();
const day = kmod_bios_time_getDay();
const hours = kmod_bios_time_getHours();
const minutes = kmod_bios_time_getMinutes();
const seconds = kmod_bios_time_getSeconds();
return (
century.toString() +
year.toString() +
"-" +
padStart(month.toString(), 2, "0") +
"-" +
padStart(day.toString(), 2, "0") +
"T" +
padStart(hours.toString(), 2, "0") +
":" +
padStart(minutes.toString(), 2, "0") +
":" +
padStart(seconds.toString(), 2, "0") +
+".000" +
"Z"
);
}

View File

@@ -1,12 +0,0 @@
import { kdriver_dev_pci_init } from "../../drivers/dev/pci";
import { kdriver_etc_serial_init } from "../../drivers/etc/serial";
const drivers = [kdriver_etc_serial_init, kdriver_dev_pci_init];
export function kmod_drivers_init(): void {}
export function kmod_drivers_register(): void {
for (let i = 0; i < drivers.length; i++) {
drivers[i]!();
}
}

View File

@@ -1,111 +0,0 @@
import { Logger } from "../../../lib/libstd/logger/logger.kmod";
import type {
KFilesystemDriver,
KFilesystemEntity,
KFilesystemMount,
KFilesystemMountdata,
KFilesystemStat,
} from "../../../types/filesystem/fs";
const kmod_filesystem_data: KFilesystemMountdata = [];
export function kmod_filesystem_init(): void {}
export function kmod_filesystem_mount(
mpoint: string,
drv: () => KFilesystemDriver
): void {
const driver = drv();
driver.init();
kmod_filesystem_data.push({
mountpoint: mpoint,
driver: driver,
});
Logger.log("[Filesystem] Mounted " + driver.id + " at " + mpoint);
}
export function kmod_filesystem_findMount(p: string): KFilesystemMount | null {
for (let i = 0; i < kmod_filesystem_data.length; i++) {
const mount = kmod_filesystem_data[i]!;
if (p.startsWith(mount.mountpoint)) {
return mount;
}
}
return null;
}
export function kmod_filesystem_stripMountpoint(
mount: KFilesystemMount,
p: string
): string {
if (mount.mountpoint === "/") return p;
return p.slice(mount.mountpoint.length) || "/";
}
export function kmod_filesystem_listDir(
path: string
): KFilesystemEntity[] | null {
const mount = kmod_filesystem_findMount(path);
if (!mount) return null;
const strippedPath = kmod_filesystem_stripMountpoint(mount, path);
return mount.driver.listDir(strippedPath);
}
export function kmod_filesystem_readFile(path: string): unknown {
const mount = kmod_filesystem_findMount(path);
if (!mount) return null;
const strippedPath = kmod_filesystem_stripMountpoint(mount, path);
return mount.driver.readFile(strippedPath);
}
export function kmod_filesystem_writeFile(
path: string,
content: unknown
): void {
const mount = kmod_filesystem_findMount(path);
if (!mount) return;
const strippedPath = kmod_filesystem_stripMountpoint(mount, path);
mount.driver.writeFile(strippedPath, content);
}
export function kmod_filesystem_createFile(
path: string,
content: unknown
): void {
const mount = kmod_filesystem_findMount(path);
if (!mount) return;
const strippedPath = kmod_filesystem_stripMountpoint(mount, path);
mount.driver.createFile(strippedPath, content);
}
export function kmod_filesystem_mkdir(path: string): void {
const mount = kmod_filesystem_findMount(path);
if (!mount) return;
const strippedPath = kmod_filesystem_stripMountpoint(mount, path);
mount.driver.mkdir(strippedPath);
}
export function kmod_filesystem_stat(path: string): KFilesystemStat | null {
const mount = kmod_filesystem_findMount(path);
if (!mount) return null;
const strippedPath = kmod_filesystem_stripMountpoint(mount, path);
return mount.driver.stat(strippedPath);
}

View File

@@ -1,3 +0,0 @@
export const CFG_KMOD_GRAPHICS_VGA_WIDTH = 80;
export const CFG_KMOD_GRAPHICS_VGA_HEIGHT = 25;
export const CFG_KMOD_GRAPGICS_VGA_MEM_ADDR = 0xb8000;

View File

@@ -1 +0,0 @@
export * from "./vga";

View File

@@ -1,72 +0,0 @@
import { charc } from "../../../lib/libts/byte";
import {
CFG_KMOD_GRAPGICS_VGA_MEM_ADDR,
CFG_KMOD_GRAPHICS_VGA_HEIGHT,
CFG_KMOD_GRAPHICS_VGA_WIDTH,
} from "./config";
let kmod_graphics_vga_lineBuf: string[] = [];
export function kmod_graphics_vga_init() {
kmod_graphics_vga_clear();
}
export function kmod_graphics_vga_pushLine(line: string) {
kmod_graphics_vga_lineBuf.push(line);
if (kmod_graphics_vga_lineBuf.length > CFG_KMOD_GRAPHICS_VGA_HEIGHT) {
kmod_graphics_vga_lineBuf.shift();
}
kmod_graphics_vga_printLines();
}
export function kmod_graphics_vga_printLines() {
for (let y = 0; y < CFG_KMOD_GRAPHICS_VGA_HEIGHT; y++) {
const line = kmod_graphics_vga_lineBuf[y] || "";
for (let x = 0; x < CFG_KMOD_GRAPHICS_VGA_WIDTH; x++) {
let char = line[x];
if (!char) char = " ";
kmod_graphics_vga_writeChar(x, y, char, 0x0f);
}
}
}
export function kmod_graphics_vga_getCharAddr(x: number, y: number): number {
return (
CFG_KMOD_GRAPGICS_VGA_MEM_ADDR + (y * CFG_KMOD_GRAPHICS_VGA_WIDTH + x) * 2
);
}
export function kmod_graphics_vga_getColorAddr(x: number, y: number): number {
return (
CFG_KMOD_GRAPGICS_VGA_MEM_ADDR +
(y * CFG_KMOD_GRAPHICS_VGA_WIDTH + x) * 2 +
1
);
}
export function kmod_graphics_vga_clear() {
kmod_graphics_vga_lineBuf = [];
for (let y = 0; y < CFG_KMOD_GRAPHICS_VGA_HEIGHT; y++) {
for (let x = 0; x < CFG_KMOD_GRAPHICS_VGA_WIDTH; x++) {
kmod_graphics_vga_writeChar(x, y, " ", 0x07);
}
}
}
export function kmod_graphics_vga_writeChar(
x: number,
y: number,
char: string,
color: number
) {
const charAddr = kmod_graphics_vga_getCharAddr(x, y);
const colorAddr = kmod_graphics_vga_getColorAddr(x, y);
$addrw(charAddr, charc(char));
$addrw(colorAddr, color);
}

View File

@@ -1,21 +0,0 @@
import {
kmod_graphics_vga_clear,
kmod_graphics_vga_writeChar,
} from "./modules/graphics/graphics.kmod";
export function kpanic(reason?: string) {
kmod_graphics_vga_clear();
const l1 = "KERNEL PANIC!";
let l2 = "Unknown: Kernel crashed.";
if (reason) l2 = "Reason: " + reason;
for (let i = 0; i < l1.length; i++) {
kmod_graphics_vga_writeChar(i, 0, l1[i]!, 0x0c);
}
for (let i = 0; i < l2.length; i++) {
kmod_graphics_vga_writeChar(i, 1, l2[i]!, 0x0c);
}
}

View File

@@ -1,12 +0,0 @@
import { charc } from "../../libts/byte";
import { kdriver_etc_serial_transmit } from "../../../kernel/drivers/etc/serial";
export const Logger = {
log(message: string) {
for (let i = 0; i < message.length; i++) {
kdriver_etc_serial_transmit(charc(message[i]!));
}
kdriver_etc_serial_transmit(charc("\n"));
},
};

View File

@@ -1,30 +0,0 @@
export const Path = {
dirname(p: string): string {
const parts = p.split("/");
parts.pop();
if (parts.length <= 1) return "/";
return parts.join("/");
},
filename(p: string): string {
const parts = p.split("/");
const n = parts.pop();
if (!n) return "";
return n;
},
join(p1: string, p2: string): string {
if (p1.endsWith("/")) {
p1 = p1.slice(0, -1);
}
if (p2.startsWith("/")) {
p2 = p2.slice(1);
}
return p1 + "/" + p2;
},
};

View File

@@ -1,3 +0,0 @@
export function charc(char: string): number {
return char.charCodeAt(0);
}

View File

@@ -1,7 +0,0 @@
export function dwordin(dw: number): number {
return $dwordin(dw);
}
export function dwordout(dw: number, value: number): void {
$dwordout(dw, value);
}

View File

@@ -1,7 +0,0 @@
export function portin(port: number): number {
return $ptin(port);
}
export function portout(port: number, value: number): void {
$ptout(port, value);
}

View File

@@ -1,11 +0,0 @@
export function padStart(
str: string,
targetLength: number,
padString: string
): string {
while (str.length < targetLength) {
str = padString + str;
}
return str;
}

View File

@@ -1,5 +0,0 @@
import { kmod_bios_time_getTimestamp } from "../../kernel/modules/bios/time";
export function getDate(): Date {
return new Date(kmod_bios_time_getTimestamp());
}

View File

@@ -1,29 +0,0 @@
import { KDriverPCIClass } from "../../../types/dev/pci/class";
const sysPCIClassNames = {
[KDriverPCIClass.MassStorageController]: "Mass Storage Controller",
[KDriverPCIClass.NetworkController]: "Network Controller",
[KDriverPCIClass.DisplayController]: "Display Controller",
[KDriverPCIClass.MultimediaController]: "Multimedia Controller",
[KDriverPCIClass.MemoryController]: "Memory Controller",
[KDriverPCIClass.BridgeDevice]: "Bridge Device",
[KDriverPCIClass.SimpleCommunicationsController]:
"Simple Communications Controller",
[KDriverPCIClass.BaseSystemPeripheral]: "Base System Peripheral",
[KDriverPCIClass.InputDevice]: "Input Device",
[KDriverPCIClass.DockingStation]: "Docking Station",
[KDriverPCIClass.Processors]: "Processors",
[KDriverPCIClass.SerialBusController]: "Serial Bus Controller",
[KDriverPCIClass.WirelessController]: "Wireless Controller",
[KDriverPCIClass.IntelligentIOController]: "Intelligent I/O Controller",
[KDriverPCIClass.SatelliteCommunicationController]:
"Satellite Communication Controller",
[KDriverPCIClass.EncryptionDecryptionController]:
"Encryption/Decryption Controller",
[KDriverPCIClass.DataAcquisitionAndSignalProcessingController]:
"Data Acquisition and Signal Processing Controller",
};
export function sys_pci_class_name(classId: KDriverPCIClass): string {
return sysPCIClassNames[classId] || "Unknown";
}

View File

@@ -1 +0,0 @@
console.log("TS-DOS Program Started");

View File

@@ -1,5 +0,0 @@
declare function $addrw(address: number, value: number): void;
declare function $ptin(port: number): number;
declare function $ptout(port: number, value: number): void;
declare function $dwordin(port: number): number;
declare function $dwordout(port: number, value: number): void;

View File

@@ -1,19 +0,0 @@
export enum KDriverPCIClass {
MassStorageController = 1,
NetworkController = 2,
DisplayController = 3,
MultimediaController = 4,
MemoryController = 5,
BridgeDevice = 6,
SimpleCommunicationsController = 7,
BaseSystemPeripheral = 8,
InputDevice = 9,
DockingStation = 10,
Processors = 11,
SerialBusController = 12,
WirelessController = 13,
IntelligentIOController = 14,
SatelliteCommunicationController = 15,
EncryptionDecryptionController = 16,
DataAcquisitionAndSignalProcessingController = 17,
}

View File

@@ -1,33 +0,0 @@
export type KFilesystemMountdata = KFilesystemMount[];
export type KFilesystemMount = {
mountpoint: string;
driver: KFilesystemDriver;
};
export type KFilesystemDriver = {
id: string;
init: () => void;
listDir(path: string): KFilesystemEntity[] | null;
readFile(path: string): unknown;
writeFile(path: string, content: unknown): void;
createFile(path: string, content: unknown): void;
mkdir(path: string): void;
stat(path: string): KFilesystemStat | null;
};
export type KFilesystemMemdata = KFilesystemEntity[];
export type KFilesystemEntity = {
name: string;
path: string;
size: number;
contents: unknown;
type: "file" | "folder";
};
export type KFilesystemStat = {
name: string;
type: "file" | "folder";
size: number;
};

150
src/scripts/build_core.sh Executable file
View File

@@ -0,0 +1,150 @@
#!/bin/bash
set -e
mkdir -p out
mkdir -p out/core
mkdir -p out/lib
mkdir -p out/lib/quickjs
mkdir -p out/img
mkdir -p out/img/EFI/BOOT
# Compile minilibc
clang -target x86_64-pc-win32-coff \
-ffreestanding \
-fno-stack-protector \
-fshort-wchar \
-mno-red-zone \
-Isrc/core/compat \
-D_GNU_SOURCE \
-DUEFI \
-O2 \
-c src/core/compat/minilibc.c -o out/core/minilibc.o
# Compile QuickJS
clang -target x86_64-pc-win32-coff \
-ffreestanding \
-fno-stack-protector \
-fshort-wchar \
-mno-red-zone \
-Isrc/core/compat \
-Isrc/lib/quickjs \
-D_GNU_SOURCE \
-DUEFI \
-DCONFIG_VERSION=\"2021-03-27\" \
-DJS_LIMB_BITS=32 \
-DNDEBUG \
-O2 \
-c src/lib/quickjs/cutils.c -o out/lib/quickjs/cutils.o
clang -target x86_64-pc-win32-coff \
-ffreestanding \
-fno-stack-protector \
-fshort-wchar \
-mno-red-zone \
-Isrc/core/compat \
-Isrc/lib/quickjs \
-D_GNU_SOURCE \
-DUEFI \
-DCONFIG_VERSION=\"2021-03-27\" \
-DJS_LIMB_BITS=32 \
-DNDEBUG \
-O2 \
-c src/lib/quickjs/libunicode.c -o out/lib/quickjs/libunicode.o
clang -target x86_64-pc-win32-coff \
-ffreestanding \
-fno-stack-protector \
-fshort-wchar \
-mno-red-zone \
-Isrc/core/compat \
-Isrc/lib/quickjs \
-D_GNU_SOURCE \
-DUEFI \
-DCONFIG_VERSION=\"2021-03-27\" \
-DJS_LIMB_BITS=32 \
-DNDEBUG \
-O2 \
-c src/lib/quickjs/libregexp.c -o out/lib/quickjs/libregexp.o
clang -target x86_64-pc-win32-coff \
-ffreestanding \
-fno-stack-protector \
-fshort-wchar \
-mno-red-zone \
-Isrc/core/compat \
-Isrc/lib/quickjs \
-D_GNU_SOURCE \
-DUEFI \
-DCONFIG_VERSION=\"2021-03-27\" \
-DJS_LIMB_BITS=32 \
-DNDEBUG \
-O2 \
-c src/lib/quickjs/dtoa.c -o out/lib/quickjs/dtoa.o
clang -target x86_64-pc-win32-coff \
-ffreestanding \
-fno-stack-protector \
-fshort-wchar \
-mno-red-zone \
-Isrc/core/compat \
-Isrc/lib/quickjs \
-D_GNU_SOURCE \
-DUEFI \
-DCONFIG_VERSION=\"2021-03-27\" \
-DJS_LIMB_BITS=32 \
-DNDEBUG \
-O2 \
-c src/lib/quickjs/quickjs.c -o out/lib/quickjs/quickjs.o
# Compile util.c
clang -target x86_64-pc-win32-coff \
-ffreestanding \
-fno-stack-protector \
-fshort-wchar \
-mno-red-zone \
-Isrc/core/compat \
-Isrc/lib/quickjs \
-D_GNU_SOURCE \
-DUEFI \
-DCONFIG_VERSION=\"2021-03-27\" \
-DJS_LIMB_BITS=32 \
-DNDEBUG \
-O2 \
-c src/core/util.c -o out/core/util.o
# Compile main application
clang -target x86_64-pc-win32-coff \
-ffreestanding \
-fno-stack-protector \
-fshort-wchar \
-mno-red-zone \
-Isrc/core/compat \
-Isrc/lib/quickjs \
-Iout/system \
-D_GNU_SOURCE \
-DUEFI \
-DCONFIG_VERSION=\"2021-03-27\" \
-DJS_LIMB_BITS=32 \
-DNDEBUG \
-O2 \
-c src/core/main.c -o out/core/main.o
# Link
lld-link \
-filealign:16 \
-subsystem:efi_application \
-nodefaultlib \
-dll \
-entry:efi_main \
out/core/main.o \
out/core/util.o \
out/core/minilibc.o \
out/lib/quickjs/cutils.o \
out/lib/quickjs/libunicode.o \
out/lib/quickjs/libregexp.o \
out/lib/quickjs/dtoa.o \
out/lib/quickjs/quickjs.o \
-out:out/img/EFI/BOOT/bootx64.efi
echo "Built efi app: out/img/EFI/BOOT/bootx64.efi"

13
src/scripts/build_iso.sh Executable file
View File

@@ -0,0 +1,13 @@
# Create a FAT12 image
dd if=/dev/zero of=out/fat.img bs=1k count=1440
mformat -i out/fat.img -f 1440 ::
# Create EFI directory structure
mmd -i out/fat.img ::/EFI
mmd -i out/fat.img ::/EFI/BOOT
# Copy the EFI application
mcopy -i out/fat.img out/img/EFI/BOOT/bootx64.efi ::/EFI/BOOT
# Create the ISO
xorriso -as mkisofs -R -f -e /fat.img -no-emul-boot -volid LintsEFI -o out/lints.iso out/img out/fat.img

7
src/scripts/build_system.sh Executable file
View File

@@ -0,0 +1,7 @@
#!/bin/bash
set -e
mkdir -p out
mkdir -p out/system
bun build --outdir out/system src/system/src/__.ts

View File

@@ -0,0 +1,6 @@
CompileFlags:
CompilationDatabase: .
Add:
- "-I%%workspaceFolder%%/src/core/compat"
- "-I%%workspaceFolder%%/src/lib/quickjs"
- "-I%%workspaceFolder%%/out/system"

28
src/scripts/embed_system.sh Executable file
View File

@@ -0,0 +1,28 @@
#!/bin/bash
set -e
echo "#ifndef SYSTEM_PROG_H" > out/system/system_prog.h
echo "#define SYSTEM_PROG_H" >> out/system/system_prog.h
echo "const char* SYSTEM_PROG_JS = \\" >> out/system/system_prog.h
remove_mode=false
while IFS= read -r line; do
if [ "$remove_mode" = true ]; then
remove_mode=false
continue
fi
ESCAPED_LINE=$(echo "$line" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g')
if echo "$line" | grep -q "___remove_next_line"; then
remove_mode=true
continue
fi
echo "\"${ESCAPED_LINE}\\n\"" >> out/system/system_prog.h
done < out/system/__.js
echo ";" >> out/system/system_prog.h
echo "#endif" >> out/system/system_prog.h

5
src/scripts/prepare_build.sh Executable file
View File

@@ -0,0 +1,5 @@
#!/bin/bash
set -e
rm -rf out

49
src/scripts/run_vbox.sh Executable file
View File

@@ -0,0 +1,49 @@
#!/bin/bash
set -e # Exit on error
VM_NAME="LintsOS"
DISK_IMG="${1:-out/fat.img}"
# Remove existing VM if it exists
if VBoxManage list vms | grep -q "\"${VM_NAME}\""; then
VBoxManage unregistervm ${VM_NAME} --delete 2>/dev/null || true
fi
# Remove old VDI if it exists
if [ -f "uefi-disk.vdi" ]; then
rm -f uefi-disk.vdi
fi
VBoxManage createvm --name "${VM_NAME}" --ostype "Other_64" --register
VBoxManage modifyvm "${VM_NAME}" \
--memory 512 \
--vram 16 \
--cpus 1 \
--firmware efi \
--boot1 disk \
--boot2 none \
--boot3 none \
--boot4 none \
--graphicscontroller vmsvga \
--mouse usbtablet
VBoxManage storagectl "${VM_NAME}" \
--name "SATA Controller" \
--add sata \
--controller IntelAhci \
--portcount 1 \
--bootable on
VBoxManage convertfromraw ${DISK_IMG} out/test-disk.vdi --format VDI
VBoxManage storageattach "${VM_NAME}" \
--storagectl "SATA Controller" \
--port 0 \
--device 0 \
--type hdd \
--medium out/test-disk.vdi
# Start the VM
VBoxManage startvm "${VM_NAME}"

1
src/scripts/setup_dev.sh Executable file
View File

@@ -0,0 +1 @@
cp ./src/scripts/dev-setup/default.clangd .clangd && sed -i.bak "s|%%workspaceFolder%%|$(pwd)|g" .clangd && rm .clangd.bak

15
src/system/README.md Normal file
View File

@@ -0,0 +1,15 @@
# lints-system
To install dependencies:
```bash
bun install
```
To run:
```bash
bun run src/index.ts
```
This project was created using `bun init` in bun v1.2.20. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.

View File

@@ -2,7 +2,7 @@
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "os",
"name": "lints-system",
"devDependencies": {
"@types/bun": "latest",
},
@@ -12,15 +12,11 @@
},
},
"packages": {
"@types/bun": ["@types/bun@1.3.2", "", { "dependencies": { "bun-types": "1.3.2" } }, "sha512-t15P7k5UIgHKkxwnMNkJbWlh/617rkDGEdSsDbu+qNHTaz9SKf7aC8fiIlUdD5RPpH6GEkP0cK7WlvmrEBRtWg=="],
"@types/bun": ["@types/bun@1.3.3", "", { "dependencies": { "bun-types": "1.3.3" } }, "sha512-ogrKbJ2X5N0kWLLFKeytG0eHDleBYtngtlbu9cyBKFtNL3cnpDZkNdQj8flVf6WTZUX5ulI9AY1oa7ljhSrp+g=="],
"@types/node": ["@types/node@24.10.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ=="],
"@types/react": ["@types/react@19.2.6", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-p/jUvulfgU7oKtj6Xpk8cA2Y1xKTtICGpJYeJXz2YVO2UcvjQgeRMLDGfDeqeRW2Ta+0QNFwcc8X3GH8SxZz6w=="],
"bun-types": ["bun-types@1.3.2", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-i/Gln4tbzKNuxP70OWhJRZz1MRfvqExowP7U6JKoI8cntFrtxg7RJK3jvz7wQW54UuvNC8tbKHHri5fy74FVqg=="],
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
"bun-types": ["bun-types@1.3.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-z3Xwlg7j2l9JY27x5Qn3Wlyos8YAp0kKRlrePAOjgjMGS5IG6E7Jnlx736vH9UVI4wUICwwhC9anYL++XeOgTQ=="],
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],

View File

@@ -1,12 +1,12 @@
{
"name": "os",
"module": "index.ts",
"name": "lints-system",
"module": "src/index.ts",
"type": "module",
"private": true,
"devDependencies": {
"@types/bun": "latest"
},
"peerDependencies": {
"typescript": "^5"
}
},
"private": true
}

10
src/system/src/__.ts Normal file
View File

@@ -0,0 +1,10 @@
// DO NOT EDIT, REMOVE OR IMPORT THIS FILE
// This is used for bundler to not remove the KEntry function (called by C code)
// The function will be removed after bundling
import { KEntry } from "./entry";
declare function ___remove_next_line(): void;
// Mark the KEntry for removal
___remove_next_line();
KEntry();

5
src/system/src/entry.ts Normal file
View File

@@ -0,0 +1,5 @@
import { KMain } from "./kernel";
export function KEntry() {
KMain();
}

View File

@@ -0,0 +1,93 @@
import { Logger } from "../../../lib/logger";
import { numtohex } from "../../../util/hex";
import { SysFS } from "../../filesystem/sys.fs";
import { KernelDriver } from "../kdriver";
export class PCIKDriver extends KernelDriver {
static instance: PCIKDriver = new this();
constructor() {
super("pci");
}
static init() {
PCIKDriver.instance.init();
}
override init() {
super.init();
SysFS.instance.pMkdir("/pci");
this.#detectDevices();
}
#detectDevices() {
Logger.log("[PCI] Scanning...");
for (let bus = 0; bus < 256; bus++) {
for (let device = 0; device < 32; device++) {
this.#checkDevice(bus, device, 0);
const headerType = this.#getHeaderType(bus, device, 0);
if ((headerType & 0x80) === 0) continue;
for (let func = 1; func < 8; func++) {
this.#checkDevice(bus, device, func);
}
}
}
}
#checkDevice(bus: number, device: number, func: number) {
const data = this.#readConfig(bus, device, func, 0);
if (data === 0 || data === 0xffffffff) return;
const vendorId = this.#getDeviceVendorId(bus, device, func);
const deviceId = this.#getDeviceId(bus, device, func);
const classId = this.#getDeviceClass(bus, device, func);
const subclassId = this.#getDeviceSubclass(bus, device, func);
const filename = `pci.${bus}.${device}.${func}`;
Logger.log(
`[PCI] Found device: ${filename} (vendor: ${numtohex(
vendorId
)}, device: ${numtohex(deviceId)}, class: ${numtohex(
classId
)}, subclass: ${numtohex(subclassId)})`
);
SysFS.instance.pMkdir(`/pci/${filename}`);
SysFS.instance.pWriteFile(`/pci/${filename}/vendor`, numtohex(vendorId));
SysFS.instance.pWriteFile(`/pci/${filename}/device`, numtohex(deviceId));
SysFS.instance.pWriteFile(`/pci/${filename}/class`, numtohex(classId));
SysFS.instance.pWriteFile(
`/pci/${filename}/subclass`,
numtohex(subclassId)
);
}
#getDeviceId(bus: number, device: number, func: number) {
return this.#readConfig(bus, device, func, 0) >>> 16;
}
#getDeviceVendorId(bus: number, device: number, func: number) {
return this.#readConfig(bus, device, func, 0) & 0xffff;
}
#getDeviceClass(bus: number, device: number, func: number) {
return (this.#readConfig(bus, device, func, 8) >> 24) & 0xff;
}
#getDeviceSubclass(bus: number, device: number, func: number) {
return (this.#readConfig(bus, device, func, 8) >> 16) & 0xff;
}
#getHeaderType(bus: number, device: number, func: number) {
return (this.#readConfig(bus, device, func, 12) >> 16) & 0xff;
}
#readConfig(bus: number, device: number, func: number, offset: number) {
return kc.pciReadDword((bus << 16) | (device << 11) | (func << 8) | offset);
}
}

View File

@@ -0,0 +1,20 @@
import { Logger } from "../../lib/logger";
export class KernelDriver {
#name: string;
#initialized: boolean = false;
constructor(name: string) {
this.#name = name;
}
init() {
Logger.log(`[Kernel] Initializing ${this.#name} driver...`);
this.#initialized = true;
}
get initialized() {
return this.#initialized;
}
}

View File

@@ -0,0 +1,51 @@
export class FSEntity {
#name: string;
#path: string;
#size: number;
#type: "d" | "f";
#content: string | string[] | FSEntity[];
constructor(
name: string,
path: string,
size: number,
type: "d" | "f",
content: string | string[] | FSEntity[]
) {
this.#name = name;
this.#path = path;
this.#size = size;
this.#type = type;
this.#content = content;
}
get name() {
return this.#name;
}
get path() {
return this.#path;
}
get size() {
return this.#size;
}
get type() {
return this.#type;
}
get content() {
return this.#content;
}
set content(content: string | string[] | FSEntity[]) {
this.#content = content;
this.#size =
this.#type == "d"
? 0
: content instanceof Array
? this.#content.length
: this.#content.length;
}
}

View File

@@ -0,0 +1,61 @@
import { Logger } from "../../../lib/logger";
import { FSEntity } from "./entity";
export class FileSystem {
#id: string;
#root: FSEntity;
constructor(id: string) {
this.#id = id;
this.#root = new FSEntity("", "/", 0, "d", []);
}
get id() {
return this.#id;
}
protected getEntity(path: string) {
if (path === "/") return this.#root;
const parts = path.split("/");
let entity = this.#root;
for (let i = 1; i < parts.length; i++) {
if (!entity.content || entity.content.length === 0) return null;
if (entity.type !== "d") return null;
entity = (entity.content as FSEntity[]).find((e) => e.name === parts[i])!;
}
return entity;
}
mkdir(path: string) {
throw new Error("FS::Mkdir Not implemented");
}
ls(path: string) {
throw new Error("FS::Ls Not implemented");
}
readFile(path: string) {
throw new Error("FS::ReadFile Not implemented");
}
writeFile(path: string, content: string) {
throw new Error("FS::WriteFile Not implemented");
}
createFile(path: string) {
throw new Error("FS::CreateFile Not implemented");
}
remove(path: string) {
throw new Error("FS::Remove Not implemented");
}
stat(path: string) {
throw new Error("FS::Stat Not implemented");
}
}

View File

@@ -0,0 +1,75 @@
import { Logger } from "../../lib/logger";
import { Path } from "../../lib/path";
import { FSEntity } from "./fs/entity";
import { FileSystem } from "./fs/fs";
export class SysFS extends FileSystem {
static instance: SysFS = new this();
constructor() {
super("sysfs");
}
override mkdir(path: string): void {
throw new Error("SysFS::Mkdir sysfs is read-only");
}
public pMkdir(path: string): void {
const parent = this.getEntity(Path.dirname(path));
if (!parent || parent.type !== "d") return;
(parent.content as FSEntity[]).push(
new FSEntity(Path.filename(path), path, 0, "d", [])
);
}
public pWriteFile(path: string, content: string): void {
const parent = this.getEntity(Path.dirname(path));
if (!parent || parent.type !== "d") return;
const existing = (parent.content as FSEntity[]).find(
(e) => e.name === Path.filename(path)
);
if (existing) {
existing.content = content;
return;
}
(parent.content as FSEntity[]).push(
new FSEntity(Path.filename(path), path, content.length, "f", content)
);
}
override ls(path: string): FSEntity[] {
const entity = this.getEntity(path);
if (!entity || entity.type !== "d") return [];
return entity.content as FSEntity[];
}
override createFile(path: string): void {
throw new Error("SysFS::CreateFile sysfs is read-only");
}
override writeFile(path: string, content: string): void {
throw new Error("SysFS::WriteFile sysfs is read-only");
}
override readFile(path: string): string {
const entity = this.getEntity(path);
if (!entity || entity.type !== "f") return "";
return entity.content as string;
}
override remove(path: string): void {
throw new Error("SysFS::Remove sysfs is read-only");
}
override stat(path: string): FSEntity | null {
const entity = this.getEntity(path);
if (!entity) return null;
return entity;
}
}

View File

@@ -0,0 +1,17 @@
import { Logger } from "../lib/logger";
import { SysFS } from "./filesystem/sys.fs";
import { ConsoleKModule } from "./modules/console/console.kmod";
import { DriverKModule } from "./modules/driver";
import { VFSKModule } from "./modules/vfs/vfs.kmod";
export function KMain() {
Logger.clear();
Logger.log("[Kernel] Initializing kernel...");
ConsoleKModule.init();
VFSKModule.init();
VFSKModule.instance.mount(SysFS.instance, "/sys");
DriverKModule.init();
}

View File

@@ -0,0 +1,25 @@
import { KernelModule } from "../kmod";
export class ConsoleKModule extends KernelModule {
static instance: ConsoleKModule = new this();
constructor() {
super("console");
}
static init() {
ConsoleKModule.instance.init();
}
println(msg: string) {
if (!this.initialized) return;
kc.println(msg);
}
clear() {
if (!this.initialized) return;
kc.clearScreen();
}
}

View File

@@ -0,0 +1,25 @@
import { PCIKDriver } from "../drivers/dev/pci.drv";
import type { KernelDriver } from "../drivers/kdriver";
import { KernelModule } from "./kmod";
export const DRIVERS: KernelDriver[] = [PCIKDriver.instance];
export class DriverKModule extends KernelModule {
static instance: DriverKModule = new this();
constructor() {
super("driver");
}
static init() {
DriverKModule.instance.init();
}
override init() {
super.init();
for (const driver of DRIVERS) {
driver.init();
}
}
}

View File

@@ -0,0 +1,20 @@
import { Logger } from "../../lib/logger";
export class KernelModule {
#name: string;
#initialized: boolean = false;
constructor(name: string) {
this.#name = name;
}
init() {
Logger.log(`[Kernel] Initializing ${this.#name} module...`);
this.#initialized = true;
}
get initialized() {
return this.#initialized;
}
}

View File

@@ -0,0 +1,89 @@
import { Logger } from "../../../lib/logger";
import type { FileSystem } from "../../filesystem/fs/fs";
import { KernelModule } from "../kmod";
export class VFSKModule extends KernelModule {
static instance: VFSKModule = new this();
#mounts: Map<string, FileSystem> = new Map();
constructor() {
super("vfs");
}
static init() {
VFSKModule.instance.init();
}
mount(fs: FileSystem, mountPoint: string) {
if (!this.initialized) return;
Logger.log(`[VFS] Mounting ${fs.id} at ${mountPoint}`);
this.#mounts.set(mountPoint, fs);
}
#resolveMount(path: string) {
const parts = path.split("/");
for (let i = 0; i < parts.length; i++) {
const mountPoint = parts.slice(0, i + 1).join("/");
if (this.#mounts.has(mountPoint))
return {
fs: this.#mounts.get(mountPoint)!,
path: parts.slice(i + 1).join("/"),
};
}
return null;
}
mkdir(path: string) {
const mount = this.#resolveMount(path);
if (!mount) return;
mount.fs.mkdir(mount.path);
}
ls(path: string) {
const mount = this.#resolveMount(path);
if (!mount) return;
return mount.fs.ls(mount.path);
}
createFile(path: string) {
const mount = this.#resolveMount(path);
if (!mount) return;
mount.fs.createFile(mount.path);
}
writeFile(path: string, content: string) {
const mount = this.#resolveMount(path);
if (!mount) return;
mount.fs.writeFile(mount.path, content);
}
readFile(path: string) {
const mount = this.#resolveMount(path);
if (!mount) return;
return mount.fs.readFile(mount.path);
}
remove(path: string) {
const mount = this.#resolveMount(path);
if (!mount) return;
mount.fs.remove(mount.path);
}
stat(path: string) {
const mount = this.#resolveMount(path);
if (!mount) return;
return mount.fs.stat(mount.path);
}
}

View File

@@ -0,0 +1,25 @@
import { ConsoleKModule } from "../kernel/modules/console/console.kmod";
export class Logger {
static log(msg: string) {
if (!ConsoleKModule.instance.initialized)
return Logger.fallbackConsolePrintln(msg);
ConsoleKModule.instance.println(msg);
}
static clear() {
if (!ConsoleKModule.instance.initialized)
return Logger.fallbackConsoleClearScreen();
ConsoleKModule.instance.clear();
}
static fallbackConsolePrintln(msg: string) {
kc.println(msg);
}
static fallbackConsoleClearScreen() {
kc.clearScreen();
}
}

View File

@@ -0,0 +1,13 @@
export class Path {
static dirname(path: string) {
return path.split("/").slice(0, -1).join("/");
}
static filename(path: string) {
return path.split("/").pop()!;
}
static join(...paths: string[]) {
return paths.join("/");
}
}

5
src/system/src/types/kc.d.ts vendored Normal file
View File

@@ -0,0 +1,5 @@
declare namespace kc {
function println(msg: string): void;
function clearScreen(): void;
function pciReadDword(addr: number): number;
}

View File

@@ -0,0 +1,3 @@
export function numtohex(num: number) {
return num.toString(16);
}