Compare commits

...

18 Commits

Author SHA1 Message Date
f6b4039348 Add dynamic heap size allocation 2025-12-04 20:59:26 +01:00
8761d6867c Add dev env setup 2025-12-04 20:55:27 +01:00
Martin Petr
f2b5e17856 Merge pull request #1 from MartinGamesCZ/dev-efi-port
Switch to EFI version
2025-12-04 19:07:03 +01:00
c289ac6f38 Add readme and license 2025-12-04 19:04:29 +01:00
868b5700cd Remove unused lib 2025-12-04 17:11:24 +01:00
092781ba57 Extend PCI driver 2025-12-03 21:31:39 +01:00
7defc557b2 Add PCI driver 2025-12-03 21:17:23 +01:00
e4b18fc8d7 Implement sysfs 2025-12-03 20:41:52 +01:00
19e034a982 Add console module 2025-12-03 20:05:06 +01:00
4b4c3022eb Change entrypoint function 2025-12-03 18:56:16 +01:00
e3dce14c64 Add TS code embedding 2025-12-03 18:32:35 +01:00
35b16bfc49 Add basic print program 2025-12-02 22:38:22 +01:00
3f0b94d2fc Add failed try 2025-12-02 19:17:05 +01:00
f483a34d3c Add PCI driver 2025-11-30 10:47:59 +01:00
af5d8c709b Add typescript kernel loader 2025-11-29 23:14:51 +01:00
b7f619b8c3 Remove gitea action 2025-11-29 22:31:30 +01:00
12c109a120 Add gitea build action
Some checks failed
Build ISO and Upload Artifact / build-and-upload (push) Failing after 27s
2025-11-29 20:06:04 +01:00
c222cae16f Make EFI port primary 2025-11-29 20:00:51 +01:00
152 changed files with 2543 additions and 126787 deletions

9
.gitignore vendored
View File

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

View File

@@ -2,7 +2,7 @@
## What the hell is this? ## 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? ## Why?
@@ -16,10 +16,30 @@ Lints is an experimental operating system kernel written almost entirely in Type
Please don't. 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 ```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... ## If you are an employer looking at this...

17
bun.lock Normal file
View File

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

View File

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

1
efi-port/.gitignore vendored
View File

@@ -1 +0,0 @@
out/

View File

@@ -1,29 +0,0 @@
#ifndef COMPAT_MATH_H
#define COMPAT_MATH_H
#define HUGE_VAL (__builtin_huge_val())
#define NAN (__builtin_nan(""))
#define INFINITY (__builtin_inf())
double fabs(double x);
double floor(double x);
double ceil(double x);
double fmod(double x, double y);
double pow(double x, double y);
double sqrt(double x);
double sin(double x);
double cos(double x);
double tan(double x);
double asin(double x);
double acos(double x);
double atan(double x);
double atan2(double y, double x);
double exp(double x);
double log(double x);
double log10(double x);
double cbrt(double x);
double log2(double x);
double trunc(double x);
#endif

View File

@@ -1,9 +0,0 @@
#ifndef COMPAT_SETJMP_H
#define COMPAT_SETJMP_H
typedef void *jmp_buf[5];
#define setjmp(env) __builtin_setjmp(env)
#define longjmp(env, val) __builtin_longjmp(env, val)
#endif

View File

@@ -1,14 +0,0 @@
#ifndef COMPAT_STDARG_H
#define COMPAT_STDARG_H
#ifndef MDE_CPU_X64
#define MDE_CPU_X64
#endif
#include <Base.h>
#include_next <stdarg.h>
#ifndef va_copy
#define va_copy(dest, src) VA_COPY(dest, src)
#endif
#endif

View File

@@ -1,31 +0,0 @@
#ifndef COMPAT_STDINT_H
#define COMPAT_STDINT_H
#ifndef MDE_CPU_X64
#define MDE_CPU_X64
#endif
#include <Base.h>
#include_next <stdint.h>
typedef int8_t int_least8_t;
typedef uint8_t uint_least8_t;
typedef int16_t int_least16_t;
typedef uint16_t uint_least16_t;
typedef int32_t int_least32_t;
typedef uint32_t uint_least32_t;
typedef int64_t int_least64_t;
typedef uint64_t uint_least64_t;
typedef int8_t int_fast8_t;
typedef uint8_t uint_fast8_t;
typedef int16_t int_fast16_t;
typedef uint16_t uint_fast16_t;
typedef int32_t int_fast32_t;
typedef uint32_t uint_fast32_t;
typedef int64_t int_fast64_t;
typedef uint64_t uint_fast64_t;
typedef int64_t intmax_t;
typedef uint64_t uintmax_t;
#endif

View File

@@ -1,14 +0,0 @@
#ifndef COMPAT_STDIO_H
#define COMPAT_STDIO_H
#ifndef MDE_CPU_X64
#define MDE_CPU_X64
#endif
#include <Base.h>
#include_next <stdio.h>
#include <stdarg.h>
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
int snprintf(char *str, size_t size, const char *format, ...);
#endif

View File

@@ -1,13 +0,0 @@
#ifndef COMPAT_TIME_H
#define COMPAT_TIME_H
#ifndef MDE_CPU_X64
#define MDE_CPU_X64
#endif
#include <Base.h>
#include_next <time.h>
double difftime(time_t time1, time_t time0);
#endif

View File

