Compare commits
10 Commits
2d52c45915
...
e2184bdc27
| Author | SHA1 | Date | |
|---|---|---|---|
| e2184bdc27 | |||
| 5b8804621c | |||
| aea99102cc | |||
| 1775af99b0 | |||
| 6f303bf656 | |||
| 4bf79e358a | |||
| 29a5cacdea | |||
| 34fc6e8d3a | |||
| 304dda0adf | |||
| 18092face9 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -2,4 +2,6 @@ _o/
|
|||||||
build/
|
build/
|
||||||
picolibc/
|
picolibc/
|
||||||
picolibc-install/
|
picolibc-install/
|
||||||
/lib/
|
/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
|
# Compiler flags
|
||||||
CFLAGS="-m32 -march=i686 -ffreestanding -nostdlib -fno-builtin"
|
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$PICOLIBC_INSTALL/include"
|
||||||
CFLAGS="$CFLAGS -I./lib/duktape/src"
|
CFLAGS="$CFLAGS -I./lib/duktape/src"
|
||||||
CFLAGS="$CFLAGS -I./src/lib"
|
CFLAGS="$CFLAGS -I./src/lib"
|
||||||
@@ -56,10 +57,19 @@ echo "=== Building kernel with picolibc ==="
|
|||||||
echo "Assembling boot code..."
|
echo "Assembling boot code..."
|
||||||
nasm -f elf32 src/boot/kernel.asm -o "$BUILD_DIR/kasm.o"
|
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
|
# Build duktape
|
||||||
echo "Building Duktape..."
|
echo "Building Duktape..."
|
||||||
gcc $CFLAGS -c lib/duktape/src/duktape.c -o "$BUILD_DIR/duktape.o"
|
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
|
# Build kernel
|
||||||
echo "Building kernel..."
|
echo "Building kernel..."
|
||||||
gcc $CFLAGS -c src/kernel/kernel.c -o "$BUILD_DIR/kc.o"
|
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..."
|
echo "Linking kernel..."
|
||||||
ld $LDFLAGS -T src/link.ld -o "$OUT_DIR/kernel" \
|
ld $LDFLAGS -T src/link.ld -o "$OUT_DIR/kernel" \
|
||||||
"$BUILD_DIR/kasm.o" \
|
"$BUILD_DIR/kasm.o" \
|
||||||
|
"$BUILD_DIR/interrupt.o" \
|
||||||
|
"$BUILD_DIR/idt.o" \
|
||||||
|
"$BUILD_DIR/isr.o" \
|
||||||
"$BUILD_DIR/kc.o" \
|
"$BUILD_DIR/kc.o" \
|
||||||
"$BUILD_DIR/duktape.o" \
|
"$BUILD_DIR/duktape.o" \
|
||||||
"$BUILD_DIR/syscalls.o" \
|
"$BUILD_DIR/syscalls.o" \
|
||||||
|
|||||||
@@ -1,3 +1,69 @@
|
|||||||
./scripts/build.sh
|
./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
|
global start
|
||||||
extern kmain ;kmain is defined in the kernel.c file
|
extern kmain ;kmain is defined in the kernel.c file
|
||||||
|
extern __stack_top
|
||||||
|
|
||||||
start:
|
start:
|
||||||
cli ; stop interrupts
|
cli ; stop interrupts during boot
|
||||||
|
mov esp, __stack_top
|
||||||
|
|
||||||
|
; Initialize FPU (x87)
|
||||||
|
finit ; Initialize FPU to default state
|
||||||
|
|
||||||
call kmain
|
call kmain
|
||||||
|
; Note: kmain will call sti to enable interrupts after IDT is set up
|
||||||
|
|
||||||
hlt ; halt the CPU
|
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 <string.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <duktape.h>
|
#include <duktape.h>
|
||||||
#include "embedded_js.h"
|
#include "embedded_js.h"
|
||||||
|
#include "interrupt/isr.h"
|
||||||
|
|
||||||
#define WHITE_TXT 0x0F
|
#define WHITE_TXT 0x0F
|
||||||
|
|
||||||
@@ -56,6 +58,35 @@ duk_ret_t native_ptout(duk_context *ctx)
|
|||||||
return 0;
|
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)
|
duk_ret_t native_dword_in(duk_context *ctx)
|
||||||
{
|
{
|
||||||
// Get the port (first argument)
|
// Get the port (first argument)
|
||||||
@@ -85,10 +116,557 @@ duk_ret_t native_dword_out(duk_context *ctx)
|
|||||||
return 0;
|
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()
|
void kmain()
|
||||||
{
|
{
|
||||||
|
// Initialize IDT and ISRs
|
||||||
|
isr_install();
|
||||||
|
irq_install();
|
||||||
|
|
||||||
// Initialize Duktape heap
|
// Initialize Duktape heap
|
||||||
ctx = duk_create_heap_default();
|
ctx = duk_create_heap_default();
|
||||||
|
global_ctx = ctx;
|
||||||
|
|
||||||
// Register native memory write function
|
// Register native memory write function
|
||||||
duk_push_c_function(ctx, native_addrw, 2);
|
duk_push_c_function(ctx, native_addrw, 2);
|
||||||
@@ -102,6 +680,14 @@ void kmain()
|
|||||||
duk_push_c_function(ctx, native_ptout, 2);
|
duk_push_c_function(ctx, native_ptout, 2);
|
||||||
duk_put_global_string(ctx, "$ptout");
|
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
|
// Register native dword in function
|
||||||
duk_push_c_function(ctx, native_dword_in, 1);
|
duk_push_c_function(ctx, native_dword_in, 1);
|
||||||
duk_put_global_string(ctx, "$dwordin");
|
duk_put_global_string(ctx, "$dwordin");
|
||||||
@@ -110,6 +696,29 @@ void kmain()
|
|||||||
duk_push_c_function(ctx, native_dword_out, 2);
|
duk_push_c_function(ctx, native_dword_out, 2);
|
||||||
duk_put_global_string(ctx, "$dwordout");
|
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
|
// Execute embedded JavaScript code from build/index.js
|
||||||
duk_push_string(ctx, embedded_js_code);
|
duk_push_string(ctx, embedded_js_code);
|
||||||
duk_int_t returnCode = duk_peval(ctx);
|
duk_int_t returnCode = duk_peval(ctx);
|
||||||
|
|||||||
14
src/link.ld
14
src/link.ld
@@ -26,15 +26,15 @@ SECTIONS
|
|||||||
*(COMMON)
|
*(COMMON)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Stack grows downward from high memory - place before heap */
|
||||||
|
. = ALIGN(4096);
|
||||||
|
__stack_bottom = .;
|
||||||
|
. = . + 0x100000; /* 1MB stack */
|
||||||
|
__stack_top = .;
|
||||||
|
|
||||||
/* Heap for malloc */
|
/* Heap for malloc */
|
||||||
. = ALIGN(4096);
|
. = ALIGN(4096);
|
||||||
__heap_start = .;
|
__heap_start = .;
|
||||||
. = . + 0x100000; /* 1MB heap */
|
. = . + 0x10000000; /* 256MB heap */
|
||||||
__heap_end = .;
|
__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 {
|
stat(path: string): KFilesystemStat | null {
|
||||||
return sysfs_statEntity(path);
|
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 { Logger } from "../lib/libstd/logger/logger.kmod";
|
||||||
import { charc } from "../lib/libts/byte";
|
import { charc } from "../lib/libts/byte";
|
||||||
import { padStart } from "../lib/libts/string";
|
import { padStart } from "../lib/libts/string";
|
||||||
|
import { uiarrtostr } from "../lib/libts/uint_arr";
|
||||||
import { getDate } from "../lib/sys/date";
|
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_dev_pci_detectDevices } from "./drivers/dev/pci";
|
||||||
import {
|
import {
|
||||||
kdriver_etc_serial_read,
|
kdriver_etc_serial_read,
|
||||||
kdriver_etc_serial_transmit,
|
kdriver_etc_serial_transmit,
|
||||||
} from "./drivers/etc/serial";
|
} 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 { 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 {
|
import {
|
||||||
kmod_drivers_init,
|
kmod_drivers_init,
|
||||||
kmod_drivers_register,
|
kmod_drivers_register,
|
||||||
} from "./modules/drivers/drivers.kmod";
|
} from "./modules/drivers/drivers.kmod";
|
||||||
import {
|
import {
|
||||||
kmod_filesystem_init,
|
kmod_filesystem_init,
|
||||||
|
kmod_filesystem_listDir,
|
||||||
kmod_filesystem_mount,
|
kmod_filesystem_mount,
|
||||||
kmod_filesystem_readFile,
|
kmod_filesystem_readFile,
|
||||||
} from "./modules/filesystem/filesystem.kmod";
|
} from "./modules/filesystem/filesystem.kmod";
|
||||||
@@ -21,7 +29,12 @@ import {
|
|||||||
kmod_graphics_vga_clear,
|
kmod_graphics_vga_clear,
|
||||||
kmod_graphics_vga_init,
|
kmod_graphics_vga_init,
|
||||||
kmod_graphics_vga_pushLine,
|
kmod_graphics_vga_pushLine,
|
||||||
|
kmod_graphics_vga_setLastLine,
|
||||||
} from "./modules/graphics/graphics.kmod";
|
} from "./modules/graphics/graphics.kmod";
|
||||||
|
import {
|
||||||
|
kmod_terminal_input_init,
|
||||||
|
kmod_terminal_input_onKeyboardInput,
|
||||||
|
} from "./modules/terminal/input";
|
||||||
|
|
||||||
export function kmain() {
|
export function kmain() {
|
||||||
kmod_drivers_init();
|
kmod_drivers_init();
|
||||||
@@ -29,18 +42,37 @@ export function kmain() {
|
|||||||
kmod_drivers_register();
|
kmod_drivers_register();
|
||||||
Logger.log("[Kernel] Drivers initialized.");
|
Logger.log("[Kernel] Drivers initialized.");
|
||||||
|
|
||||||
|
Logger.log("[Kernel] Initializing VGA module...");
|
||||||
|
kmod_graphics_vga_init();
|
||||||
|
|
||||||
Logger.log("[Kernel] Initializing filesystem module...");
|
Logger.log("[Kernel] Initializing filesystem module...");
|
||||||
kmod_filesystem_init();
|
kmod_filesystem_init();
|
||||||
kmod_filesystem_mount("/sys", sysfs_driver);
|
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...");
|
Logger.log("[Kernel] Initializing PCI devices...");
|
||||||
kdriver_dev_pci_detectDevices();
|
kdriver_dev_pci_detectDevices();
|
||||||
|
|
||||||
Logger.log("[Kernel] Initializing VGA module...");
|
Logger.log("[Kernel] Initializing drives...");
|
||||||
kmod_graphics_vga_init();
|
kmod_disks_detectDisks();
|
||||||
kmod_graphics_vga_pushLine("[Kernel] Kernel initialized successfully.");
|
|
||||||
kmod_graphics_vga_pushLine("Current date: " + getDate().toDateString());
|
const dev = devfs_getDevice("/hda1");
|
||||||
kmod_graphics_vga_pushLine(
|
if (!dev) throw new Error("System drive not found");
|
||||||
Number(kmod_filesystem_readFile("/sys/pci/0:1:0/vendor")).toString(16)
|
|
||||||
);
|
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_dev_pci_init } from "../../drivers/dev/pci";
|
||||||
import { kdriver_etc_serial_init } from "../../drivers/etc/serial";
|
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 {}
|
export function kmod_drivers_init(): void {}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Logger } from "../../../lib/libstd/logger/logger.kmod";
|
import { Logger } from "../../../lib/libstd/logger/logger.kmod";
|
||||||
|
import { Path } from "../../../lib/libstd/path";
|
||||||
import type {
|
import type {
|
||||||
KFilesystemDriver,
|
KFilesystemDriver,
|
||||||
KFilesystemEntity,
|
KFilesystemEntity,
|
||||||
@@ -48,24 +49,42 @@ export function kmod_filesystem_stripMountpoint(
|
|||||||
return p.slice(mount.mountpoint.length) || "/";
|
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(
|
export function kmod_filesystem_listDir(
|
||||||
path: string
|
path: string
|
||||||
): KFilesystemEntity[] | null {
|
): KFilesystemEntity[] | null {
|
||||||
const mount = kmod_filesystem_findMount(path);
|
const mount = kmod_filesystem_findMount(path);
|
||||||
if (!mount) return null;
|
if (!mount) return kmod_filesystem_lsMountAsFsEntity();
|
||||||
|
|
||||||
const strippedPath = kmod_filesystem_stripMountpoint(mount, path);
|
const strippedPath = kmod_filesystem_stripMountpoint(mount, path);
|
||||||
|
|
||||||
return mount.driver.listDir(strippedPath);
|
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);
|
const mount = kmod_filesystem_findMount(path);
|
||||||
if (!mount) return null;
|
if (!mount) return null;
|
||||||
|
|
||||||
const strippedPath = kmod_filesystem_stripMountpoint(mount, path);
|
const strippedPath = kmod_filesystem_stripMountpoint(mount, path);
|
||||||
|
|
||||||
return mount.driver.readFile(strippedPath);
|
return mount.driver.readFile(strippedPath) as number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function kmod_filesystem_writeFile(
|
export function kmod_filesystem_writeFile(
|
||||||
@@ -109,3 +128,9 @@ export function kmod_filesystem_stat(path: string): KFilesystemStat | null {
|
|||||||
|
|
||||||
return mount.driver.stat(strippedPath);
|
return mount.driver.stat(strippedPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function kmod_filesystem_directRead(
|
||||||
|
path: string,
|
||||||
|
count: number,
|
||||||
|
offset: number
|
||||||
|
) {}
|
||||||
|
|||||||
@@ -6,12 +6,17 @@ import {
|
|||||||
} from "./config";
|
} from "./config";
|
||||||
|
|
||||||
let kmod_graphics_vga_lineBuf: string[] = [];
|
let kmod_graphics_vga_lineBuf: string[] = [];
|
||||||
|
let init = false;
|
||||||
|
|
||||||
export function kmod_graphics_vga_init() {
|
export function kmod_graphics_vga_init() {
|
||||||
|
init = true;
|
||||||
|
|
||||||
kmod_graphics_vga_clear();
|
kmod_graphics_vga_clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function kmod_graphics_vga_pushLine(line: string) {
|
export function kmod_graphics_vga_pushLine(line: string) {
|
||||||
|
if (!init) return;
|
||||||
|
|
||||||
kmod_graphics_vga_lineBuf.push(line);
|
kmod_graphics_vga_lineBuf.push(line);
|
||||||
|
|
||||||
if (kmod_graphics_vga_lineBuf.length > CFG_KMOD_GRAPHICS_VGA_HEIGHT) {
|
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();
|
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() {
|
export function kmod_graphics_vga_printLines() {
|
||||||
|
if (!init) return;
|
||||||
|
|
||||||
for (let y = 0; y < CFG_KMOD_GRAPHICS_VGA_HEIGHT; y++) {
|
for (let y = 0; y < CFG_KMOD_GRAPHICS_VGA_HEIGHT; y++) {
|
||||||
const line = kmod_graphics_vga_lineBuf[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() {
|
export function kmod_graphics_vga_clear() {
|
||||||
|
if (!init) return;
|
||||||
|
|
||||||
kmod_graphics_vga_lineBuf = [];
|
kmod_graphics_vga_lineBuf = [];
|
||||||
|
|
||||||
for (let y = 0; y < CFG_KMOD_GRAPHICS_VGA_HEIGHT; y++) {
|
for (let y = 0; y < CFG_KMOD_GRAPHICS_VGA_HEIGHT; y++) {
|
||||||
@@ -64,6 +85,8 @@ export function kmod_graphics_vga_writeChar(
|
|||||||
char: string,
|
char: string,
|
||||||
color: number
|
color: number
|
||||||
) {
|
) {
|
||||||
|
if (!init) return;
|
||||||
|
|
||||||
const charAddr = kmod_graphics_vga_getCharAddr(x, y);
|
const charAddr = kmod_graphics_vga_getCharAddr(x, y);
|
||||||
const colorAddr = kmod_graphics_vga_getColorAddr(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 { charc } from "../../libts/byte";
|
||||||
import { kdriver_etc_serial_transmit } from "../../../kernel/drivers/etc/serial";
|
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 = {
|
export const Logger = {
|
||||||
log(message: string) {
|
log(message: string) {
|
||||||
|
kmod_graphics_vga_pushLine(message);
|
||||||
|
|
||||||
for (let i = 0; i < message.length; i++) {
|
for (let i = 0; i < message.length; i++) {
|
||||||
kdriver_etc_serial_transmit(charc(message[i]!));
|
kdriver_etc_serial_transmit(charc(message[i]!));
|
||||||
}
|
}
|
||||||
|
|
||||||
kdriver_etc_serial_transmit(charc("\n"));
|
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 {
|
export function charc(char: string): number {
|
||||||
return char.charCodeAt(0);
|
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 $addrw(address: number, value: number): void;
|
||||||
declare function $ptin(port: number): number;
|
declare function $ptin(port: number): number;
|
||||||
declare function $ptout(port: number, value: number): void;
|
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 $dwordin(port: number): number;
|
||||||
declare function $dwordout(port: number, value: number): void;
|
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 KFilesystemMountdata = KFilesystemMount[];
|
||||||
|
|
||||||
export type KFilesystemMount = {
|
export type KFilesystemMount = {
|
||||||
@@ -5,6 +7,8 @@ export type KFilesystemMount = {
|
|||||||
driver: KFilesystemDriver;
|
driver: KFilesystemDriver;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type KFilesystemDirectReadResponse = number[];
|
||||||
|
|
||||||
export type KFilesystemDriver = {
|
export type KFilesystemDriver = {
|
||||||
id: string;
|
id: string;
|
||||||
init: () => void;
|
init: () => void;
|
||||||
@@ -13,7 +17,13 @@ export type KFilesystemDriver = {
|
|||||||
writeFile(path: string, content: unknown): void;
|
writeFile(path: string, content: unknown): void;
|
||||||
createFile(path: string, content: unknown): void;
|
createFile(path: string, content: unknown): void;
|
||||||
mkdir(path: string): void;
|
mkdir(path: string): void;
|
||||||
|
rm(path: string): void;
|
||||||
stat(path: string): KFilesystemStat | null;
|
stat(path: string): KFilesystemStat | null;
|
||||||
|
directRead?(
|
||||||
|
path: string,
|
||||||
|
count: number,
|
||||||
|
offset: number
|
||||||
|
): KFilesystemDirectReadResponse;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type KFilesystemMemdata = KFilesystemEntity[];
|
export type KFilesystemMemdata = KFilesystemEntity[];
|
||||||
@@ -31,3 +41,11 @@ export type KFilesystemStat = {
|
|||||||
type: "file" | "folder";
|
type: "file" | "folder";
|
||||||
size: number;
|
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