Compare commits
18 Commits
e2184bdc27
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| f6b4039348 | |||
| 8761d6867c | |||
|
|
f2b5e17856 | ||
| c289ac6f38 | |||
| 868b5700cd | |||
| 092781ba57 | |||
| 7defc557b2 | |||
| e4b18fc8d7 | |||
| 19e034a982 | |||
| 4b4c3022eb | |||
| e3dce14c64 | |||
| 35b16bfc49 | |||
| 3f0b94d2fc | |||
| f483a34d3c | |||
| af5d8c709b | |||
| b7f619b8c3 | |||
| 12c109a120 | |||
| c222cae16f |
11
.gitignore
vendored
11
.gitignore
vendored
@@ -1,7 +1,6 @@
|
|||||||
_o/
|
old/
|
||||||
build/
|
out/
|
||||||
picolibc/
|
node_modules/
|
||||||
picolibc-install/
|
|
||||||
/lib/
|
|
||||||
*.iso
|
*.iso
|
||||||
*.img
|
*.img
|
||||||
|
.clangd
|
||||||
2
LICENSE
2
LICENSE
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
26
README.md
26
README.md
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## What the hell is this?
|
## 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
17
bun.lock
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"workspaces": {
|
||||||
|
"": {
|
||||||
|
"dependencies": {
|
||||||
|
"sailet": "^0.1.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"packages": {
|
||||||
|
"chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
|
||||||
|
|
||||||
|
"sailet": ["sailet@0.1.1", "", { "dependencies": { "chalk": "^5.6.2" }, "peerDependencies": { "typescript": "^5" }, "bin": { "sailet": "dist/cli/index.js", "st": "dist/cli/index.js" } }, "sha512-zKcCvANgxqB2YY/XbLtgLomHJvOvcYHDg0qpZ831XxORUm45oVFNWeBItaZzxFGZDfoXNXr6VqzDuRIoukMXaA=="],
|
||||||
|
|
||||||
|
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
FROM fedora:41
|
|
||||||
|
|
||||||
RUN dnf install -y \
|
|
||||||
gcc \
|
|
||||||
gcc-c++ \
|
|
||||||
make \
|
|
||||||
nasm \
|
|
||||||
python3 \
|
|
||||||
git \
|
|
||||||
qemu-system-x86 \
|
|
||||||
wget \
|
|
||||||
meson \
|
|
||||||
unzip \
|
|
||||||
&& dnf clean all
|
|
||||||
|
|
||||||
RUN curl -fsSL https://bun.sh/install | bash
|
|
||||||
ENV PATH="/root/.bun/bin:${PATH}"
|
|
||||||
|
|
||||||
WORKDIR /workspace
|
|
||||||
|
|
||||||
CMD ["bash", "-c", "/workspace/scripts/build-picolibc.sh && /workspace/scripts/build-kernel.sh"]
|
|
||||||
1
efi-port/.gitignore
vendored
1
efi-port/.gitignore
vendored
@@ -1 +0,0 @@
|
|||||||
out/
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
@@ -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
@@ -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
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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
@@ -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
|
|
||||||
@@ -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
5
package.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"sailet": "^0.1.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Meson cross-compilation file for i686-elf with picolibc
|
|
||||||
[binaries]
|
|
||||||
c = 'gcc'
|
|
||||||
ar = 'ar'
|
|
||||||
as = 'as'
|
|
||||||
ld = 'ld'
|
|
||||||
strip = 'strip'
|
|
||||||
|
|
||||||
[host_machine]
|
|
||||||
system = 'none'
|
|
||||||
cpu_family = 'x86'
|
|
||||||
cpu = 'i686'
|
|
||||||
endian = 'little'
|
|
||||||
|
|
||||||
[properties]
|
|
||||||
c_args = ['-m32', '-march=i686']
|
|
||||||
c_link_args = ['-m32']
|
|
||||||
skip_sanity_check = true
|
|
||||||
18
sailet.config.ts
Normal file
18
sailet.config.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
// sailet.config.ts
|
||||||
|
|
||||||
|
import { script, step, cmd, $ } from "sailet";
|
||||||
|
|
||||||
|
script("build", () => [
|
||||||
|
step("Prepare", () => [cmd($`./src/scripts/prepare_build.sh`)]),
|
||||||
|
step("Build EFI", () => [
|
||||||
|
cmd($`./src/scripts/build_system.sh`),
|
||||||
|
cmd($`./src/scripts/embed_system.sh`),
|
||||||
|
cmd($`./src/scripts/build_core.sh`),
|
||||||
|
]),
|
||||||
|
step("Build ISO", () => [cmd($`./src/scripts/build_iso.sh`)]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
script("vbox", () => [
|
||||||
|
step("Build", () => [cmd($`st run build`)]),
|
||||||
|
step("Run", () => [cmd($`./src/scripts/run_vbox.sh`)]),
|
||||||
|
]);
|
||||||
@@ -1,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 ""
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Script to build picolibc for i686 freestanding environment
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
PICOLIBC_DIR="picolibc"
|
|
||||||
BUILD_DIR="build/picolibc"
|
|
||||||
INSTALL_DIR="$(pwd)/picolibc-install"
|
|
||||||
|
|
||||||
echo "=== Building Picolibc for i686 freestanding ==="
|
|
||||||
|
|
||||||
# Check if picolibc exists
|
|
||||||
if [ ! -d "$PICOLIBC_DIR" ]; then
|
|
||||||
echo "Error: Picolibc source not found at $PICOLIBC_DIR"
|
|
||||||
echo "Cloning..."
|
|
||||||
git clone --branch 1.8.10 https://github.com/picolibc/picolibc.git "$PICOLIBC_DIR"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Get current version
|
|
||||||
cd "$PICOLIBC_DIR"
|
|
||||||
CURRENT_VERSION=$(git describe --tags 2>/dev/null || echo "unknown")
|
|
||||||
echo "Using picolibc version: $CURRENT_VERSION"
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
# Create build directory
|
|
||||||
mkdir -p "$BUILD_DIR"
|
|
||||||
|
|
||||||
echo "Configuring picolibc with meson..."
|
|
||||||
meson setup "$BUILD_DIR" "$PICOLIBC_DIR" \
|
|
||||||
--cross-file picolibc-i686.txt \
|
|
||||||
--prefix="$INSTALL_DIR" \
|
|
||||||
--wipe \
|
|
||||||
-Dmultilib=false \
|
|
||||||
-Dpicocrt=false \
|
|
||||||
-Dsemihost=false \
|
|
||||||
-Dspecsdir=none \
|
|
||||||
-Dtinystdio=true \
|
|
||||||
-Dio-long-long=true \
|
|
||||||
-Dformat-default=double \
|
|
||||||
-Dtests=false
|
|
||||||
|
|
||||||
echo "Building picolibc..."
|
|
||||||
meson compile -C "$BUILD_DIR"
|
|
||||||
|
|
||||||
echo "Installing picolibc..."
|
|
||||||
meson install -C "$BUILD_DIR"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "=== Picolibc build complete! ==="
|
|
||||||
echo "Installation directory: $INSTALL_DIR"
|
|
||||||
echo ""
|
|
||||||
echo "To use picolibc in your kernel:"
|
|
||||||
echo " Include path: -I$INSTALL_DIR/include"
|
|
||||||
echo " Library path: -L$INSTALL_DIR/lib"
|
|
||||||
echo " Link with: -lc"
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
docker build -t lints-dev -f docker/Dockerfile .
|
|
||||||
docker run -it --rm -v "$(pwd)":/workspace -w /workspace lints-dev
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
#! /usr/bin/env bun
|
|
||||||
import { readFileSync, writeFileSync } from "fs";
|
|
||||||
|
|
||||||
writeFileSync(
|
|
||||||
"build/index.js",
|
|
||||||
readFileSync("build/index.js", "utf-8")
|
|
||||||
.replaceAll("let ", "var ")
|
|
||||||
.replaceAll("const ", "var ")
|
|
||||||
.replaceAll("\n`", "\\n`")
|
|
||||||
.replaceAll("`", "'")
|
|
||||||
);
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""
|
|
||||||
Embed JavaScript file as a C string constant
|
|
||||||
"""
|
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
def escape_c_string(s):
|
|
||||||
"""Escape a string for use in C source code"""
|
|
||||||
result = []
|
|
||||||
for char in s:
|
|
||||||
if char == "\n":
|
|
||||||
result.append("\\n")
|
|
||||||
elif char == "\r":
|
|
||||||
result.append("\\r")
|
|
||||||
elif char == "\t":
|
|
||||||
result.append("\\t")
|
|
||||||
elif char == "\\":
|
|
||||||
result.append("\\\\")
|
|
||||||
elif char == '"':
|
|
||||||
result.append('\\"')
|
|
||||||
elif ord(char) < 32 or ord(char) > 126:
|
|
||||||
result.append(f"\\x{ord(char):02x}")
|
|
||||||
else:
|
|
||||||
result.append(char)
|
|
||||||
return "".join(result)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
if len(sys.argv) != 2:
|
|
||||||
print("Usage: embed_js.py <input.js>", file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
input_file = sys.argv[1]
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(input_file, "r") as f:
|
|
||||||
js_code = f.read()
|
|
||||||
except FileNotFoundError:
|
|
||||||
print(f"Error: File not found: {input_file}", file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# Generate C header file
|
|
||||||
print("/* Auto-generated file - do not edit */")
|
|
||||||
print("#ifndef EMBEDDED_JS_H")
|
|
||||||
print("#define EMBEDDED_JS_H")
|
|
||||||
print()
|
|
||||||
|
|
||||||
escaped = escape_c_string(js_code)
|
|
||||||
print(f'const char *embedded_js_code = "{escaped}";')
|
|
||||||
|
|
||||||
print()
|
|
||||||
print("#endif /* EMBEDDED_JS_H */")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Script to download Duktape library if not present
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
DUKTAPE_DIR="lib/duktape"
|
|
||||||
DUKTAPE_REPO="https://github.com/joeqread/arduino-duktape.git"
|
|
||||||
TEMP_DIR="lib/temp_duktape"
|
|
||||||
|
|
||||||
echo "=== Checking for Duktape library ==="
|
|
||||||
|
|
||||||
if [ -d "$DUKTAPE_DIR" ]; then
|
|
||||||
echo "Duktape already exists at $DUKTAPE_DIR"
|
|
||||||
else
|
|
||||||
echo "Duktape not found. Cloning from $DUKTAPE_REPO..."
|
|
||||||
git clone "$DUKTAPE_REPO" "$TEMP_DIR"
|
|
||||||
|
|
||||||
echo "Extracting src folder..."
|
|
||||||
mkdir -p "$DUKTAPE_DIR"
|
|
||||||
mv "$TEMP_DIR/src" "$DUKTAPE_DIR/"
|
|
||||||
|
|
||||||
echo "Cleaning up temporary directory..."
|
|
||||||
rm -rf "$TEMP_DIR"
|
|
||||||
|
|
||||||
echo "Duktape cloned successfully!"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Done."
|
|
||||||
@@ -1,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
|
|
||||||
@@ -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
9
src/core/compat/assert.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
//---------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// !!! AI GENERATE SLOP, PLEASE FIX !!!
|
||||||
|
//
|
||||||
|
//---------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#define assert(x) ((void)0)
|
||||||
|
#define NDEBUG 1
|
||||||
0
src/core/compat/ctype.h
Normal file
0
src/core/compat/ctype.h
Normal file
0
src/core/compat/fenv.h
Normal file
0
src/core/compat/fenv.h
Normal file
27
src/core/compat/inttypes.h
Normal file
27
src/core/compat/inttypes.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
//---------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// !!! AI GENERATE SLOP, PLEASE FIX !!!
|
||||||
|
//
|
||||||
|
//---------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef _INTTYPES_H
|
||||||
|
#define _INTTYPES_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define PRId64 "lld"
|
||||||
|
#define PRIu64 "llu"
|
||||||
|
#define PRIx64 "llx"
|
||||||
|
#define PRIX64 "llX"
|
||||||
|
|
||||||
|
#define PRId32 "d"
|
||||||
|
#define PRIu32 "u"
|
||||||
|
#define PRIx32 "x"
|
||||||
|
#define PRIX32 "X"
|
||||||
|
|
||||||
|
#define PRIdPTR "ld"
|
||||||
|
#define PRIuPTR "lu"
|
||||||
|
#define PRIxPTR "lx"
|
||||||
|
#define PRIXPTR "lX"
|
||||||
|
|
||||||
|
#endif
|
||||||
195
src/core/compat/main.c
Normal file
195
src/core/compat/main.c
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include "stdio.h"
|
||||||
|
#include "quickjs.h"
|
||||||
|
|
||||||
|
#define NULL ((void*)0)
|
||||||
|
|
||||||
|
// EFI definitions
|
||||||
|
typedef uint64_t EFI_STATUS;
|
||||||
|
typedef void* EFI_HANDLE;
|
||||||
|
#define EFI_SUCCESS 0
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64_t signature;
|
||||||
|
uint32_t revision;
|
||||||
|
uint32_t headerSize;
|
||||||
|
uint32_t crc32;
|
||||||
|
uint32_t reserved;
|
||||||
|
} EFI_TABLE_HEADER;
|
||||||
|
|
||||||
|
struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL;
|
||||||
|
typedef EFI_STATUS (*EFI_TEXT_STRING)(
|
||||||
|
struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
|
||||||
|
uint16_t *String
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef EFI_STATUS (*EFI_TEXT_CLEAR_SCREEN)(
|
||||||
|
struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL {
|
||||||
|
void *reset;
|
||||||
|
EFI_TEXT_STRING OutputString;
|
||||||
|
void *testString;
|
||||||
|
void *queryMode;
|
||||||
|
void *setMode;
|
||||||
|
void *setAttribute;
|
||||||
|
EFI_TEXT_CLEAR_SCREEN ClearScreen;
|
||||||
|
void *setCursorPosition;
|
||||||
|
void *enableCursor;
|
||||||
|
void *mode;
|
||||||
|
} EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL;
|
||||||
|
|
||||||
|
typedef struct EFI_SYSTEM_TABLE {
|
||||||
|
EFI_TABLE_HEADER hdr;
|
||||||
|
uint16_t *firmwareVendor;
|
||||||
|
uint32_t firmwareRevision;
|
||||||
|
void *consoleInHandle;
|
||||||
|
void *conIn;
|
||||||
|
void *consoleOutHandle;
|
||||||
|
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
|
||||||
|
void *standardErrorHandle;
|
||||||
|
void *stdErr;
|
||||||
|
void *runtimeServices;
|
||||||
|
void *bootServices;
|
||||||
|
uint64_t numberOfTableEntries;
|
||||||
|
void *configurationTable;
|
||||||
|
} EFI_SYSTEM_TABLE;
|
||||||
|
|
||||||
|
static EFI_SYSTEM_TABLE *gST = NULL;
|
||||||
|
|
||||||
|
static void Print(uint16_t *str) {
|
||||||
|
if (gST && gST->ConOut)
|
||||||
|
gST->ConOut->OutputString(gST->ConOut, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t *AsciiToUnicode(const char *ascii) {
|
||||||
|
static uint16_t buffer[1024];
|
||||||
|
int i;
|
||||||
|
for (i = 0; ascii[i] && i < 1023; i++) {
|
||||||
|
buffer[i] = (uint16_t)ascii[i];
|
||||||
|
}
|
||||||
|
buffer[i] = 0;
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// stdio implementation
|
||||||
|
int printf(const char *format, ...) {
|
||||||
|
char buf[1024];
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, format);
|
||||||
|
int ret = vsnprintf(buf, sizeof(buf), format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
Print(AsciiToUnicode(buf));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fprintf(FILE *stream, const char *format, ...) {
|
||||||
|
if (stream != stdout && stream != stderr) return 0;
|
||||||
|
char buf[1024];
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, format);
|
||||||
|
int ret = vsnprintf(buf, sizeof(buf), format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
Print(AsciiToUnicode(buf));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) {
|
||||||
|
if (stream != stdout && stream != stderr) return 0;
|
||||||
|
const char *p = ptr;
|
||||||
|
size_t total = size * nmemb;
|
||||||
|
char buf[1025];
|
||||||
|
size_t i = 0;
|
||||||
|
while (i < total) {
|
||||||
|
size_t chunk = total - i;
|
||||||
|
if (chunk > 1024) chunk = 1024;
|
||||||
|
memcpy(buf, p + i, chunk);
|
||||||
|
buf[chunk] = 0;
|
||||||
|
Print(AsciiToUnicode(buf));
|
||||||
|
i += chunk;
|
||||||
|
}
|
||||||
|
return nmemb;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fputc(int c, FILE *stream) {
|
||||||
|
if (stream != stdout && stream != stderr) return c;
|
||||||
|
char buf[2] = { (char)c, 0 };
|
||||||
|
Print(AsciiToUnicode(buf));
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
int putchar(int c) {
|
||||||
|
return fputc(c, stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
EFI_STATUS efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
|
||||||
|
(void)ImageHandle;
|
||||||
|
|
||||||
|
gST = SystemTable;
|
||||||
|
gST->ConOut->ClearScreen(gST->ConOut);
|
||||||
|
|
||||||
|
Print(L"UEFI QuickJS\r\n");
|
||||||
|
Print(L"============\r\n\r\n");
|
||||||
|
|
||||||
|
JSRuntime *rt = JS_NewRuntime();
|
||||||
|
if (!rt) {
|
||||||
|
Print(L"Failed to create runtime\r\n");
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSContext *ctx = JS_NewContext(rt);
|
||||||
|
if (!ctx) {
|
||||||
|
Print(L"Failed to create context\r\n");
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
Print(L"QuickJS initialized!\r\n\r\n");
|
||||||
|
|
||||||
|
// Test Classes
|
||||||
|
const char *code =
|
||||||
|
"class Test { "
|
||||||
|
" constructor(val) { this.val = val; } "
|
||||||
|
" getVal() { return this.val; } "
|
||||||
|
"} "
|
||||||
|
"let t = new Test(42); "
|
||||||
|
"t.getVal();";
|
||||||
|
|
||||||
|
Print(L"Evaluating code...\r\n");
|
||||||
|
|
||||||
|
JSValue val = JS_Eval(ctx, code, strlen(code), "<input>", JS_EVAL_TYPE_GLOBAL);
|
||||||
|
|
||||||
|
if (JS_IsException(val)) {
|
||||||
|
JSValue ex = JS_GetException(ctx);
|
||||||
|
const char *str = JS_ToCString(ctx, ex);
|
||||||
|
if (str) {
|
||||||
|
printf("Exception: %s\n", str);
|
||||||
|
JS_FreeCString(ctx, str);
|
||||||
|
} else {
|
||||||
|
printf("Exception: [unknown]\n");
|
||||||
|
}
|
||||||
|
JS_FreeValue(ctx, ex);
|
||||||
|
} else {
|
||||||
|
const char *str = JS_ToCString(ctx, val);
|
||||||
|
if (str) {
|
||||||
|
printf("Result: %s\n", str);
|
||||||
|
JS_FreeCString(ctx, str);
|
||||||
|
} else {
|
||||||
|
printf("Result: [unknown]\n");
|
||||||
|
}
|
||||||
|
JS_FreeValue(ctx, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_FreeContext(ctx);
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
|
||||||
|
Print(L"\r\nSuccess!\r\n");
|
||||||
|
Print(L"\r\nPress Ctrl+C...\r\n");
|
||||||
|
for(;;);
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
51
src/core/compat/math.h
Normal file
51
src/core/compat/math.h
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
//---------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// !!! AI GENERATE SLOP, PLEASE FIX !!!
|
||||||
|
//
|
||||||
|
//---------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef _MATH_H
|
||||||
|
#define _MATH_H
|
||||||
|
|
||||||
|
#define NAN (__builtin_nan(""))
|
||||||
|
#define INFINITY (__builtin_inf())
|
||||||
|
#define signbit(x) __builtin_signbit(x)
|
||||||
|
|
||||||
|
double floor(double x);
|
||||||
|
double ceil(double x);
|
||||||
|
double fabs(double x);
|
||||||
|
double modf(double x, double *iptr);
|
||||||
|
double fmod(double x, double y);
|
||||||
|
double sqrt(double x);
|
||||||
|
double pow(double x, double y);
|
||||||
|
double log(double x);
|
||||||
|
double exp(double x);
|
||||||
|
double sin(double x);
|
||||||
|
double cos(double x);
|
||||||
|
double tan(double x);
|
||||||
|
int isnan(double x);
|
||||||
|
int isinf(double x);
|
||||||
|
int isfinite(double x);
|
||||||
|
double trunc(double x);
|
||||||
|
double fmin(double x, double y);
|
||||||
|
double fmax(double x, double y);
|
||||||
|
double hypot(double x, double y);
|
||||||
|
double acos(double x);
|
||||||
|
double asin(double x);
|
||||||
|
double atan(double x);
|
||||||
|
double atan2(double y, double x);
|
||||||
|
double cbrt(double x);
|
||||||
|
double cosh(double x);
|
||||||
|
double expm1(double x);
|
||||||
|
double log1p(double x);
|
||||||
|
double log2(double x);
|
||||||
|
double log10(double x);
|
||||||
|
double sinh(double x);
|
||||||
|
double tanh(double x);
|
||||||
|
double asinh(double x);
|
||||||
|
double acosh(double x);
|
||||||
|
double atanh(double x);
|
||||||
|
double round(double x);
|
||||||
|
long int lrint(double x);
|
||||||
|
|
||||||
|
#endif
|
||||||
768
src/core/compat/minilibc.c
Normal file
768
src/core/compat/minilibc.c
Normal file
@@ -0,0 +1,768 @@
|
|||||||
|
//---------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// !!! AI GENERATE SLOP, PLEASE FIX !!!
|
||||||
|
//
|
||||||
|
//---------------------------------------------------------------
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
extern int printf(const char *format, ...);
|
||||||
|
|
||||||
|
// Basic libc stub implementations for Elk
|
||||||
|
|
||||||
|
// String functions
|
||||||
|
void *memset(void *s, int c, size_t n) {
|
||||||
|
unsigned char *p = s;
|
||||||
|
while (n--) *p++ = (unsigned char)c;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *memcpy(void *dest, const void *src, size_t n) {
|
||||||
|
unsigned char *d = dest;
|
||||||
|
const unsigned char *s = src;
|
||||||
|
while (n--) *d++ = *s++;
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *memmove(void *dest, const void *src, size_t n) {
|
||||||
|
unsigned char *d = dest;
|
||||||
|
const unsigned char *s = src;
|
||||||
|
if (d < s) {
|
||||||
|
while (n--) *d++ = *s++;
|
||||||
|
} else {
|
||||||
|
d += n;
|
||||||
|
s += n;
|
||||||
|
while (n--) *--d = *--s;
|
||||||
|
}
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
int memcmp(const void *s1, const void *s2, size_t n) {
|
||||||
|
const unsigned char *p1 = s1, *p2 = s2;
|
||||||
|
while (n--) {
|
||||||
|
if (*p1 != *p2) return *p1 - *p2;
|
||||||
|
p1++;
|
||||||
|
p2++;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t strlen(const char *s) {
|
||||||
|
size_t len = 0;
|
||||||
|
while (s[len]) len++;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int strcmp(const char *s1, const char *s2) {
|
||||||
|
while (*s1 && (*s1 == *s2)) {
|
||||||
|
s1++;
|
||||||
|
s2++;
|
||||||
|
}
|
||||||
|
return *(unsigned char *)s1 - *(unsigned char *)s2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int strncmp(const char *s1, const char *s2, size_t n) {
|
||||||
|
while (n && *s1 && (*s1 == *s2)) {
|
||||||
|
s1++;
|
||||||
|
s2++;
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
if (n == 0) return 0;
|
||||||
|
return *(unsigned char *)s1 - *(unsigned char *)s2;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *strcpy(char *dest, const char *src) {
|
||||||
|
char *d = dest;
|
||||||
|
while ((*d++ = *src++));
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *strncpy(char *dest, const char *src, size_t n) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < n && src[i]; i++)
|
||||||
|
dest[i] = src[i];
|
||||||
|
for (; i < n; i++)
|
||||||
|
dest[i] = '\0';
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Math functions - basic implementations
|
||||||
|
double floor(double x) {
|
||||||
|
if (x >= 0) {
|
||||||
|
return (double)(int64_t)x;
|
||||||
|
} else {
|
||||||
|
int64_t i = (int64_t)x;
|
||||||
|
return (i == x) ? x : (double)(i - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double ceil(double x) {
|
||||||
|
if (x >= 0) {
|
||||||
|
int64_t i = (int64_t)x;
|
||||||
|
return (i == x) ? x : (double)(i + 1);
|
||||||
|
} else {
|
||||||
|
return (double)(int64_t)x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double fabs(double x) {
|
||||||
|
return x < 0 ? -x : x;
|
||||||
|
}
|
||||||
|
|
||||||
|
double modf(double x, double *iptr) {
|
||||||
|
*iptr = (double)(int64_t)x;
|
||||||
|
return x - *iptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
double fmod(double x, double y) {
|
||||||
|
if (y == 0.0) return 0.0;
|
||||||
|
return x - floor(x / y) * y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple sqrt using Newton's method
|
||||||
|
double sqrt(double x) {
|
||||||
|
if (x < 0) return 0.0;
|
||||||
|
if (x == 0) return 0.0;
|
||||||
|
|
||||||
|
double guess = x / 2.0;
|
||||||
|
double prev;
|
||||||
|
int iterations = 10;
|
||||||
|
|
||||||
|
while (iterations--) {
|
||||||
|
prev = guess;
|
||||||
|
guess = (guess + x / guess) / 2.0;
|
||||||
|
if (fabs(guess - prev) < 0.0001) break;
|
||||||
|
}
|
||||||
|
return guess;
|
||||||
|
}
|
||||||
|
|
||||||
|
double pow(double x, double y) {
|
||||||
|
// Very basic pow - only handles integer exponents
|
||||||
|
if (y == 0.0) return 1.0;
|
||||||
|
if (y < 0.0) return 1.0 / pow(x, -y);
|
||||||
|
|
||||||
|
double result = 1.0;
|
||||||
|
int64_t exp = (int64_t)y;
|
||||||
|
while (exp--) result *= x;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
double log(double x) {
|
||||||
|
// Simplified log (not accurate, just enough for Elk)
|
||||||
|
if (x <= 0) return 0.0;
|
||||||
|
return 0.0; // Stub
|
||||||
|
}
|
||||||
|
|
||||||
|
double exp(double x) {
|
||||||
|
// Simplified exp
|
||||||
|
(void)x;
|
||||||
|
return 1.0; // Stub
|
||||||
|
}
|
||||||
|
|
||||||
|
double sin(double x) {
|
||||||
|
(void)x;
|
||||||
|
return 0.0; // Stub
|
||||||
|
}
|
||||||
|
|
||||||
|
double cos(double x) {
|
||||||
|
(void)x;
|
||||||
|
return 1.0; // Stub
|
||||||
|
}
|
||||||
|
|
||||||
|
double tan(double x) {
|
||||||
|
(void)x;
|
||||||
|
return 0.0; // Stub
|
||||||
|
}
|
||||||
|
|
||||||
|
int isnan(double x) {
|
||||||
|
return x != x;
|
||||||
|
}
|
||||||
|
|
||||||
|
int isinf(double x) {
|
||||||
|
return x == __builtin_inf() || x == -__builtin_inf();
|
||||||
|
}
|
||||||
|
|
||||||
|
int isfinite(double x) {
|
||||||
|
return !isnan(x) && !isinf(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stdlib functions
|
||||||
|
double strtod(const char *str, char **endptr) {
|
||||||
|
double result = 0.0;
|
||||||
|
double sign = 1.0;
|
||||||
|
double scale = 0.1;
|
||||||
|
int decimal = 0;
|
||||||
|
|
||||||
|
while (*str == ' ' || *str == '\t') str++;
|
||||||
|
|
||||||
|
if (*str == '-') {
|
||||||
|
sign = -1.0;
|
||||||
|
str++;
|
||||||
|
} else if (*str == '+') {
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*str) {
|
||||||
|
if (*str >= '0' && *str <= '9') {
|
||||||
|
if (decimal) {
|
||||||
|
result += (*str - '0') * scale;
|
||||||
|
scale *= 0.1;
|
||||||
|
} else {
|
||||||
|
result = result * 10.0 + (*str - '0');
|
||||||
|
}
|
||||||
|
} else if (*str == '.' && !decimal) {
|
||||||
|
decimal = 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endptr) *endptr = (char *)str;
|
||||||
|
return result * sign;
|
||||||
|
}
|
||||||
|
|
||||||
|
long strtol(const char *str, char **endptr, int base) {
|
||||||
|
long result = 0;
|
||||||
|
int sign = 1;
|
||||||
|
|
||||||
|
while (*str == ' ') str++;
|
||||||
|
|
||||||
|
if (*str == '-') {
|
||||||
|
sign = -1;
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*str >= '0' && *str <= '9') {
|
||||||
|
result = result * base + (*str - '0');
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endptr) *endptr = (char *)str;
|
||||||
|
return result * sign;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dynamic heap - will be initialized based on available RAM
|
||||||
|
static unsigned char *heap = NULL;
|
||||||
|
static size_t heap_size = 0;
|
||||||
|
static size_t heap_pos = 0;
|
||||||
|
|
||||||
|
// Forward declare EFI types we need
|
||||||
|
typedef uint64_t EFI_STATUS;
|
||||||
|
typedef void* EFI_HANDLE;
|
||||||
|
typedef uint64_t UINT64;
|
||||||
|
typedef uint32_t UINT32;
|
||||||
|
typedef uintptr_t UINTN;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UINT32 Type;
|
||||||
|
UINT64 PhysicalStart;
|
||||||
|
UINT64 VirtualStart;
|
||||||
|
UINT64 NumberOfPages;
|
||||||
|
UINT64 Attribute;
|
||||||
|
} EFI_MEMORY_DESCRIPTOR;
|
||||||
|
|
||||||
|
typedef struct EFI_BOOT_SERVICES_PARTIAL {
|
||||||
|
// EFI_TABLE_HEADER (24 bytes) + 5 pointers (RaiseTPL, RestoreTPL, AllocatePages, FreePages, GetMemoryMap)
|
||||||
|
char padding[64]; // 24 + 5*8 = 64 bytes to reach AllocatePool
|
||||||
|
EFI_STATUS (*AllocatePool)(UINT32 PoolType, UINTN Size, void **Buffer);
|
||||||
|
} EFI_BOOT_SERVICES_PARTIAL;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char hdr[24]; // EFI_TABLE_HEADER
|
||||||
|
void *firmwareVendor;
|
||||||
|
UINT32 firmwareRevision;
|
||||||
|
void *consoleInHandle;
|
||||||
|
void *conIn;
|
||||||
|
void *consoleOutHandle;
|
||||||
|
void *ConOut;
|
||||||
|
void *standardErrorHandle;
|
||||||
|
void *stdErr;
|
||||||
|
void *runtimeServices;
|
||||||
|
EFI_BOOT_SERVICES_PARTIAL *BootServices;
|
||||||
|
} EFI_SYSTEM_TABLE_PARTIAL;
|
||||||
|
|
||||||
|
#define EfiConventionalMemory 7
|
||||||
|
|
||||||
|
// Initialize heap with maximum available memory
|
||||||
|
void init_heap(void *system_table) {
|
||||||
|
// Static fallback heap in case EFI allocation fails
|
||||||
|
static unsigned char static_heap[64 * 1024 * 1024]; // 64 MB fallback
|
||||||
|
|
||||||
|
EFI_SYSTEM_TABLE_PARTIAL *st = (EFI_SYSTEM_TABLE_PARTIAL*)system_table;
|
||||||
|
|
||||||
|
// Safety check
|
||||||
|
if (!st || !st->BootServices || !st->BootServices->AllocatePool) {
|
||||||
|
printf("WARNING: EFI Boot Services not available, using static heap\n");
|
||||||
|
heap = static_heap;
|
||||||
|
heap_size = sizeof(static_heap);
|
||||||
|
heap_pos = 0;
|
||||||
|
printf("Heap initialized: %zu MB (static fallback)\n", heap_size / (1024 * 1024));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to allocate a very large heap - start with 16 GB and work down if needed
|
||||||
|
size_t sizes[] = {
|
||||||
|
16ULL * 1024 * 1024 * 1024, // 16 GB
|
||||||
|
8ULL * 1024 * 1024 * 1024, // 8 GB
|
||||||
|
4ULL * 1024 * 1024 * 1024, // 4 GB
|
||||||
|
2ULL * 1024 * 1024 * 1024, // 2 GB
|
||||||
|
1ULL * 1024 * 1024 * 1024, // 1 GB
|
||||||
|
512ULL * 1024 * 1024, // 512 MB
|
||||||
|
256ULL * 1024 * 1024, // 256 MB
|
||||||
|
128ULL * 1024 * 1024, // 128 MB
|
||||||
|
64ULL * 1024 * 1024, // 64 MB
|
||||||
|
32ULL * 1024 * 1024, // 32 MB
|
||||||
|
16ULL * 1024 * 1024, // 16 MB
|
||||||
|
8ULL * 1024 * 1024 // 8 MB (fallback)
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < 12; i++) {
|
||||||
|
EFI_STATUS status = st->BootServices->AllocatePool(
|
||||||
|
EfiConventionalMemory,
|
||||||
|
sizes[i],
|
||||||
|
(void**)&heap
|
||||||
|
);
|
||||||
|
|
||||||
|
if (status == 0) { // EFI_SUCCESS
|
||||||
|
heap_size = sizes[i];
|
||||||
|
heap_pos = 0;
|
||||||
|
if (heap_size >= 1024ULL * 1024 * 1024) {
|
||||||
|
printf("Heap initialized: %zu GB (%zu bytes)\n",
|
||||||
|
heap_size / (1024ULL * 1024 * 1024), heap_size);
|
||||||
|
} else {
|
||||||
|
printf("Heap initialized: %zu MB (%zu bytes)\n",
|
||||||
|
heap_size / (1024 * 1024), heap_size);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If all EFI allocations failed, use static heap
|
||||||
|
printf("WARNING: EFI allocation failed, using static heap\n");
|
||||||
|
heap = static_heap;
|
||||||
|
heap_size = sizeof(static_heap);
|
||||||
|
heap_pos = 0;
|
||||||
|
printf("Heap initialized: %zu MB (static fallback)\n", heap_size / (1024 * 1024));
|
||||||
|
}
|
||||||
|
|
||||||
|
void *malloc(size_t size) {
|
||||||
|
if (!heap) {
|
||||||
|
printf("malloc failed: heap not initialized\n");
|
||||||
|
return (void*)0;
|
||||||
|
}
|
||||||
|
size = (size + 7) & ~7;
|
||||||
|
size_t total = size + 8;
|
||||||
|
if (heap_pos + total > heap_size) {
|
||||||
|
printf("malloc failed: OOM (requested %zu, available %zu)\n", total, heap_size - heap_pos);
|
||||||
|
return (void*)0;
|
||||||
|
}
|
||||||
|
*(size_t*)&heap[heap_pos] = size;
|
||||||
|
void *ptr = &heap[heap_pos + 8];
|
||||||
|
heap_pos += total;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(void *ptr) {
|
||||||
|
(void)ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *realloc(void *ptr, size_t size) {
|
||||||
|
if (!ptr) return malloc(size);
|
||||||
|
size_t *p_size = (size_t*)((char*)ptr - 8);
|
||||||
|
size_t old_size = *p_size;
|
||||||
|
if (size <= old_size) return ptr;
|
||||||
|
|
||||||
|
void *new_ptr = malloc(size);
|
||||||
|
if (!new_ptr) return (void*)0;
|
||||||
|
memcpy(new_ptr, ptr, old_size);
|
||||||
|
return new_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *calloc(size_t nmemb, size_t size) {
|
||||||
|
size_t total = nmemb * size;
|
||||||
|
void *ptr = malloc(total);
|
||||||
|
if (ptr) memset(ptr, 0, total);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void abort(void) {
|
||||||
|
printf("ABORT called!\n");
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// stdio functions
|
||||||
|
int vsnprintf(char *str, size_t size, const char *format, __builtin_va_list ap) {
|
||||||
|
size_t i = 0;
|
||||||
|
const char *p = format;
|
||||||
|
|
||||||
|
while (*p && i < size - 1) {
|
||||||
|
if (*p != '%') {
|
||||||
|
str[i++] = *p++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
p++; // Skip '%'
|
||||||
|
|
||||||
|
// Parse flags, width, precision, length modifiers
|
||||||
|
int precision = -1;
|
||||||
|
|
||||||
|
// Flags (ignored for now)
|
||||||
|
while (*p == '-' || *p == '+' || *p == ' ' || *p == '#' || *p == '0') p++;
|
||||||
|
|
||||||
|
// Width
|
||||||
|
if (*p == '*') {
|
||||||
|
__builtin_va_arg(ap, int); // Consume width
|
||||||
|
p++;
|
||||||
|
} else {
|
||||||
|
while (*p >= '0' && *p <= '9') p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Precision
|
||||||
|
if (*p == '.') {
|
||||||
|
p++;
|
||||||
|
if (*p == '*') {
|
||||||
|
precision = __builtin_va_arg(ap, int);
|
||||||
|
p++;
|
||||||
|
} else {
|
||||||
|
int val = 0;
|
||||||
|
while (*p >= '0' && *p <= '9') {
|
||||||
|
val = val * 10 + (*p - '0');
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
precision = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Length modifiers (ignored)
|
||||||
|
while (*p == 'h' || *p == 'l' || *p == 'L' || *p == 'z' || *p == 't') p++;
|
||||||
|
|
||||||
|
if (*p == 'd' || *p == 'i') {
|
||||||
|
int val = __builtin_va_arg(ap, int);
|
||||||
|
char buf[32];
|
||||||
|
int pos = 0;
|
||||||
|
int neg = 0;
|
||||||
|
if (val < 0) { neg = 1; val = -val; }
|
||||||
|
if (val == 0) buf[pos++] = '0';
|
||||||
|
while (val) {
|
||||||
|
buf[pos++] = '0' + (val % 10);
|
||||||
|
val /= 10;
|
||||||
|
}
|
||||||
|
if (neg) buf[pos++] = '-';
|
||||||
|
while (pos > 0 && i < size - 1) str[i++] = buf[--pos];
|
||||||
|
} else if (*p == 'u') {
|
||||||
|
unsigned int val = __builtin_va_arg(ap, unsigned int);
|
||||||
|
char buf[32];
|
||||||
|
int pos = 0;
|
||||||
|
if (val == 0) buf[pos++] = '0';
|
||||||
|
while (val) {
|
||||||
|
buf[pos++] = '0' + (val % 10);
|
||||||
|
val /= 10;
|
||||||
|
}
|
||||||
|
while (pos > 0 && i < size - 1) str[i++] = buf[--pos];
|
||||||
|
} else if (*p == 's') {
|
||||||
|
const char *s = __builtin_va_arg(ap, const char *);
|
||||||
|
if (!s) s = "(null)";
|
||||||
|
|
||||||
|
size_t len = 0;
|
||||||
|
const char *tmp = s;
|
||||||
|
while (*tmp++) len++;
|
||||||
|
|
||||||
|
if (precision >= 0 && len > (size_t)precision) len = (size_t)precision;
|
||||||
|
|
||||||
|
size_t k = 0;
|
||||||
|
while (k < len && i < size - 1) str[i++] = s[k++];
|
||||||
|
} else if (*p == 'c') {
|
||||||
|
char c = (char)__builtin_va_arg(ap, int);
|
||||||
|
if (i < size - 1) str[i++] = c;
|
||||||
|
} else if (*p == 'g' || *p == 'f') {
|
||||||
|
// Basic double support
|
||||||
|
double val = __builtin_va_arg(ap, double);
|
||||||
|
int ival = (int)val;
|
||||||
|
|
||||||
|
// Print integer part
|
||||||
|
char buf[32];
|
||||||
|
int pos = 0;
|
||||||
|
int neg = 0;
|
||||||
|
if (val < 0) { neg = 1; val = -val; ival = -ival; }
|
||||||
|
|
||||||
|
if (ival == 0) buf[pos++] = '0';
|
||||||
|
int temp = ival;
|
||||||
|
while (temp) {
|
||||||
|
buf[pos++] = '0' + (temp % 10);
|
||||||
|
temp /= 10;
|
||||||
|
}
|
||||||
|
if (neg) buf[pos++] = '-';
|
||||||
|
while (pos > 0 && i < size - 1) str[i++] = buf[--pos];
|
||||||
|
|
||||||
|
// Simple decimal part (up to 4 digits)
|
||||||
|
val -= (int)val;
|
||||||
|
if (val > 0.0001) {
|
||||||
|
if (i < size - 1) str[i++] = '.';
|
||||||
|
for (int k=0; k<4 && val > 0.0001 && i < size-1; k++) {
|
||||||
|
val *= 10;
|
||||||
|
int digit = (int)val;
|
||||||
|
str[i++] = '0' + digit;
|
||||||
|
val -= digit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (i < size - 1) str[i++] = *p;
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
str[i] = '\0';
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int snprintf(char *str, size_t size, const char *format, ...) {
|
||||||
|
__builtin_va_list ap;
|
||||||
|
__builtin_va_start(ap, format);
|
||||||
|
int ret = vsnprintf(str, size, format, ap);
|
||||||
|
__builtin_va_end(ap);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Compiler intrinsics for Windows target
|
||||||
|
void __chkstk(void) {
|
||||||
|
// Stack checking - not needed for UEFI
|
||||||
|
}
|
||||||
|
|
||||||
|
int _fltused = 0; // Floating point used marker
|
||||||
|
|
||||||
|
char *strchr(const char *s, int c) {
|
||||||
|
while (*s != (char)c) {
|
||||||
|
if (!*s++) {
|
||||||
|
return (void*)0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (char *)s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
double trunc(double x) {
|
||||||
|
return (x > 0) ? floor(x) : ceil(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
double fmin(double x, double y) {
|
||||||
|
return (x < y) ? x : y;
|
||||||
|
}
|
||||||
|
|
||||||
|
double fmax(double x, double y) {
|
||||||
|
return (x > y) ? x : y;
|
||||||
|
}
|
||||||
|
|
||||||
|
double hypot(double x, double y) {
|
||||||
|
return sqrt(x*x + y*y);
|
||||||
|
}
|
||||||
|
|
||||||
|
double acos(double x) { (void)x; return 0.0; }
|
||||||
|
double asin(double x) { (void)x; return 0.0; }
|
||||||
|
double atan(double x) { (void)x; return 0.0; }
|
||||||
|
double atan2(double y, double x) { (void)y; (void)x; return 0.0; }
|
||||||
|
double cbrt(double x) { (void)x; return 0.0; }
|
||||||
|
double cosh(double x) { (void)x; return 0.0; }
|
||||||
|
double expm1(double x) { (void)x; return 0.0; }
|
||||||
|
double log1p(double x) { (void)x; return 0.0; }
|
||||||
|
double log2(double x) { (void)x; return 0.0; }
|
||||||
|
double log10(double x) { (void)x; return 0.0; }
|
||||||
|
double sinh(double x) { (void)x; return 0.0; }
|
||||||
|
double tanh(double x) { (void)x; return 0.0; }
|
||||||
|
double asinh(double x) { (void)x; return 0.0; }
|
||||||
|
double acosh(double x) { (void)x; return 0.0; }
|
||||||
|
double atanh(double x) { (void)x; return 0.0; }
|
||||||
|
|
||||||
|
double round(double x) {
|
||||||
|
return (x >= 0.0) ? floor(x + 0.5) : ceil(x - 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
long int lrint(double x) {
|
||||||
|
return (long int)round(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
size_t _msize(void *ptr) {
|
||||||
|
if (!ptr) return 0;
|
||||||
|
return *(size_t*)((char*)ptr - 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fesetround(int round) { (void)round; return 0; }
|
||||||
|
int fegetround(void) { return 0; }
|
||||||
|
|
||||||
|
int errno = 0;
|
||||||
|
|
||||||
|
#include "time.h"
|
||||||
|
#include "sys/time.h"
|
||||||
|
|
||||||
|
time_t time(time_t *t) {
|
||||||
|
if (t) *t = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct tm tm_buf;
|
||||||
|
|
||||||
|
struct tm *gmtime(const time_t *timep) {
|
||||||
|
(void)timep;
|
||||||
|
// Stub: return 1970-01-01
|
||||||
|
tm_buf.tm_year = 70;
|
||||||
|
tm_buf.tm_mon = 0;
|
||||||
|
tm_buf.tm_mday = 1;
|
||||||
|
return &tm_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tm *localtime(const time_t *timep) {
|
||||||
|
return gmtime(timep);
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t mktime(struct tm *tm) {
|
||||||
|
(void)tm;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int gettimeofday(struct timeval *tv, struct timezone *tz) {
|
||||||
|
if (tv) {
|
||||||
|
tv->tv_sec = 0;
|
||||||
|
tv->tv_usec = 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *memchr(const void *s, int c, size_t n) {
|
||||||
|
const unsigned char *p = s;
|
||||||
|
while (n--) {
|
||||||
|
if (*p == (unsigned char)c) return (void *)p;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
return (void*)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *strcat(char *dest, const char *src) {
|
||||||
|
char *d = dest;
|
||||||
|
while (*d) d++;
|
||||||
|
while ((*d++ = *src++));
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *strncat(char *dest, const char *src, size_t n) {
|
||||||
|
char *d = dest;
|
||||||
|
while (*d) d++;
|
||||||
|
while (n-- && *src) *d++ = *src++;
|
||||||
|
*d = 0;
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *strstr(const char *haystack, const char *needle) {
|
||||||
|
size_t len = strlen(needle);
|
||||||
|
if (len == 0) return (char *)haystack;
|
||||||
|
while (*haystack) {
|
||||||
|
if (!memcmp(haystack, needle, len)) return (char *)haystack;
|
||||||
|
haystack++;
|
||||||
|
}
|
||||||
|
return (void*)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *strdup(const char *s) {
|
||||||
|
size_t len = strlen(s) + 1;
|
||||||
|
char *new = malloc(len);
|
||||||
|
if (new) memcpy(new, s, len);
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *strrchr(const char *s, int c) {
|
||||||
|
const char *found = (void*)0;
|
||||||
|
while (*s) {
|
||||||
|
if (*s == (char)c) found = s;
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
if (*s == (char)c) found = s;
|
||||||
|
return (char *)found;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int abs(int j) {
|
||||||
|
return (j < 0) ? -j : j;
|
||||||
|
}
|
||||||
|
|
||||||
|
int isdigit(int c) {
|
||||||
|
return (c >= '0' && c <= '9');
|
||||||
|
}
|
||||||
|
|
||||||
|
int isspace(int c) {
|
||||||
|
return (c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r');
|
||||||
|
}
|
||||||
|
|
||||||
|
int isupper(int c) {
|
||||||
|
return (c >= 'A' && c <= 'Z');
|
||||||
|
}
|
||||||
|
|
||||||
|
int islower(int c) {
|
||||||
|
return (c >= 'a' && c <= 'z');
|
||||||
|
}
|
||||||
|
|
||||||
|
int isalpha(int c) {
|
||||||
|
return isupper(c) || islower(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
int isalnum(int c) {
|
||||||
|
return isalpha(c) || isdigit(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
int tolower(int c) {
|
||||||
|
return isupper(c) ? c + 32 : c;
|
||||||
|
}
|
||||||
|
|
||||||
|
int toupper(int c) {
|
||||||
|
return islower(c) ? c - 32 : c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) {
|
||||||
|
// Simple bubble sort for now
|
||||||
|
if (nmemb < 2 || size == 0) return;
|
||||||
|
char *b = (char *)base;
|
||||||
|
|
||||||
|
// Byte-by-byte swap to avoid malloc
|
||||||
|
for (size_t i = 0; i < nmemb - 1; i++) {
|
||||||
|
for (size_t j = 0; j < nmemb - i - 1; j++) {
|
||||||
|
if (compar(b + j * size, b + (j + 1) * size) > 0) {
|
||||||
|
char *p1 = b + j * size;
|
||||||
|
char *p2 = b + (j + 1) * size;
|
||||||
|
for (size_t k = 0; k < size; k++) {
|
||||||
|
char t = p1[k];
|
||||||
|
p1[k] = p2[k];
|
||||||
|
p2[k] = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "setjmp.h"
|
||||||
|
|
||||||
|
int setjmp(jmp_buf env) {
|
||||||
|
(void)env;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void longjmp(jmp_buf env, int val) {
|
||||||
|
(void)env; (void)val;
|
||||||
|
printf("longjmp called!\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
18
src/core/compat/setjmp.h
Normal file
18
src/core/compat/setjmp.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
//---------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// !!! AI GENERATE SLOP, PLEASE FIX !!!
|
||||||
|
//
|
||||||
|
//---------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef _SETJMP_H
|
||||||
|
#define _SETJMP_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// x86_64 jmp_buf: rbx, rbp, r12, r13, r14, r15, rsp, rip
|
||||||
|
typedef uint64_t jmp_buf[8];
|
||||||
|
|
||||||
|
int setjmp(jmp_buf env);
|
||||||
|
void longjmp(jmp_buf env, int val);
|
||||||
|
|
||||||
|
#endif
|
||||||
12
src/core/compat/stdarg.h
Normal file
12
src/core/compat/stdarg.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
//---------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// !!! AI GENERATE SLOP, PLEASE FIX !!!
|
||||||
|
//
|
||||||
|
//---------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef __builtin_va_list va_list;
|
||||||
|
#define va_start(ap, last) __builtin_va_start(ap, last)
|
||||||
|
#define va_end(ap) __builtin_va_end(ap)
|
||||||
|
#define va_arg(ap, type) __builtin_va_arg(ap, type)
|
||||||
23
src/core/compat/stdio.h
Normal file
23
src/core/compat/stdio.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
//---------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// !!! AI GENERATE SLOP, PLEASE FIX !!!
|
||||||
|
//
|
||||||
|
//---------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
typedef struct FILE FILE;
|
||||||
|
|
||||||
|
#define stdout ((FILE*)1)
|
||||||
|
#define stderr ((FILE*)2)
|
||||||
|
#define stdin ((FILE*)0)
|
||||||
|
|
||||||
|
int printf(const char *format, ...);
|
||||||
|
int fprintf(FILE *stream, const char *format, ...);
|
||||||
|
int snprintf(char *str, size_t size, const char *format, ...);
|
||||||
|
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
|
||||||
|
int fputc(int c, FILE *stream);
|
||||||
|
int putchar(int c);
|
||||||
|
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
|
||||||
20
src/core/compat/stdlib.h
Normal file
20
src/core/compat/stdlib.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
//---------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// !!! AI GENERATE SLOP, PLEASE FIX !!!
|
||||||
|
//
|
||||||
|
//---------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
void *malloc(size_t size);
|
||||||
|
void free(void *ptr);
|
||||||
|
void *realloc(void *ptr, size_t size);
|
||||||
|
void *calloc(size_t nmemb, size_t size);
|
||||||
|
double strtod(const char *str, char **endptr);
|
||||||
|
long strtol(const char *str, char **endptr, int base);
|
||||||
|
void abort(void);
|
||||||
|
#define alloca __builtin_alloca
|
||||||
|
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
|
||||||
|
int abs(int j);
|
||||||
|
size_t _msize(void *ptr);
|
||||||
29
src/core/compat/string.h
Normal file
29
src/core/compat/string.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
//---------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// !!! AI GENERATE SLOP, PLEASE FIX !!!
|
||||||
|
//
|
||||||
|
//---------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef _STRING_H
|
||||||
|
#define _STRING_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
void *memset(void *s, int c, size_t n);
|
||||||
|
void *memcpy(void *dest, const void *src, size_t n);
|
||||||
|
void *memmove(void *dest, const void *src, size_t n);
|
||||||
|
int memcmp(const void *s1, const void *s2, size_t n);
|
||||||
|
size_t strlen(const char *s);
|
||||||
|
int strcmp(const char *s1, const char *s2);
|
||||||
|
int strncmp(const char *s1, const char *s2, size_t n);
|
||||||
|
char *strcpy(char *dest, const char *src);
|
||||||
|
char *strncpy(char *dest, const char *src, size_t n);
|
||||||
|
char *strcat(char *dest, const char *src);
|
||||||
|
char *strncat(char *dest, const char *src, size_t n);
|
||||||
|
char *strchr(const char *s, int c);
|
||||||
|
char *strrchr(const char *s, int c);
|
||||||
|
char *strstr(const char *haystack, const char *needle);
|
||||||
|
char *strdup(const char *s);
|
||||||
|
void *memchr(const void *s, int c, size_t n);
|
||||||
|
|
||||||
|
#endif
|
||||||
24
src/core/compat/sys/time.h
Normal file
24
src/core/compat/sys/time.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
//---------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// !!! AI GENERATE SLOP, PLEASE FIX !!!
|
||||||
|
//
|
||||||
|
//---------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef _SYS_TIME_H
|
||||||
|
#define _SYS_TIME_H
|
||||||
|
|
||||||
|
#include "time.h"
|
||||||
|
|
||||||
|
struct timeval {
|
||||||
|
long tv_sec;
|
||||||
|
long tv_usec;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct timezone {
|
||||||
|
int tz_minuteswest;
|
||||||
|
int tz_dsttime;
|
||||||
|
};
|
||||||
|
|
||||||
|
int gettimeofday(struct timeval *tv, struct timezone *tz);
|
||||||
|
|
||||||
|
#endif
|
||||||
31
src/core/compat/time.h
Normal file
31
src/core/compat/time.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
//---------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// !!! AI GENERATE SLOP, PLEASE FIX !!!
|
||||||
|
//
|
||||||
|
//---------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef _TIME_H
|
||||||
|
#define _TIME_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
typedef long time_t;
|
||||||
|
|
||||||
|
struct tm {
|
||||||
|
int tm_sec;
|
||||||
|
int tm_min;
|
||||||
|
int tm_hour;
|
||||||
|
int tm_mday;
|
||||||
|
int tm_mon;
|
||||||
|
int tm_year;
|
||||||
|
int tm_wday;
|
||||||
|
int tm_yday;
|
||||||
|
int tm_isdst;
|
||||||
|
};
|
||||||
|
|
||||||
|
time_t time(time_t *t);
|
||||||
|
struct tm *gmtime(const time_t *timep);
|
||||||
|
struct tm *localtime(const time_t *timep);
|
||||||
|
time_t mktime(struct tm *tm);
|
||||||
|
|
||||||
|
#endif
|
||||||
184
src/core/efi.h
Normal file
184
src/core/efi.h
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
#ifndef EFI_H
|
||||||
|
#define EFI_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define NULL ((void*)0)
|
||||||
|
|
||||||
|
// Basic Types
|
||||||
|
typedef uint64_t UINT64;
|
||||||
|
typedef uint32_t UINT32;
|
||||||
|
typedef uint16_t UINT16;
|
||||||
|
typedef uint8_t UINT8;
|
||||||
|
typedef uintptr_t UINTN;
|
||||||
|
typedef intptr_t INTN;
|
||||||
|
typedef void VOID;
|
||||||
|
|
||||||
|
typedef uint64_t EFI_STATUS;
|
||||||
|
typedef void* EFI_HANDLE;
|
||||||
|
|
||||||
|
#define EFI_SUCCESS 0
|
||||||
|
#define EFI_ERROR(status) (((INTN)(status)) < 0)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UINT32 Data1;
|
||||||
|
UINT16 Data2;
|
||||||
|
UINT16 Data3;
|
||||||
|
UINT8 Data4[8];
|
||||||
|
} EFI_GUID;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64_t signature;
|
||||||
|
uint32_t revision;
|
||||||
|
uint32_t headerSize;
|
||||||
|
uint32_t crc32;
|
||||||
|
uint32_t reserved;
|
||||||
|
} EFI_TABLE_HEADER;
|
||||||
|
|
||||||
|
// Simple Text Output Protocol
|
||||||
|
struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL;
|
||||||
|
typedef EFI_STATUS (*EFI_TEXT_STRING)(
|
||||||
|
struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
|
||||||
|
uint16_t *String
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef EFI_STATUS (*EFI_TEXT_CLEAR_SCREEN)(
|
||||||
|
struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL {
|
||||||
|
void *reset;
|
||||||
|
EFI_TEXT_STRING OutputString;
|
||||||
|
void *testString;
|
||||||
|
void *queryMode;
|
||||||
|
void *setMode;
|
||||||
|
void *setAttribute;
|
||||||
|
EFI_TEXT_CLEAR_SCREEN ClearScreen;
|
||||||
|
void *setCursorPosition;
|
||||||
|
void *enableCursor;
|
||||||
|
void *mode;
|
||||||
|
} EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL;
|
||||||
|
|
||||||
|
// Boot Services
|
||||||
|
typedef struct {
|
||||||
|
EFI_TABLE_HEADER Hdr;
|
||||||
|
void *RaiseTPL;
|
||||||
|
void *RestoreTPL;
|
||||||
|
void *AllocatePages;
|
||||||
|
void *FreePages;
|
||||||
|
void *GetMemoryMap;
|
||||||
|
void *AllocatePool;
|
||||||
|
void *FreePool;
|
||||||
|
void *CreateEvent;
|
||||||
|
void *SetTimer;
|
||||||
|
void *WaitForEvent;
|
||||||
|
void *SignalEvent;
|
||||||
|
void *CloseEvent;
|
||||||
|
void *CheckEvent;
|
||||||
|
void *InstallProtocolInterface;
|
||||||
|
void *ReinstallProtocolInterface;
|
||||||
|
void *UninstallProtocolInterface;
|
||||||
|
void *HandleProtocol;
|
||||||
|
void *Reserved;
|
||||||
|
void *RegisterProtocolNotify;
|
||||||
|
void *LocateHandle;
|
||||||
|
void *LocateDevicePath;
|
||||||
|
void *InstallConfigurationTable;
|
||||||
|
void *LoadImage;
|
||||||
|
void *StartImage;
|
||||||
|
void *Exit;
|
||||||
|
void *UnloadImage;
|
||||||
|
void *ExitBootServices;
|
||||||
|
void *GetNextMonotonicCount;
|
||||||
|
void *Stall;
|
||||||
|
void *SetWatchdogTimer;
|
||||||
|
void *ConnectController;
|
||||||
|
void *DisconnectController;
|
||||||
|
void *OpenProtocol;
|
||||||
|
void *CloseProtocol;
|
||||||
|
void *OpenProtocolInformation;
|
||||||
|
void *ProtocolsPerHandle;
|
||||||
|
void *LocateHandleBuffer;
|
||||||
|
EFI_STATUS (*LocateProtocol)(EFI_GUID *Protocol, void *Registration, void **Interface);
|
||||||
|
void *InstallMultipleProtocolInterfaces;
|
||||||
|
void *UninstallMultipleProtocolInterfaces;
|
||||||
|
void *CalculateCrc32;
|
||||||
|
void *CopyMem;
|
||||||
|
void *SetMem;
|
||||||
|
void *CreateEventEx;
|
||||||
|
} EFI_BOOT_SERVICES;
|
||||||
|
|
||||||
|
// PCI Root Bridge IO Protocol
|
||||||
|
#define EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID \
|
||||||
|
{ 0x2f707ebb, 0x4a1a, 0x11d4, {0x9a, 0x38, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} }
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EfiPciWidthUint8,
|
||||||
|
EfiPciWidthUint16,
|
||||||
|
EfiPciWidthUint32,
|
||||||
|
EfiPciWidthUint64,
|
||||||
|
EfiPciWidthFifoUint8,
|
||||||
|
EfiPciWidthFifoUint16,
|
||||||
|
EfiPciWidthFifoUint32,
|
||||||
|
EfiPciWidthFifoUint64,
|
||||||
|
EfiPciWidthFillUint8,
|
||||||
|
EfiPciWidthFillUint16,
|
||||||
|
EfiPciWidthFillUint32,
|
||||||
|
EfiPciWidthFillUint64,
|
||||||
|
EfiPciWidthMaximum
|
||||||
|
} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH;
|
||||||
|
|
||||||
|
typedef struct _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL;
|
||||||
|
|
||||||
|
typedef
|
||||||
|
EFI_STATUS
|
||||||
|
(*EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM) (
|
||||||
|
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
|
||||||
|
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
|
||||||
|
UINT64 Address,
|
||||||
|
UINTN Count,
|
||||||
|
VOID *Buffer
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM Read;
|
||||||
|
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM Write;
|
||||||
|
} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS;
|
||||||
|
|
||||||
|
struct _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL {
|
||||||
|
void *ParentHandle;
|
||||||
|
void *PollMem;
|
||||||
|
void *PollIo;
|
||||||
|
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Mem;
|
||||||
|
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Io;
|
||||||
|
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Pci;
|
||||||
|
void *CopyMem;
|
||||||
|
void *Map;
|
||||||
|
void *Unmap;
|
||||||
|
void *AllocateBuffer;
|
||||||
|
void *FreeBuffer;
|
||||||
|
void *Flush;
|
||||||
|
void *GetAttributes;
|
||||||
|
void *SetAttributes;
|
||||||
|
void *Configuration;
|
||||||
|
UINT32 SegmentNumber;
|
||||||
|
};
|
||||||
|
|
||||||
|
// System Table
|
||||||
|
typedef struct EFI_SYSTEM_TABLE {
|
||||||
|
EFI_TABLE_HEADER hdr;
|
||||||
|
uint16_t *firmwareVendor;
|
||||||
|
uint32_t firmwareRevision;
|
||||||
|
void *consoleInHandle;
|
||||||
|
void *conIn;
|
||||||
|
void *consoleOutHandle;
|
||||||
|
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
|
||||||
|
void *standardErrorHandle;
|
||||||
|
void *stdErr;
|
||||||
|
void *runtimeServices;
|
||||||
|
EFI_BOOT_SERVICES *BootServices;
|
||||||
|
uint64_t numberOfTableEntries;
|
||||||
|
void *configurationTable;
|
||||||
|
} EFI_SYSTEM_TABLE;
|
||||||
|
|
||||||
|
#endif
|
||||||
231
src/core/main.c
Normal file
231
src/core/main.c
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
#include "efi.h"
|
||||||
|
#include "quickjs.h"
|
||||||
|
#include "stdio.h"
|
||||||
|
#include "system_prog.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
static EFI_SYSTEM_TABLE *gST = NULL;
|
||||||
|
|
||||||
|
// Declare heap initialization function from minilibc.c
|
||||||
|
extern void init_heap(void *system_table);
|
||||||
|
|
||||||
|
void print(uint16_t *str) {
|
||||||
|
if (gST && gST->ConOut)
|
||||||
|
gST->ConOut->OutputString(gST->ConOut, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
int printf(const char *format, ...) {
|
||||||
|
char buf[1024];
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
int ret = vsnprintf(buf, sizeof(buf), format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
print(AsciiToUnicode(buf));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fprintf(FILE *stream, const char *format, ...) {
|
||||||
|
if (stream != stdout && stream != stderr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
char buf[1024];
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
int ret = vsnprintf(buf, sizeof(buf), format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
print(AsciiToUnicode(buf));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) {
|
||||||
|
if (stream != stdout && stream != stderr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const char *p = ptr;
|
||||||
|
size_t total = size * nmemb;
|
||||||
|
char buf[1025];
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
while (i < total) {
|
||||||
|
size_t chunk = total - i;
|
||||||
|
if (chunk > 1024)
|
||||||
|
chunk = 1024;
|
||||||
|
|
||||||
|
memcpy(buf, p + i, chunk);
|
||||||
|
buf[chunk] = 0;
|
||||||
|
|
||||||
|
print(AsciiToUnicode(buf));
|
||||||
|
i += chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nmemb;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fputc(int c, FILE *stream) {
|
||||||
|
if (stream != stdout && stream != stderr)
|
||||||
|
return c;
|
||||||
|
char buf[2] = {(char)c, 0};
|
||||||
|
|
||||||
|
print(AsciiToUnicode(buf));
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
int putchar(int c) { return fputc(c, stdout); }
|
||||||
|
|
||||||
|
// ------------------------------- Kernel C TS bindings
|
||||||
|
// -------------------------------
|
||||||
|
JSValue jsKCPrintln(JSContext *ctx, JSValueConst jsThis, int argc,
|
||||||
|
JSValueConst *argv) {
|
||||||
|
if (argc < 1)
|
||||||
|
return JS_ThrowSyntaxError(ctx, "Missing argument");
|
||||||
|
|
||||||
|
const char *str = JS_ToCString(ctx, argv[0]);
|
||||||
|
if (!str)
|
||||||
|
return JS_EXCEPTION;
|
||||||
|
|
||||||
|
print(AsciiToUnicode(str));
|
||||||
|
print(L"\r\n");
|
||||||
|
|
||||||
|
JS_FreeCString(ctx, str);
|
||||||
|
|
||||||
|
return JS_UNDEFINED;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue jsKCClearScreen(JSContext *ctx, JSValueConst jsThis, int argc,
|
||||||
|
JSValueConst *argv) {
|
||||||
|
gST->ConOut->ClearScreen(gST->ConOut);
|
||||||
|
|
||||||
|
return JS_UNDEFINED;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue jsKCPCIReadDword(JSContext *ctx, JSValueConst jsThis, int argc,
|
||||||
|
JSValueConst *argv) {
|
||||||
|
if (argc < 1)
|
||||||
|
return JS_ThrowSyntaxError(ctx, "Missing argument");
|
||||||
|
|
||||||
|
uint32_t addr_u32;
|
||||||
|
JS_ToUint32(ctx, &addr_u32, argv[0]);
|
||||||
|
UINT64 addr = (UINT64)
|
||||||
|
addr_u32; // Ensure type matches EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_RW's
|
||||||
|
// Address parameter
|
||||||
|
|
||||||
|
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *pci;
|
||||||
|
EFI_GUID pciGuid = EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID;
|
||||||
|
EFI_STATUS status =
|
||||||
|
gST->BootServices->LocateProtocol(&pciGuid, NULL, (void **)&pci);
|
||||||
|
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
return JS_ThrowInternalError(
|
||||||
|
ctx, "Failed to locate PCI Root Bridge IO Protocol: %d", status);
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT32 data = 0;
|
||||||
|
|
||||||
|
status = pci->Pci.Read(pci, EfiPciWidthUint32, addr, 1, &data);
|
||||||
|
|
||||||
|
return JS_NewUint32(ctx, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initKC(JSContext *ctx) {
|
||||||
|
JSValue global = JS_GetGlobalObject(ctx);
|
||||||
|
JSValue kc = JS_NewObject(ctx);
|
||||||
|
|
||||||
|
JS_SetPropertyStr(ctx, global, "kc", kc);
|
||||||
|
|
||||||
|
JS_SetPropertyStr(ctx, kc, "println", JS_NewCFunction(ctx, jsKCPrintln, "println", 1));
|
||||||
|
JS_SetPropertyStr(ctx, kc, "clearScreen", JS_NewCFunction(ctx, jsKCClearScreen, "clearScreen", 0));
|
||||||
|
JS_SetPropertyStr(ctx, kc, "pciReadDword", JS_NewCFunction(ctx, jsKCPCIReadDword, "pciReadDword", 1));
|
||||||
|
|
||||||
|
JS_FreeValue(ctx, global);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------- EFI main
|
||||||
|
// -------------------------------------
|
||||||
|
EFI_STATUS efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
|
||||||
|
(void)ImageHandle;
|
||||||
|
|
||||||
|
gST = SystemTable;
|
||||||
|
gST->ConOut->ClearScreen(gST->ConOut);
|
||||||
|
|
||||||
|
print(L"Booting LintsOS...\r\n");
|
||||||
|
|
||||||
|
// Initialize heap with maximum available memory
|
||||||
|
init_heap(SystemTable);
|
||||||
|
|
||||||
|
JSRuntime *rt = JS_NewRuntime();
|
||||||
|
if (!rt) {
|
||||||
|
print(L"!!! Kernel panic: Failed to create runtime !!!\r\n");
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSContext *ctx = JS_NewContext(rt);
|
||||||
|
if (!ctx) {
|
||||||
|
print(L"!!! Kernel panic: Failed to create context !!!\r\n");
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
initKC(ctx);
|
||||||
|
|
||||||
|
JSValue val;
|
||||||
|
JSValue eval_result = JS_Eval(ctx, SYSTEM_PROG_JS, strlen(SYSTEM_PROG_JS),
|
||||||
|
"<input>", JS_EVAL_TYPE_GLOBAL);
|
||||||
|
if (JS_IsException(eval_result))
|
||||||
|
val = eval_result;
|
||||||
|
else {
|
||||||
|
JS_FreeValue(ctx, eval_result);
|
||||||
|
|
||||||
|
JSValue global_obj = JS_GetGlobalObject(ctx);
|
||||||
|
JSValue kentry_func = JS_GetPropertyStr(ctx, global_obj, "KEntry");
|
||||||
|
|
||||||
|
if (JS_IsFunction(ctx, kentry_func))
|
||||||
|
val = JS_Call(ctx, kentry_func, JS_UNDEFINED, 0, NULL);
|
||||||
|
else
|
||||||
|
val = JS_ThrowReferenceError(ctx,
|
||||||
|
"KEntry function not found or not callable");
|
||||||
|
|
||||||
|
JS_FreeValue(ctx, kentry_func);
|
||||||
|
JS_FreeValue(ctx, global_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (JS_IsException(val)) {
|
||||||
|
JSValue ex = JS_GetException(ctx);
|
||||||
|
const char *str = JS_ToCString(ctx, ex);
|
||||||
|
|
||||||
|
if (str) {
|
||||||
|
printf("!!! Kernel panic: %s !!!\n", str);
|
||||||
|
JS_FreeCString(ctx, str);
|
||||||
|
} else
|
||||||
|
printf("!!! Kernel panic: [unknown] !!!\n");
|
||||||
|
|
||||||
|
JS_FreeValue(ctx, ex);
|
||||||
|
} else {
|
||||||
|
const char *str = JS_ToCString(ctx, val);
|
||||||
|
if (str) {
|
||||||
|
printf("!!! Kernel panic: %s !!!\n", str);
|
||||||
|
JS_FreeCString(ctx, str);
|
||||||
|
} else
|
||||||
|
printf("!!! Kernel panic: [unknown] !!!\n");
|
||||||
|
|
||||||
|
JS_FreeValue(ctx, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_FreeContext(ctx);
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
;
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
32
src/core/util.c
Normal file
32
src/core/util.c
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#include "util.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include "stdio.h"
|
||||||
|
#include "quickjs.h"
|
||||||
|
#include "efi.h"
|
||||||
|
|
||||||
|
|
||||||
|
void halt() {
|
||||||
|
for(;;);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// !!! AI GENERATE SLOP, PLEASE FIX !!!
|
||||||
|
//
|
||||||
|
//---------------------------------------------------------------
|
||||||
|
|
||||||
|
uint16_t *AsciiToUnicode(const char *ascii) {
|
||||||
|
static uint16_t buffer[1024];
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; ascii[i] && i < 1023; i++) {
|
||||||
|
buffer[i] = (uint16_t)ascii[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[i] = 0;
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
13
src/core/util.h
Normal file
13
src/core/util.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include "stdio.h"
|
||||||
|
|
||||||
|
#ifndef UTIL_H
|
||||||
|
#define UTIL_H
|
||||||
|
|
||||||
|
void halt();
|
||||||
|
uint16_t *AsciiToUnicode(const char *ascii);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,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));
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
1
src/lib/quickjs
Submodule
Submodule src/lib/quickjs added at 177e1b32a4
@@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Minimal system stubs for freestanding picolibc
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
/* Exit function - halt the system */
|
|
||||||
void _exit(int status)
|
|
||||||
{
|
|
||||||
(void)status;
|
|
||||||
/* Halt the CPU */
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
__asm__ volatile("hlt");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get time of day - not supported in freestanding */
|
|
||||||
int gettimeofday(struct timeval *tv, void *tz)
|
|
||||||
{
|
|
||||||
(void)tz;
|
|
||||||
if (tv)
|
|
||||||
{
|
|
||||||
tv->tv_sec = 0;
|
|
||||||
tv->tv_usec = 0;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sbrk - memory allocation (picolibc uses __heap_start and __heap_end from linker script) */
|
|
||||||
/* No need to implement sbrk as picolibc uses the linker symbols directly */
|
|
||||||
40
src/link.ld
40
src/link.ld
@@ -1,40 +0,0 @@
|
|||||||
/*
|
|
||||||
* link.ld
|
|
||||||
*/
|
|
||||||
|
|
||||||
OUTPUT_FORMAT(elf32-i386)
|
|
||||||
ENTRY(start)
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
. = 0x100000;
|
|
||||||
|
|
||||||
.text : {
|
|
||||||
*(.text)
|
|
||||||
*(.text.*)
|
|
||||||
*(.rodata)
|
|
||||||
*(.rodata.*)
|
|
||||||
}
|
|
||||||
|
|
||||||
.data : {
|
|
||||||
*(.data)
|
|
||||||
*(.data.*)
|
|
||||||
}
|
|
||||||
|
|
||||||
.bss : {
|
|
||||||
*(.bss)
|
|
||||||
*(.bss.*)
|
|
||||||
*(COMMON)
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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 = .;
|
|
||||||
}
|
|
||||||
@@ -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: " ",
|
|
||||||
};
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
import { kmain } from "./kernel";
|
|
||||||
import { kpanic } from "./kernel/panic";
|
|
||||||
|
|
||||||
try {
|
|
||||||
kmain();
|
|
||||||
} catch (e) {
|
|
||||||
kpanic(e instanceof Error ? e.message : String(e));
|
|
||||||
}
|
|
||||||
@@ -1,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,
|
|
||||||
};
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
import { dwordin, dwordout } from "../../../lib/libts/dword";
|
|
||||||
import { portin, portout } from "../../../lib/libts/port";
|
|
||||||
import { Logger } from "../../../lib/libstd/logger/logger.kmod";
|
|
||||||
import { sysfs_mkdir, sysfs_writeFile } from "../../filesystem/sysfs";
|
|
||||||
import { Path } from "../../../lib/libstd/path";
|
|
||||||
|
|
||||||
const KDRIVER_PCI_CONFIG_ADDR = 0xcf8;
|
|
||||||
const KDRIVER_PCI_CONFIG_DATA = 0xcfc;
|
|
||||||
|
|
||||||
export function kdriver_dev_pci_init() {}
|
|
||||||
|
|
||||||
export function kdriver_dev_pci_detectDevices() {
|
|
||||||
Logger.log("[PCI] Scanning...");
|
|
||||||
|
|
||||||
for (let bus = 0; bus < 256; bus++) {
|
|
||||||
for (let device = 0; device < 32; device++) {
|
|
||||||
kdriver_dev_pci_checkDevice(bus, device, 0);
|
|
||||||
|
|
||||||
const headerType = kdriver_dev_pci_getHeaderType(bus, device, 0);
|
|
||||||
if ((headerType & 0x80) !== 0) {
|
|
||||||
for (let func = 1; func < 8; func++) {
|
|
||||||
kdriver_dev_pci_checkDevice(bus, device, func);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function kdriver_dev_pci_checkDevice(
|
|
||||||
bus: number,
|
|
||||||
device: number,
|
|
||||||
func: number
|
|
||||||
) {
|
|
||||||
const vendorId = kdriver_dev_pci_getVendorId(bus, device, func);
|
|
||||||
|
|
||||||
if (vendorId === 0xffff) return;
|
|
||||||
|
|
||||||
const deviceId = kdriver_dev_pci_getDeviceId(bus, device, func);
|
|
||||||
const classCode = kdriver_dev_pci_getClassCode(bus, device, func);
|
|
||||||
const subclass = kdriver_dev_pci_getSubclass(bus, device, func);
|
|
||||||
|
|
||||||
const filename = bus + ":" + device + ":" + func;
|
|
||||||
|
|
||||||
Logger.log(
|
|
||||||
"[PCI] Found device pci:" +
|
|
||||||
filename +
|
|
||||||
" (vendor:" +
|
|
||||||
vendorId.toString(16) +
|
|
||||||
", device:" +
|
|
||||||
deviceId.toString(16) +
|
|
||||||
", class:" +
|
|
||||||
classCode.toString(16) +
|
|
||||||
", subclass:" +
|
|
||||||
subclass.toString(16) +
|
|
||||||
")"
|
|
||||||
);
|
|
||||||
|
|
||||||
const dirname = Path.join("/pci", filename);
|
|
||||||
|
|
||||||
sysfs_mkdir(dirname);
|
|
||||||
sysfs_writeFile(Path.join(dirname, "vendor"), vendorId);
|
|
||||||
sysfs_writeFile(Path.join(dirname, "device"), deviceId);
|
|
||||||
sysfs_writeFile(Path.join(dirname, "class"), classCode);
|
|
||||||
sysfs_writeFile(Path.join(dirname, "subclass"), subclass);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function kdriver_dev_pci_getDeviceId(
|
|
||||||
bus: number,
|
|
||||||
device: number,
|
|
||||||
func: number
|
|
||||||
) {
|
|
||||||
const data = kdriver_dev_pci_readConfigDword(bus, device, func, 0);
|
|
||||||
|
|
||||||
return data >> 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function kdriver_dev_pci_getVendorId(
|
|
||||||
bus: number,
|
|
||||||
device: number,
|
|
||||||
func: number
|
|
||||||
) {
|
|
||||||
const data = kdriver_dev_pci_readConfigDword(bus, device, func, 0);
|
|
||||||
|
|
||||||
return data & 0xffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function kdriver_dev_pci_getClassCode(
|
|
||||||
bus: number,
|
|
||||||
device: number,
|
|
||||||
func: number
|
|
||||||
) {
|
|
||||||
const data = kdriver_dev_pci_readConfigDword(bus, device, func, 8);
|
|
||||||
|
|
||||||
return (data >> 24) & 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function kdriver_dev_pci_getSubclass(
|
|
||||||
bus: number,
|
|
||||||
device: number,
|
|
||||||
func: number
|
|
||||||
) {
|
|
||||||
const data = kdriver_dev_pci_readConfigDword(bus, device, func, 8);
|
|
||||||
|
|
||||||
return (data >> 16) & 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function kdriver_dev_pci_getHeaderType(
|
|
||||||
bus: number,
|
|
||||||
device: number,
|
|
||||||
func: number
|
|
||||||
) {
|
|
||||||
const data = kdriver_dev_pci_readConfigDword(bus, device, func, 12);
|
|
||||||
|
|
||||||
return (data >> 16) & 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function kdriver_dev_pci_readConfigDword(
|
|
||||||
bus: number,
|
|
||||||
device: number,
|
|
||||||
func: number,
|
|
||||||
offset: number
|
|
||||||
) {
|
|
||||||
const address =
|
|
||||||
(1 << 31) | (bus << 16) | (device << 11) | (func << 8) | (offset & 0xfc);
|
|
||||||
|
|
||||||
dwordout(KDRIVER_PCI_CONFIG_ADDR, address);
|
|
||||||
const data = dwordin(KDRIVER_PCI_CONFIG_DATA);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
import { portin, portout } from "../../../lib/libts/port";
|
|
||||||
|
|
||||||
const SERIAL_PORT_COM1 = 0x3f8;
|
|
||||||
|
|
||||||
export function kdriver_etc_serial_init() {
|
|
||||||
portout(SERIAL_PORT_COM1 + 1, 0x00); // Disable all interrupts
|
|
||||||
portout(SERIAL_PORT_COM1 + 3, 0x80); // Enable DLAB
|
|
||||||
portout(SERIAL_PORT_COM1 + 0, 0x03); // 38400 baud
|
|
||||||
portout(SERIAL_PORT_COM1 + 1, 0x00);
|
|
||||||
portout(SERIAL_PORT_COM1 + 3, 0x03); // 8 bits, no parity, one stop bit
|
|
||||||
portout(SERIAL_PORT_COM1 + 2, 0xc7); // Enable FIFO, clear them, with 14-byte threshold
|
|
||||||
portout(SERIAL_PORT_COM1 + 4, 0x0b);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function kdriver_etc_serial_isTransmitBufferEmpty(): boolean {
|
|
||||||
return (portin(SERIAL_PORT_COM1 + 5) & 0x20) !== 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function kdriver_etc_serial_transmit(byte: number): void {
|
|
||||||
while (!kdriver_etc_serial_isTransmitBufferEmpty()) {}
|
|
||||||
|
|
||||||
portout(SERIAL_PORT_COM1, byte);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function kdriver_etc_serial_read(): number {
|
|
||||||
return portin(SERIAL_PORT_COM1);
|
|
||||||
}
|
|
||||||
@@ -1,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 [];
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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, "");
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export * from "./time"
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
export const CFG_KMOD_BIOS_TIME_CMOS_ADDR = 0x70;
|
|
||||||
export const CFG_KMOD_BIOS_TIME_CMOS_DATA_ADDR = 0x71;
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
import { portin, portout } from "../../../lib/libts/port";
|
|
||||||
import { padStart } from "../../../lib/libts/string";
|
|
||||||
import {
|
|
||||||
CFG_KMOD_BIOS_TIME_CMOS_ADDR,
|
|
||||||
CFG_KMOD_BIOS_TIME_CMOS_DATA_ADDR,
|
|
||||||
} from "./config";
|
|
||||||
|
|
||||||
export function kmod_bios_time_getCentury(): number {
|
|
||||||
const val = 0x32;
|
|
||||||
|
|
||||||
portout(CFG_KMOD_BIOS_TIME_CMOS_ADDR, val);
|
|
||||||
const data = portin(CFG_KMOD_BIOS_TIME_CMOS_DATA_ADDR);
|
|
||||||
|
|
||||||
return (data & 0x0f) + ((data >> 4) & 0x0f) * 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function kmod_bios_time_getYear(): number {
|
|
||||||
const val = 0x09;
|
|
||||||
|
|
||||||
portout(CFG_KMOD_BIOS_TIME_CMOS_ADDR, val);
|
|
||||||
const data = portin(CFG_KMOD_BIOS_TIME_CMOS_DATA_ADDR);
|
|
||||||
|
|
||||||
return (data & 0x0f) + ((data >> 4) & 0x0f) * 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function kmod_bios_time_getMonth(): number {
|
|
||||||
const val = 0x08;
|
|
||||||
|
|
||||||
portout(CFG_KMOD_BIOS_TIME_CMOS_ADDR, val);
|
|
||||||
const data = portin(CFG_KMOD_BIOS_TIME_CMOS_DATA_ADDR);
|
|
||||||
|
|
||||||
return (data & 0x0f) + ((data >> 4) & 0x0f) * 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function kmod_bios_time_getDay(): number {
|
|
||||||
const val = 0x07;
|
|
||||||
|
|
||||||
portout(CFG_KMOD_BIOS_TIME_CMOS_ADDR, val);
|
|
||||||
const data = portin(CFG_KMOD_BIOS_TIME_CMOS_DATA_ADDR);
|
|
||||||
|
|
||||||
return (data & 0x0f) + ((data >> 4) & 0x0f) * 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function kmod_bios_time_getHours(): number {
|
|
||||||
const val = 0x04;
|
|
||||||
|
|
||||||
portout(CFG_KMOD_BIOS_TIME_CMOS_ADDR, val);
|
|
||||||
const data = portin(CFG_KMOD_BIOS_TIME_CMOS_DATA_ADDR);
|
|
||||||
|
|
||||||
return (data & 0x0f) + ((data >> 4) & 0x0f) * 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function kmod_bios_time_getMinutes(): number {
|
|
||||||
const val = 0x02;
|
|
||||||
|
|
||||||
portout(CFG_KMOD_BIOS_TIME_CMOS_ADDR, val);
|
|
||||||
const data = portin(CFG_KMOD_BIOS_TIME_CMOS_DATA_ADDR);
|
|
||||||
|
|
||||||
return (data & 0x0f) + ((data >> 4) & 0x0f) * 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function kmod_bios_time_getSeconds(): number {
|
|
||||||
const val = 0x00;
|
|
||||||
|
|
||||||
portout(CFG_KMOD_BIOS_TIME_CMOS_ADDR, val);
|
|
||||||
const data = portin(CFG_KMOD_BIOS_TIME_CMOS_DATA_ADDR);
|
|
||||||
|
|
||||||
return (data & 0x0f) + ((data >> 4) & 0x0f) * 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function kmod_bios_time_getTimestamp(): string {
|
|
||||||
const century = kmod_bios_time_getCentury();
|
|
||||||
const year = kmod_bios_time_getYear();
|
|
||||||
const month = kmod_bios_time_getMonth();
|
|
||||||
const day = kmod_bios_time_getDay();
|
|
||||||
const hours = kmod_bios_time_getHours();
|
|
||||||
const minutes = kmod_bios_time_getMinutes();
|
|
||||||
const seconds = kmod_bios_time_getSeconds();
|
|
||||||
|
|
||||||
return (
|
|
||||||
century.toString() +
|
|
||||||
year.toString() +
|
|
||||||
"-" +
|
|
||||||
padStart(month.toString(), 2, "0") +
|
|
||||||
"-" +
|
|
||||||
padStart(day.toString(), 2, "0") +
|
|
||||||
"T" +
|
|
||||||
padStart(hours.toString(), 2, "0") +
|
|
||||||
":" +
|
|
||||||
padStart(minutes.toString(), 2, "0") +
|
|
||||||
":" +
|
|
||||||
padStart(seconds.toString(), 2, "0") +
|
|
||||||
+".000" +
|
|
||||||
"Z"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,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;
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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]!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
) {}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
export const CFG_KMOD_GRAPHICS_VGA_WIDTH = 80;
|
|
||||||
export const CFG_KMOD_GRAPHICS_VGA_HEIGHT = 25;
|
|
||||||
export const CFG_KMOD_GRAPGICS_VGA_MEM_ADDR = 0xb8000;
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export * from "./vga";
|
|
||||||
@@ -1,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);
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export * from "./input";
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import {
|
|
||||||
kmod_graphics_vga_clear,
|
|
||||||
kmod_graphics_vga_writeChar,
|
|
||||||
} from "./modules/graphics/graphics.kmod";
|
|
||||||
|
|
||||||
export function kpanic(reason?: string) {
|
|
||||||
kmod_graphics_vga_clear();
|
|
||||||
|
|
||||||
const l1 = "KERNEL PANIC!";
|
|
||||||
let l2 = "Unknown: Kernel crashed.";
|
|
||||||
|
|
||||||
if (reason) l2 = "Reason: " + reason;
|
|
||||||
|
|
||||||
for (let i = 0; i < l1.length; i++) {
|
|
||||||
kmod_graphics_vga_writeChar(i, 0, l1[i]!, 0x0c);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < l2.length; i++) {
|
|
||||||
kmod_graphics_vga_writeChar(i, 1, l2[i]!, 0x0c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,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;
|
|
||||||
}
|
|
||||||
@@ -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]!));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
export const Path = {
|
|
||||||
dirname(p: string): string {
|
|
||||||
const parts = p.split("/");
|
|
||||||
|
|
||||||
parts.pop();
|
|
||||||
|
|
||||||
if (parts.length <= 1) return "/";
|
|
||||||
|
|
||||||
return parts.join("/");
|
|
||||||
},
|
|
||||||
filename(p: string): string {
|
|
||||||
const parts = p.split("/");
|
|
||||||
|
|
||||||
const n = parts.pop();
|
|
||||||
|
|
||||||
if (!n) return "";
|
|
||||||
return n;
|
|
||||||
},
|
|
||||||
join(p1: string, p2: string): string {
|
|
||||||
if (p1.endsWith("/")) {
|
|
||||||
p1 = p1.slice(0, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p2.startsWith("/")) {
|
|
||||||
p2 = p2.slice(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return p1 + "/" + p2;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,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]!;
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
export function dwordin(dw: number): number {
|
|
||||||
return $dwordin(dw);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function dwordout(dw: number, value: number): void {
|
|
||||||
$dwordout(dw, value);
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
export function iexec(code: string) {
|
|
||||||
return $isolatedExec(code);
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
export function portin(port: number): number {
|
|
||||||
return $ptin(port);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function portout(port: number, value: number): void {
|
|
||||||
$ptout(port, value);
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
export function padStart(
|
|
||||||
str: string,
|
|
||||||
targetLength: number,
|
|
||||||
padString: string
|
|
||||||
): string {
|
|
||||||
while (str.length < targetLength) {
|
|
||||||
str = padString + str;
|
|
||||||
}
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
@@ -1,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;
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
export function wordin(w: number): number {
|
|
||||||
return $wordin(w);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function wordout(w: number, value: number): void {
|
|
||||||
$wordout(w, value);
|
|
||||||
}
|
|
||||||
@@ -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());
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user