@@ -1,12 +0,0 @@
/* Dummy windows.h for Duktape compatibility in EFI */
#ifndef WINDOWS_H
#define WINDOWS_H
#ifndef MDE_CPU_X64
#define MDE_CPU_X64
#endif
#include <Uefi.h>
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,996 +0,0 @@
{
"type": "duk_source_meta",
"comment": "Metadata for prepared Duktape sources and configuration",
"git_commit": "b5d069a96ba0989c444dad8e6f002a0a057b4df0",
"git_branch": "master",
"git_describe": "v2.5.0-393-gb5d069a9",
"duk_version": 29999,
"duk_version_string": "2.99.99",
"line_map": [
{
"original_file": "duk_unicode_tables.c",
"original_line": 1,
"combined_line": 159
},
{
"original_file": "duk_internal.h",
"original_line": 1,
"combined_line": 164
},
{
"original_file": "duk_dblunion.h",
"original_line": 1,
"combined_line": 201
},
{
"original_file": "duk_fltunion.h",
"original_line": 1,
"combined_line": 621
},
{
"original_file": "duk_replacements.h",
"original_line": 1,
"combined_line": 661
},
{
"original_file": "duk_jmpbuf.h",
"original_line": 1,
"combined_line": 691
},
{
"original_file": "duk_exception.h",
"original_line": 1,
"combined_line": 716
},
{
"original_file": "duk_forwdecl.h",
"original_line": 1,
"combined_line": 748
},
{
"original_file": "duk_tval.h",
"original_line": 1,
"combined_line": 881
},
{
"original_file": "duk_builtins.h",
"original_line": 1,
"combined_line": 1582
},
{
"original_file": "duk_internal.h",
"original_line": 45,
"combined_line": 3156
},
{
"original_file": "duk_util.h",
"original_line": 1,
"combined_line": 3158
},
{
"original_file": "duk_strings.h",
"original_line": 1,
"combined_line": 3954
},
{
"original_file": "duk_js_bytecode.h",
"original_line": 1,
"combined_line": 4130
},
{
"original_file": "duk_lexer.h",
"original_line": 1,
"combined_line": 4604
},
{
"original_file": "duk_js_compiler.h",
"original_line": 1,
"combined_line": 5040
},
{
"original_file": "duk_regexp.h",
"original_line": 1,
"combined_line": 5273
},
{
"original_file": "duk_heaphdr.h",
"original_line": 1,
"combined_line": 5362
},
{
"original_file": "duk_refcount.h",
"original_line": 1,
"combined_line": 5848
},
{
"original_file": "duk_api_internal.h",
"original_line": 1,
"combined_line": 6897
},
{
"original_file": "duk_hstring.h",
"original_line": 1,
"combined_line": 7337
},
{
"original_file": "duk_hobject.h",
"original_line": 1,
"combined_line": 7536
},
{
"original_file": "duk_hcompfunc.h",
"original_line": 1,
"combined_line": 8163
},
{
"original_file": "duk_hnatfunc.h",
"original_line": 1,
"combined_line": 8423
},
{
"original_file": "duk_hboundfunc.h",
"original_line": 1,
"combined_line": 8468
},
{
"original_file": "duk_hbufobj.h",
"original_line": 1,
"combined_line": 8511
},
{
"original_file": "duk_hthread.h",
"original_line": 1,
"combined_line": 8657
},
{
"original_file": "duk_harray.h",
"original_line": 1,
"combined_line": 9075
},
{
"original_file": "duk_henv.h",
"original_line": 1,
"combined_line": 9187
},
{
"original_file": "duk_hbuffer.h",
"original_line": 1,
"combined_line": 9243
},
{
"original_file": "duk_hproxy.h",
"original_line": 1,
"combined_line": 9591
},
{
"original_file": "duk_heap.h",
"original_line": 1,
"combined_line": 9623
},
{
"original_file": "duk_debugger.h",
"original_line": 1,
"combined_line": 10385
},
{
"original_file": "duk_debug.h",
"original_line": 1,
"combined_line": 10537
},
{
"original_file": "duk_error.h",
"original_line": 1,
"combined_line": 10734
},
{
"original_file": "duk_unicode.h",
"original_line": 1,
"combined_line": 11456
},
{
"original_file": "duk_unicode_ids_noa.h",
"original_line": 1,
"combined_line": 11640
},
{
"original_file": "duk_unicode.h",
"original_line": 185,
"combined_line": 11643
},
{
"original_file": "duk_unicode_ids_noabmp.h",
"original_line": 1,
"combined_line": 11645
},
{
"original_file": "duk_unicode.h",
"original_line": 187,
"combined_line": 11648
},
{
"original_file": "duk_unicode_ids_m_let_noa.h",
"original_line": 1,
"combined_line": 11652
},
{
"original_file": "duk_unicode.h",
"original_line": 191,
"combined_line": 11655
},
{
"original_file": "duk_unicode_ids_m_let_noabmp.h",
"original_line": 1,
"combined_line": 11657
},
{
"original_file": "duk_unicode.h",
"original_line": 193,
"combined_line": 11660
},
{
"original_file": "duk_unicode_idp_m_ids_noa.h",
"original_line": 1,
"combined_line": 11664
},
{
"original_file": "duk_unicode.h",
"original_line": 197,
"combined_line": 11667
},
{
"original_file": "duk_unicode_idp_m_ids_noabmp.h",
"original_line": 1,
"combined_line": 11669
},
{
"original_file": "duk_unicode.h",
"original_line": 199,
"combined_line": 11672
},
{
"original_file": "duk_unicode_caseconv.h",
"original_line": 1,
"combined_line": 11675
},
{
"original_file": "duk_unicode.h",
"original_line": 202,
"combined_line": 11679
},
{
"original_file": "duk_unicode_re_canon_lookup.h",
"original_line": 1,
"combined_line": 11682
},
{
"original_file": "duk_unicode.h",
"original_line": 205,
"combined_line": 11685
},
{
"original_file": "duk_unicode_re_canon_bitmap.h",
"original_line": 1,
"combined_line": 11689
},
{
"original_file": "duk_unicode.h",
"original_line": 209,
"combined_line": 11695
},
{
"original_file": "duk_json.h",
"original_line": 1,
"combined_line": 11783
},
{
"original_file": "duk_js.h",
"original_line": 1,
"combined_line": 11852
},
{
"original_file": "duk_numconv.h",
"original_line": 1,
"combined_line": 11999
},
{
"original_file": "duk_bi_protos.h",
"original_line": 1,
"combined_line": 12107
},
{
"original_file": "duk_selftest.h",
"original_line": 1,
"combined_line": 12185
},
{
"original_file": "duk_prop.h",
"original_line": 1,
"combined_line": 12201
},
{
"original_file": "duk_internal.h",
"original_line": 77,
"combined_line": 12298
},
{
"original_file": "duk_unicode_tables.c",
"original_line": 6,
"combined_line": 12300
},
{
"original_file": "duk_unicode_ids_noa.c",
"original_line": 1,
"combined_line": 12317
},
{
"original_file": "duk_unicode_tables.c",
"original_line": 23,
"combined_line": 12369
},
{
"original_file": "duk_unicode_ids_noabmp.c",
"original_line": 1,
"combined_line": 12373
},
{
"original_file": "duk_unicode_tables.c",
"original_line": 27,
"combined_line": 12403
},
{
"original_file": "duk_unicode_ids_m_let_noa.c",
"original_line": 1,
"combined_line": 12409
},
{
"original_file": "duk_unicode_tables.c",
"original_line": 33,
"combined_line": 12413
},
{
"original_file": "duk_unicode_ids_m_let_noabmp.c",
"original_line": 1,
"combined_line": 12417
},
{
"original_file": "duk_unicode_tables.c",
"original_line": 37,
"combined_line": 12421
},
{
"original_file": "duk_unicode_idp_m_ids_noa.c",
"original_line": 1,
"combined_line": 12427
},
{
"original_file": "duk_unicode_tables.c",
"original_line": 43,
"combined_line": 12457
},
{
"original_file": "duk_unicode_idp_m_ids_noabmp.c",
"original_line": 1,
"combined_line": 12461
},
{
"original_file": "duk_unicode_tables.c",
"original_line": 47,
"combined_line": 12480
},
{
"original_file": "duk_unicode_caseconv.c",
"original_line": 1,
"combined_line": 12490
},
{
"original_file": "duk_unicode_tables.c",
"original_line": 57,
"combined_line": 12595
},
{
"original_file": "duk_unicode_re_canon_lookup.c",
"original_line": 1,
"combined_line": 12598
},
{
"original_file": "duk_unicode_tables.c",
"original_line": 60,
"combined_line": 18426
},
{
"original_file": "duk_unicode_re_canon_bitmap.c",
"original_line": 1,
"combined_line": 18430
},
{
"original_file": "duk_unicode_tables.c",
"original_line": 64,
"combined_line": 18446
},
{
"original_file": "duk_replacements.c",
"original_line": 1,
"combined_line": 18447
},
{
"original_file": "duk_debug_macros.c",
"original_line": 1,
"combined_line": 18529
},
{
"original_file": "duk_builtins.c",
"original_line": 2,
"combined_line": 18621
},
{
"original_file": "duk_error_macros.c",
"original_line": 1,
"combined_line": 23804
},
{
"original_file": "duk_unicode_support.c",
"original_line": 1,
"combined_line": 24000
},
{
"original_file": "duk_util_memrw.c",
"original_line": 1,
"combined_line": 25219
},
{
"original_file": "duk_util_misc.c",
"original_line": 1,
"combined_line": 25367
},
{
"original_file": "duk_hobject_class.c",
"original_line": 1,
"combined_line": 25532
},
{
"original_file": "duk_alloc_default.c",
"original_line": 1,
"combined_line": 25661
},
{
"original_file": "duk_api_buffer.c",
"original_line": 1,
"combined_line": 25693
},
{
"original_file": "duk_api_bytecode.c",
"original_line": 1,
"combined_line": 25766
},
{
"original_file": "duk_api_call.c",
"original_line": 1,
"combined_line": 26546
},
{
"original_file": "duk_api_codec.c",
"original_line": 1,
"combined_line": 27072
},
{
"original_file": "duk_api_compile.c",
"original_line": 1,
"combined_line": 28010
},
{
"original_file": "duk_api_debug.c",
"original_line": 1,
"combined_line": 28185
},
{
"original_file": "duk_api_heap.c",
"original_line": 1,
"combined_line": 28446
},
{
"original_file": "duk_api_inspect.c",
"original_line": 1,
"combined_line": 28655
},
{
"original_file": "duk_api_memory.c",
"original_line": 1,
"combined_line": 28958
},
{
"original_file": "duk_api_object.c",
"original_line": 1,
"combined_line": 29038
},
{
"original_file": "duk_api_random.c",
"original_line": 1,
"combined_line": 30159
},
{
"original_file": "duk_api_readable.c",
"original_line": 2,
"combined_line": 30169
},
{
"original_file": "duk_api_stack.c",
"original_line": 1,
"combined_line": 30525
},
{
"original_file": "duk_api_string.c",
"original_line": 1,
"combined_line": 37426
},
{
"original_file": "duk_api_time.c",
"original_line": 1,
"combined_line": 37817
},
{
"original_file": "duk_bi_array.c",
"original_line": 1,
"combined_line": 37927
},
{
"original_file": "duk_bi_boolean.c",
"original_line": 1,
"combined_line": 39581
},
{
"original_file": "duk_bi_buffer.c",
"original_line": 1,
"combined_line": 39650
},
{
"original_file": "duk_bi_cbor.c",
"original_line": 1,
"combined_line": 42576
},
{
"original_file": "duk_bi_date.c",
"original_line": 1,
"combined_line": 44504
},
{
"original_file": "duk_bi_date_unix.c",
"original_line": 1,
"combined_line": 46402
},
{
"original_file": "duk_bi_date_windows.c",
"original_line": 1,
"combined_line": 46750
},
{
"original_file": "duk_bi_duktape.c",
"original_line": 1,
"combined_line": 46945
},
{
"original_file": "duk_bi_encoding.c",
"original_line": 1,
"combined_line": 47095
},
{
"original_file": "duk_bi_error.c",
"original_line": 1,
"combined_line": 47646
},
{
"original_file": "duk_bi_function.c",
"original_line": 1,
"combined_line": 48046
},
{
"original_file": "duk_bi_global.c",
"original_line": 1,
"combined_line": 48500
},
{
"original_file": "duk_bi_json.c",
"original_line": 1,
"combined_line": 49221
},
{
"original_file": "duk_bi_math.c",
"original_line": 1,
"combined_line": 52561
},
{
"original_file": "duk_bi_number.c",
"original_line": 1,
"combined_line": 53052
},
{
"original_file": "duk_bi_object.c",
"original_line": 1,
"combined_line": 53316
},
{
"original_file": "duk_bi_performance.c",
"original_line": 1,
"combined_line": 54033
},
{
"original_file": "duk_bi_pointer.c",
"original_line": 1,
"combined_line": 54064
},
{
"original_file": "duk_bi_promise.c",
"original_line": 1,
"combined_line": 54138
},
{
"original_file": "duk_bi_proxy.c",
"original_line": 1,
"combined_line": 54182
},
{
"original_file": "duk_bi_reflect.c",
"original_line": 1,
"combined_line": 54233
},
{
"original_file": "duk_bi_regexp.c",
"original_line": 1,
"combined_line": 54321
},
{
"original_file": "duk_bi_string.c",
"original_line": 1,
"combined_line": 54549
},
{
"original_file": "duk_bi_symbol.c",
"original_line": 1,
"combined_line": 56036
},
{
"original_file": "duk_bi_thread.c",
"original_line": 1,
"combined_line": 56208
},
{
"original_file": "duk_bi_thrower.c",
"original_line": 1,
"combined_line": 56532
},
{
"original_file": "duk_debug_fixedbuffer.c",
"original_line": 1,
"combined_line": 56541
},
{
"original_file": "duk_debug_vsnprintf.c",
"original_line": 1,
"combined_line": 56610
},
{
"original_file": "duk_debugger.c",
"original_line": 1,
"combined_line": 57855
},
{
"original_file": "duk_error_augment.c",
"original_line": 1,
"combined_line": 60927
},
{
"original_file": "duk_error_longjmp.c",
"original_line": 1,
"combined_line": 61528
},
{
"original_file": "duk_error_misc.c",
"original_line": 1,
"combined_line": 61635
},
{
"original_file": "duk_error_throw.c",
"original_line": 1,
"combined_line": 61813
},
{
"original_file": "duk_hbuffer_alloc.c",
"original_line": 1,
"combined_line": 61972
},
{
"original_file": "duk_hbuffer_assert.c",
"original_line": 1,
"combined_line": 62106
},
{
"original_file": "duk_hbuffer_ops.c",
"original_line": 1,
"combined_line": 62119
},
{
"original_file": "duk_hbufobj_misc.c",
"original_line": 2,
"combined_line": 62197
},
{
"original_file": "duk_heap_alloc.c",
"original_line": 1,
"combined_line": 62319
},
{
"original_file": "duk_heap_finalize.c",
"original_line": 1,
"combined_line": 63595
},
{
"original_file": "duk_heap_hashstring.c",
"original_line": 1,
"combined_line": 64044
},
{
"original_file": "duk_heap_markandsweep.c",
"original_line": 1,
"combined_line": 64165
},
{
"original_file": "duk_heap_memory.c",
"original_line": 1,
"combined_line": 65771
},
{
"original_file": "duk_heap_misc.c",
"original_line": 1,
"combined_line": 66205
},
{
"original_file": "duk_heap_refcount.c",
"original_line": 1,
"combined_line": 66392
},
{
"original_file": "duk_heap_stringcache.c",
"original_line": 1,
"combined_line": 67364
},
{
"original_file": "duk_heap_stringtable.c",
"original_line": 1,
"combined_line": 67865
},
{
"original_file": "duk_heaphdr_assert.c",
"original_line": 1,
"combined_line": 69108
},
{
"original_file": "duk_hobject_alloc.c",
"original_line": 1,
"combined_line": 69199
},
{
"original_file": "duk_hobject_array.c",
"original_line": 2,
"combined_line": 69479
},
{
"original_file": "duk_hobject_assert.c",
"original_line": 1,
"combined_line": 69758
},
{
"original_file": "duk_hobject_lookup.c",
"original_line": 2,
"combined_line": 69998
},
{
"original_file": "duk_hobject_misc.c",
"original_line": 1,
"combined_line": 70556
},
{
"original_file": "duk_hobject_pc2line.c",
"original_line": 1,
"combined_line": 71019
},
{
"original_file": "duk_hobject_props.c",
"original_line": 1,
"combined_line": 71265
},
{
"original_file": "duk_hobject_proxy.c",
"original_line": 2,
"combined_line": 71721
},
{
"original_file": "duk_hobject_resize.c",
"original_line": 2,
"combined_line": 71885
},
{
"original_file": "duk_hstring_assert.c",
"original_line": 1,
"combined_line": 73228
},
{
"original_file": "duk_hstring_misc.c",
"original_line": 1,
"combined_line": 73250
},
{
"original_file": "duk_hthread_alloc.c",
"original_line": 1,
"combined_line": 73479
},
{
"original_file": "duk_hthread_builtins.c",
"original_line": 1,
"combined_line": 73538
},
{
"original_file": "duk_hthread_misc.c",
"original_line": 1,
"combined_line": 74438
},
{
"original_file": "duk_hthread_stacks.c",
"original_line": 1,
"combined_line": 74535
},
{
"original_file": "duk_js_arith.c",
"original_line": 1,
"combined_line": 74898
},
{
"original_file": "duk_js_call.c",
"original_line": 1,
"combined_line": 75039
},
{
"original_file": "duk_js_compiler.c",
"original_line": 1,
"combined_line": 77862
},
{
"original_file": "duk_js_executor.c",
"original_line": 1,
"combined_line": 86010
},
{
"original_file": "duk_js_ops.c",
"original_line": 1,
"combined_line": 91409
},
{
"original_file": "duk_js_prop.c",
"original_line": 2,
"combined_line": 92848
},
{
"original_file": "duk_js_var.c",
"original_line": 1,
"combined_line": 93095
},
{
"original_file": "duk_lexer.c",
"original_line": 1,
"combined_line": 94829
},
{
"original_file": "duk_numconv.c",
"original_line": 1,
"combined_line": 97281
},
{
"original_file": "duk_prop_defown.c",
"original_line": 1,
"combined_line": 99623
},
{
"original_file": "duk_prop_delete.c",
"original_line": 1,
"combined_line": 101144
},
{
"original_file": "duk_prop_enum.c",
"original_line": 1,
"combined_line": 102280
},
{
"original_file": "duk_prop_get.c",
"original_line": 1,
"combined_line": 102538
},
{
"original_file": "duk_prop_getown.c",
"original_line": 1,
"combined_line": 104476
},
{
"original_file": "duk_prop_has.c",
"original_line": 1,
"combined_line": 105079
},
{
"original_file": "duk_prop_ownpropkeys.c",
"original_line": 1,
"combined_line": 105712
},
{
"original_file": "duk_prop_set.c",
"original_line": 1,
"combined_line": 106347
},
{
"original_file": "duk_prop_util.c",
"original_line": 1,
"combined_line": 109579
},
{
"original_file": "duk_regexp_compiler.c",
"original_line": 1,
"combined_line": 109893
},
{
"original_file": "duk_regexp_executor.c",
"original_line": 1,
"combined_line": 111194
},
{
"original_file": "duk_selftest.c",
"original_line": 1,
"combined_line": 112187
},
{
"original_file": "duk_tval.c",
"original_line": 2,
"combined_line": 112934
},
{
"original_file": "duk_unicode_wtf8.c",
"original_line": 1,
"combined_line": 113085
},
{
"original_file": "duk_util_bitdecoder.c",
"original_line": 1,
"combined_line": 114166
},
{
"original_file": "duk_util_bitencoder.c",
"original_line": 1,
"combined_line": 114330
},
{
"original_file": "duk_util_bufwriter.c",
"original_line": 1,
"combined_line": 114373
},
{
"original_file": "duk_util_cast.c",
"original_line": 1,
"combined_line": 114659
},
{
"original_file": "duk_util_double.c",
"original_line": 1,
"combined_line": 114831
},
{
"original_file": "duk_util_hashbytes.c",
"original_line": 1,
"combined_line": 115174
},
{
"original_file": "duk_util_memory.c",
"original_line": 1,
"combined_line": 115236
},
{
"original_file": "duk_util_tinyrandom.c",
"original_line": 1,
"combined_line": 115272
}
]
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,319 +0,0 @@
#include <Uefi.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/PrintLib.h>
#include <Library/UefiBootServicesTableLib.h>
// EDK2 CRT Support Header
#include <CrtLibSupport.h>
// Global variables required by CrtLibSupport.h
int errno = 0;
FILE *stderr = NULL;
// Better malloc/free with size tracking
typedef struct {
size_t size;
char data[];
} AllocHeader;
void *my_malloc(size_t size) {
AllocHeader *hdr;
if (gBS->AllocatePool(EfiLoaderData, size + sizeof(AllocHeader), (void**)&hdr) != EFI_SUCCESS) {
return NULL;
}
hdr->size = size;
return hdr->data;
}
void my_free(void *ptr) {
if (ptr) {
AllocHeader *hdr = (AllocHeader*)((char*)ptr - sizeof(AllocHeader));
gBS->FreePool(hdr);
}
}
void *my_realloc(void *ptr, size_t size) {
if (!ptr) return my_malloc(size);
if (size == 0) {
my_free(ptr);
return NULL;
}
AllocHeader *old_hdr = (AllocHeader*)((char*)ptr - sizeof(AllocHeader));
size_t old_size = old_hdr->size;
void *new_ptr = my_malloc(size);
if (!new_ptr) return NULL;
CopyMem(new_ptr, ptr, old_size < size ? old_size : size);
my_free(ptr);
return new_ptr;
}
// Redirect standard malloc/free/realloc to our versions
#undef malloc
#undef free
#undef realloc
void *malloc(size_t size) { return my_malloc(size); }
void free(void *ptr) { my_free(ptr); }
void *realloc(void *ptr, size_t size) { return my_realloc(ptr, size); }
void *calloc(size_t nmemb, size_t size) {
size_t total = nmemb * size;
void *ptr = malloc(total);
if (ptr) {
SetMem(ptr, total, 0);
}
return ptr;
}
// IO
int printf(const char *format, ...) {
return 0;
}
int vsnprintf(char *str, size_t size, const char *format, va_list ap) {
return (int)AsciiVSPrint(str, size, format, ap);
}
int snprintf(char *str, size_t size, const char *format, ...) {
VA_LIST Marker;
VA_START(Marker, format);
UINTN Return = AsciiVSPrint(str, size, format, Marker);
VA_END(Marker);
return (int)Return;
}
// sprintf is a macro in CrtLibSupport.h, so we don't define it.
// Math
// Duktape needs math. EDK2 doesn't provide standard math lib.
// We might need to implement simple versions or pull in a math lib.
// For now, stubs.
double floor(double x) { return (double)(int)x; } // Very wrong for negative/large
double ceil(double x) { return (double)(int)x + 1; }
double fabs(double x) { return x < 0 ? -x : x; }
double pow(double x, double y) { return 0; } // TODO
double sqrt(double x) { return 0; }
double sin(double x) { return 0; }
double cos(double x) { return 0; }
double tan(double x) { return 0; }
double asin(double x) { return 0; }
double acos(double x) { return 0; }
double atan(double x) { return 0; }
double atan2(double y, double x) { return 0; }
double exp(double x) { return 0; }
double log(double x) { return 0; }
double log10(double x) { return 0; }
double fmod(double x, double y) { return 0; }
// Other
void abort(void) {
// CpuDeadLoop();
while(1);
}
void exit(int status) {
// CpuDeadLoop();
while(1);
}
// Global gBS
EFI_BOOT_SERVICES *gBS = NULL;
int _fltused = 0;
// Stack probe (needed for MSVC ABI)
void __chkstk(void) { return; }
// Memory functions
#undef memset
#undef memcpy
#undef memcmp
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) {
char *d = dest;
const char *s = src;
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;
}
void *SetMem(void *Buffer, UINTN Length, UINT8 Value) {
return memset(Buffer, Value, Length);
}
void *CopyMem(void *Destination, const void *Source, UINTN Length) {
return memcpy(Destination, Source, Length);
}
INTN CompareMem(const void *Destination, const void *Source, UINTN Length) {
return (INTN)memcmp(Destination, Source, Length);
}
// String functions
UINTN AsciiStrnLenS(const CHAR8 *String, UINTN MaxSize) {
UINTN len = 0;
while (len < MaxSize && String[len] != 0) {
len++;
}
return len;
}
INTN AsciiStrnCmp(const CHAR8 *FirstString, const CHAR8 *SecondString, UINTN Length) {
if (Length == 0) return 0;
while (Length > 0 && *FirstString && *SecondString) {
if (*FirstString != *SecondString) break;
FirstString++;
SecondString++;
Length--;
}
if (Length == 0) return 0;
return *FirstString - *SecondString;
}
int strcmp(const char *s1, const char *s2) {
while (*s1 && (*s1 == *s2)) {
s1++;
s2++;
}
return *(const unsigned char *)s1 - *(const unsigned char *)s2;
}
// Print functions
// Minimal vsnprintf implementation
#include <stdarg.h>
static void simple_append(char **str, size_t *size, char c) {
if (*size > 1) {
**str = c;
(*str)++;
(*size)--;
}
}
static void simple_append_str(char **str, size_t *size, const char *s) {
while (*s) {
simple_append(str, size, *s++);
}
}
static void simple_append_hex(char **str, size_t *size, UINT64 num) {
char buf[17];
const char *digits = "0123456789ABCDEF";
int i = 0;
if (num == 0) {
simple_append(str, size, '0');
return;
}
while (num > 0) {
buf[i++] = digits[num % 16];
num /= 16;
}
while (i > 0) {
simple_append(str, size, buf[--i]);
}
}
static void simple_append_dec(char **str, size_t *size, INT64 num) {
char buf[21];
int i = 0;
int neg = 0;
if (num < 0) {
neg = 1;
num = -num;
}
if (num == 0) {
simple_append(str, size, '0');
return;
}
while (num > 0) {
buf[i++] = (num % 10) + '0';
num /= 10;
}
if (neg) simple_append(str, size, '-');
while (i > 0) {
simple_append(str, size, buf[--i]);
}
}
UINTN AsciiVSPrint(CHAR8 *StartOfBuffer, UINTN BufferSize, CONST CHAR8 *FormatString, VA_LIST Marker) {
char *str = StartOfBuffer;
size_t size = BufferSize;
const char *fmt = FormatString;
while (*fmt) {
if (*fmt == '%') {
fmt++;
if (*fmt == 's') {
char *s = VA_ARG(Marker, char*);
simple_append_str(&str, &size, s ? s : "(null)");
} else if (*fmt == 'd') {
int d = VA_ARG(Marker, int);
simple_append_dec(&str, &size, d);
} else if (*fmt == 'x' || *fmt == 'X') {
unsigned int x = VA_ARG(Marker, unsigned int);
simple_append_hex(&str, &size, x);
} else if (*fmt == 'p') {
void *p = VA_ARG(Marker, void*);
simple_append_hex(&str, &size, (UINT64)p);
} else if (*fmt == '%') {
simple_append(&str, &size, '%');
} else {
simple_append(&str, &size, '%');
simple_append(&str, &size, *fmt);
}
} else {
simple_append(&str, &size, *fmt);
}
fmt++;
}
*str = 0;
return (UINTN)(str - StartOfBuffer);
}
UINTN AsciiSPrint(CHAR8 *StartOfBuffer, UINTN BufferSize, CONST CHAR8 *FormatString, ...) {
VA_LIST Marker;
VA_START(Marker, FormatString);
UINTN ret = AsciiVSPrint(StartOfBuffer, BufferSize, FormatString, Marker);
VA_END(Marker);
return ret;
}
// Time functions
struct tm *gmtime(const time_t *timep) { return NULL; }
time_t mktime(struct tm *tm) { return 0; }
int sscanf(const char *str, const char *format, ...) { return 0; }
time_t time(time_t *tloc) { return 0; }
double difftime(time_t time1, time_t time0) { return (double)(time1 - time0); }
double cbrt(double x) { return 0; }
double log2(double x) { return 0; }
double trunc(double x) { return (double)(int)x; }
// Needed for CrtLibSupport headers to work?
// They use VA_LIST etc which are in Base.h

View File

@@ -1,12 +0,0 @@
#include "efi.h"
#include "main.h"
extern EFI_BOOT_SERVICES *gBS;
EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
gBS = SystemTable->BootServices;
// Initialize standard library (if needed)
// ...
return kernel_main(SystemTable);
}

View File

