Files
nt-lite/code/kernel/io_ddk.c
T

136 lines
4.3 KiB
C

// Kernel DDK-table provider implementation.
#include <stdint.h>
#include <ntlite/ddk/ddk.h>
#include <kernel/hal/hal_api.h>
#include <kernel/io_ddk.h>
#include <kernel/io_dma.h>
#include <kernel/ke_audio.h>
#include <kernel/ke_debug.h>
#include <kernel/ke_irq.h>
#include <kernel/ke_sched.h>
#include <kernel/mm_pte.h>
static const HAL_API* gIoDdkHal;
static uintptr_t gIoDdkPhysicalWindowBase;
// Returns the kernel direct-map alias for a physical address.
static void* IoDdkPhysToVirt(uint64_t physicalAddress) {
if (!gIoDdkPhysicalWindowBase || physicalAddress > UINTPTR_MAX - gIoDdkPhysicalWindowBase)
return (void*)0;
return (void*)(gIoDdkPhysicalWindowBase + (uintptr_t)physicalAddress);
}
// Maps one kernel page through the DDK memory surface.
static KSTATUS IoDdkMapPage(uintptr_t virtualAddress,
uint64_t physicalAddress,
uint64_t pageFlags,
NTL_DDK_MAP_MODE mode) {
MM_PTE_MAP_MODE kernelMode = MmPteMapFailIfPresent;
if (mode == NtlDdkMapReplaceExisting)
kernelMode = MmPteMapReplaceExisting;
return MmPteMapPage(virtualAddress, physicalAddress, pageFlags, kernelMode);
}
// Reads one aligned PCI configuration DWORD through the platform HAL.
static uint32_t IoDdkPciRead32(uint16_t segment,
uint8_t bus,
uint8_t device,
uint8_t function,
uint16_t offset) {
if (!gIoDdkHal || !gIoDdkHal->Pci.Read32)
return 0xFFFFFFFFu;
return gIoDdkHal->Pci.Read32(segment, bus, device, function, offset);
}
// Writes one aligned PCI configuration DWORD through the platform HAL.
static void IoDdkPciWrite32(uint16_t segment,
uint8_t bus,
uint8_t device,
uint8_t function,
uint16_t offset,
uint32_t value) {
if (!gIoDdkHal || !gIoDdkHal->Pci.Write32)
return;
gIoDdkHal->Pci.Write32(segment, bus, device, function, offset, value);
}
// Allocates one kernel IRQ slot for MSI delivery.
static KSTATUS IoDdkAllocateMsiVector(uint8_t* outIrq) {
return KeIrqAllocateMsiVector(outIrq);
}
// Composes one platform MSI message for an allocated nt-lite IRQ slot.
static KSTATUS IoDdkComposeMsiMessage(uint8_t irq, NTL_DDK_MSI_MESSAGE* messageOut) {
if (!gIoDdkHal || !messageOut || irq >= 24u)
return NTLSTATUS_INVALID_PARAMETER;
HAL_MSI_MESSAGE message;
KSTATUS status = gIoDdkHal->InterruptController.ComposeMsi((uint8_t)(0x20u + irq), &message);
if (!KSUCCESS(status))
return status;
messageOut->Address = message.Address;
messageOut->Data = message.Data;
messageOut->Reserved = 0;
return NTLSTATUS_SUCCESS;
}
static const NTL_DDK_DEBUG gIoDdkDebug = {
.Print = DbgPrint,
.GetFlags = KeGetDebugFlags,
};
static const NTL_DDK_INTERRUPT gIoDdkInterrupt = {
.AllocateMsiVector = IoDdkAllocateMsiVector,
.ComposeMsiMessage = IoDdkComposeMsiMessage,
};
static const NTL_DDK_MEMORY gIoDdkMemory = {
.PhysToVirt = IoDdkPhysToVirt,
.MapPage = IoDdkMapPage,
};
static const NTL_DDK_PLATFORM gIoDdkPlatform = {
.PciRead32 = IoDdkPciRead32,
.PciWrite32 = IoDdkPciWrite32,
};
static const NTL_DDK_SCHEDULER gIoDdkScheduler = {
.DelayThread = KeDelayThread,
.Yield = KeYield,
};
static NTL_DDK_TIMER gIoDdkTimer = {
.QueryTicks = 0,
.Stall = 0,
};
static NTL_DDK gIoDdk = {
.Version = NTL_DDK_VERSION,
.Debug = &gIoDdkDebug,
.Audio = (const NTL_DDK_AUDIO*)0,
.Dma = (const NTL_DDK_DMA*)0,
.Interrupt = &gIoDdkInterrupt,
.Memory = &gIoDdkMemory,
.Platform = &gIoDdkPlatform,
.Scheduler = &gIoDdkScheduler,
.Timer = &gIoDdkTimer,
};
// Initializes the kernel-owned DDK table from platform services.
void IoInitializeDdk(const HAL_API* hal, uintptr_t physicalWindowBase) {
gIoDdkHal = hal;
gIoDdkPhysicalWindowBase = physicalWindowBase;
gIoDdk.Audio = KeAudioGetDdk();
gIoDdk.Dma = IoGetDmaDdk();
gIoDdkTimer.QueryTicks = hal ? hal->Timer.QueryTicks : 0;
gIoDdkTimer.Stall = hal ? hal->Timer.Stall : 0;
}
// Returns the kernel-owned DDK table passed to driver entrypoints.
const NTL_DDK* IoGetDdk(void) {
return &gIoDdk;
}