Compare commits
10 Commits
2d52c45915
...
e2184bdc27
| Author | SHA1 | Date | |
|---|---|---|---|
| e2184bdc27 | |||
| 5b8804621c | |||
| aea99102cc | |||
| 1775af99b0 | |||
| 6f303bf656 | |||
| 4bf79e358a | |||
| 29a5cacdea | |||
| 34fc6e8d3a | |||
| 304dda0adf | |||
| 18092face9 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -3,3 +3,5 @@ build/
|
||||
picolibc/
|
||||
picolibc-install/
|
||||
/lib/
|
||||
*.iso
|
||||
*.img
|
||||
1
efi-port/.gitignore
vendored
Normal file
1
efi-port/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
out/
|
||||
29
efi-port/core/compat/math.h
Normal file
29
efi-port/core/compat/math.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#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
|
||||
9
efi-port/core/compat/setjmp.h
Normal file
9
efi-port/core/compat/setjmp.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#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
|
||||
14
efi-port/core/compat/stdarg.h
Normal file
14
efi-port/core/compat/stdarg.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#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
|
||||
31
efi-port/core/compat/stdint.h
Normal file
31
efi-port/core/compat/stdint.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#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
|
||||
14
efi-port/core/compat/stdio.h
Normal file
14
efi-port/core/compat/stdio.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#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
|
||||
13
efi-port/core/compat/time.h
Normal file
13
efi-port/core/compat/time.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#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
|
||||
12
efi-port/core/compat/windows.h
Normal file
12
efi-port/core/compat/windows.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/* 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
|
||||
|
||||
3256
efi-port/core/lib/duktape/src/duk_config.h
Normal file
3256
efi-port/core/lib/duktape/src/duk_config.h
Normal file
File diff suppressed because it is too large
Load Diff
996
efi-port/core/lib/duktape/src/duk_source_meta.json
Normal file
996
efi-port/core/lib/duktape/src/duk_source_meta.json
Normal file
@@ -0,0 +1,996 @@
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
115403
efi-port/core/lib/duktape/src/duktape.c
Normal file
115403
efi-port/core/lib/duktape/src/duktape.c
Normal file
File diff suppressed because it is too large
Load Diff
1469
efi-port/core/lib/duktape/src/duktape.h
Normal file
1469
efi-port/core/lib/duktape/src/duktape.h
Normal file
File diff suppressed because it is too large
Load Diff
319
efi-port/core/src/compat.c
Normal file
319
efi-port/core/src/compat.c
Normal file
@@ -0,0 +1,319 @@
|
||||
#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
|
||||
12
efi-port/core/src/efi.c
Normal file
12
efi-port/core/src/efi.c
Normal file
@@ -0,0 +1,12 @@
|
||||
#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);
|
||||
}
|
||||
13
efi-port/core/src/efi.h
Normal file
13
efi-port/core/src/efi.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#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
|
||||
57
efi-port/core/src/main.c
Normal file
57
efi-port/core/src/main.c
Normal file
@@ -0,0 +1,57 @@
|
||||
#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;
|
||||
}
|
||||
8
efi-port/core/src/main.h
Normal file
8
efi-port/core/src/main.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#include "efi.h"
|
||||
|
||||
#ifndef MAIN_H
|
||||
#define MAIN_H
|
||||
|
||||
int kernel_main(EFI_SYSTEM_TABLE* systemTable);
|
||||
|
||||
#endif
|
||||
1
efi-port/edk2
Submodule
1
efi-port/edk2
Submodule
Submodule efi-port/edk2 added at aacfbe667e
11
efi-port/scripts/build_c.sh
Executable file
11
efi-port/scripts/build_c.sh
Executable file
@@ -0,0 +1,11 @@
|
||||
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
|
||||
19
efi-port/scripts/out_to_iso.sh
Executable file
19
efi-port/scripts/out_to_iso.sh
Executable file
@@ -0,0 +1,19 @@
|
||||
# Create a FAT12 image
|
||||
dd if=/dev/zero of=out/fat.img bs=1k count=1440
|
||||
mformat -i out/fat.img -f 1440 ::
|
||||
|
||||
# Create EFI directory structure
|
||||
mmd -i out/fat.img ::/EFI
|
||||
mmd -i out/fat.img ::/EFI/BOOT
|
||||
|
||||
# Copy the EFI application
|
||||
mcopy -i out/fat.img out/img/EFI/BOOT/BOOTX64.EFI ::/EFI/BOOT
|
||||
|
||||
# Verify content
|
||||
echo "Verifying FAT image content:"
|
||||
mdir -i out/fat.img -/ ::
|
||||
|
||||
# Create the ISO
|
||||
# -e specifies the boot image (the FAT image)
|
||||
# -no-emul-boot is required for UEFI
|
||||
xorriso -as mkisofs -R -f -e /fat.img -no-emul-boot -volid LintsEFI -o out/lints.iso out/img out/fat.img
|
||||
22
efi-port/scripts/run_vbox.sh
Executable file
22
efi-port/scripts/run_vbox.sh
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/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"
|
||||
@@ -37,6 +37,7 @@ 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"
|
||||
@@ -56,10 +57,19 @@ echo "=== Building kernel with picolibc ==="
|
||||
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"
|
||||
@@ -72,6 +82,9 @@ gcc $CFLAGS -c src/lib/syscalls.c -o "$BUILD_DIR/syscalls.o"
|
||||
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" \
|
||||
|
||||
@@ -1,3 +1,69 @@
|
||||
./scripts/build.sh
|
||||
|
||||
qemu-system-i386 -serial stdio -kernel "build/out/kernel"
|
||||
# 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
|
||||
@@ -8,10 +8,18 @@ section .text
|
||||
|
||||
global start
|
||||
extern kmain ;kmain is defined in the kernel.c file
|
||||
extern __stack_top
|
||||
|
||||
start:
|
||||
cli ; stop interrupts
|
||||
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
|
||||
22
src/kernel/interrupt/idt.c
Normal file
22
src/kernel/interrupt/idt.c
Normal file
@@ -0,0 +1,22 @@
|
||||
#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));
|
||||
}
|
||||
40
src/kernel/interrupt/idt.h
Normal file
40
src/kernel/interrupt/idt.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#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
|
||||
446
src/kernel/interrupt/interrupt.asm
Normal file
446
src/kernel/interrupt/interrupt.asm
Normal file
@@ -0,0 +1,446 @@
|
||||
; 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
|
||||
317
src/kernel/interrupt/isr.c
Normal file
317
src/kernel/interrupt/isr.c
Normal file
@@ -0,0 +1,317 @@
|
||||
#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);
|
||||
}
|
||||
}
|
||||
78
src/kernel/interrupt/isr.h
Normal file
78
src/kernel/interrupt/isr.h
Normal file
@@ -0,0 +1,78 @@
|
||||
#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
|
||||
16
src/kernel/interrupt/types.h
Normal file
16
src/kernel/interrupt/types.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#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,7 +1,9 @@
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <duktape.h>
|
||||
#include "embedded_js.h"
|
||||
#include "interrupt/isr.h"
|
||||
|
||||
#define WHITE_TXT 0x0F
|
||||
|
||||
@@ -56,6 +58,35 @@ duk_ret_t native_ptout(duk_context *ctx)
|
||||
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)
|
||||
@@ -85,10 +116,557 @@ duk_ret_t native_dword_out(duk_context *ctx)
|
||||
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);
|
||||
@@ -102,6 +680,14 @@ void kmain()
|
||||
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");
|
||||
@@ -110,6 +696,29 @@ void kmain()
|
||||
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);
|
||||
|
||||
14
src/link.ld
14
src/link.ld
@@ -26,15 +26,15 @@ SECTIONS
|
||||
*(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 = .;
|
||||
. = . + 0x100000; /* 1MB heap */
|
||||
. = . + 0x10000000; /* 256MB heap */
|
||||
__heap_end = .;
|
||||
|
||||
/* Stack grows downward from high memory */
|
||||
. = ALIGN(4096);
|
||||
__stack_bottom = .;
|
||||
. = . + 0x10000; /* 64KB stack */
|
||||
__stack_top = .;
|
||||
}
|
||||
67
src/os/src/config/keyboard.ts
Normal file
67
src/os/src/config/keyboard.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
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: " ",
|
||||
};
|
||||
365
src/os/src/kernel/drivers/dev/ata.ts
Normal file
365
src/os/src/kernel/drivers/dev/ata.ts
Normal file
@@ -0,0 +1,365 @@
|
||||
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,
|
||||
};
|
||||
31
src/os/src/kernel/drivers/dev/keyboard.ts
Normal file
31
src/os/src/kernel/drivers/dev/keyboard.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
154
src/os/src/kernel/filesystem/devfs.ts
Normal file
154
src/os/src/kernel/filesystem/devfs.ts
Normal file
@@ -0,0 +1,154 @@
|
||||
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 [];
|
||||
}
|
||||
370
src/os/src/kernel/filesystem/fat32.ts
Normal file
370
src/os/src/kernel/filesystem/fat32.ts
Normal file
@@ -0,0 +1,370 @@
|
||||
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;
|
||||
}
|
||||
168
src/os/src/kernel/filesystem/procfs.ts
Normal file
168
src/os/src/kernel/filesystem/procfs.ts
Normal file
@@ -0,0 +1,168 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,9 @@ export function sysfs_driver(): KFilesystemDriver {
|
||||
stat(path: string): KFilesystemStat | null {
|
||||
return sysfs_statEntity(path);
|
||||
},
|
||||
rm(path: string): void {
|
||||
throw new Error("Cannot remove objects in sysfs.");
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,27 @@
|
||||
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";
|
||||
@@ -21,7 +29,12 @@ 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();
|
||||
@@ -29,18 +42,37 @@ export function kmain() {
|
||||
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 VGA module...");
|
||||
kmod_graphics_vga_init();
|
||||
kmod_graphics_vga_pushLine("[Kernel] Kernel initialized successfully.");
|
||||
kmod_graphics_vga_pushLine("Current date: " + getDate().toDateString());
|
||||
kmod_graphics_vga_pushLine(
|
||||
Number(kmod_filesystem_readFile("/sys/pci/0:1:0/vendor")).toString(16)
|
||||
);
|
||||
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, "");
|
||||
}
|
||||
|
||||
152
src/os/src/kernel/modules/app/app.kmod.ts
Normal file
152
src/os/src/kernel/modules/app/app.kmod.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
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);
|
||||
}
|
||||
43
src/os/src/kernel/modules/cpu/interrupts.ts
Normal file
43
src/os/src/kernel/modules/cpu/interrupts.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
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;
|
||||
}
|
||||
163
src/os/src/kernel/modules/disks/disks.kmod.ts
Normal file
163
src/os/src/kernel/modules/disks/disks.kmod.ts
Normal file
@@ -0,0 +1,163 @@
|
||||
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,7 +1,14 @@
|
||||
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];
|
||||
const drivers = [
|
||||
kdriver_etc_serial_init,
|
||||
kdriver_dev_pci_init,
|
||||
kdriver_dev_keyboard_init,
|
||||
kdriver_dev_ata_init,
|
||||
];
|
||||
|
||||
export function kmod_drivers_init(): void {}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Logger } from "../../../lib/libstd/logger/logger.kmod";
|
||||
import { Path } from "../../../lib/libstd/path";
|
||||
import type {
|
||||
KFilesystemDriver,
|
||||
KFilesystemEntity,
|
||||
@@ -48,24 +49,42 @@ export function kmod_filesystem_stripMountpoint(
|
||||
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 null;
|
||||
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): unknown {
|
||||
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);
|
||||
return mount.driver.readFile(strippedPath) as number[];
|
||||
}
|
||||
|
||||
export function kmod_filesystem_writeFile(
|
||||
@@ -109,3 +128,9 @@ export function kmod_filesystem_stat(path: string): KFilesystemStat | null {
|
||||
|
||||
return mount.driver.stat(strippedPath);
|
||||
}
|
||||
|
||||
export function kmod_filesystem_directRead(
|
||||
path: string,
|
||||
count: number,
|
||||
offset: number
|
||||
) {}
|
||||
|
||||
@@ -6,12 +6,17 @@ import {
|
||||
} 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) {
|
||||
@@ -21,7 +26,21 @@ export function kmod_graphics_vga_pushLine(line: string) {
|
||||
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] || "";
|
||||
|
||||
@@ -49,6 +68,8 @@ export function kmod_graphics_vga_getColorAddr(x: number, y: number): number {
|
||||
}
|
||||
|
||||
export function kmod_graphics_vga_clear() {
|
||||
if (!init) return;
|
||||
|
||||
kmod_graphics_vga_lineBuf = [];
|
||||
|
||||
for (let y = 0; y < CFG_KMOD_GRAPHICS_VGA_HEIGHT; y++) {
|
||||
@@ -64,6 +85,8 @@ export function kmod_graphics_vga_writeChar(
|
||||
char: string,
|
||||
color: number
|
||||
) {
|
||||
if (!init) return;
|
||||
|
||||
const charAddr = kmod_graphics_vga_getCharAddr(x, y);
|
||||
const colorAddr = kmod_graphics_vga_getColorAddr(x, y);
|
||||
|
||||
|
||||
28
src/os/src/kernel/modules/terminal/input.ts
Normal file
28
src/os/src/kernel/modules/terminal/input.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
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
src/os/src/kernel/modules/terminal/terminal.kmod.ts
Normal file
1
src/os/src/kernel/modules/terminal/terminal.kmod.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./input";
|
||||
192
src/os/src/kernel/utils/block_cache.ts
Normal file
192
src/os/src/kernel/utils/block_cache.ts
Normal file
@@ -0,0 +1,192 @@
|
||||
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,12 +1,27 @@
|
||||
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,3 +1,15 @@
|
||||
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]!;
|
||||
}
|
||||
|
||||
3
src/os/src/lib/libts/exec.ts
Normal file
3
src/os/src/lib/libts/exec.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export function iexec(code: string) {
|
||||
return $isolatedExec(code);
|
||||
}
|
||||
9
src/os/src/lib/libts/uint_arr.ts
Normal file
9
src/os/src/lib/libts/uint_arr.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export function uiarrtostr(a: number[]) {
|
||||
let s = "";
|
||||
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
s += String.fromCharCode(a[i]!);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
7
src/os/src/lib/libts/word.ts
Normal file
7
src/os/src/lib/libts/word.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export function wordin(w: number): number {
|
||||
return $wordin(w);
|
||||
}
|
||||
|
||||
export function wordout(w: number, value: number): void {
|
||||
$wordout(w, value);
|
||||
}
|
||||
22
src/os/src/lib/sys/env.ts
Normal file
22
src/os/src/lib/sys/env.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { kmod_filesystem_readFile } from "../../kernel/modules/filesystem/filesystem.kmod";
|
||||
import { uiarrtostr } from "../libts/uint_arr";
|
||||
|
||||
export function getEnv(key: string): string | null {
|
||||
const data = uiarrtostr(kmod_filesystem_readFile("/disk/uenv")!);
|
||||
const lines = data.split("\n");
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const kv = lines[i]!.split("=");
|
||||
|
||||
if (kv[0] == key) return kv[1]!;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function getPathEnv(): string[] | null {
|
||||
const path = getEnv("PATH");
|
||||
if (!path) return null;
|
||||
|
||||
return path.split(":");
|
||||
}
|
||||
5
src/os/src/oskrnl/app/launcher.ts
Normal file
5
src/os/src/oskrnl/app/launcher.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { kmod_app_run } from "../../kernel/modules/app/app.kmod";
|
||||
|
||||
export function oskrnl_app_launcher_run(path: string, args: string) {
|
||||
return kmod_app_run(path, args);
|
||||
}
|
||||
25
src/os/src/oskrnl/app/proc.ts
Normal file
25
src/os/src/oskrnl/app/proc.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import {
|
||||
kmod_app_proc_addExitListener,
|
||||
kmod_app_proc_exit,
|
||||
kmod_app_proc_getArgs,
|
||||
kmod_app_proc_running,
|
||||
} from "../../kernel/modules/app/app.kmod";
|
||||
|
||||
export function oskrnl_app_proc_getArgs(pid: string): string {
|
||||
return kmod_app_proc_getArgs(pid);
|
||||
}
|
||||
|
||||
export function oskrnl_app_proc_addExitListener(
|
||||
pid: string,
|
||||
listener: () => void
|
||||
): void {
|
||||
kmod_app_proc_addExitListener(pid, listener);
|
||||
}
|
||||
|
||||
export function oskrnl_app_proc_exit(pid: string): void {
|
||||
kmod_app_proc_exit(pid);
|
||||
}
|
||||
|
||||
export function oskrnl_app_proc_running(pid: string): boolean {
|
||||
return kmod_app_proc_running(pid);
|
||||
}
|
||||
9
src/os/src/oskrnl/console/console.ts
Normal file
9
src/os/src/oskrnl/console/console.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { Logger } from "../../lib/libstd/logger/logger.kmod";
|
||||
|
||||
export function oskrnl_console_log(data: any) {
|
||||
Logger.log(String(data));
|
||||
}
|
||||
|
||||
export function oskrnl_console_update(data: any) {
|
||||
Logger.update(String(data));
|
||||
}
|
||||
22
src/os/src/oskrnl/index.ts
Normal file
22
src/os/src/oskrnl/index.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { oskrnl_app_launcher_run } from "./app/launcher";
|
||||
import {
|
||||
oskrnl_app_proc_addExitListener,
|
||||
oskrnl_app_proc_exit,
|
||||
oskrnl_app_proc_getArgs,
|
||||
oskrnl_app_proc_running,
|
||||
} from "./app/proc";
|
||||
import { oskrnl_console_log, oskrnl_console_update } from "./console/console";
|
||||
import { oskrnl_input_onKeyPress } from "./input/input";
|
||||
|
||||
export function oskrnl_register() {
|
||||
(globalThis as any).__oskrnl = {
|
||||
console_log: oskrnl_console_log,
|
||||
console_update: oskrnl_console_update,
|
||||
input_onKeyPress: oskrnl_input_onKeyPress,
|
||||
app_launcher_run: oskrnl_app_launcher_run,
|
||||
app_proc_getArgs: oskrnl_app_proc_getArgs,
|
||||
app_proc_addExitListener: oskrnl_app_proc_addExitListener,
|
||||
app_proc_exit: oskrnl_app_proc_exit,
|
||||
app_proc_running: oskrnl_app_proc_running,
|
||||
};
|
||||
}
|
||||
24
src/os/src/oskrnl/input/input.ts
Normal file
24
src/os/src/oskrnl/input/input.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import {
|
||||
kmod_app_proc_generateHandle,
|
||||
kmod_app_proc_registerHandle,
|
||||
kmod_app_proc_running,
|
||||
kmod_app_proc_addExitListener,
|
||||
} from "../../kernel/modules/app/app.kmod";
|
||||
import { kmod_terminal_input_onKeyboardInput } from "../../kernel/modules/terminal/input";
|
||||
|
||||
export function oskrnl_input_onKeyPress(
|
||||
pid: string,
|
||||
handler: (key: string) => void
|
||||
) {
|
||||
kmod_app_proc_registerHandle(pid, kmod_app_proc_generateHandle());
|
||||
const removeHandler = kmod_terminal_input_onKeyboardInput(function (
|
||||
key: string
|
||||
) {
|
||||
const running = kmod_app_proc_running(pid);
|
||||
if (!running) return;
|
||||
|
||||
handler(key);
|
||||
});
|
||||
|
||||
kmod_app_proc_addExitListener(pid, removeHandler);
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
console.log("TS-DOS Program Started");
|
||||
10
src/os/src/types/c/bindings.d.ts
vendored
10
src/os/src/types/c/bindings.d.ts
vendored
@@ -1,5 +1,15 @@
|
||||
declare function $addrw(address: number, value: number): void;
|
||||
declare function $ptin(port: number): number;
|
||||
declare function $ptout(port: number, value: number): void;
|
||||
declare function $bytein(port: number): number;
|
||||
declare function $byteout(port: number, value: number): void;
|
||||
declare function $dwordin(port: number): number;
|
||||
declare function $dwordout(port: number, value: number): void;
|
||||
declare function $wordin(port: number): number;
|
||||
declare function $wordout(port: number, value: number): void;
|
||||
declare const $irqregister: (
|
||||
irq: number,
|
||||
handler: (irqNum: number) => void
|
||||
) => boolean;
|
||||
declare function $isolatedExec(code: string): number;
|
||||
declare function $destroyIsolatedHeap(handle: number): void;
|
||||
|
||||
11
src/os/src/types/dev/ata/drive.ts
Normal file
11
src/os/src/types/dev/ata/drive.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export type AtaDriveDescriptor = {
|
||||
controller: number;
|
||||
drive: number;
|
||||
present: boolean;
|
||||
slave: number;
|
||||
atapi: boolean;
|
||||
model: string;
|
||||
serial: string;
|
||||
firmware: string;
|
||||
size: number;
|
||||
};
|
||||
4
src/os/src/types/dev/device.ts
Normal file
4
src/os/src/types/dev/device.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export enum DeviceType {
|
||||
BlockDevice,
|
||||
CharDevice,
|
||||
}
|
||||
13
src/os/src/types/filesystem/disk.ts
Normal file
13
src/os/src/types/filesystem/disk.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import type { AtaDriveDescriptor } from "../dev/ata/drive";
|
||||
|
||||
export type Disk = {
|
||||
dnum: number;
|
||||
type: DiskType;
|
||||
descriptor: AtaDriveDescriptor;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export enum DiskType {
|
||||
ATA,
|
||||
ATAPI,
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { DeviceType } from "../dev/device";
|
||||
|
||||
export type KFilesystemMountdata = KFilesystemMount[];
|
||||
|
||||
export type KFilesystemMount = {
|
||||
@@ -5,6 +7,8 @@ export type KFilesystemMount = {
|
||||
driver: KFilesystemDriver;
|
||||
};
|
||||
|
||||
export type KFilesystemDirectReadResponse = number[];
|
||||
|
||||
export type KFilesystemDriver = {
|
||||
id: string;
|
||||
init: () => void;
|
||||
@@ -13,7 +17,13 @@ export type KFilesystemDriver = {
|
||||
writeFile(path: string, content: unknown): void;
|
||||
createFile(path: string, content: unknown): void;
|
||||
mkdir(path: string): void;
|
||||
rm(path: string): void;
|
||||
stat(path: string): KFilesystemStat | null;
|
||||
directRead?(
|
||||
path: string,
|
||||
count: number,
|
||||
offset: number
|
||||
): KFilesystemDirectReadResponse;
|
||||
};
|
||||
|
||||
export type KFilesystemMemdata = KFilesystemEntity[];
|
||||
@@ -31,3 +41,11 @@ export type KFilesystemStat = {
|
||||
type: "file" | "folder";
|
||||
size: number;
|
||||
};
|
||||
|
||||
export type KFilesystemDevice = KFilesystemEntity & {
|
||||
dtype: DeviceType;
|
||||
driver: unknown;
|
||||
data: unknown;
|
||||
};
|
||||
|
||||
export type KFilesystemMemdev = (KFilesystemDevice | KFilesystemEntity)[];
|
||||
|
||||
9
src/os/src/types/interrupt.ts
Normal file
9
src/os/src/types/interrupt.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export type KInterruptHandler = (
|
||||
interruptNumber: number,
|
||||
data?: unknown
|
||||
) => void;
|
||||
|
||||
export type KInterrupt = {
|
||||
handler: KInterruptHandler;
|
||||
data: unknown;
|
||||
};
|
||||
4
src/os/src/types/utils/block_cache.ts
Normal file
4
src/os/src/types/utils/block_cache.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export type BlockCache = {
|
||||
payload_size: number;
|
||||
blocks: number;
|
||||
};
|
||||
1
test-hdd/apps/echo/index.js
Normal file
1
test-hdd/apps/echo/index.js
Normal file
@@ -0,0 +1 @@
|
||||
__oskrnl.console_log(__oskrnl.app_proc_getArgs(__oskrnl_procd_pid));
|
||||
5
test-hdd/apps/echo/meta.lam
Normal file
5
test-hdd/apps/echo/meta.lam
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"app:name": "echo",
|
||||
"app:version": "1.0.0",
|
||||
"app:entrypoint": "index.js"
|
||||
}
|
||||
31
test-hdd/apps/tysh/index.js
Normal file
31
test-hdd/apps/tysh/index.js
Normal file
@@ -0,0 +1,31 @@
|
||||
__oskrnl.console_log("> ");
|
||||
|
||||
var input = "";
|
||||
var pid = "";
|
||||
|
||||
__oskrnl.input_onKeyPress(__oskrnl_procd_pid, function (key) {
|
||||
if (pid != "" && __oskrnl.app_proc_running(pid)) return;
|
||||
|
||||
if (key == "Backspace") input = input.slice(0, -1);
|
||||
else if (key == "Enter") {
|
||||
process();
|
||||
return;
|
||||
} else input += key.toLowerCase();
|
||||
|
||||
__oskrnl.console_update("> " + input);
|
||||
});
|
||||
|
||||
function process() {
|
||||
var app = input.split(" ")[0];
|
||||
var args = input.split(" ").slice(1);
|
||||
pid = __oskrnl.app_launcher_run(app, args.join(" "));
|
||||
__oskrnl.app_proc_addExitListener(pid, function () {
|
||||
input = "";
|
||||
__oskrnl.console_log("> ");
|
||||
});
|
||||
|
||||
if (!__oskrnl.app_proc_running(pid)) {
|
||||
input = "";
|
||||
__oskrnl.console_log("> ");
|
||||
}
|
||||
}
|
||||
5
test-hdd/apps/tysh/meta.lam
Normal file
5
test-hdd/apps/tysh/meta.lam
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"app:name": "tysh",
|
||||
"app:version": "1.0.0",
|
||||
"app:entrypoint": "index.js"
|
||||
}
|
||||
6
test-hdd/apps/wfkey/index.js
Normal file
6
test-hdd/apps/wfkey/index.js
Normal file
@@ -0,0 +1,6 @@
|
||||
__oskrnl.input_onKeyPress(__oskrnl_procd_pid, function (key) {
|
||||
if (key == __oskrnl.app_proc_getArgs(__oskrnl_procd_pid)[0].toUpperCase()) {
|
||||
__oskrnl.app_proc_exit(__oskrnl_procd_pid);
|
||||
return;
|
||||
}
|
||||
});
|
||||
5
test-hdd/apps/wfkey/meta.lam
Normal file
5
test-hdd/apps/wfkey/meta.lam
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"app:name": "wfkey",
|
||||
"app:version": "1.0.0",
|
||||
"app:entrypoint": "index.js"
|
||||
}
|
||||
1
test-hdd/uenv
Normal file
1
test-hdd/uenv
Normal file
@@ -0,0 +1 @@
|
||||
PATH=/disk/apps
|
||||
1
test-hdd/ushellc
Normal file
1
test-hdd/ushellc
Normal file
@@ -0,0 +1 @@
|
||||
/disk/apps/tysh
|
||||
Reference in New Issue
Block a user