@@ -1,13 +0,0 @@
#ifndef EFI_H
#define EFI_H
#ifndef MDE_CPU_X64
#define MDE_CPU_X64
#endif
#include <Uefi.h>
// Map legacy names if needed, or update main.c
typedef EFI_SYSTEM_TABLE EfiSystemTable;
#endif

View File

@@ -1,57 +0,0 @@
#include "main.h"
#include "efi.h"
#include "duktape.h"
duk_context *ctx;
EFI_SYSTEM_TABLE* systemTable;
void halt() {
for (;;) {}
}
void ascii_to_utf16(const char *ascii, CHAR16 *utf16) {
while (*ascii) {
*utf16++ = (CHAR16)*ascii++;
}
*utf16 = 0;
}
duk_ret_t native_log(duk_context *ctx) {
CHAR16 buffer[256];
ascii_to_utf16(duk_safe_to_string(ctx, 0), buffer);
systemTable->ConOut->OutputString(systemTable->ConOut, buffer);
return 0;
}
int kernel_main(EFI_SYSTEM_TABLE *st) {
systemTable = st;
ctx = duk_create_heap_default();
duk_push_c_function(ctx, native_log, 1);
duk_put_global_string(ctx, "$log");
duk_push_object(ctx);
duk_push_pointer(ctx, (void *)st);
duk_put_prop_string(ctx, -2, "st");
duk_put_global_string(ctx, "$st");
duk_push_string(ctx, "$log($st.st.ConOut)");
duk_int_t returnCode = duk_peval(ctx);
if (returnCode != 0)
{
duk_safe_to_stacktrace(ctx, -1);
CHAR16 buffer[256];
ascii_to_utf16(duk_safe_to_string(ctx, -1), buffer);
systemTable->ConOut->OutputString(systemTable->ConOut, buffer);
}
duk_pop(ctx);
halt();
return 0;
}

View File

@@ -1,8 +0,0 @@
#include "efi.h"
#ifndef MAIN_H
#define MAIN_H
int kernel_main(EFI_SYSTEM_TABLE* systemTable);
#endif

Submodule efi-port/edk2 deleted from aacfbe667e

View File

@@ -1,11 +0,0 @@
mkdir -p out
mkdir -p out/core
mkdir -p out/img/EFI/BOOT
mkdir -p out/lib
clang -target x86_64-pc-win32-coff -fno-stack-protector -fshort-wchar -mno-red-zone -Iedk2/MdePkg/Include -Iedk2/MdePkg/Include/X64 -c core/src/efi.c -o out/core/efi.o
clang -target x86_64-pc-win32-coff -fno-stack-protector -fshort-wchar -mno-red-zone -Icore/compat -Icore/lib/duktape/src -Iedk2/MdePkg/Include -Iedk2/MdePkg/Include/X64 -Iedk2/CryptoPkg/Library/Include -c core/src/main.c -o out/core/main.o
clang -target x86_64-pc-win32-coff -fno-stack-protector -fshort-wchar -mno-red-zone -DDUK_F_GENERIC -U_WIN32 -UWIN32 -U_WIN64 -UWIN64 -Icore/compat -Iedk2/MdePkg/Include -Iedk2/MdePkg/Include/X64 -Iedk2/CryptoPkg/Library/Include -c core/lib/duktape/src/duktape.c -o out/lib/duktape.o
clang -target x86_64-pc-win32-coff -fno-stack-protector -fshort-wchar -mno-red-zone -Icore/compat -Iedk2/MdePkg/Include -Iedk2/MdePkg/Include/X64 -Iedk2/CryptoPkg/Library/Include -c core/src/compat.c -o out/core/compat.o
lld-link -filealign:16 -subsystem:efi_application -nodefaultlib -dll -entry:efi_main out/core/main.o out/core/efi.o out/lib/duktape.o out/core/compat.o -out:out/img/EFI/BOOT/BOOTX64.EFI

View File

@@ -1,22 +0,0 @@
#!/bin/bash
VM_NAME="LintsEFI"
ISO_PATH="$(pwd)/out/lints.iso"
# Check if VM exists
if VBoxManage list vms | grep -q "\"$VM_NAME\""; then
echo "VM '$VM_NAME' already exists."
else
echo "Creating VM '$VM_NAME'..."
VBoxManage createvm --name "$VM_NAME" --ostype "Other_64" --register
VBoxManage modifyvm "$VM_NAME" --memory 128 --firmware efi --graphicscontroller vmsvga
VBoxManage storagectl "$VM_NAME" --name "IDE Controller" --add ide
fi
# Attach ISO (force unmount first just in case)
echo "Attaching ISO..."
VBoxManage storageattach "$VM_NAME" --storagectl "IDE Controller" --port 0 --device 0 --type dvddrive --medium emptydrive --forceunmount
VBoxManage storageattach "$VM_NAME" --storagectl "IDE Controller" --port 0 --device 0 --type dvddrive --medium "$ISO_PATH"
# Start VM
echo "Starting VM..."
VBoxManage startvm "$VM_NAME"

5
package.json Normal file
View File

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

View File

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

18
sailet.config.ts Normal file
View File

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

View File

@@ -1,98 +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 -mno-sse -mno-sse2 -mno-mmx -mno-3dnow"
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 interrupt assembly
echo "Assembling interrupt handlers..."
nasm -f elf32 src/kernel/interrupt/interrupt.asm -o "$BUILD_DIR/interrupt.o"
# Build duktape
echo "Building Duktape..."
gcc $CFLAGS -c lib/duktape/src/duktape.c -o "$BUILD_DIR/duktape.o"
# Build interrupt system
echo "Building interrupt system..."
gcc $CFLAGS -c src/kernel/interrupt/idt.c -o "$BUILD_DIR/idt.o"
gcc $CFLAGS -c src/kernel/interrupt/isr.c -o "$BUILD_DIR/isr.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/interrupt.o" \
"$BUILD_DIR/idt.o" \
"$BUILD_DIR/isr.o" \
"$BUILD_DIR/kc.o" \
"$BUILD_DIR/duktape.o" \
"$BUILD_DIR/syscalls.o" \
-lc "$LIBGCC"
echo ""
echo "=== Build complete! ==="
echo ""
echo "Running kernel in QEMU..."
echo "(Press Ctrl+A then X to exit)"
echo ""

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,69 +0,0 @@
./scripts/build.sh
# Create disk image if it doesn't exist
if [ ! -f hdd.img ]; then
echo "Creating disk image..."
qemu-img create -f raw hdd.img 10M
# Create a proper MBR partition table with one FAT32 partition
# Using fdisk commands
(
echo o # Create new DOS partition table
echo n # New partition
echo p # Primary partition
echo 1 # Partition number 1
echo # Default first sector
echo # Default last sector (use all space)
echo t # Change partition type
echo c # FAT32 LBA
echo a # Make bootable
echo w # Write changes
) | fdisk hdd.img >/dev/null 2>&1
# Format the partition as FAT32
# First, get the partition offset using sfdisk
OFFSET=$(sfdisk -l hdd.img 2>/dev/null | grep 'hdd.img1' | awk '{print $2}')
# Check if OFFSET is empty or non-numeric and set default if needed
if [ -z "$OFFSET" ] || ! [[ "$OFFSET" =~ ^[0-9]+$ ]]; then
OFFSET=2048 # Default first sector for most partition tables
fi
# Create FAT32 filesystem on the partition
echo "Formatting partition as FAT32..."
mkfs.vfat -F 32 -n "TESTDISK" --offset $OFFSET hdd.img
echo "Disk image created with FAT32 partition"
fi
# Get the partition offset for file operations
OFFSET=$(sfdisk -l hdd.img 2>/dev/null | grep 'hdd.img1' | awk '{print $2}')
if [ -z "$OFFSET" ] || ! [[ "$OFFSET" =~ ^[0-9]+$ ]]; then
OFFSET=2048
fi
# Copy test-hdd contents into the disk image
if [ -d "test-hdd" ]; then
echo "Copying test-hdd contents to disk image..."
# Use mcopy to copy files to the FAT32 partition
MTOOLS_SKIP_CHECK=1 mcopy -i hdd.img@@$((OFFSET * 512)) -s test-hdd/* :: || {
echo "Warning: mcopy failed, retrying individual files..."
for file in test-hdd/*; do
if [ -f "$file" ]; then
MTOOLS_SKIP_CHECK=1 mcopy -i hdd.img@@$((OFFSET * 512)) "$file" :: && echo "Copied $(basename "$file")"
fi
done
}
fi
# Create CD-ROM image if it doesn't exist
if [ ! -f cdrom.iso ]; then
mkdir -p /tmp/cdrom_content
echo "Test CD-ROM" > /tmp/cdrom_content/readme.txt
genisoimage -o cdrom.iso -V "TESTCD" -r -J /tmp/cdrom_content 2>/dev/null || touch cdrom.iso
fi
qemu-system-i386 -serial stdio -kernel "build/out/kernel" \
-drive file=hdd.img,if=ide,format=raw,index=0,media=disk \
-drive file=cdrom.iso,if=ide,format=raw,index=1,media=cdrom

View File

@@ -1,25 +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
extern __stack_top
start:
cli ; stop interrupts during boot
mov esp, __stack_top
; Initialize FPU (x87)
finit ; Initialize FPU to default state
call kmain
; Note: kmain will call sti to enable interrupts after IDT is set up
hang:
hlt ; halt the CPU
jmp hang

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

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

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

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

View File

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

View File

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

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

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

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

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

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

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

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

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

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

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

View File

@@ -1,22 +0,0 @@
#include "idt.h"
/* Define the IDT and IDT register here */
idt_gate_t idt[IDT_ENTRIES];
idt_register_t idt_reg;
void set_idt_gate(int n, u32 handler)
{
idt[n].low_offset = low_16(handler);
idt[n].sel = KERNEL_CS;
idt[n].always0 = 0;
idt[n].flags = 0x8E;
idt[n].high_offset = high_16(handler);
}
void set_idt()
{
idt_reg.base = (u32)&idt;
idt_reg.limit = IDT_ENTRIES * sizeof(idt_gate_t) - 1;
/* Don't make the mistake of loading &idt -- always load &idt_reg */
__asm__ __volatile__("lidtl (%0)" : : "r"(&idt_reg));
}

View File

@@ -1,40 +0,0 @@
#ifndef IDT_H
#define IDT_H
#include "types.h"
/* Segment selectors */
#define KERNEL_CS 0x08
/* How every interrupt gate (handler) is defined */
typedef struct
{
u16 low_offset; /* Lower 16 bits of handler function address */
u16 sel; /* Kernel segment selector */
u8 always0;
/* First byte
* Bit 7: "Interrupt is present"
* Bits 6-5: Privilege level of caller (0=kernel..3=user)
* Bit 4: Set to 0 for interrupt gates
* Bits 3-0: bits 1110 = decimal 14 = "32 bit interrupt gate" */
u8 flags;
u16 high_offset; /* Higher 16 bits of handler function address */
} __attribute__((packed)) idt_gate_t;
/* A pointer to the array of interrupt handlers.
* Assembly instruction 'lidt' will read it */
typedef struct
{
u16 limit;
u32 base;
} __attribute__((packed)) idt_register_t;
#define IDT_ENTRIES 256
extern idt_gate_t idt[IDT_ENTRIES];
extern idt_register_t idt_reg;
/* Functions implemented in idt.c */
void set_idt_gate(int n, u32 handler);
void set_idt();
#endif

View File

@@ -1,446 +0,0 @@
; Defined in isr.c
[extern isr_handler]
[extern irq_handler]
; Common ISR code
isr_common_stub:
; 1. Save CPU state
pusha ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
mov ax, ds ; Lower 16-bits of eax = ds.
push eax ; save the data segment descriptor
mov ax, 0x10 ; kernel data segment descriptor
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
; 2. Call C handler - pass pointer to registers_t struct on stack
push esp
call isr_handler
add esp, 4
; 3. Restore state
pop eax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
popa
add esp, 8 ; Cleans up the pushed error code and pushed ISR number
iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP (and restores interrupt flag)
; Common IRQ code
irq_common_stub:
; 1. Save CPU state
pusha
mov ax, ds
push eax
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
; 2. Call C handler - pass pointer to registers_t struct on stack
push esp
call irq_handler
add esp, 4
; 3. Restore state
pop ebx
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx
popa
add esp, 8
iret ; iret restores the interrupt flag automatically from saved EFLAGS
; We don't get information about which interrupt was caller
; when the handler is run, so we will need to have a different handler
; for every interrupt.
; Furthermore, some interrupts push an error code onto the stack but others
; don't, so we will push a dummy error code for those which don't, so that
; we have a consistent stack for all of them.
; First make the ISRs global
global isr0
global isr1
global isr2
global isr3
global isr4
global isr5
global isr6
global isr7
global isr8
global isr9
global isr10
global isr11
global isr12
global isr13
global isr14
global isr15
global isr16
global isr17
global isr18
global isr19
global isr20
global isr21
global isr22
global isr23
global isr24
global isr25
global isr26
global isr27
global isr28
global isr29
global isr30
global isr31
; 0: Divide By Zero Exception
isr0:
cli
push byte 0
push byte 0
jmp isr_common_stub
; 1: Debug Exception
isr1:
cli
push byte 0
push byte 1
jmp isr_common_stub
; 2: Non Maskable Interrupt Exception
isr2:
cli
push byte 0
push byte 2
jmp isr_common_stub
; 3: Int 3 Exception
isr3:
cli
push byte 0
push byte 3
jmp isr_common_stub
; 4: INTO Exception
isr4:
cli
push byte 0
push byte 4
jmp isr_common_stub
; 5: Out of Bounds Exception
isr5:
cli
push byte 0
push byte 5
jmp isr_common_stub
; 6: Invalid Opcode Exception
isr6:
cli
push byte 0
push byte 6
jmp isr_common_stub
; 7: Coprocessor Not Available Exception
isr7:
cli
push byte 0
push byte 7
jmp isr_common_stub
; 8: Double Fault Exception (With Error Code!)
isr8:
cli
push byte 8
jmp isr_common_stub
; 9: Coprocessor Segment Overrun Exception
isr9:
cli
push byte 0
push byte 9
jmp isr_common_stub
; 10: Bad TSS Exception (With Error Code!)
isr10:
cli
push byte 10
jmp isr_common_stub
; 11: Segment Not Present Exception (With Error Code!)
isr11:
cli
push byte 11
jmp isr_common_stub
; 12: Stack Fault Exception (With Error Code!)
isr12:
cli
push byte 12
jmp isr_common_stub
; 13: General Protection Fault Exception (With Error Code!)
isr13:
cli
push byte 13
jmp isr_common_stub
; 14: Page Fault Exception (With Error Code!)
isr14:
cli
push byte 14
jmp isr_common_stub
; 15: Reserved Exception
isr15:
cli
push byte 0
push byte 15
jmp isr_common_stub
; 16: Floating Point Exception
isr16:
cli
push byte 0
push byte 16
jmp isr_common_stub
; 17: Alignment Check Exception
isr17:
cli
push byte 0
push byte 17
jmp isr_common_stub
; 18: Machine Check Exception
isr18:
cli
push byte 0
push byte 18
jmp isr_common_stub
; 19: Reserved
isr19:
cli
push byte 0
push byte 19
jmp isr_common_stub
; 20: Reserved
isr20:
cli
push byte 0
push byte 20
jmp isr_common_stub
; 21: Reserved
isr21:
cli
push byte 0
push byte 21
jmp isr_common_stub
; 22: Reserved
isr22:
cli
push byte 0
push byte 22
jmp isr_common_stub
; 23: Reserved
isr23:
cli
push byte 0
push byte 23
jmp isr_common_stub
; 24: Reserved
isr24:
cli
push byte 0
push byte 24
jmp isr_common_stub
; 25: Reserved
isr25:
cli
push byte 0
push byte 25
jmp isr_common_stub
; 26: Reserved
isr26:
cli
push byte 0
push byte 26
jmp isr_common_stub
; 27: Reserved
isr27:
cli
push byte 0
push byte 27
jmp isr_common_stub
; 28: Reserved
isr28:
cli
push byte 0
push byte 28
jmp isr_common_stub
; 29: Reserved
isr29:
cli
push byte 0
push byte 29
jmp isr_common_stub
; 30: Reserved
isr30:
cli
push byte 0
push byte 30
jmp isr_common_stub
; 31: Reserved
isr31:
cli
push byte 0
push byte 31
jmp isr_common_stub
; IRQ handlers
global irq0
global irq1
global irq2
global irq3
global irq4
global irq5
global irq6
global irq7
global irq8
global irq9
global irq10
global irq11
global irq12
global irq13
global irq14
global irq15
; IRQ 0: System Timer
irq0:
cli
push byte 0
push byte 32
jmp irq_common_stub
; IRQ 1: Keyboard
irq1:
cli
push byte 0
push byte 33
jmp irq_common_stub
; IRQ 2: Cascade (never raised)
irq2:
cli
push byte 0
push byte 34
jmp irq_common_stub
; IRQ 3: COM2
irq3:
cli
push byte 0
push byte 35
jmp irq_common_stub
; IRQ 4: COM1
irq4:
cli
push byte 0
push byte 36
jmp irq_common_stub
; IRQ 5: LPT2
irq5:
cli
push byte 0
push byte 37
jmp irq_common_stub
; IRQ 6: Floppy Disk
irq6:
cli
push byte 0
push byte 38
jmp irq_common_stub
; IRQ 7: LPT1
irq7:
cli
push byte 0
push byte 39
jmp irq_common_stub
; IRQ 8: CMOS Real-time Clock
irq8:
cli
push byte 0
push byte 40
jmp irq_common_stub
; IRQ 9: Free for peripherals
irq9:
cli
push byte 0
push byte 41
jmp irq_common_stub
; IRQ 10: Free for peripherals
irq10:
cli
push byte 0
push byte 42
jmp irq_common_stub
; IRQ 11: Free for peripherals
irq11:
cli
push byte 0
push byte 43
jmp irq_common_stub
; IRQ 12: PS/2 Mouse
irq12:
cli
push byte 0
push byte 44
jmp irq_common_stub
; IRQ 13: FPU
irq13:
cli
push byte 0
push byte 45
jmp irq_common_stub
; IRQ 14: Primary ATA Hard Disk
irq14:
cli
push byte 0
push byte 46
jmp irq_common_stub
; IRQ 15: Secondary ATA Hard Disk
irq15:
cli
push byte 0
push byte 47
jmp irq_common_stub

