Add PCI driver

This commit is contained in:
2025-12-03 21:17:23 +01:00
parent e4b18fc8d7
commit 7defc557b2
9 changed files with 289 additions and 8 deletions

View File

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

View File

@@ -99,6 +99,28 @@ JSValue jsKCClearScreen(JSContext *ctx, JSValueConst jsThis, int argc, JSValueCo
return JS_UNDEFINED;
}
JSValue jsKCPCIReadDword(JSContext *ctx, JSValueConst jsThis, int argc, JSValueConst *argv) {
if (argc < 1) return JS_ThrowSyntaxError(ctx, "Missing argument");
uint32_t addr_u32;
JS_ToUint32(ctx, &addr_u32, argv[0]);
UINT64 addr = (UINT64)addr_u32; // Ensure type matches EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_RW's Address parameter
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL* pci;
EFI_GUID pciGuid = EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID;
EFI_STATUS status = gST->BootServices->LocateProtocol(&pciGuid, NULL, (void**)&pci);
if (EFI_ERROR(status)) {
return JS_ThrowInternalError(ctx, "Failed to locate PCI Root Bridge IO Protocol: %d", status);
}
UINT32 data = 0;
status = pci->Pci.Read(pci, EfiPciWidthUint32, addr, 1, &data);
return JS_NewUint32(ctx, data);
}
void initKC(JSContext *ctx) {
JSValue global = JS_GetGlobalObject(ctx);
JSValue kc = JS_NewObject(ctx);
@@ -107,6 +129,7 @@ void initKC(JSContext *ctx) {
JS_SetPropertyStr(ctx, kc, "println", JS_NewCFunction(ctx, jsKCPrintln, "println", 1));
JS_SetPropertyStr(ctx, kc, "clearScreen", JS_NewCFunction(ctx, jsKCClearScreen, "clearScreen", 0));
JS_SetPropertyStr(ctx, kc, "pciReadDword", JS_NewCFunction(ctx, jsKCPCIReadDword, "pciReadDword", 1));
JS_FreeValue(ctx, global);
}

View File

@@ -0,0 +1,82 @@
import { Logger } from "../../../lib/logger";
import { numtohex } from "../../../util/hex";
import { SysFS } from "../../filesystem/sys.fs";
import { KernelDriver } from "../kdriver";
export class PCIKDriver extends KernelDriver {
static instance: PCIKDriver = new this();
constructor() {
super("pci");
}
static init() {
PCIKDriver.instance.init();
}
override init() {
super.init();
SysFS.instance.pMkdir("/pci");
this.#detectDevices();
}
#detectDevices() {
Logger.log("[PCI] Scanning...");
for (let bus = 0; bus < 256; bus++) {
for (let device = 0; device < 32; device++) {
this.#checkDevice(bus, device, 0);
}
}
}
#checkDevice(bus: number, device: number, func: number) {
const data = this.#readConfig(bus, device, func, 0);
if (data === 0 || data === 0xffffffff) return;
const vendorId = this.#getDeviceVendorId(bus, device, func);
const deviceId = this.#getDeviceId(bus, device, func);
const classId = this.#getDeviceClass(bus, device, func);
const subclassId = this.#getDeviceSubclass(bus, device, func);
const filename = `pci.${bus}.${device}.${func}`;
Logger.log(
`[PCI] Found device: ${filename} (vendor: ${numtohex(
vendorId
)}, device: ${numtohex(deviceId)}, class: ${numtohex(
classId
)}, subclass: ${numtohex(subclassId)})`
);
SysFS.instance.pMkdir(`/pci/${filename}`);
SysFS.instance.pWriteFile(`/pci/${filename}/vendor`, numtohex(vendorId));
SysFS.instance.pWriteFile(`/pci/${filename}/device`, numtohex(deviceId));
SysFS.instance.pWriteFile(`/pci/${filename}/class`, numtohex(classId));
SysFS.instance.pWriteFile(
`/pci/${filename}/subclass`,
numtohex(subclassId)
);
}
#getDeviceId(bus: number, device: number, func: number) {
return this.#readConfig(bus, device, func, 0) >>> 16;
}
#getDeviceVendorId(bus: number, device: number, func: number) {
return this.#readConfig(bus, device, func, 0) & 0xffff;
}
#getDeviceClass(bus: number, device: number, func: number) {
return (this.#readConfig(bus, device, func, 8) >> 24) & 0xff;
}
#getDeviceSubclass(bus: number, device: number, func: number) {
return (this.#readConfig(bus, device, func, 8) >> 16) & 0xff;
}
#readConfig(bus: number, device: number, func: number, offset: number) {
return kc.pciReadDword((bus << 16) | (device << 11) | (func << 8) | offset);
}
}

View File

@@ -0,0 +1,20 @@
import { Logger } from "../../lib/logger";
export class KernelDriver {
#name: string;
#initialized: boolean = false;
constructor(name: string) {
this.#name = name;
}
init() {
Logger.log(`[Kernel] Initializing ${this.#name} driver...`);
this.#initialized = true;
}
get initialized() {
return this.#initialized;
}
}

View File

@@ -1,6 +1,7 @@
import { Logger } from "../lib/logger";
import { SysFS } from "./filesystem/sys.fs";
import { ConsoleKModule } from "./modules/console/console.kmod";
import { DriverKModule } from "./modules/driver";
import { VFSKModule } from "./modules/vfs/vfs.kmod";
export function KMain() {
@@ -8,11 +9,9 @@ export function KMain() {
Logger.log("[Kernel] Initializing kernel...");
ConsoleKModule.init();
VFSKModule.init();
VFSKModule.instance.mount(SysFS.instance, "/sys");
SysFS.instance.pMkdir("/pci");
SysFS.instance.pWriteFile("/pci/test", "test");
Logger.log(SysFS.instance.readFile("/pci/test"));
DriverKModule.init();
}

View File

@@ -0,0 +1,25 @@
import { PCIKDriver } from "../drivers/dev/pci.drv";
import type { KernelDriver } from "../drivers/kdriver";
import { KernelModule } from "./kmod";
export const DRIVERS: KernelDriver[] = [PCIKDriver.instance];
export class DriverKModule extends KernelModule {
static instance: DriverKModule = new this();
constructor() {
super("driver");
}
static init() {
DriverKModule.instance.init();
}
override init() {
super.init();
for (const driver of DRIVERS) {
driver.init();
}
}
}

View File

@@ -18,7 +18,7 @@ export class VFSKModule extends KernelModule {
mount(fs: FileSystem, mountPoint: string) {
if (!this.initialized) return;
Logger.log(`Mounting ${fs.id} at ${mountPoint}`);
Logger.log(`[VFS] Mounting ${fs.id} at ${mountPoint}`);
this.#mounts.set(mountPoint, fs);
}

View File

@@ -1,4 +1,5 @@
declare namespace kc {
function println(msg: string): void;
function clearScreen(): void;
function pciReadDword(addr: number): number;
}

View File

@@ -0,0 +1,3 @@
export function numtohex(num: number) {
return num.toString(16);
}