From f483a34d3c87a7d9f7585b1bd582951c73f12cb6 Mon Sep 17 00:00:00 2001 From: Martin Petr Date: Sun, 30 Nov 2025 10:47:59 +0100 Subject: [PATCH] Add PCI driver --- core/src/compat.c | 119 ++++++++++++++++++----- core/src/main.c | 77 +++++++++++++++ os/src/kernel/drivers/dev/pci.kdriver.ts | 113 +++++++++++++++++++++ os/src/kernel/index.ts | 6 ++ os/src/kernel/modules/drivers.kmod.ts | 12 +++ os/src/libs/io.ts | 7 ++ os/src/types/global_c_bindings.d.ts | 21 ++++ scripts/process_js.js | 4 +- scripts/run.sh | 4 + 9 files changed, 338 insertions(+), 25 deletions(-) create mode 100644 os/src/kernel/drivers/dev/pci.kdriver.ts create mode 100644 os/src/kernel/modules/drivers.kmod.ts create mode 100644 os/src/libs/io.ts create mode 100755 scripts/run.sh diff --git a/core/src/compat.c b/core/src/compat.c index eac8579..6bf1fb3 100644 --- a/core/src/compat.c +++ b/core/src/compat.c @@ -90,26 +90,102 @@ int snprintf(char *str, size_t size, const char *format, ...) { // 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; } +// Math functions +// Duktape needs math functions for proper numeric conversions and bitwise operations. +// EDK2 doesn't provide a standard math library, so we implement basic versions here. + +double fabs(double x) { + return x < 0.0 ? -x : x; +} + +double floor(double x) { + if (x >= 0.0) { + return (double)(INT64)x; + } else { + INT64 i = (INT64)x; + return (double)((x == (double)i) ? i : i - 1); + } +} + +double ceil(double x) { + if (x >= 0.0) { + INT64 i = (INT64)x; + return (double)((x == (double)i) ? i : i + 1); + } else { + return (double)(INT64)x; + } +} + +double trunc(double x) { + return (double)(INT64)x; +} + +double fmod(double x, double y) { + if (y == 0.0) return 0.0; + INT64 quotient = (INT64)(x / y); + return x - quotient * y; +} + +// Newton-Raphson square root implementation +double sqrt(double x) { + if (x < 0.0) return 0.0; // Return 0 for negative (should be NaN) + if (x == 0.0) return 0.0; + + double guess = x; + double epsilon = 0.00001; + + // Newton-Raphson: x_new = (x_old + n/x_old) / 2 + for (int i = 0; i < 50; i++) { + double next = (guess + x / guess) / 2.0; + if (fabs(next - guess) < epsilon) break; + guess = next; + } + + return guess; +} + +// Power function using binary exponentiation for integer exponents +double pow(double base, double exponent) { + // Handle special cases + if (exponent == 0.0) return 1.0; + if (base == 0.0) return 0.0; + if (base == 1.0) return 1.0; + if (exponent == 1.0) return base; + + // Check if exponent is an integer + INT64 exp_int = (INT64)exponent; + if ((double)exp_int == exponent) { + // Integer exponent - use binary exponentiation + double result = 1.0; + double current = base; + UINT64 n = (exp_int < 0) ? -exp_int : exp_int; + + while (n > 0) { + if (n & 1) result *= current; + current *= current; + n >>= 1; + } + + return (exp_int < 0) ? (1.0 / result) : result; + } + + // For non-integer exponents, return 0 (would need exp/log) + return 0.0; +} + +// Trigonometric functions - stubs (not needed for bitwise ops) +double sin(double x) { return 0.0; } +double cos(double x) { return 0.0; } +double tan(double x) { return 0.0; } +double asin(double x) { return 0.0; } +double acos(double x) { return 0.0; } +double atan(double x) { return 0.0; } +double atan2(double y, double x) { return 0.0; } +double exp(double x) { return 0.0; } +double log(double x) { return 0.0; } +double log10(double x) { return 0.0; } +double cbrt(double x) { return 0.0; } +double log2(double x) { return 0.0; } // Other void abort(void) { @@ -310,9 +386,6 @@ 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? diff --git a/core/src/main.c b/core/src/main.c index 12750ef..9c011b2 100644 --- a/core/src/main.c +++ b/core/src/main.c @@ -1,5 +1,8 @@ #include "main.h" #include "efi.h" +#include "efi.h" +#include +#include #include "duktape.h" #include "embedded_js.h" @@ -35,6 +38,63 @@ duk_ret_t native_systable_conout_set_attribute(duk_context *ctx) { return 0; } + +duk_ret_t native_systable_io_dword_in(duk_context *ctx) { + EFI_CPU_IO2_PROTOCOL* cpuIo; + EFI_GUID cpuIoGuid = EFI_CPU_IO2_PROTOCOL_GUID; + systemTable->BootServices->LocateProtocol(&cpuIoGuid, NULL, (void**)&cpuIo); + + UINT32 data; + cpuIo->Io.Read(cpuIo, EfiCpuIoWidthUint32, duk_to_uint(ctx, 0), 1, &data); + duk_push_uint(ctx, data); + return 1; +} + +duk_ret_t native_systable_io_dword_out(duk_context *ctx) { + EFI_CPU_IO2_PROTOCOL* cpuIo; + EFI_GUID cpuIoGuid = EFI_CPU_IO2_PROTOCOL_GUID; + systemTable->BootServices->LocateProtocol(&cpuIoGuid, NULL, (void**)&cpuIo); + + UINT32 data = duk_to_uint(ctx, 1); + cpuIo->Io.Write(cpuIo, EfiCpuIoWidthUint32, duk_to_uint(ctx, 0), 1, &data); + return 0; +} + +duk_ret_t native_systable_pci_read_config(duk_context *ctx) { + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL* pci; + EFI_GUID pciGuid = EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID; + systemTable->BootServices->LocateProtocol(&pciGuid, NULL, (void**)&pci); + + UINT64 bus = duk_to_uint(ctx, 0); + UINT64 device = duk_to_uint(ctx, 1); + UINT64 func = duk_to_uint(ctx, 2); + UINT64 offset = duk_to_uint(ctx, 3); + UINT64 address = (bus << 24) | (device << 16) | (func << 8) | (offset & 0xff); + UINT32 data = 0; + + pci->Pci.Read(pci, EfiPciWidthUint32, address, 1, &data); + + duk_push_uint(ctx, data); + return 1; +} + +duk_ret_t native_systable_pci_write_config(duk_context *ctx) { + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL* pci; + EFI_GUID pciGuid = EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID; + systemTable->BootServices->LocateProtocol(&pciGuid, NULL, (void**)&pci); + + UINT64 bus = duk_to_uint(ctx, 0); + UINT64 device = duk_to_uint(ctx, 1); + UINT64 func = duk_to_uint(ctx, 2); + UINT64 offset = duk_to_uint(ctx, 3); + UINT64 address = (bus << 24) | (device << 16) | (func << 8) | (offset & 0xff); + UINT32 data = duk_to_uint(ctx, 4); + + pci->Pci.Write(pci, EfiPciWidthUint32, address, 1, &data); + + return 0; +} + int kernel_main(EFI_SYSTEM_TABLE *st) { systemTable = st; ctx = duk_create_heap_default(); @@ -48,12 +108,27 @@ int kernel_main(EFI_SYSTEM_TABLE *st) { duk_push_c_function(ctx, native_systable_conout_set_attribute, 1); duk_put_global_string(ctx, "$___native_systable_conout_setAttribute"); + duk_push_c_function(ctx, native_systable_io_dword_in, 1); + duk_put_global_string(ctx, "$___native_systable_io_dword_in"); + + duk_push_c_function(ctx, native_systable_io_dword_out, 2); + duk_put_global_string(ctx, "$___native_systable_io_dword_out"); + + duk_push_c_function(ctx, native_systable_pci_read_config, 4); + duk_put_global_string(ctx, "$___native_systable_pci_read_config"); + + duk_push_c_function(ctx, native_systable_pci_write_config, 5); + duk_put_global_string(ctx, "$___native_systable_pci_write_config"); + + + duk_push_string(ctx, EMBEDDED_JS); 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); @@ -61,6 +136,8 @@ int kernel_main(EFI_SYSTEM_TABLE *st) { duk_pop(ctx); + systemTable->ConOut->OutputString(systemTable->ConOut, L"!!! KERNEL EXITED UNEXPECTEDLY !!!\r\n"); + halt(); return 0; diff --git a/os/src/kernel/drivers/dev/pci.kdriver.ts b/os/src/kernel/drivers/dev/pci.kdriver.ts new file mode 100644 index 0000000..94bda4e --- /dev/null +++ b/os/src/kernel/drivers/dev/pci.kdriver.ts @@ -0,0 +1,113 @@ +import { Logger } from "../../../libs/logger"; + +export function kdriver_dev_pci_init() {} + +export function kdriver_dev_pci_detectDevices() { + Logger.log("[PCI] Scanning..."); + + for (let bus = 0; bus < 256; bus++) { + for (let device = 0; device < 32; device++) { + kdriver_dev_pci_checkDevice(bus, device, 0); + + const headerType = kdriver_dev_pci_getHeaderType(bus, device, 0); + if ((headerType & 0x80) !== 0) { + for (let func = 1; func < 8; func++) { + kdriver_dev_pci_checkDevice(bus, device, func); + } + } + } + } +} + +export function kdriver_dev_pci_checkDevice( + bus: number, + device: number, + func: number +) { + const data = kdriver_dev_pci_readConfigDword(bus, device, func, 0); + + if (data === 0 || data === -1) return; + + const vendorId = data & 0xffff; + const deviceId = data >>> 16; + + if (vendorId === 0 || vendorId === 0xffff) return; + + const classCode = kdriver_dev_pci_getClassCode(bus, device, func); + const subclass = kdriver_dev_pci_getSubclass(bus, device, func); + + const filename = bus + ":" + device + ":" + func; + + Logger.log( + "[PCI] Found device pci:" + + filename + + " (vendor:" + + vendorId.toString(16) + + ", device:" + + deviceId.toString(16) + + ", class:" + + classCode.toString(16) + + ", subclass:" + + subclass.toString(16) + + ")" + ); +} + +export function kdriver_dev_pci_getDeviceId( + bus: number, + device: number, + func: number +) { + const data = kdriver_dev_pci_readConfigDword(bus, device, func, 0); + + return data >>> 16; +} + +export function kdriver_dev_pci_getVendorId( + bus: number, + device: number, + func: number +) { + const data = kdriver_dev_pci_readConfigDword(bus, device, func, 0); + + return data & 0xffff; +} + +export function kdriver_dev_pci_getClassCode( + bus: number, + device: number, + func: number +) { + const data = kdriver_dev_pci_readConfigDword(bus, device, func, 8); + + return (data >> 24) & 0xff; +} + +export function kdriver_dev_pci_getSubclass( + bus: number, + device: number, + func: number +) { + const data = kdriver_dev_pci_readConfigDword(bus, device, func, 8); + + return (data >> 16) & 0xff; +} + +export function kdriver_dev_pci_getHeaderType( + bus: number, + device: number, + func: number +) { + const data = kdriver_dev_pci_readConfigDword(bus, device, func, 12); + + return (data >> 16) & 0xff; +} + +export function kdriver_dev_pci_readConfigDword( + bus: number, + device: number, + func: number, + offset: number +) { + return $___native_systable_pci_read_config(bus, device, func, offset); +} diff --git a/os/src/kernel/index.ts b/os/src/kernel/index.ts index 1a9d1d9..ad0fe79 100644 --- a/os/src/kernel/index.ts +++ b/os/src/kernel/index.ts @@ -1,13 +1,19 @@ import { Logger } from "../libs/logger"; +import { kdriver_dev_pci_detectDevices } from "./drivers/dev/pci.kdriver"; import { kmod_console_clearScreen, kmod_console_outputString, } from "./modules/console/console.kmod"; +import { kmod_drivers_init } from "./modules/drivers.kmod"; export function kmain() { kmod_console_clearScreen(); Logger.log("[Kernel] Starting kernel..."); + kmod_drivers_init(); + + kdriver_dev_pci_detectDevices(); + return 0; } diff --git a/os/src/kernel/modules/drivers.kmod.ts b/os/src/kernel/modules/drivers.kmod.ts new file mode 100644 index 0000000..8520465 --- /dev/null +++ b/os/src/kernel/modules/drivers.kmod.ts @@ -0,0 +1,12 @@ +import { Logger } from "../../libs/logger"; +import { kdriver_dev_pci_init } from "../drivers/dev/pci.kdriver"; + +const drivers = [kdriver_dev_pci_init]; + +export function kmod_drivers_init() { + Logger.log("[Kernel] Initializing drivers..."); + + for (let i = 0; i < drivers.length; i++) { + drivers[i]!(); + } +} diff --git a/os/src/libs/io.ts b/os/src/libs/io.ts new file mode 100644 index 0000000..033c140 --- /dev/null +++ b/os/src/libs/io.ts @@ -0,0 +1,7 @@ +export function dwordin(port: number): number { + return $___native_systable_io_dwordin(port); +} + +export function dwordout(port: number, value: number) { + $___native_systable_io_dwordout(port, value); +} diff --git a/os/src/types/global_c_bindings.d.ts b/os/src/types/global_c_bindings.d.ts index 3b6abd8..94a3de2 100644 --- a/os/src/types/global_c_bindings.d.ts +++ b/os/src/types/global_c_bindings.d.ts @@ -3,3 +3,24 @@ declare function $___native_systable_conout_clearScreen(): void; declare function $___native_systable_conout_setAttribute( attribute: number ): void; + +declare function $___native_systable_io_dwordin(port: number): number; +declare function $___native_systable_io_dwordout( + port: number, + value: number +): void; + +declare function $___native_systable_pci_read_config( + bus: number, + device: number, + func: number, + offset: number +): number; + +declare function $___native_systable_pci_write_config( + bus: number, + device: number, + func: number, + offset: number, + value: number +): void; diff --git a/scripts/process_js.js b/scripts/process_js.js index e059c45..039ddbb 100755 --- a/scripts/process_js.js +++ b/scripts/process_js.js @@ -3,8 +3,8 @@ const fs = require("fs"); const script = fs.readFileSync("out/os/index.js", "utf-8"); const processed = script - /*.replaceAll("let ", "var ") - .replaceAll("const ", "var ")*/ + .replaceAll("let ", "var ") + .replaceAll("const ", "var ") .replaceAll("\n`", "\\n`") .replaceAll("`", "'"); diff --git a/scripts/run.sh b/scripts/run.sh new file mode 100755 index 0000000..221398e --- /dev/null +++ b/scripts/run.sh @@ -0,0 +1,4 @@ +./scripts/build_ts.sh +./scripts/build_c.sh +./scripts/out_to_iso.sh +./scripts/run_vbox.sh \ No newline at end of file