View File

@@ -1,317 +0,0 @@
#include "isr.h"
#include "idt.h"
/* Port I/O functions */
static inline void outb(u16 port, u8 val)
{
__asm__ volatile("outb %0, %1" : : "a"(val), "Nd"(port));
}
static inline u8 inb(u16 port)
{
u8 ret;
__asm__ volatile("inb %1, %0" : "=a"(ret) : "Nd"(port));
return ret;
}
/* PIC (Programmable Interrupt Controller) constants */
#define PIC1_COMMAND 0x20
#define PIC1_DATA 0x21
#define PIC2_COMMAND 0xA0
#define PIC2_DATA 0xA1
#define PIC_EOI 0x20
/* Array to store custom IRQ handlers */
static irq_handler_t irq_handlers[16] = {0};
/* Can't do this with a loop because we need the address
* of the function names */
void isr_install()
{
set_idt_gate(0, (u32)isr0);
set_idt_gate(1, (u32)isr1);
set_idt_gate(2, (u32)isr2);
set_idt_gate(3, (u32)isr3);
set_idt_gate(4, (u32)isr4);
set_idt_gate(5, (u32)isr5);
set_idt_gate(6, (u32)isr6);
set_idt_gate(7, (u32)isr7);
set_idt_gate(8, (u32)isr8);
set_idt_gate(9, (u32)isr9);
set_idt_gate(10, (u32)isr10);
set_idt_gate(11, (u32)isr11);
set_idt_gate(12, (u32)isr12);
set_idt_gate(13, (u32)isr13);
set_idt_gate(14, (u32)isr14);
set_idt_gate(15, (u32)isr15);
set_idt_gate(16, (u32)isr16);
set_idt_gate(17, (u32)isr17);
set_idt_gate(18, (u32)isr18);
set_idt_gate(19, (u32)isr19);
set_idt_gate(20, (u32)isr20);
set_idt_gate(21, (u32)isr21);
set_idt_gate(22, (u32)isr22);
set_idt_gate(23, (u32)isr23);
set_idt_gate(24, (u32)isr24);
set_idt_gate(25, (u32)isr25);
set_idt_gate(26, (u32)isr26);
set_idt_gate(27, (u32)isr27);
set_idt_gate(28, (u32)isr28);
set_idt_gate(29, (u32)isr29);
set_idt_gate(30, (u32)isr30);
set_idt_gate(31, (u32)isr31);
set_idt(); // Load with ASM
}
/* Remap the PIC to avoid conflicts with CPU exceptions */
static void pic_remap(void)
{
// Start initialization
outb(PIC1_COMMAND, 0x11);
outb(PIC2_COMMAND, 0x11);
// Set vector offsets (IRQs 0-7 -> interrupts 32-39, IRQs 8-15 -> interrupts 40-47)
outb(PIC1_DATA, 0x20);
outb(PIC2_DATA, 0x28);
// Tell master PIC there's a slave PIC at IRQ2
outb(PIC1_DATA, 0x04);
// Tell slave PIC its cascade identity
outb(PIC2_DATA, 0x02);
// Set to 8086 mode
outb(PIC1_DATA, 0x01);
outb(PIC2_DATA, 0x01);
// Mask all interrupts initially
outb(PIC1_DATA, 0xFF);
outb(PIC2_DATA, 0xFF);
}
/* Install IRQ handlers */
void irq_install()
{
// Remap the PIC
pic_remap();
// Install IRQ handlers (32-47)
set_idt_gate(32, (u32)irq0);
set_idt_gate(33, (u32)irq1);
set_idt_gate(34, (u32)irq2);
set_idt_gate(35, (u32)irq3);
set_idt_gate(36, (u32)irq4);
set_idt_gate(37, (u32)irq5);
set_idt_gate(38, (u32)irq6);
set_idt_gate(39, (u32)irq7);
set_idt_gate(40, (u32)irq8);
set_idt_gate(41, (u32)irq9);
set_idt_gate(42, (u32)irq10);
set_idt_gate(43, (u32)irq11);
set_idt_gate(44, (u32)irq12);
set_idt_gate(45, (u32)irq13);
set_idt_gate(46, (u32)irq14);
set_idt_gate(47, (u32)irq15);
set_idt(); // Reload IDT
}
/* To print the message which defines every exception */
char *exception_messages[] = {
"Division By Zero",
"Debug",
"Non Maskable Interrupt",
"Breakpoint",
"Into Detected Overflow",
"Out of Bounds",
"Invalid Opcode",
"No Coprocessor",
"Double Fault",
"Coprocessor Segment Overrun",
"Bad TSS",
"Segment Not Present",
"Stack Fault",
"General Protection Fault",
"Page Fault",
"Unknown Interrupt",
"Coprocessor Fault",
"Alignment Check",
"Machine Check",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved"};
void isr_handler(registers_t *r)
{
// Write exception to VGA memory
char *vidmem = (char *)0xb8000;
const char *msg = "EXCEPTION: ";
int i = 0;
// Clear first line
for (i = 0; i < 80 * 2; i++)
{
vidmem[i] = 0;
}
// Write message
i = 0;
while (msg[i])
{
vidmem[i * 2] = msg[i];
vidmem[i * 2 + 1] = 0x4F; // White on red
i++;
}
// Write exception number
vidmem[i * 2] = '0' + (r->int_no / 10);
vidmem[i * 2 + 1] = 0x4F;
i++;
vidmem[i * 2] = '0' + (r->int_no % 10);
vidmem[i * 2 + 1] = 0x4F;
i++;
// Write error code
vidmem[i * 2] = ' ';
vidmem[i * 2 + 1] = 0x4F;
i++;
vidmem[i * 2] = 'E';
vidmem[i * 2 + 1] = 0x4F;
i++;
vidmem[i * 2] = 'R';
vidmem[i * 2 + 1] = 0x4F;
i++;
vidmem[i * 2] = 'R';
vidmem[i * 2 + 1] = 0x4F;
i++;
vidmem[i * 2] = ':';
vidmem[i * 2 + 1] = 0x4F;
i++;
// Write error code in hex
u32 err = r->err_code;
for (int j = 7; j >= 0; j--)
{
u8 nibble = (err >> (j * 4)) & 0xF;
vidmem[i * 2] = nibble < 10 ? '0' + nibble : 'A' + (nibble - 10);
vidmem[i * 2 + 1] = 0x4F;
i++;
}
// Write EIP
i++;
vidmem[i * 2] = 'E';
vidmem[i * 2 + 1] = 0x4F;
i++;
vidmem[i * 2] = 'I';
vidmem[i * 2 + 1] = 0x4F;
i++;
vidmem[i * 2] = 'P';
vidmem[i * 2 + 1] = 0x4F;
i++;
vidmem[i * 2] = ':';
vidmem[i * 2 + 1] = 0x4F;
i++;
// Write EIP in hex
u32 eip = r->eip;
for (int j = 7; j >= 0; j--)
{
u8 nibble = (eip >> (j * 4)) & 0xF;
vidmem[i * 2] = nibble < 10 ? '0' + nibble : 'A' + (nibble - 10);
vidmem[i * 2 + 1] = 0x4F;
i++;
}
// Halt
__asm__ volatile("cli; hlt");
while (1)
;
}
/* IRQ handler */
void irq_handler(registers_t *r)
{
// Calculate IRQ number (interrupts 32-47 map to IRQ 0-15)
u8 irq_no = r->int_no - 32;
// Handle spurious IRQ7 (from master PIC)
if (irq_no == 7)
{
// Read In-Service Register (ISR)
outb(PIC1_COMMAND, 0x0B);
u8 isr = inb(PIC1_COMMAND);
if (!(isr & 0x80))
{
// Spurious interrupt, don't send EOI
return;
}
}
// Handle spurious IRQ15 (from slave PIC)
if (irq_no == 15)
{
// Read In-Service Register (ISR) of slave PIC
outb(PIC2_COMMAND, 0x0B);
u8 isr = inb(PIC2_COMMAND);
if (!(isr & 0x80))
{
// Spurious interrupt from slave, send EOI to master only
outb(PIC1_COMMAND, PIC_EOI);
return;
}
}
// Call custom handler if registered
if (irq_handlers[irq_no] != 0)
{
irq_handlers[irq_no](r);
}
// Send EOI to PIC
if (r->int_no >= 40)
{
// IRQ came from slave PIC, send EOI to both
outb(PIC2_COMMAND, PIC_EOI);
}
outb(PIC1_COMMAND, PIC_EOI);
}
/* Register a custom IRQ handler */
void irq_register_handler(u8 irq, irq_handler_t handler)
{
if (irq < 16)
{
irq_handlers[irq] = handler;
// Unmask the IRQ on the PIC
u16 port;
u8 value;
if (irq < 8)
{
port = PIC1_DATA;
}
else
{
port = PIC2_DATA;
irq -= 8;
}
value = inb(port) & ~(1 << irq);
outb(port, value);
}
}

View File

@@ -1,78 +0,0 @@
#ifndef ISR_H
#define ISR_H
#include "types.h"
/* ISRs reserved for CPU exceptions */
extern void isr0();
extern void isr1();
extern void isr2();
extern void isr3();
extern void isr4();
extern void isr5();
extern void isr6();
extern void isr7();
extern void isr8();
extern void isr9();
extern void isr10();
extern void isr11();
extern void isr12();
extern void isr13();
extern void isr14();
extern void isr15();
extern void isr16();
extern void isr17();
extern void isr18();
extern void isr19();
extern void isr20();
extern void isr21();
extern void isr22();
extern void isr23();
extern void isr24();
extern void isr25();
extern void isr26();
extern void isr27();
extern void isr28();
extern void isr29();
extern void isr30();
extern void isr31();
/* IRQ handlers */
extern void irq0();
extern void irq1();
extern void irq2();
extern void irq3();
extern void irq4();
extern void irq5();
extern void irq6();
extern void irq7();
extern void irq8();
extern void irq9();
extern void irq10();
extern void irq11();
extern void irq12();
extern void irq13();
extern void irq14();
extern void irq15();
/* Struct which aggregates many registers */
typedef struct
{
u32 ds; /* Data segment selector */
u32 edi, esi, ebp, esp, ebx, edx, ecx, eax; /* Pushed by pusha. */
u32 int_no, err_code; /* Interrupt number and error code (if applicable) */
u32 eip, cs, eflags, useresp, ss; /* Pushed by the processor automatically */
} registers_t;
/* Function pointer type for IRQ handlers */
typedef void (*irq_handler_t)(registers_t *);
void isr_install();
void isr_handler(registers_t *r);
void irq_install();
void irq_handler(registers_t *r);
/* Register a custom IRQ handler */
void irq_register_handler(u8 irq, irq_handler_t handler);
#endif

View File

@@ -1,16 +0,0 @@
#ifndef TYPES_H
#define TYPES_H
/* Instead of using 'chars' to allocate non-character bytes,
* we will use these new type with no semantic meaning */
typedef unsigned int u32;
typedef int s32;
typedef unsigned short u16;
typedef short s16;
typedef unsigned char u8;
typedef char s8;
#define low_16(address) (u16)((address) & 0xFFFF)
#define high_16(address) (u16)(((address) >> 16) & 0xFFFF)
#endif

View File

@@ -1,762 +0,0 @@
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <duktape.h>
#include "embedded_js.h"
#include "interrupt/isr.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_byte_in(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;
}
duk_ret_t native_byte_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)
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;
}
duk_ret_t native_word_in(duk_context *ctx)
{
uint16_t port = (uint16_t)duk_to_uint32(ctx, 0);
uint16_t result;
__asm__ volatile("inw %1, %0"
: "=a"(result)
: "Nd"(port));
duk_push_uint(ctx, (duk_uint_t)result);
return 1;
}
duk_ret_t native_word_out(duk_context *ctx)
{
uint16_t port = (uint16_t)duk_to_uint32(ctx, 0);
// Get the value to write (second argument)
uint16_t value = (uint16_t)duk_to_uint32(ctx, 1);
__asm__ volatile("outw %0, %1"
:
: "a"(value), "Nd"(port));
return 0;
}
// Global context for IRQ handlers
duk_context *global_ctx = NULL;
// Pending heaps to destroy
duk_context *pending_heaps[16];
int pending_heaps_count = 0;
void process_pending_heaps()
{
for (int i = 0; i < pending_heaps_count; i++)
{
if (pending_heaps[i] != NULL)
{
duk_destroy_heap(pending_heaps[i]);
}
}
pending_heaps_count = 0;
}
// JavaScript IRQ wrapper
void js_irq_callback(registers_t *r)
{
if (global_ctx == NULL)
return;
// Get IRQ number
u8 irq_no = r->int_no - 32;
// Build the key for this IRQ handler manually (avoid snprintf in interrupt)
char key[32] = "irq_handler_";
int key_len = 12;
if (irq_no >= 10)
{
key[key_len++] = '0' + (irq_no / 10);
key[key_len++] = '0' + (irq_no % 10);
}
else
{
key[key_len++] = '0' + irq_no;
}
key[key_len] = '\0';
// Call the JavaScript handler
duk_push_global_stash(global_ctx);
if (duk_get_prop_string(global_ctx, -1, key))
{
// Function found, call it with IRQ number
duk_push_uint(global_ctx, irq_no);
// Try protected call with error handler
duk_int_t rc = duk_pcall(global_ctx, 1);
duk_pop(global_ctx); // Pop result or error
}
else
{
duk_pop(global_ctx); // Pop undefined value
}
duk_pop(global_ctx); // Pop stash
// Process any pending heaps
process_pending_heaps();
}
// Native function to register IRQ from JavaScript
duk_ret_t native_irq_register(duk_context *ctx)
{
// Get the IRQ number
u8 irq = (u8)duk_to_uint32(ctx, 0);
// Get the handler function
if (!duk_is_function(ctx, 1))
{
duk_push_boolean(ctx, 0);
return 1;
}
// Store function in global stash
char key[32];
snprintf(key, sizeof(key), "irq_handler_%d", irq);
duk_push_global_stash(ctx);
duk_dup(ctx, 1); // Duplicate the function
duk_put_prop_string(ctx, -2, key);
duk_pop(ctx); // Pop stash
// Register the C wrapper
irq_register_handler(irq, js_irq_callback);
duk_push_boolean(ctx, 1);
return 1;
}
// Proxy getter for __oskrnl that forwards to root context's globalThis.__oskrnl
duk_ret_t oskrnl_proxy_getter(duk_context *isolated_ctx)
{
// Get the property name being accessed
const char *prop_name = duk_require_string(isolated_ctx, 1);
// Get the root context from the hidden symbol in the isolated context
duk_push_global_stash(isolated_ctx);
duk_get_prop_string(isolated_ctx, -1, "\xFF"
"root_ctx_ptr");
duk_context *root_ctx = (duk_context *)duk_get_pointer(isolated_ctx, -1);
duk_pop_2(isolated_ctx);
if (root_ctx == NULL)
{
duk_push_undefined(isolated_ctx);
return 1;
}
// Access globalThis.__oskrnl[prop_name] in the root context
duk_push_global_object(root_ctx);
duk_get_prop_string(root_ctx, -1, "__oskrnl");
if (!duk_is_object(root_ctx, -1))
{
duk_pop_2(root_ctx);
duk_push_undefined(isolated_ctx);
return 1;
}
duk_get_prop_string(root_ctx, -1, prop_name);
// If it's a function, we need to create a wrapper that calls it in root context
if (duk_is_function(root_ctx, -1))
{
// Store the function reference in root context's stash
char stash_key[128];
snprintf(stash_key, sizeof(stash_key), "\xFF"
"oskrnl_fn_%s",
prop_name);
duk_push_global_stash(root_ctx);
duk_dup(root_ctx, -2); // Duplicate the function
duk_put_prop_string(root_ctx, -2, stash_key);
duk_pop(root_ctx); // Pop stash
duk_pop_3(root_ctx); // Pop function, __oskrnl, globalThis
// Create a wrapper function in the isolated context
// Use ES5 syntax compatible with Duktape
const char *wrapper_code =
"(function(propName) {"
" return function() {"
" var args = Array.prototype.slice.call(arguments);"
" return __oskrnl_call_native(propName, args);"
" };"
"})";
duk_push_string(isolated_ctx, wrapper_code);
if (duk_peval(isolated_ctx) != 0)
{
duk_pop(isolated_ctx);
duk_push_undefined(isolated_ctx);
return 1;
}
duk_push_string(isolated_ctx, prop_name);
if (duk_pcall(isolated_ctx, 1) != 0)
{
duk_pop(isolated_ctx);
duk_push_undefined(isolated_ctx);
return 1;
}
return 1;
}
// For non-function properties, just get the value (primitives)
if (duk_is_number(root_ctx, -1))
{
double val = duk_get_number(root_ctx, -1);
duk_pop_3(root_ctx);
duk_push_number(isolated_ctx, val);
return 1;
}
else if (duk_is_string(root_ctx, -1))
{
const char *val = duk_get_string(root_ctx, -1);
duk_pop_3(root_ctx);
duk_push_string(isolated_ctx, val);
return 1;
}
else if (duk_is_boolean(root_ctx, -1))
{
int val = duk_get_boolean(root_ctx, -1);
duk_pop_3(root_ctx);
duk_push_boolean(isolated_ctx, val);
return 1;
}
duk_pop_3(root_ctx);
duk_push_undefined(isolated_ctx);
return 1;
}
// Callback bridge to call from root context back to isolated context
duk_ret_t native_bridge_callback(duk_context *root_ctx)
{
// Get metadata from the current function (the bridge)
duk_push_current_function(root_ctx);
duk_get_prop_string(root_ctx, -1, "\xFF"
"isolated_ctx_ptr");
duk_context *isolated_ctx = (duk_context *)duk_get_pointer(root_ctx, -1);
duk_pop(root_ctx);
duk_get_prop_string(root_ctx, -1, "\xFF"
"fn_id");
const char *fn_id = duk_get_string(root_ctx, -1);
duk_pop(root_ctx);
duk_pop(root_ctx); // Pop current function
if (isolated_ctx == NULL || fn_id == NULL)
{
return 0;
}
// Get the target function from isolated context stash
duk_push_global_stash(isolated_ctx);
duk_get_prop_string(isolated_ctx, -1, fn_id);
duk_remove(isolated_ctx, -2); // Remove stash
if (!duk_is_function(isolated_ctx, -1))
{
duk_pop(isolated_ctx);
return 0;
}
// Marshal arguments from root to isolated
duk_idx_t nargs = duk_get_top(root_ctx);
for (duk_idx_t i = 0; i < nargs; i++)
{
if (duk_is_number(root_ctx, i))
{
duk_push_number(isolated_ctx, duk_get_number(root_ctx, i));
}
else if (duk_is_string(root_ctx, i))
{
duk_push_string(isolated_ctx, duk_get_string(root_ctx, i));
}
else if (duk_is_boolean(root_ctx, i))
{
duk_push_boolean(isolated_ctx, duk_get_boolean(root_ctx, i));
}
else
{
duk_push_undefined(isolated_ctx);
}
}
// Call the isolated function
if (duk_pcall(isolated_ctx, nargs) != 0)
{
// Error occurred
const char *err = duk_safe_to_string(isolated_ctx, -1);
// k_printf((char *)"[Bridge] Error: ", 24);
// k_printf((char *)err, 25);
duk_pop(isolated_ctx); // Pop error
return 0;
}
// Marshal return value back to root
if (duk_is_number(isolated_ctx, -1))
{
duk_push_number(root_ctx, duk_get_number(isolated_ctx, -1));
}
else if (duk_is_string(isolated_ctx, -1))
{
duk_push_string(root_ctx, duk_get_string(isolated_ctx, -1));
}
else if (duk_is_boolean(isolated_ctx, -1))
{
duk_push_boolean(root_ctx, duk_get_boolean(isolated_ctx, -1));
}
else
{
duk_push_undefined(root_ctx);
}
duk_pop(isolated_ctx); // Pop result
return 1;
}
// Native helper to call root context oskrnl functions
duk_ret_t oskrnl_call_native(duk_context *isolated_ctx)
{
// Get function name and arguments
const char *fn_name = duk_require_string(isolated_ctx, 0);
if (!duk_is_array(isolated_ctx, 1))
{
duk_push_undefined(isolated_ctx);
return 1;
}
// Get the root context
duk_push_global_stash(isolated_ctx);
duk_get_prop_string(isolated_ctx, -1, "\xFF"
"root_ctx_ptr");
duk_context *root_ctx = (duk_context *)duk_get_pointer(isolated_ctx, -1);
duk_pop_2(isolated_ctx);
if (root_ctx == NULL)
{
duk_push_undefined(isolated_ctx);
return 1;
}
// Get the function from root context stash
char stash_key[128];
snprintf(stash_key, sizeof(stash_key), "\xFF"
"oskrnl_fn_%s",
fn_name);
duk_push_global_stash(root_ctx);
duk_get_prop_string(root_ctx, -1, stash_key);
if (!duk_is_function(root_ctx, -1))
{
duk_pop_2(root_ctx);
duk_push_undefined(isolated_ctx);
return 1;
}
// Transfer arguments from isolated context to root context
duk_size_t arg_count = duk_get_length(isolated_ctx, 1);
for (duk_size_t i = 0; i < arg_count; i++)
{
duk_get_prop_index(isolated_ctx, 1, i);
if (duk_is_number(isolated_ctx, -1))
{
duk_push_number(root_ctx, duk_get_number(isolated_ctx, -1));
}
else if (duk_is_string(isolated_ctx, -1))
{
duk_push_string(root_ctx, duk_get_string(isolated_ctx, -1));
}
else if (duk_is_boolean(isolated_ctx, -1))
{
duk_push_boolean(root_ctx, duk_get_boolean(isolated_ctx, -1));
}
else if (duk_is_function(isolated_ctx, -1))
{
// Create a bridge function in root context
static int bridge_cnt = 0;
char bridge_id[32];
snprintf(bridge_id, sizeof(bridge_id), "b_%d", bridge_cnt++);
// Stash isolated function
duk_push_global_stash(isolated_ctx);
duk_dup(isolated_ctx, -2);
duk_put_prop_string(isolated_ctx, -2, bridge_id);
duk_pop(isolated_ctx);
// Create bridge in root
duk_push_c_function(root_ctx, native_bridge_callback, DUK_VARARGS);
// Attach metadata
duk_push_pointer(root_ctx, isolated_ctx);
duk_put_prop_string(root_ctx, -2, "\xFF"
"isolated_ctx_ptr");
duk_push_string(root_ctx, bridge_id);
duk_put_prop_string(root_ctx, -2, "\xFF"
"fn_id");
}
else
{
duk_push_undefined(root_ctx);
}
duk_pop(isolated_ctx);
}
// Call the function in root context
duk_int_t rc = duk_pcall(root_ctx, arg_count);
// Transfer return value back to isolated context
if (rc == 0)
{
if (duk_is_number(root_ctx, -1))
{
duk_push_number(isolated_ctx, duk_get_number(root_ctx, -1));
}
else if (duk_is_string(root_ctx, -1))
{
duk_push_string(isolated_ctx, duk_get_string(root_ctx, -1));
}
else if (duk_is_boolean(root_ctx, -1))
{
duk_push_boolean(isolated_ctx, duk_get_boolean(root_ctx, -1));
}
else
{
duk_push_undefined(isolated_ctx);
}
duk_pop(root_ctx); // Pop result
}
else
{
duk_pop(root_ctx); // Pop error
duk_push_undefined(isolated_ctx);
}
duk_pop(root_ctx); // Pop stash
return 1;
}
// Native function to execute JS code in isolated context with __oskrnl access
duk_ret_t native_isolated_exec(duk_context *ctx)
{
// Get the JS code to execute
const char *js_code = duk_require_string(ctx, 0);
// Create a new isolated Duktape heap
duk_context *isolated_ctx = duk_create_heap_default();
if (isolated_ctx == NULL)
{
duk_push_boolean(ctx, 0);
return 1;
}
// Store reference to root context in isolated context's stash
duk_push_global_stash(isolated_ctx);
duk_push_pointer(isolated_ctx, ctx);
duk_put_prop_string(isolated_ctx, -2, "\xFF"
"root_ctx_ptr");
duk_pop(isolated_ctx);
// Register the native call helper in isolated context
duk_push_c_function(isolated_ctx, oskrnl_call_native, 2);
duk_put_global_string(isolated_ctx, "__oskrnl_call_native");
// Register the getter function
duk_push_c_function(isolated_ctx, oskrnl_proxy_getter, 2);
duk_put_global_string(isolated_ctx, "__oskrnl_get_prop");
// Create __oskrnl proxy object using ES6 Proxy
const char *proxy_code =
"(function() {"
" var handler = {"
" get: function(target, prop) {"
" if (typeof prop === 'symbol') return undefined;"
" return __oskrnl_get_prop(null, String(prop));"
" }"
" };"
" return new Proxy({}, handler);"
"})()";
duk_push_string(isolated_ctx, proxy_code);
if (duk_peval(isolated_ctx) != 0)
{
duk_pop(isolated_ctx);
duk_destroy_heap(isolated_ctx);
duk_push_boolean(ctx, 0);
return 1;
}
duk_put_global_string(isolated_ctx, "__oskrnl");
// Execute the provided JS code
duk_push_string(isolated_ctx, js_code);
duk_int_t rc = duk_peval(isolated_ctx);
// Check for errors
int success = (rc == 0);
if (!success)
{
// Transfer error message back to root context for display
const char *err = duk_safe_to_string(isolated_ctx, -1);
k_printf((char *)"[Isolated] Execution error: ", 12);
k_printf((char *)err, 13);
}
duk_pop(isolated_ctx); // Pop result or error
// Clean up the isolated heap
// duk_destroy_heap(isolated_ctx);
// Return success/failure
// Return the heap pointer as a number (uint32_t)
duk_push_uint(ctx, (duk_uint_t)isolated_ctx);
return 1;
}
// Native function to destroy an isolated heap
duk_ret_t native_destroy_isolated_heap(duk_context *ctx)
{
// Get the heap pointer
duk_uint_t heap_ptr = duk_require_uint(ctx, 0);
duk_context *isolated_ctx = (duk_context *)heap_ptr;
if (isolated_ctx != NULL)
{
if (pending_heaps_count < 16)
{
pending_heaps[pending_heaps_count++] = isolated_ctx;
}
}
return 0;
}
void kmain()
{
// Initialize IDT and ISRs
isr_install();
irq_install();
// Initialize Duktape heap
ctx = duk_create_heap_default();
global_ctx = ctx;
// 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 byte in function
duk_push_c_function(ctx, native_byte_in, 1);
duk_put_global_string(ctx, "$bytein");
// Register native byte out function
duk_push_c_function(ctx, native_byte_out, 2);
duk_put_global_string(ctx, "$byteout");
// 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");
// Register native dword in function
duk_push_c_function(ctx, native_word_in, 1);
duk_put_global_string(ctx, "$wordin");
// Register native dword out function
duk_push_c_function(ctx, native_word_out, 2);
duk_put_global_string(ctx, "$wordout");
// Register native IRQ registration function
duk_push_c_function(ctx, native_irq_register, 2);
duk_put_global_string(ctx, "$irqregister");
// Register native isolated execution function
duk_push_c_function(ctx, native_isolated_exec, 1);
duk_put_global_string(ctx, "$isolatedExec");
// Register native isolated heap destruction function
duk_push_c_function(ctx, native_destroy_isolated_heap, 1);
duk_put_global_string(ctx, "$destroyIsolatedHeap");
// Enable interrupts before JavaScript execution
__asm__ volatile("sti");
// Execute embedded JavaScript code from build/index.js
duk_push_string(ctx, embedded_js_code);
duk_int_t returnCode = duk_peval(ctx);
if (returnCode != 0)
{
// Error occurred - display stack trace
duk_safe_to_stacktrace(ctx, -1);
k_printf((char *)duk_safe_to_string(ctx, -1), 1);
}
duk_pop(ctx);
}
unsigned int k_printf(char *message, unsigned int line)
{
char *vidmem = (char *)0xb8000;
unsigned int i = 0;
i = (line * 80 * 2);
while (*message != 0)
{
if (*message == '\n') // check for a new line
{
line++;
i = (line * 80 * 2);
*message++;
}
else
{
vidmem[i] = *message;
*message++;
i++;
vidmem[i] = WHITE_TXT;
i++;
};
};
return (1);
}

