Compare commits
28 Commits
2d52c45915
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| f6b4039348 | |||
| 8761d6867c | |||
|
|
f2b5e17856 | ||
| c289ac6f38 | |||
| 868b5700cd | |||
| 092781ba57 | |||
| 7defc557b2 | |||
| e4b18fc8d7 | |||
| 19e034a982 | |||
| 4b4c3022eb | |||
| e3dce14c64 | |||
| 35b16bfc49 | |||
| 3f0b94d2fc | |||
| f483a34d3c | |||
| af5d8c709b | |||
| b7f619b8c3 | |||
| 12c109a120 | |||
| c222cae16f | |||
| e2184bdc27 | |||
| 5b8804621c | |||
| aea99102cc | |||
| 1775af99b0 | |||
| 6f303bf656 | |||
| 4bf79e358a | |||
| 29a5cacdea | |||
| 34fc6e8d3a | |||
| 304dda0adf | |||
| 18092face9 |
11
.gitignore
vendored
11
.gitignore
vendored
@@ -1,5 +1,6 @@
|
||||
_o/
|
||||
build/
|
||||
picolibc/
|
||||
picolibc-install/
|
||||
/lib/
|
||||
old/
|
||||
out/
|
||||
node_modules/
|
||||
*.iso
|
||||
*.img
|
||||
.clangd
|
||||
2
LICENSE
2
LICENSE
@@ -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.
|
||||
26
README.md
26
README.md
@@ -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
17
bun.lock
Normal 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=="],
|
||||
}
|
||||
}
|
||||
@@ -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
5
package.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"sailet": "^0.1.1"
|
||||
}
|
||||
}
|
||||
@@ -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
18
sailet.config.ts
Normal 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`)]),
|
||||
]);
|
||||
@@ -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 ""
|
||||
@@ -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"
|
||||
@@ -1,2 +0,0 @@
|
||||
docker build -t lints-dev -f docker/Dockerfile .
|
||||
docker run -it --rm -v "$(pwd)":/workspace -w /workspace lints-dev
|
||||
@@ -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("`", "'")
|
||||
);
|
||||
@@ -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()
|
||||
@@ -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."
|
||||
@@ -1,3 +0,0 @@
|
||||
./scripts/build.sh
|
||||
|
||||
qemu-system-i386 -serial stdio -kernel "build/out/kernel"
|
||||
@@ -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
9
src/core/compat/assert.h
Normal 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
0
src/core/compat/ctype.h
Normal file
0
src/core/compat/fenv.h
Normal file
0
src/core/compat/fenv.h
Normal file
27
src/core/compat/inttypes.h
Normal file
27
src/core/compat/inttypes.h
Normal 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
195
src/core/compat/main.c
Normal 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
51
src/core/compat/math.h
Normal 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
768
src/core/compat/minilibc.c
Normal 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
18
src/core/compat/setjmp.h
Normal 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
12
src/core/compat/stdarg.h
Normal 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
23
src/core/compat/stdio.h
Normal 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
20
src/core/compat/stdlib.h
Normal 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
29
src/core/compat/string.h
Normal 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
|
||||
24
src/core/compat/sys/time.h
Normal file
24
src/core/compat/sys/time.h
Normal 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
31
src/core/compat/time.h
Normal 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
184
src/core/efi.h
Normal 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
231
src/core/main.c
Normal 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
32
src/core/util.c
Normal 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
13
src/core/util.h
Normal 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
|
||||
@@ -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
1
src/lib/quickjs
Submodule
Submodule src/lib/quickjs added at 177e1b32a4
@@ -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 */
|
||||
40
src/link.ld
40
src/link.ld
@@ -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 = .;
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
);
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export * from "./time"
|
||||
@@ -1,2 +0,0 @@
|
||||
export const CFG_KMOD_BIOS_TIME_CMOS_ADDR = 0x70;
|
||||
export const CFG_KMOD_BIOS_TIME_CMOS_DATA_ADDR = 0x71;
|
||||
@@ -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"
|
||||
);
|
||||
}
|
||||
@@ -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]!();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
@@ -1 +0,0 @@
|
||||
export * from "./vga";
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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"));
|
||||
},
|
||||
};
|
||||
@@ -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;
|
||||
},
|
||||
};
|
||||
@@ -1,3 +0,0 @@
|
||||
export function charc(char: string): number {
|
||||
return char.charCodeAt(0);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
export function dwordin(dw: number): number {
|
||||
return $dwordin(dw);
|
||||
}
|
||||
|
||||
export function dwordout(dw: number, value: number): void {
|
||||
$dwordout(dw, value);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
export function portin(port: number): number {
|
||||
return $ptin(port);
|
||||
}
|
||||
|
||||
export function portout(port: number, value: number): void {
|
||||
$ptout(port, value);
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
export function padStart(
|
||||
str: string,
|
||||
targetLength: number,
|
||||
padString: string
|
||||
): string {
|
||||
while (str.length < targetLength) {
|
||||
str = padString + str;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
console.log("TS-DOS Program Started");
|
||||
5
src/os/src/types/c/bindings.d.ts
vendored
5
src/os/src/types/c/bindings.d.ts
vendored
@@ -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;
|
||||
@@ -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,
|
||||
}
|
||||
@@ -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
150
src/scripts/build_core.sh
Executable 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
13
src/scripts/build_iso.sh
Executable 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
7
src/scripts/build_system.sh
Executable 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
|
||||
6
src/scripts/dev-setup/default.clangd
Normal file
6
src/scripts/dev-setup/default.clangd
Normal 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
28
src/scripts/embed_system.sh
Executable 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
5
src/scripts/prepare_build.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
rm -rf out
|
||||
|
||||
49
src/scripts/run_vbox.sh
Executable file
49
src/scripts/run_vbox.sh
Executable 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
1
src/scripts/setup_dev.sh
Executable 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
15
src/system/README.md
Normal 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.
|
||||
@@ -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=="],
|
||||
|
||||
@@ -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
10
src/system/src/__.ts
Normal 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
5
src/system/src/entry.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { KMain } from "./kernel";
|
||||
|
||||
export function KEntry() {
|
||||
KMain();
|
||||
}
|
||||
93
src/system/src/kernel/drivers/dev/pci.drv.ts
Normal file
93
src/system/src/kernel/drivers/dev/pci.drv.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
20
src/system/src/kernel/drivers/kdriver.ts
Normal file
20
src/system/src/kernel/drivers/kdriver.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
51
src/system/src/kernel/filesystem/fs/entity.ts
Normal file
51
src/system/src/kernel/filesystem/fs/entity.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
61
src/system/src/kernel/filesystem/fs/fs.ts
Normal file
61
src/system/src/kernel/filesystem/fs/fs.ts
Normal 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");
|
||||
}
|
||||
}
|
||||
75
src/system/src/kernel/filesystem/sys.fs.ts
Normal file
75
src/system/src/kernel/filesystem/sys.fs.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
17
src/system/src/kernel/index.ts
Normal file
17
src/system/src/kernel/index.ts
Normal 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();
|
||||
}
|
||||
25
src/system/src/kernel/modules/console/console.kmod.ts
Normal file
25
src/system/src/kernel/modules/console/console.kmod.ts
Normal 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();
|
||||
}
|
||||
}
|
||||
25
src/system/src/kernel/modules/driver.ts
Normal file
25
src/system/src/kernel/modules/driver.ts
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
20
src/system/src/kernel/modules/kmod.ts
Normal file
20
src/system/src/kernel/modules/kmod.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
89
src/system/src/kernel/modules/vfs/vfs.kmod.ts
Normal file
89
src/system/src/kernel/modules/vfs/vfs.kmod.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
25
src/system/src/lib/logger.ts
Normal file
25
src/system/src/lib/logger.ts
Normal 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();
|
||||
}
|
||||
}
|
||||
13
src/system/src/lib/path.ts
Normal file
13
src/system/src/lib/path.ts
Normal 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
5
src/system/src/types/kc.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
declare namespace kc {
|
||||
function println(msg: string): void;
|
||||
function clearScreen(): void;
|
||||
function pciReadDword(addr: number): number;
|
||||
}
|
||||
3
src/system/src/util/hex.ts
Normal file
3
src/system/src/util/hex.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export function numtohex(num: number) {
|
||||
return num.toString(16);
|
||||
}
|
||||
Reference in New Issue
Block a user