1
src/lib/quickjs Submodule

Submodule src/lib/quickjs added at 177e1b32a4

View File

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

View File

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

View File

@@ -1,67 +0,0 @@
export const Keycode = {
Enter: 28,
Backspace: 14,
Q: 16,
W: 17,
E: 18,
R: 19,
T: 20,
Y: 21,
U: 22,
I: 23,
O: 24,
P: 25,
A: 30,
S: 31,
D: 32,
F: 33,
G: 34,
H: 35,
J: 36,
K: 37,
L: 38,
Z: 44,
X: 45,
C: 46,
V: 47,
B: 48,
N: 49,
M: 50,
".": 52,
"/": 53,
" ": 57,
};
export const RKeycode = {
28: "Enter",
14: "Backspace",
16: "Q",
17: "W",
18: "E",
19: "R",
20: "T",
21: "Y",
22: "U",
23: "I",
24: "O",
25: "P",
30: "A",
31: "S",
32: "D",
33: "F",
34: "G",
35: "H",
36: "J",
37: "K",
38: "L",
44: "Z",
45: "X",
46: "C",
47: "V",
48: "B",
49: "N",
50: "M",
52: ".",
53: "/",
57: " ",
};

View File

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

View File

@@ -1,365 +0,0 @@
import { Logger } from "../../../lib/libstd/logger/logger.kmod";
import { bytein, byteout } from "../../../lib/libts/byte";
import { dwordin } from "../../../lib/libts/dword";
import { wordin } from "../../../lib/libts/word";
import type { AtaDriveDescriptor } from "../../../types/dev/ata/drive";
import type { BlockCache } from "../../../types/utils/block_cache";
import {
blockCache_block,
blockCache_create,
blockCache_init,
} from "../../utils/block_cache";
const KDRIVER_DEV_ATA_PRIMARY = 0x1f0;
const KDRIVER_DEV_ATA_SECONDARY = 0x170;
const KDRIVER_DEV_ATA_PRIMARY_CTL = 0x3f6;
const KDRIVER_DEV_ATA_SECONDARY_CTL = 0x376;
const KDRIVER_DEV_ATA_CTL_nIEN = 0x02;
const KDRIVER_DEV_ATA_MASTER_BIT = 0;
const KDRIVER_DEV_ATA_SLAVE_BIT = 1;
const KDRIVER_DEV_ATA_DRV_HEAD = 6;
const KDRIVER_DEV_ATA_NSECTOR = 2;
const KDRIVER_DEV_ATA_SECTOR = 3;
const KDRIVER_DEV_ATA_LCYL = 4;
const KDRIVER_DEV_ATA_HCYL = 5;
const KDRIVER_DEV_ATA_STATUS = 7;
const KDRIVER_DEV_ATA_COMMAND = 7;
const KDRIVER_DEV_ATA_IDENTIFY = 0xec;
const KDRIVER_DEV_ATA_READ_SECTORS = 0x20;
const KDRIVER_DEV_ATA_STATUS_ERROR = 0x01;
const KDRIVER_DEV_ATA_STATUS_BSY = 0x80;
const KDRIVER_DEV_ATA_STATUS_DRQ = 0x08;
const KDRIVER_DEV_ATA_DATA = 0;
const KDRIVER_DEV_ATA_BLOCK_SIZE = 512;
let drives: AtaDriveDescriptor[] = [];
let cache = blockCache_create();
export function kdriver_dev_ata_init(): void {}
export function kdriver_dev_ata_400ns_delay(controller: number) {
bytein(controller + KDRIVER_DEV_ATA_STATUS);
bytein(controller + KDRIVER_DEV_ATA_STATUS);
bytein(controller + KDRIVER_DEV_ATA_STATUS);
bytein(controller + KDRIVER_DEV_ATA_STATUS);
bytein(controller + KDRIVER_DEV_ATA_STATUS);
bytein(controller + KDRIVER_DEV_ATA_STATUS);
bytein(controller + KDRIVER_DEV_ATA_STATUS);
bytein(controller + KDRIVER_DEV_ATA_STATUS);
bytein(controller + KDRIVER_DEV_ATA_STATUS);
}
function ide_string(info: number[], start: number, size: number): string {
const buffer = new Array(50);
const t = info.slice(start);
for (let i = 0; i < size; ++i) {
const wordIndex = Math.floor(i / 2);
const isHighByte = i % 2 === 1;
buffer[i] = isHighByte ? (t[wordIndex]! >> 8) & 0xff : t[wordIndex]! & 0xff;
}
for (let i = 0; i < size; i += 2) {
const c = buffer[i];
buffer[i] = buffer[i + 1];
buffer[i + 1] = c;
}
let end = size - 1;
while (true) {
const c = buffer[end];
if (c > 32 && c < 127) {
break;
}
if (end == 0) {
break;
}
--end;
}
//buffer[end + 1] = 0;
let target = "";
for (let i = 0; i <= end; i++) {
target += String.fromCharCode(buffer[i]);
}
return target;
}
export function kdriver_dev_ata_identify(drive: AtaDriveDescriptor) {
byteout(
drive.controller + KDRIVER_DEV_ATA_DRV_HEAD,
0xa0 | (drive.slave << 4)
);
kdriver_dev_ata_400ns_delay(drive.controller);
const floatingBus = bytein(drive.controller + KDRIVER_DEV_ATA_STATUS);
if (floatingBus == 0xff) {
return;
}
byteout(drive.controller + KDRIVER_DEV_ATA_COMMAND, KDRIVER_DEV_ATA_IDENTIFY);
kdriver_dev_ata_400ns_delay(drive.controller);
if (bytein(drive.controller + KDRIVER_DEV_ATA_STATUS) == 0) return;
let notAta = false;
let iterations = 0;
while (1) {
const status = bytein(drive.controller + KDRIVER_DEV_ATA_STATUS);
iterations++;
if (status & KDRIVER_DEV_ATA_STATUS_ERROR) {
notAta = true;
break;
}
if (
!(status & KDRIVER_DEV_ATA_STATUS_BSY) &&
status & KDRIVER_DEV_ATA_STATUS_DRQ
)
break;
if (iterations > 100000) {
return;
}
}
drive.atapi = false;
if (notAta) {
const cl = bytein(drive.controller + KDRIVER_DEV_ATA_LCYL);
const ch = bytein(drive.controller + KDRIVER_DEV_ATA_HCYL);
if (cl == 0x14 && ch == 0xeb) drive.atapi = true;
else if (cl == 0x69 && ch == 0x96) drive.atapi = true;
else return;
byteout(drive.controller + KDRIVER_DEV_ATA_COMMAND, 0xa1);
kdriver_dev_ata_400ns_delay(drive.controller);
}
drive.present = true;
const info = new Array(256);
for (let i = 0; i < 256; i++) {
info[i] = wordin(drive.controller + KDRIVER_DEV_ATA_DATA);
}
drive.model = ide_string(info, 27, 40);
drive.serial = ide_string(info, 10, 20);
drive.firmware = ide_string(info, 23, 8);
const sectors = info[0] + 114;
drive.size = sectors * 4096;
Logger.log(
"[ATA] Found drive " +
drive.model +
" (" +
drive.serial +
") FW: " +
drive.firmware +
" Size: " +
drive.size
);
}
export function kdriver_dev_ata_numberOfDrives(): number {
return 4;
}
export function kdriver_dev_ata_getDrive(n: number) {
return drives[n]!;
}
export function kdriver_dev_ata_detectDisks(): void {
blockCache_init(cache, KDRIVER_DEV_ATA_BLOCK_SIZE, 256);
drives = new Array<AtaDriveDescriptor>(4);
drives[0] = {
controller: KDRIVER_DEV_ATA_PRIMARY,
drive: 0xe0,
present: false,
slave: KDRIVER_DEV_ATA_MASTER_BIT,
atapi: false,
model: "",
serial: "",
firmware: "",
size: 0,
};
drives[1] = {
controller: KDRIVER_DEV_ATA_PRIMARY,
drive: 0xf0,
present: false,
slave: KDRIVER_DEV_ATA_SLAVE_BIT,
atapi: false,
model: "",
serial: "",
firmware: "",
size: 0,
};
drives[2] = {
controller: KDRIVER_DEV_ATA_SECONDARY,
drive: 0xe0,
present: false,
slave: KDRIVER_DEV_ATA_MASTER_BIT,
atapi: false,
model: "",
serial: "",
firmware: "",
size: 0,
};
drives[3] = {
controller: KDRIVER_DEV_ATA_SECONDARY,
drive: 0xf0,
present: false,
slave: KDRIVER_DEV_ATA_SLAVE_BIT,
atapi: false,
model: "",
serial: "",
firmware: "",
size: 0,
};
byteout(KDRIVER_DEV_ATA_PRIMARY_CTL, KDRIVER_DEV_ATA_CTL_nIEN);
byteout(KDRIVER_DEV_ATA_SECONDARY_CTL, KDRIVER_DEV_ATA_CTL_nIEN);
for (let i = 0; i < 4; i++) {
const drive = drives[i]!;
kdriver_dev_ata_identify(drive);
}
byteout(KDRIVER_DEV_ATA_PRIMARY_CTL, 0);
byteout(KDRIVER_DEV_ATA_SECONDARY_CTL, 0);
// TODO: INTERRUPTS
}
export function kdriver_dev_ata_readSectors(
descriptor: AtaDriveDescriptor,
start: number,
count: number,
read: number
) {
let buffer: number[] = [];
for (let i = 0; i < count; ++i) {
const sectorNum = start + i;
const valid = { valid: false };
const block = blockCache_block(
cache,
(descriptor.controller << 8) + descriptor.drive,
sectorNum,
valid
);
if (!valid.valid) {
// Need to actually read from disk
byteout(
descriptor.controller + KDRIVER_DEV_ATA_DRV_HEAD,
0xe0 | (descriptor.slave << 4) | ((sectorNum >> 24) & 0x0f)
);
byteout(descriptor.controller + KDRIVER_DEV_ATA_NSECTOR, 1);
byteout(descriptor.controller + KDRIVER_DEV_ATA_SECTOR, sectorNum & 0xff);
byteout(
descriptor.controller + KDRIVER_DEV_ATA_LCYL,
(sectorNum >> 8) & 0xff
);
byteout(
descriptor.controller + KDRIVER_DEV_ATA_HCYL,
(sectorNum >> 16) & 0xff
);
byteout(
descriptor.controller + KDRIVER_DEV_ATA_COMMAND,
KDRIVER_DEV_ATA_READ_SECTORS
);
// Wait for drive to be ready
let timeout = 0;
while (timeout < 100000) {
const status = bytein(descriptor.controller + KDRIVER_DEV_ATA_STATUS);
if (
!(status & KDRIVER_DEV_ATA_STATUS_BSY) &&
status & KDRIVER_DEV_ATA_STATUS_DRQ
) {
break;
}
timeout++;
}
// Read 256 words (512 bytes)
for (let j = 0; j < 256; j++) {
const word = wordin(descriptor.controller + KDRIVER_DEV_ATA_DATA);
block[j * 2] = word & 0xff;
block[j * 2 + 1] = (word >> 8) & 0xff;
}
}
// Copy the block to the output buffer
for (let n = 0; n < block.length; n++) {
buffer.push(block[n]!);
}
read += 512;
}
return buffer;
}
export function kdriver_dev_ata_fsDriver_read(
data: AtaDriveDescriptor,
count: number,
offset: number
) {
if (count % KDRIVER_DEV_ATA_BLOCK_SIZE != 0) throw new Error("Invalid count");
if (offset % KDRIVER_DEV_ATA_BLOCK_SIZE != 0)
throw new Error("Invalid offset");
const sectors = count / KDRIVER_DEV_ATA_BLOCK_SIZE;
const start = offset / KDRIVER_DEV_ATA_BLOCK_SIZE;
const buffer = kdriver_dev_ata_readSectors(data, start, sectors, 0);
return buffer;
}
export function kdriver_dev_ata_partition_fsDriver_read(
data: any,
count: number,
offset: number
) {
if (count % KDRIVER_DEV_ATA_BLOCK_SIZE != 0) throw new Error("Invalid count");
if (offset % KDRIVER_DEV_ATA_BLOCK_SIZE != 0)
throw new Error("Invalid offset");
const partition = data;
const disk = partition.disk as { descriptor: AtaDriveDescriptor };
const sectors = count / KDRIVER_DEV_ATA_BLOCK_SIZE;
const start = partition.lbaStart + offset / KDRIVER_DEV_ATA_BLOCK_SIZE;
const buffer = kdriver_dev_ata_readSectors(
disk.descriptor,
start,
sectors,
0
);
return buffer;
}
export const kdriver_dev_ata_fsDriver = {
read: kdriver_dev_ata_fsDriver_read,
};
export const kdriver_dev_ata_partition_fsDriver = {
read: kdriver_dev_ata_partition_fsDriver_read,
};

View File

@@ -1,31 +0,0 @@
import { Keycode, RKeycode } from "../../../config/keyboard";
import { Logger } from "../../../lib/libstd/logger/logger.kmod";
import { bytein } from "../../../lib/libts/byte";
import { kmod_cpu_irq_register } from "../../modules/cpu/interrupts";
import { kmod_terminal_input_handleKeyboardInput } from "../../modules/terminal/input";
export function kdriver_dev_keyboard_handleInterrupt(): void {
const scancode = bytein(0x60);
const key = RKeycode[scancode as keyof typeof RKeycode] as
| keyof typeof Keycode
| undefined;
//Logger.log(String(scancode));
if (key == undefined) return;
kmod_terminal_input_handleKeyboardInput(key);
}
export function kdriver_dev_keyboard_init(): void {
if (!kmod_cpu_irq_register(1, kdriver_dev_keyboard_handleInterrupt, null)) {
Logger.log("[keyboard] Failed to register keyboard interrupt");
return;
}
let key = 0;
while ((key = bytein(0x64) & 1) == 1) {
bytein(0x60);
}
}

View File

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

View File

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

View File

@@ -1,154 +0,0 @@
import { Path } from "../../lib/libstd/path";
import type { AtaDriveDescriptor } from "../../types/dev/ata/drive";
import type { DeviceType } from "../../types/dev/device";
import type {
KFilesystemDevice,
KFilesystemDirectReadResponse,
KFilesystemDriver,
KFilesystemEntity,
KFilesystemMemdata,
KFilesystemMemdev,
KFilesystemStat,
} from "../../types/filesystem/fs";
const devfs_data: KFilesystemMemdev = [];
export function devfs_driver(): KFilesystemDriver {
return {
id: "devfs",
init: devfs_init,
listDir(path: string): (KFilesystemEntity | KFilesystemDevice)[] | null {
return devfs_listDir(path);
},
readFile(path: string): unknown {
throw new Error("Cannot read files in devfs.");
},
writeFile(path: string, content: unknown): void {
throw new Error("Cannot write files in devfs.");
},
createFile(path: string, content: unknown): void {
throw new Error("Cannot create files in devfs.");
},
mkdir(path: string): void {
throw new Error("Cannot make directories in devfs.");
},
stat(path: string): KFilesystemStat | null {
return devfs_statEntity(path);
},
rm(path: string): void {
throw new Error("Cannot remove objects in devfs.")
}
};
}
export function devfs_init(): void {
devfs_data.push({
name: "root",
path: "/",
type: "folder",
size: 0,
contents: null,
});
}
export function devfs_getEntity(
path: string
): KFilesystemDevice | KFilesystemEntity | null {
for (let i = 0; i < devfs_data.length; i++) {
const entity = devfs_data[i]!;
if (entity.path === path) return entity;
}
return null;
}
export function devfs_statEntity(path: string): KFilesystemStat | null {
const entity = devfs_getEntity(path);
if (!entity) return null;
return {
name: entity.name,
type: entity.type,
size: entity.size,
};
}
export function devfs_mkdir(path: string): void {
if (devfs_getEntity(path)) return;
const parent = Path.dirname(path);
if (!devfs_getEntity(parent)) return;
devfs_data.push({
name: Path.filename(path),
path,
type: "folder",
size: 0,
contents: null,
});
}
export function devfs_listDir(
path: string
): (KFilesystemEntity | KFilesystemDevice)[] | null {
const entity = devfs_getEntity(path);
if (!entity) return null;
if (entity.type !== "folder") return null;
const contents: (KFilesystemEntity | KFilesystemDevice)[] = [];
for (let i = 0; i < devfs_data.length; i++) {
const e = devfs_data[i]!;
if (Path.dirname(e.path) === path) {
contents.push(e);
}
}
return contents;
}
export function devfs_registerDevice(
path: string,
type: DeviceType,
driver: unknown,
data: unknown
) {
if (devfs_getEntity(path)) return;
const parent = Path.dirname(path);
if (!devfs_getEntity(parent)) return;
devfs_data.push({
name: Path.filename(path),
path,
type: "file",
size: 0,
contents: "",
dtype: type,
driver: driver,
data: data,
});
}
export function devfs_getDevice(path: string): KFilesystemDevice | null {
const e = devfs_getEntity(path);
if (!e) return null;
if (!("driver" in e)) return null;
return e;
}
export function devfs_directRead(
path: string,
count: number,
offset: number
): KFilesystemDirectReadResponse | null {
const device = devfs_getDevice(path);
if (!device) return null;
//return (device.driver as any).read(device.data, count, offset);
return [];
}

View File

@@ -1,370 +0,0 @@
import { Logger } from "../../lib/libstd/logger/logger.kmod";
import type {
KFilesystemDriver,
KFilesystemEntity,
KFilesystemStat,
} from "../../types/filesystem/fs";
interface Fat32BootSector {
bytesPerSector: number;
sectorsPerCluster: number;
reservedSectors: number;
numberOfFATs: number;
sectorsPerFAT: number;
rootCluster: number;
totalSectors: number;
}
interface Fat32State {
driver: any;
data: any;
boot: Fat32BootSector;
fatStart: number;
dataStart: number;
}
interface DirectoryEntry {
name: string;
extension: string;
attributes: number;
firstCluster: number;
fileSize: number;
}
const ATTR_READ_ONLY = 0x01;
const ATTR_HIDDEN = 0x02;
const ATTR_SYSTEM = 0x04;
const ATTR_VOLUME_ID = 0x08;
const ATTR_DIRECTORY = 0x10;
const ATTR_ARCHIVE = 0x20;
const ATTR_LONG_NAME =
ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID;
export function fat32_driver(driver: any, data: any): KFilesystemDriver {
const state: Fat32State = {
driver,
data,
boot: {} as Fat32BootSector,
fatStart: 0,
dataStart: 0,
};
return {
id: "fat32",
init() {
return fat32_init(state);
},
listDir(path: string) {
return fat32_listDir(state, path);
},
readFile(path: string) {
return fat32_readFile(state, path);
},
writeFile(path: string, content: unknown) {
throw new Error("FAT32 write not implemented");
},
createFile(path: string, content: unknown) {
throw new Error("FAT32 createFile not implemented");
},
mkdir(path: string) {
throw new Error("FAT32 mkdir not implemented");
},
stat(path: string) {
return fat32_stat(state, path);
},
directRead(path: string, count: number, offset: number) {
return fat32_directRead(state, path, count, offset);
},
rm(path: string): void {
throw new Error("Cannot remove objects in fat32.");
},
};
}
function fat32_init(state: Fat32State): void {
const bootSector = state.driver.read(state.data, 512, 0);
state.boot = {
bytesPerSector: bootSector[11] | (bootSector[12] << 8),
sectorsPerCluster: bootSector[13],
reservedSectors: bootSector[14] | (bootSector[15] << 8),
numberOfFATs: bootSector[16],
sectorsPerFAT:
bootSector[36] |
(bootSector[37] << 8) |
(bootSector[38] << 16) |
(bootSector[39] << 24),
rootCluster:
bootSector[44] |
(bootSector[45] << 8) |
(bootSector[46] << 16) |
(bootSector[47] << 24),
totalSectors:
bootSector[32] |
(bootSector[33] << 8) |
(bootSector[34] << 16) |
(bootSector[35] << 24),
};
state.fatStart = state.boot.reservedSectors;
state.dataStart =
state.boot.reservedSectors +
state.boot.numberOfFATs * state.boot.sectorsPerFAT;
}
function fat32_clusterToSector(state: Fat32State, cluster: number): number {
return state.dataStart + (cluster - 2) * state.boot.sectorsPerCluster;
}
function fat32_readCluster(state: Fat32State, cluster: number): number[] {
const sector = fat32_clusterToSector(state, cluster);
const size = state.boot.sectorsPerCluster * state.boot.bytesPerSector;
return state.driver.read(
state.data,
size,
sector * state.boot.bytesPerSector
);
}
function fat32_getNextCluster(state: Fat32State, cluster: number): number {
const fatOffset = cluster * 4;
const fatSector =
state.fatStart + Math.floor(fatOffset / state.boot.bytesPerSector);
const entryOffset = fatOffset % state.boot.bytesPerSector;
const sector = state.driver.read(
state.data,
state.boot.bytesPerSector,
fatSector * state.boot.bytesPerSector
);
const nextCluster =
sector[entryOffset] |
(sector[entryOffset + 1] << 8) |
(sector[entryOffset + 2] << 16) |
(sector[entryOffset + 3] << 24);
return nextCluster & 0x0fffffff;
}
function fat32_parseDirectoryEntry(
data: number[],
offset: number
): DirectoryEntry | null {
if (data[offset] === 0x00) return null; // End of directory
if (data[offset] === 0xe5) return null; // Deleted entry
const attr = data[offset + 11];
if ((attr & ATTR_LONG_NAME) === ATTR_LONG_NAME) return null; // LFN entry
let name = "";
for (let i = 0; i < 8; i++) {
const c = data[offset + i];
if (c !== 0x20) name += String.fromCharCode(c);
}
let extension = "";
for (let i = 0; i < 3; i++) {
const c = data[offset + 8 + i];
if (c !== 0x20) extension += String.fromCharCode(c);
}
const firstClusterLow = data[offset + 26] | (data[offset + 27] << 8);
const firstClusterHigh = data[offset + 20] | (data[offset + 21] << 8);
const firstCluster = (firstClusterHigh << 16) | firstClusterLow;
const fileSize =
data[offset + 28] |
(data[offset + 29] << 8) |
(data[offset + 30] << 16) |
(data[offset + 31] << 24);
return {
name: name.trim(),
extension: extension.trim(),
attributes: attr,
firstCluster,
fileSize,
};
}
function fat32_listDir(
state: Fat32State,
path: string
): KFilesystemEntity[] | null {
let cluster: number | undefined;
if (path === "/") cluster = state.boot.rootCluster;
else {
const entry = fat32_findEntry(state, path);
if (!entry) {
return null;
}
cluster = entry.firstCluster;
}
if (!cluster) {
return null;
}
const entries: KFilesystemEntity[] = [];
let currentCluster = cluster;
while (currentCluster < 0x0ffffff8) {
const clusterData = fat32_readCluster(state, currentCluster);
for (let i = 0; i < clusterData.length; i += 32) {
const entry = fat32_parseDirectoryEntry(clusterData, i);
if (!entry) continue;
// Skip volume label entries
if ((entry.attributes & ATTR_VOLUME_ID) !== 0) continue;
const fullName = entry.extension
? entry.name + "." + entry.extension
: entry.name;
const isDir = (entry.attributes & ATTR_DIRECTORY) !== 0;
entries.push({
name: fullName,
path: path === "/" ? "/" + fullName : path + "/" + fullName,
type: isDir ? "folder" : "file",
size: entry.fileSize,
contents: null,
});
}
currentCluster = fat32_getNextCluster(state, currentCluster);
}
return entries;
}
function fat32_findEntry(
state: Fat32State,
path: string
): DirectoryEntry | null {
const parts = path.split("/").filter(function (p) {
return p.length > 0;
});
if (parts.length === 0) return null;
let currentCluster = state.boot.rootCluster;
for (let i = 0; i < parts.length; i++) {
const targetName = parts[i]!.toUpperCase();
let found = false;
while (currentCluster < 0x0ffffff8) {
const clusterData = fat32_readCluster(state, currentCluster);
for (let j = 0; j < clusterData.length; j += 32) {
const entry = fat32_parseDirectoryEntry(clusterData, j);
if (!entry) continue;
const entryName = entry.extension
? entry.name + "." + entry.extension
: entry.name;
if (entryName.toUpperCase() === targetName) {
if (i === parts.length - 1) return entry;
currentCluster = entry.firstCluster;
found = true;
break;
}
}
if (found) break;
currentCluster = fat32_getNextCluster(state, currentCluster);
}
if (!found) return null;
}
return null;
}
function fat32_readFile(state: Fat32State, path: string): number[] {
const entry = fat32_findEntry(state, path);
if (!entry || (entry.attributes & ATTR_DIRECTORY) !== 0) {
throw new Error("File not found or is a directory");
}
const data: number[] = [];
let currentCluster = entry.firstCluster;
let remaining = entry.fileSize;
while (currentCluster < 0x0ffffff8 && remaining > 0) {
const clusterData = fat32_readCluster(state, currentCluster);
const bytesToCopy = Math.min(remaining, clusterData.length);
for (let i = 0; i < bytesToCopy; i++) {
data.push(clusterData[i]!);
}
remaining -= bytesToCopy;
currentCluster = fat32_getNextCluster(state, currentCluster);
}
return data;
}
function fat32_stat(state: Fat32State, path: string): KFilesystemStat | null {
if (path === "/") {
return { name: "/", type: "folder", size: 0 };
}
const entry = fat32_findEntry(state, path);
if (!entry) return null;
const fullName = entry.extension
? entry.name + "." + entry.extension
: entry.name;
return {
name: fullName,
type: (entry.attributes & ATTR_DIRECTORY) !== 0 ? "folder" : "file",
size: entry.fileSize,
};
}
function fat32_directRead(
state: Fat32State,
path: string,
count: number,
offset: number
): number[] {
const entry = fat32_findEntry(state, path);
if (!entry || (entry.attributes & ATTR_DIRECTORY) !== 0) {
throw new Error("File not found or is a directory");
}
const clusterSize = state.boot.sectorsPerCluster * state.boot.bytesPerSector;
let currentCluster = entry.firstCluster;
let currentOffset = 0;
const data: number[] = [];
// Skip to the cluster containing the offset
while (offset >= currentOffset + clusterSize && currentCluster < 0x0ffffff8) {
currentOffset += clusterSize;
currentCluster = fat32_getNextCluster(state, currentCluster);
}
let remaining = count;
const startOffsetInCluster = offset - currentOffset;
while (remaining > 0 && currentCluster < 0x0ffffff8) {
const clusterData = fat32_readCluster(state, currentCluster);
const start = data.length === 0 ? startOffsetInCluster : 0;
const bytesToCopy = Math.min(remaining, clusterData.length - start);
for (let i = start; i < start + bytesToCopy; i++) {
data.push(clusterData[i]!);
}
remaining -= bytesToCopy;
currentCluster = fat32_getNextCluster(state, currentCluster);
}
return data;
}

View File

@@ -1,168 +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 procfs_data: KFilesystemMemdata = [];
export function procfs_driver(): KFilesystemDriver {
return {
id: "procfs",
init: procfs_init,
listDir(path: string): KFilesystemEntity[] | null {
return procfs_listDir(path);
},
readFile(path: string): unknown {
return procfs_readFile(path);
},
writeFile(path: string, content: unknown): void {
throw new Error("Cannot write files in procfs.");
},
createFile(path: string, content: unknown): void {
throw new Error("Cannot create files in procfs.");
},
mkdir(path: string): void {
throw new Error("Cannot make directories in procfs.");
},
stat(path: string): KFilesystemStat | null {
return procfs_statEntity(path);
},
rm(path: string): void {
procfs_rm(path);
},
};
}
export function procfs_init(): void {
procfs_data.push({
name: "root",
path: "/",
type: "folder",
size: 0,
contents: null,
});
}
export function procfs_getEntity(path: string): KFilesystemEntity | null {
for (let i = 0; i < procfs_data.length; i++) {
const entity = procfs_data[i]!;
if (entity.path === path) return entity;
}
return null;
}
export function procfs_statEntity(path: string): KFilesystemStat | null {
const entity = procfs_getEntity(path);
if (!entity) return null;
return {
name: entity.name,
type: entity.type,
size: entity.size,
};
}
export function procfs_mkdir(path: string): void {
if (procfs_getEntity(path)) return;
const parent = Path.dirname(path);
if (!procfs_getEntity(parent)) return;
procfs_data.push({
name: Path.filename(path),
path,
type: "folder",
size: 0,
contents: null,
});
}
export function procfs_createFile(path: string, content: unknown): void {
if (procfs_getEntity(path)) return;
const parent = Path.dirname(path);
if (!procfs_getEntity(parent)) return;
const size = String(content).length;
procfs_data.push({
name: Path.filename(path),
path,
type: "file",
size,
contents: content,
});
}
export function procfs_writeFile(path: string, content: unknown): void {
const entity = procfs_getEntity(path);
if (!entity) return procfs_createFile(path, content);
if (entity.type !== "file") return;
entity.contents = content;
entity.size = String(content).length;
}
export function procfs_readFile(path: string): unknown {
const entity = procfs_getEntity(path);
if (!entity) return null;
if (entity.type !== "file") return null;
return entity.contents;
}
export function procfs_listDir(path: string): KFilesystemEntity[] | null {
const entity = procfs_getEntity(path);
if (!entity) return null;
if (entity.type !== "folder") return null;
const contents: KFilesystemEntity[] = [];
for (let i = 0; i < procfs_data.length; i++) {
const e = procfs_data[i]!;
if (Path.dirname(e.path) === path) {
contents.push(e);
}
}
return contents;
}
export function procfs_rm(path: string): void {
const entity = procfs_getEntity(path);
if (!entity) return;
if (entity.type === "file") {
const index = procfs_data.indexOf(entity);
if (index !== -1) procfs_data.splice(index, 1);
} else if (entity.type === "folder") {
const entitiesToRemove: KFilesystemEntity[] = [];
const pathPrefix = path === "/" ? "/" : path + "/";
for (let i = 0; i < procfs_data.length; i++) {
const e = procfs_data[i]!;
if (e.path === path || e.path.startsWith(pathPrefix)) {
entitiesToRemove.push(e);
}
}
for (let i = 0; i < entitiesToRemove.length; i++) {
const toRemove = entitiesToRemove[i]!;
const index = procfs_data.indexOf(toRemove);
if (index !== -1) procfs_data.splice(index, 1);
}
}
}

View File

@@ -1,141 +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);
},
rm(path: string): void {
throw new Error("Cannot remove objects in sysfs.");
},
};
}
export function sysfs_init(): void {
sysfs_data.push({
name: "root",
path: "/",
type: "folder",
size: 0,
contents: null,
});
sysfs_mkdir("/pci");
}
export function sysfs_getEntity(path: string): KFilesystemEntity | null {
for (let i = 0; i < sysfs_data.length; i++) {
const entity = sysfs_data[i]!;
if (entity.path === path) return entity;
}
return null;
}
export function sysfs_statEntity(path: string): KFilesystemStat | null {
const entity = sysfs_getEntity(path);
if (!entity) return null;
return {
name: entity.name,
type: entity.type,
size: entity.size,
};
}
export function sysfs_mkdir(path: string): void {
if (sysfs_getEntity(path)) return;
const parent = Path.dirname(path);
if (!sysfs_getEntity(parent)) return;
sysfs_data.push({
name: Path.filename(path),
path,
type: "folder",
size: 0,
contents: null,
});
}
export function sysfs_createFile(path: string, content: unknown): void {
if (sysfs_getEntity(path)) return;
const parent = Path.dirname(path);
if (!sysfs_getEntity(parent)) return;
const size = String(content).length;
sysfs_data.push({
name: Path.filename(path),
path,
type: "file",
size,
contents: content,
});
}
export function sysfs_writeFile(path: string, content: unknown): void {
const entity = sysfs_getEntity(path);
if (!entity) return sysfs_createFile(path, content);
if (entity.type !== "file") return;
entity.contents = content;
entity.size = String(content).length;
}
export function sysfs_readFile(path: string): unknown {
const entity = sysfs_getEntity(path);
if (!entity) return null;
if (entity.type !== "file") return null;
return entity.contents;
}
export function sysfs_listDir(path: string): KFilesystemEntity[] | null {
const entity = sysfs_getEntity(path);
if (!entity) return null;
if (entity.type !== "folder") return null;
const contents: KFilesystemEntity[] = [];
for (let i = 0; i < sysfs_data.length; i++) {
const e = sysfs_data[i]!;
if (Path.dirname(e.path) === path) {
contents.push(e);
}
}
return contents;
}

View File

@@ -1,78 +0,0 @@
import { Logger } from "../lib/libstd/logger/logger.kmod";
import { charc } from "../lib/libts/byte";
import { padStart } from "../lib/libts/string";
import { uiarrtostr } from "../lib/libts/uint_arr";
import { getDate } from "../lib/sys/date";
import { kdriver_dev_ata_detectDisks } from "./drivers/dev/ata";
import { kdriver_dev_pci_detectDevices } from "./drivers/dev/pci";
import {
kdriver_etc_serial_read,
kdriver_etc_serial_transmit,
} from "./drivers/etc/serial";
import { devfs_driver, devfs_getDevice } from "./filesystem/devfs";
import { fat32_driver } from "./filesystem/fat32";
import { procfs_driver } from "./filesystem/procfs";
import { sysfs_driver, sysfs_readFile } from "./filesystem/sysfs";
import { kmod_app_init, kmod_app_run } from "./modules/app/app.kmod";
import { kmod_disks_detectDisks } from "./modules/disks/disks.kmod";
import {
kmod_drivers_init,
kmod_drivers_register,
} from "./modules/drivers/drivers.kmod";
import {
kmod_filesystem_init,
kmod_filesystem_listDir,
kmod_filesystem_mount,
kmod_filesystem_readFile,
} from "./modules/filesystem/filesystem.kmod";
import {
kmod_graphics_vga_clear,
kmod_graphics_vga_init,
kmod_graphics_vga_pushLine,
kmod_graphics_vga_setLastLine,
} from "./modules/graphics/graphics.kmod";
import {
kmod_terminal_input_init,
kmod_terminal_input_onKeyboardInput,
} from "./modules/terminal/input";
export function kmain() {
kmod_drivers_init();
kmod_drivers_register();
Logger.log("[Kernel] Drivers initialized.");
Logger.log("[Kernel] Initializing VGA module...");
kmod_graphics_vga_init();
Logger.log("[Kernel] Initializing filesystem module...");
kmod_filesystem_init();
kmod_filesystem_mount("/sys", sysfs_driver);
kmod_filesystem_mount("/dev", devfs_driver);
kmod_filesystem_mount("/proc", procfs_driver);
Logger.log("[Kernel] Initializing terminal module...");
kmod_terminal_input_init();
Logger.log("[Kernel] Initializing PCI devices...");
kdriver_dev_pci_detectDevices();
Logger.log("[Kernel] Initializing drives...");
kmod_disks_detectDisks();
const dev = devfs_getDevice("/hda1");
if (!dev) throw new Error("System drive not found");
kmod_filesystem_mount("/disk", function () {
return fat32_driver(dev.driver, dev.data);
});
Logger.log("[Kernel] Initializing app module...");
kmod_app_init();
Logger.log("[Kernel] Kernel initialized successfully.");
const shell = uiarrtostr(kmod_filesystem_readFile("/disk/ushellc")!);
kmod_app_run(shell, "");
}

View File

@@ -1,152 +0,0 @@
import { Logger } from "../../../lib/libstd/logger/logger.kmod";
import { Path } from "../../../lib/libstd/path";
import { iexec } from "../../../lib/libts/exec";
import { uiarrtostr } from "../../../lib/libts/uint_arr";
import {
kmod_filesystem_listDir,
kmod_filesystem_readFile,
kmod_filesystem_stat,
} from "../filesystem/filesystem.kmod";
import { oskrnl_register } from "../../../oskrnl";
import { getPathEnv } from "../../../lib/sys/env";
import {
procfs_mkdir,
procfs_readFile,
procfs_rm,
procfs_writeFile,
} from "../../filesystem/procfs";
const exitListeners: { [pid: string]: (() => void)[] } = {};
const heapHandles: { [pid: string]: number } = {};
export function kmod_app_init() {
oskrnl_register();
}
export function kmod_app_run(path: string, args: string) {
const appPath = kmod_app_resolve(path);
if (!appPath) throw new Error("App not found");
const meta = JSON.parse(
uiarrtostr(kmod_filesystem_readFile(Path.join(appPath, "meta.lam"))!)
);
if (!meta) throw new Error("App metadata not found");
const entrypoint = Path.join(appPath, meta["app:entrypoint"]);
const code = uiarrtostr(kmod_filesystem_readFile(entrypoint)!);
const pid = kmod_app_proc_generateId().toString();
kmod_app_proc_init(pid, meta["app:name"]!, args);
kmod_app_proc_registerHandle(pid, "app");
const heapHandle = iexec("var __oskrnl_procd_pid = " + pid + ";\n" + code);
if (heapHandle) heapHandles[pid] = heapHandle;
kmod_app_proc_unregisterHandle(pid, "app");
return pid;
}
export function kmod_app_resolve(path: string): string | null {
if (kmod_filesystem_stat(path)) return path;
const pathEnv = getPathEnv();
if (!pathEnv) return null;
for (let i = 0; i < pathEnv.length; i++) {
const p = Path.join(pathEnv[i]!, path);
if (kmod_filesystem_stat(p)) return p;
}
return null;
}
export function kmod_app_proc_generateId(): number {
return Math.floor(Math.random() * 0xffffffff);
}
export function kmod_app_proc_init(id: string, name: string, args: string) {
const root = "/" + id;
procfs_mkdir(root);
procfs_writeFile(Path.join(root, "name"), name);
procfs_writeFile(Path.join(root, "args"), args);
procfs_writeFile(Path.join(root, "pid"), id);
procfs_writeFile(Path.join(root, "handles"), "");
}
export function kmod_app_proc_getArgs(pid: string): string {
const res = procfs_readFile(Path.join("/" + pid, "args"));
return res as string;
}
export function kmod_app_proc_registerHandle(
pid: string,
handle: string
): string {
const handles = procfs_readFile(Path.join("/" + pid, "handles")) as string;
const handlesArr = handles == "" ? [] : handles.split(",");
handlesArr.push(handle);
procfs_writeFile(Path.join("/" + pid, "handles"), handlesArr.join(","));
return handle;
}
export function kmod_app_proc_unregisterHandle(
pid: string,
handle: string
): void {
const handles = procfs_readFile(Path.join("/" + pid, "handles")) as string;
if (handles == "") return;
const handlesArr = handles.split(",");
handlesArr.splice(handlesArr.indexOf(handle), 1);
procfs_writeFile(Path.join("/" + pid, "handles"), handlesArr.join(","));
if (handlesArr.length < 1) kmod_app_proc_handleExit(pid);
}
export function kmod_app_proc_generateHandle(): string {
return Math.floor(Math.random() * 0xffffffff).toString();
}
export function kmod_app_proc_handleExit(pid: string): void {
procfs_writeFile(Path.join("/", pid + "/handles"), "");
procfs_rm("/" + pid);
if (exitListeners[pid]) {
for (let i = 0; i < exitListeners[pid].length; i++) {
exitListeners[pid][i]!();
}
}
exitListeners[pid] = [];
delete exitListeners[pid];
if (heapHandles[pid]) {
$destroyIsolatedHeap(heapHandles[pid]!);
delete heapHandles[pid];
}
}
export function kmod_app_proc_running(pid: string): boolean {
const handles = procfs_readFile(Path.join("/" + pid, "handles")) as string;
if (handles === null || handles === undefined) return false;
return handles !== "";
}
export function kmod_app_proc_addExitListener(
pid: string,
listener: () => void
): void {
if (!exitListeners[pid]) exitListeners[pid] = [];
exitListeners[pid].push(listener);
}
export function kmod_app_proc_exit(pid: string): void {
kmod_app_proc_handleExit(pid);
}

View File

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

View File

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

View File

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

View File

@@ -1,43 +0,0 @@
import { Logger } from "../../../lib/libstd/logger/logger.kmod";
import type { KInterrupt, KInterruptHandler } from "../../../types/interrupt";
const kmod_cpu_irq_data: KInterrupt[] = [];
export function kmod_cpu_irq_register(
irq: number,
handler: KInterruptHandler,
data: unknown
): boolean {
if (kmod_cpu_irq_data[irq]) {
Logger.log("[IRQ] IRQ " + irq + " is already registered.");
return false;
}
if (irq > 15) {
Logger.log("[IRQ] IRQ " + irq + " is out of bounds.");
return false;
}
kmod_cpu_irq_data[irq] = {
handler: handler,
data: data,
};
function wrapper(irqNum: number) {
const irqData = kmod_cpu_irq_data[irqNum];
if (irqData) {
irqData.handler(irqNum, irqData.data);
}
}
const success = $irqregister(irq, wrapper);
if (!success) {
Logger.log("[IRQ] Failed to register IRQ " + irq + " with hardware.");
delete kmod_cpu_irq_data[irq];
return false;
}
Logger.log("[IRQ] Successfully registered IRQ " + irq);
return true;
}

View File

@@ -1,163 +0,0 @@
import { Logger } from "../../../lib/libstd/logger/logger.kmod";
import { Path } from "../../../lib/libstd/path";
import { cchar, charc } from "../../../lib/libts/byte";
import { DeviceType } from "../../../types/dev/device";
import { DiskType, type Disk } from "../../../types/filesystem/disk";
import {
kdriver_dev_ata_detectDisks,
kdriver_dev_ata_fsDriver,
kdriver_dev_ata_getDrive,
kdriver_dev_ata_numberOfDrives,
kdriver_dev_ata_partition_fsDriver,
kdriver_dev_ata_readSectors,
} from "../../drivers/dev/ata";
import { devfs_registerDevice } from "../../filesystem/devfs";
import { sysfs_mkdir, sysfs_writeFile } from "../../filesystem/sysfs";
let disks: Disk[] = [];
export function kmod_disks_detectDisks() {
kdriver_dev_ata_detectDisks();
let cdrom = charc("a");
let disk = charc("a");
let numOfDisks = 0;
for (let i = 0; i < kdriver_dev_ata_numberOfDrives(); ++i) {
const descriptor = kdriver_dev_ata_getDrive(i);
if (!descriptor.present) continue;
let name = "";
if (descriptor.atapi) {
name = "cd" + cchar(cdrom);
cdrom++;
disks.push({
dnum: numOfDisks,
name: name,
descriptor: descriptor,
type: DiskType.ATAPI,
});
devfs_registerDevice(
"/" + name,
DeviceType.BlockDevice,
null,
descriptor
);
} else {
name = "hd" + cchar(disk);
disk++;
disks.push({
dnum: numOfDisks,
name: name,
descriptor: descriptor,
type: DiskType.ATA,
});
devfs_registerDevice(
"/" + name,
DeviceType.BlockDevice,
kdriver_dev_ata_fsDriver,
descriptor
);
let part = charc("1");
const partitions = kmod_disks_getPartitions(disks[numOfDisks]!);
for (let n = 0; n < partitions.length; n++) {
const partition = partitions[n];
let part_name = name + cchar(part);
part++;
(partition as any).disk = disks[numOfDisks]!;
devfs_registerDevice(
"/" + part_name,
DeviceType.BlockDevice,
kdriver_dev_ata_partition_fsDriver,
partition
);
}
}
const p = Path.join("/ata", name);
sysfs_mkdir(p);
sysfs_writeFile(Path.join(p, "model"), descriptor.model);
sysfs_writeFile(Path.join(p, "serial"), descriptor.serial);
sysfs_writeFile(Path.join(p, "firmware"), descriptor.firmware);
numOfDisks++;
}
}
export function kmod_disks_getPartitions(disk: Disk) {
const sectors = kdriver_dev_ata_readSectors(disk.descriptor, 0, 1, 0);
const signature = (sectors[511]! << 8) | sectors[510]!;
if (signature !== 0xaa55) {
throw new Error("Invalid MBR signature");
}
const partitions = [];
// Parse partition table (starts at offset 446, 4 entries of 16 bytes each)
for (let i = 0; i < 4; i++) {
const offset = 446 + i * 16;
const status = sectors[offset]!;
const partitionType = sectors[offset + 4]!;
// LBA of first sector (little-endian)
const lbaStart =
sectors[offset + 8]! |
(sectors[offset + 9]! << 8) |
(sectors[offset + 10]! << 16) |
(sectors[offset + 11]! << 24);
// Number of sectors (little-endian)
const sectorCount =
sectors[offset + 12]! |
(sectors[offset + 13]! << 8) |
(sectors[offset + 14]! << 16) |
(sectors[offset + 15]! << 24);
// Skip empty partition entries
if (partitionType === 0 || sectorCount === 0) {
continue;
}
partitions.push({
index: i,
bootable: status === 0x80,
type: partitionType,
lbaStart: lbaStart,
sectors: sectorCount,
size: sectorCount * 512,
});
Logger.log(
"[Disk] Partition " +
i +
": Type=0x" +
partitionType.toString(16) +
" " +
"LBA=" +
lbaStart +
" Sectors=" +
sectorCount +
" " +
"Bootable=" +
(status === 0x80)
);
}
return partitions;
}

View File

@@ -1,19 +0,0 @@
import { kdriver_dev_ata_init } from "../../drivers/dev/ata";
import { kdriver_dev_keyboard_init } from "../../drivers/dev/keyboard";
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,
kdriver_dev_keyboard_init,
kdriver_dev_ata_init,
];
export function kmod_drivers_init(): void {}
export function kmod_drivers_register(): void {
for (let i = 0; i < drivers.length; i++) {
drivers[i]!();
}
}

View File

@@ -1,136 +0,0 @@
import { Logger } from "../../../lib/libstd/logger/logger.kmod";
import { Path } from "../../../lib/libstd/path";
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_lsMountAsFsEntity() {
let out: KFilesystemEntity[] = [];
for (let i = 0; i < kmod_filesystem_data.length; i++) {
const mount = kmod_filesystem_data[i]!;
out.push({
name: Path.filename(mount.mountpoint),
path: mount.mountpoint,
type: "folder",
size: 0,
contents: 0,
});
}
return out;
}
export function kmod_filesystem_listDir(
path: string
): KFilesystemEntity[] | null {
const mount = kmod_filesystem_findMount(path);
if (!mount) return kmod_filesystem_lsMountAsFsEntity();
const strippedPath = kmod_filesystem_stripMountpoint(mount, path);
return mount.driver.listDir(strippedPath);
}
export function kmod_filesystem_readFile(path: string): number[] | null {
const mount = kmod_filesystem_findMount(path);
if (!mount) return null;
const strippedPath = kmod_filesystem_stripMountpoint(mount, path);
return mount.driver.readFile(strippedPath) as number[];
}
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);
}
export function kmod_filesystem_directRead(
path: string,
count: number,
offset: number
) {}

View File

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

View File

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

View File

@@ -1,95 +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[] = [];
let init = false;
export function kmod_graphics_vga_init() {
init = true;
kmod_graphics_vga_clear();
}
export function kmod_graphics_vga_pushLine(line: string) {
if (!init) return;
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_setLastLine(line: string) {
if (!init) return;
if (kmod_graphics_vga_lineBuf.length === 0) {
kmod_graphics_vga_lineBuf.push(line);
} else {
kmod_graphics_vga_lineBuf[kmod_graphics_vga_lineBuf.length - 1] = line;
}
kmod_graphics_vga_printLines();
}
export function kmod_graphics_vga_printLines() {
if (!init) return;
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() {
if (!init) return;
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
) {
if (!init) return;
const charAddr = kmod_graphics_vga_getCharAddr(x, y);
const colorAddr = kmod_graphics_vga_getColorAddr(x, y);
$addrw(charAddr, charc(char));
$addrw(colorAddr, color);
}

View File

@@ -1,28 +0,0 @@
import type { Keycode } from "../../../config/keyboard";
const kmod_terminal_input_keyboardInputHandlers: Array<
(keycode: keyof typeof Keycode) => void
> = [];
export function kmod_terminal_input_init(): void {}
export function kmod_terminal_input_onKeyboardInput(
handler: (keycode: keyof typeof Keycode) => void
): () => void {
kmod_terminal_input_keyboardInputHandlers.push(handler);
return function () {
const index = kmod_terminal_input_keyboardInputHandlers.indexOf(handler);
if (index !== -1) {
kmod_terminal_input_keyboardInputHandlers.splice(index, 1);
}
};
}
export function kmod_terminal_input_handleKeyboardInput(
keycode: keyof typeof Keycode
): void {
for (let i = 0; i < kmod_terminal_input_keyboardInputHandlers.length; i++) {
kmod_terminal_input_keyboardInputHandlers[i]!(keycode);
}
}

View File

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

View File

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

View File

@@ -1,192 +0,0 @@
interface Block {
key: number;
hashNext: Block | null;
freeNext: Block | null;
freePrev: Block | null;
payload: number[]; // Array instead of Uint8Array
}
interface BlockCacheState {
payloadSize: number;
blocks: number;
hashTable: (Block | null)[];
blocksMemory: Block[];
front: Block | null;
rear: Block | null;
}
export function blockCache_create(): BlockCacheState {
return {
payloadSize: 0,
blocks: 0,
hashTable: [],
blocksMemory: [],
front: null,
rear: null,
};
}
export function blockCache_init(
state: BlockCacheState,
payloadSize: number,
blocks: number
): void {
state.payloadSize = payloadSize;
state.blocks = blocks;
// Initialize hash table (2x the number of blocks)
var hashTableSize = blocks * 2;
state.hashTable = [];
for (var i = 0; i < hashTableSize; i++) {
state.hashTable.push(null);
}
// Allocate blocks in memory
state.blocksMemory = [];
var previous: Block | null = null;
for (var i = 0; i < blocks; i++) {
var payload: number[] = [];
for (var j = 0; j < payloadSize; j++) {
payload.push(0);
}
var block: Block = {
key: 0,
hashNext: null,
freeNext: null,
freePrev: previous,
payload: payload,
};
if (previous) {
previous.freeNext = block;
}
state.blocksMemory.push(block);
previous = block;
}
state.front = state.blocksMemory[0];
state.rear = previous;
}
export function blockCache_blockIfPresent(
state: BlockCacheState,
deviceOrKey: number,
sector?: number
): number[] | null {
var origKey =
sector !== undefined ? deviceOrKey * 65536 + sector : deviceOrKey;
var key = origKey % (state.blocks * 2);
if (state.hashTable[key]) {
var entry = state.hashTable[key];
while (entry) {
if (entry.key === origKey) {
return entry.payload;
}
entry = entry.hashNext;
}
}
return null;
}
export function blockCache_block(
state: BlockCacheState,
deviceOrKey: number,
sectorOrValid: number | { valid: boolean },
valid?: { valid: boolean }
): number[] {
var origKey: number;
var validRef: { valid: boolean };
if (valid !== undefined) {
// block(state, device, sector, valid)
origKey = deviceOrKey * 65536 + (sectorOrValid as number);
validRef = valid;
} else {
// block(state, key, valid)
origKey = deviceOrKey;
validRef = sectorOrValid as { valid: boolean };
}
var key = origKey % (state.blocks * 2);
// Try to get from hash table
var direct = blockCache_blockIfPresent(state, origKey);
if (direct) {
validRef.valid = true;
return direct;
}
// Allocate new block from front of free list
validRef.valid = false;
if (!state.front) {
throw new Error("No free blocks available");
}
var blk = state.front;
// Remove block from previous hash table entry if it was used
if (blk.key) {
var previousKey = blk.key % (state.blocks * 2);
if (state.hashTable[previousKey] === blk) {
state.hashTable[previousKey] = blk.hashNext;
} else {
var entry = state.hashTable[previousKey];
var found = false;
while (entry && entry.hashNext) {
if (entry.hashNext === blk) {
entry.hashNext = blk.hashNext;
found = true;
break;
}
entry = entry.hashNext;
}
if (!found) {
throw new Error("The hash table chain did not contain the used block");
}
}
}
// Insert block into hash table
blk.key = origKey;
if (!state.hashTable[key]) {
blk.hashNext = null;
state.hashTable[key] = blk;
} else {
// Insert at end of chain
var entry = state.hashTable[key]!;
while (entry.hashNext) {
entry = entry.hashNext;
}
entry.hashNext = blk;
blk.hashNext = null;
}
// Move block to rear of free list
state.front = state.front.freeNext;
if (state.front) {
state.front.freePrev = null;
}
if (state.rear) {
state.rear.freeNext = blk;
}
blk.freePrev = state.rear;
blk.freeNext = null;
state.rear = blk;
return blk.payload;
}

View File

@@ -1,27 +0,0 @@
import { charc } from "../../libts/byte";
import { kdriver_etc_serial_transmit } from "../../../kernel/drivers/etc/serial";
import {
kmod_graphics_vga_pushLine,
kmod_graphics_vga_setLastLine,
} from "../../../kernel/modules/graphics/vga";
export const Logger = {
log(message: string) {
kmod_graphics_vga_pushLine(message);
for (let i = 0; i < message.length; i++) {
kdriver_etc_serial_transmit(charc(message[i]!));
}
kdriver_etc_serial_transmit(charc("\n"));
},
update(message: string) {
kmod_graphics_vga_setLastLine(message);
kdriver_etc_serial_transmit(charc("\x1b[2K"));
kdriver_etc_serial_transmit(charc("\r"));
for (let i = 0; i < message.length; i++) {
kdriver_etc_serial_transmit(charc(message[i]!));
}
},
};

View File

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

View File

@@ -1,15 +0,0 @@
export function bytein(port: number): number {
return $bytein(port);
}
export function byteout(port: number, value: number): void {
$byteout(port, value);
}
export function charc(char: string): number {
return char.charCodeAt(0);
}
export function cchar(code: number): string {
return String.fromCharCode(code)[0]!;
}

View File

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

View File

@@ -1,3 +0,0 @@
export function iexec(code: string) {
return $isolatedExec(code);
}

View File

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

View File

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

View File

@@ -1,9 +0,0 @@
export function uiarrtostr(a: number[]) {
let s = "";
for (let i = 0; i < a.length; i++) {
s += String.fromCharCode(a[i]!);
}
return s;
}

View File

@@ -1,7 +0,0 @@
export function wordin(w: number): number {
return $wordin(w);
}
export function wordout(w: number, value: number): void {
$wordout(w, value);
}

View File

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

View File

@@ -1,22 +0,0 @@
import { kmod_filesystem_readFile } from "../../kernel/modules/filesystem/filesystem.kmod";
import { uiarrtostr } from "../libts/uint_arr";
export function getEnv(key: string): string | null {
const data = uiarrtostr(kmod_filesystem_readFile("/disk/uenv")!);
const lines = data.split("\n");
for (let i = 0; i < lines.length; i++) {
const kv = lines[i]!.split("=");
if (kv[0] == key) return kv[1]!;
}
return null;
}
export function getPathEnv(): string[] | null {
const path = getEnv("PATH");
if (!path) return null;
return path.split(":");
}

Some files were not shown because too many files have changed in this diff Show More