replace nob with ms' build, move disk creation to build.bat, major comment cleanup, remove old and stupid tests, overhaul interrupt management with per-CPU vector allocation, affinity migration and safe teardown, add proper IOAPIC routing and PCI MSI/MSI-X/INTx support, migrate drivers to the new interrupt API, integrate ACPICA with a proper OS services layer, move ACPI firmware events, power button handling and S5 shutdown into acpi.sys, add parallel driver startup and atomic publication, replace PnP arrays with dynamic lists, redesign service startup again to be asynchronous, add delayed startup mode for services, allow omitting keys in services.ini, fix acpi ec deferred work handling, fix kernel threads having garbage exit code.

This commit is contained in:
maksw committed 2026-10-28 15:18:43 +01:00
1 parent d36f19509c
commit 36eef8f58d
696 files changed
+147281 -7530

No files matched your search

+1
View File
@@ -0,0 +1 @@
!include $(BASEDIR)\makefile.def
+297 -78
View File
@@ -26,13 +26,12 @@ static uint32_t gPciDeviceCount;
#define PCI_MMIO_VA_LIMIT 0xFFFF980000000000ULL
static uintptr_t gPciMmioNext = PCI_MMIO_VA_BASE;
static SPINLOCK gPciMmioLock = SPINLOCK_INIT;
// Implements the align Up64 operation.
static uint64_t PciAlignUp64(uint64_t value, uint64_t alignment) {
return (value + alignment - 1u) & ~(alignment - 1u);
}
// Implements the default Mmio Flags operation.
static uint64_t PciDefaultMmioFlags(void) {
return NTL_DDK_PAGE_PRESENT | NTL_DDK_PAGE_WRITE | NTL_DDK_PAGE_CACHE_UC | NTL_DDK_PAGE_NX;
}
@@ -43,13 +42,15 @@ static KSTATUS PciAllocateMmioVa(uint64_t length, uintptr_t* outVa) {
return NTLSTATUS_INVALID_PARAMETER;
uint64_t alignedLength = PciAlignUp64(length, NTL_DDK_PAGE_SIZE);
uintptr_t cookie = KeAcquireSpinlock(&gPciMmioLock);
uintptr_t va = (uintptr_t)PciAlignUp64((uint64_t)gPciMmioNext, NTL_DDK_PAGE_SIZE);
if (va < PCI_MMIO_VA_BASE || va >= PCI_MMIO_VA_LIMIT)
if (va < PCI_MMIO_VA_BASE || va >= PCI_MMIO_VA_LIMIT ||
alignedLength > (uint64_t)(PCI_MMIO_VA_LIMIT - va)) {
KeReleaseSpinlock(&gPciMmioLock, cookie);
return NTLSTATUS_NO_MEMORY;
if (alignedLength > (uint64_t)(PCI_MMIO_VA_LIMIT - va))
return NTLSTATUS_NO_MEMORY;
}
gPciMmioNext = va + (uintptr_t)alignedLength;
KeReleaseSpinlock(&gPciMmioLock, cookie);
*outVa = va;
return NTLSTATUS_SUCCESS;
}
@@ -64,31 +65,26 @@ static bool PciIsPdo(DEVICE_OBJECT* pdo, PCI_PDO_EXTENSION** outExt) {
return true;
}
// Implements the raw Read32 operation.
static uint32_t PciRawRead32(uint8_t bus, uint8_t dev, uint8_t fn, uint16_t offset) {
if (offset > 0xFCu) return 0xFFFFFFFFu;
return KePciReadConfig32(0, bus, dev, fn, offset & 0xFCu);
}
// Implements the raw Write32 operation.
static void PciRawWrite32(uint8_t bus, uint8_t dev, uint8_t fn, uint16_t offset, uint32_t value) {
if (offset > 0xFCu) return;
KePciWriteConfig32(0, bus, dev, fn, offset & 0xFCu, value);
}
// Implements the raw Read8 operation.
static uint8_t PciRawRead8(uint8_t bus, uint8_t dev, uint8_t fn, uint16_t offset) {
uint32_t v = PciRawRead32(bus, dev, fn, offset);
return (uint8_t)(v >> ((offset & 3u) * 8u));
}
// Implements the raw Read16 operation.
static uint16_t PciRawRead16(uint8_t bus, uint8_t dev, uint8_t fn, uint16_t offset) {
uint32_t v = PciRawRead32(bus, dev, fn, offset);
return (uint16_t)(v >> ((offset & 2u) * 8u));
}
// Implements the raw Write8 operation.
static void PciRawWrite8(uint8_t bus, uint8_t dev, uint8_t fn, uint16_t offset, uint8_t value) {
uint16_t aligned = offset & ~3u;
uint32_t shift = (offset & 3u) * 8u;
@@ -98,7 +94,6 @@ static void PciRawWrite8(uint8_t bus, uint8_t dev, uint8_t fn, uint16_t offset,
PciRawWrite32(bus, dev, fn, aligned, old);
}
// Implements the raw Write16 operation.
static void PciRawWrite16(uint8_t bus, uint8_t dev, uint8_t fn, uint16_t offset, uint16_t value) {
uint16_t aligned = offset & ~3u;
uint32_t shift = (offset & 2u) * 8u;
@@ -108,7 +103,6 @@ static void PciRawWrite16(uint8_t bus, uint8_t dev, uint8_t fn, uint16_t offset,
PciRawWrite32(bus, dev, fn, aligned, old);
}
// Implements the bar Size From Mask operation.
static uint64_t PciBarSizeFromMask(uint64_t mask, uint64_t baseMask) {
uint64_t sizeMask = mask & baseMask;
if (!sizeMask || sizeMask == baseMask)
@@ -116,7 +110,6 @@ static uint64_t PciBarSizeFromMask(uint64_t mask, uint64_t baseMask) {
return (~sizeMask + 1u) & baseMask;
}
// Implements the header Bar Count operation.
static uint8_t PciHeaderBarCount(uint8_t headerType) {
switch (headerType & PCI_HEADER_TYPE_MASK) {
case 0x00: return 6;
@@ -126,7 +119,6 @@ static uint8_t PciHeaderBarCount(uint8_t headerType) {
}
}
// Implements the decode Bars operation.
static void PciDecodeBars(PCI_PDO_EXTENSION* ext) {
uint8_t barCount = PciHeaderBarCount(ext->Info.HeaderType);
for (uint8_t i = 0; i < PCI_MAX_BARS; i++) {
@@ -398,7 +390,6 @@ static KSTATUS PciCreatePdo(uint8_t bus, uint8_t dev, uint8_t fn) {
return NTLSTATUS_SUCCESS;
}
// Implements the enumerate Bus operation.
static void PciEnumerateBus(void) {
for (uint32_t bus = 0; bus < 256u; bus++) {
for (uint32_t dev = 0; dev < 32u; dev++) {
@@ -440,7 +431,6 @@ static KSTATUS PciDispatchPnp(DEVICE_OBJECT* device, IRP* irp) {
}
}
// Implements the driver Abi Version operation.
__declspec(dllexport) uint32_t PciDriverAbiVersion(void) {
return 1u;
}
@@ -601,77 +591,306 @@ static uint8_t PciFindCapability(PCI_PDO_EXTENSION* ext, uint8_t capId) {
return offset;
}
// Enables msi.
__declspec(dllexport) KSTATUS PciEnableMsi(DEVICE_OBJECT* pdo, uint8_t irqSlot) {
// PCI owns message programming, while the kernel owns CPU/vector placement.
typedef struct PCI_MESSAGE_CONTEXT {
DEVICE_OBJECT* Pdo;
uint32_t TableOffset;
uint16_t Capability;
uint8_t Msix;
uint8_t Reserved;
} PCI_MESSAGE_CONTEXT;
static KSTATUS PciUpdateMessageRoute(void* opaque,
KE_INTERRUPT_MESSAGE_OPERATION operation, const NTL_DDK_MSI_MESSAGE* message) {
PCI_MESSAGE_CONTEXT* ctx = (PCI_MESSAGE_CONTEXT*)opaque;
PCI_PDO_EXTENSION* ext;
if (!PciIsPdo(pdo, &ext))
return NTLSTATUS_INVALID_PARAMETER;
if (irqSlot >= 24u)
return NTLSTATUS_INVALID_PARAMETER;
uint8_t cap = PciFindCapability(ext, PCI_CAP_ID_MSI);
if (!cap)
return NTLSTATUS_NOT_SUPPORTED;
uint8_t bus = ext->Info.Address.Bus;
uint8_t dev = ext->Info.Address.Device;
if (!ctx || !PciIsPdo(ctx->Pdo, &ext)) return NTLSTATUS_INVALID_PARAMETER;
uint8_t bus = ext->Info.Address.Bus, dev = ext->Info.Address.Device;
uint8_t fn = ext->Info.Address.Function;
uint16_t control = PciRawRead16(bus, dev, fn, (uint16_t)(cap + 2u));
bool is64 = (control & PCI_MSI_CTRL_64BIT) != 0;
bool pvm = (control & PCI_MSI_CTRL_PVM) != 0;
NTL_DDK_MSI_MESSAGE message;
KSTATUS messageStatus = KeIrqComposeMsiMessage(irqSlot, &message);
if (!KSUCCESS(messageStatus))
return messageStatus;
PciRawWrite32(bus, dev, fn, (uint16_t)(cap + 4u), (uint32_t)message.Address);
if (is64) {
PciRawWrite32(bus, dev, fn, (uint16_t)(cap + 8u), (uint32_t)(message.Address >> 32));
PciRawWrite16(bus, dev, fn, (uint16_t)(cap + 12u), (uint16_t)message.Data);
if (pvm)
PciRawWrite32(bus, dev, fn, (uint16_t)(cap + 16u), 0);
} else {
PciRawWrite16(bus, dev, fn, (uint16_t)(cap + 8u), (uint16_t)message.Data);
if (pvm)
PciRawWrite32(bus, dev, fn, (uint16_t)(cap + 12u), 0);
if (ctx->Msix) {
if (!ext->MsixTable || ctx->TableOffset > ext->MsixMappedLength ||
ext->MsixMappedLength - ctx->TableOffset < 16u)
return NTLSTATUS_DEVICE_ERROR;
volatile uint32_t* entry = (volatile uint32_t*)(ext->MsixTable + ctx->TableOffset);
if (operation == KeInterruptMessageQuiesce) {
entry[3] = 1u;
} else if (operation == KeInterruptMessageProgram && message) {
entry[0] = (uint32_t)message->Address;
entry[1] = (uint32_t)(message->Address >> 32);
entry[2] = message->Data;
} else if (operation == KeInterruptMessageResume) {
entry[3] = 0u;
} else return NTLSTATUS_INVALID_PARAMETER;
(void)entry[3];
return NTLSTATUS_SUCCESS;
}
control &= (uint16_t)~PCI_MSI_CTRL_MME_MASK;
control |= PCI_MSI_CTRL_ENABLE;
PciRawWrite16(bus, dev, fn, (uint16_t)(cap + 2u), control);
uint16_t cmd = PciRawRead16(bus, dev, fn, PCI_REG_COMMAND_STATUS);
cmd |= PCI_COMMAND_INTX_DISABLE;
PciRawWrite16(bus, dev, fn, PCI_REG_COMMAND_STATUS, cmd);
DbgPrint("pci: MSI enabled %02x:%02x.%u cap=0x%02x vector=0x%02x irqslot=%u %s\n",
bus, dev, fn, cap, (unsigned)(message.Data & 0xFFu), irqSlot, is64 ? "64-bit" : "32-bit");
uint16_t control = PciRawRead16(bus, dev, fn, ctx->Capability + 2u);
bool is64 = (control & PCI_MSI_CTRL_64BIT) != 0;
// MSI per-vector masking preserves pending messages during retargeting.
// Devices without PVM retain their initial affinity until disconnect.
if (!(control & PCI_MSI_CTRL_PVM)) return NTLSTATUS_NOT_SUPPORTED;
uint16_t maskOffset = ctx->Capability + (is64 ? 16u : 12u);
if (operation == KeInterruptMessageQuiesce) {
uint32_t mask = PciRawRead32(bus, dev, fn, maskOffset);
PciRawWrite32(bus, dev, fn, maskOffset, mask | 1u);
(void)PciRawRead32(bus, dev, fn, maskOffset);
} else if (operation == KeInterruptMessageProgram && message) {
PciRawWrite32(bus, dev, fn, ctx->Capability + 4u, (uint32_t)message->Address);
if (is64) {
PciRawWrite32(bus, dev, fn, ctx->Capability + 8u,
(uint32_t)(message->Address >> 32));
PciRawWrite16(bus, dev, fn, ctx->Capability + 12u, (uint16_t)message->Data);
} else PciRawWrite16(bus, dev, fn, ctx->Capability + 8u, (uint16_t)message->Data);
} else if (operation == KeInterruptMessageResume) {
uint32_t mask = PciRawRead32(bus, dev, fn, maskOffset);
PciRawWrite32(bus, dev, fn, maskOffset, mask & ~1u);
(void)PciRawRead32(bus, dev, fn, maskOffset);
} else return NTLSTATUS_INVALID_PARAMETER;
(void)PciRawRead16(bus, dev, fn, ctx->Capability + 2u);
return NTLSTATUS_SUCCESS;
}
// Enables a single MSI vector, allocating the nt-lite IRQ slot internally.
__declspec(dllexport) KSTATUS PciEnableMsiAuto(DEVICE_OBJECT* pdo, uint8_t* outIrqSlot) {
PCI_PDO_EXTENSION* ext;
if (!outIrqSlot || !PciIsPdo(pdo, &ext))
return NTLSTATUS_INVALID_PARAMETER;
if (!PciFindCapability(ext, PCI_CAP_ID_MSI))
return NTLSTATUS_NOT_SUPPORTED;
uint8_t irq = 0xFFu;
KSTATUS st = KeIrqAllocateMsiVector(&irq);
if (!KSUCCESS(st))
static KSTATUS PciBindMessage(DEVICE_OBJECT* pdo, PCI_INTERRUPT_REQUEST* request,
uint8_t msix, uint16_t capability, uint32_t tableOffset) {
PCI_MESSAGE_CONTEXT* ctx = (PCI_MESSAGE_CONTEXT*)MmAllocatePool(sizeof(*ctx));
if (!ctx) return NTLSTATUS_NO_MEMORY;
ctx->Pdo = pdo;
ctx->Msix = msix;
ctx->Capability = capability;
ctx->TableOffset = tableOffset;
ctx->Reserved = 0;
KSTATUS st = KeInterruptBindMessageSource(request->Interrupt, PciUpdateMessageRoute, ctx);
if (!KSUCCESS(st)) {
MmFreePool(ctx);
return st;
st = PciEnableMsi(pdo, irq);
if (!KSUCCESS(st))
return st;
*outIrqSlot = irq;
}
request->BusContext = ctx;
return NTLSTATUS_SUCCESS;
}
// Programs a pre-allocated interrupt group. All routes exist before device delivery begins.
static KSTATUS PciConnectMsix(DEVICE_OBJECT* pdo, PCI_PDO_EXTENSION* ext,
PCI_INTERRUPT_REQUEST* requests, uint32_t count) {
uint8_t cap = PciFindCapability(ext, PCI_CAP_ID_MSIX);
if (!cap) return NTLSTATUS_NOT_SUPPORTED;
uint8_t bus = ext->Info.Address.Bus, dev = ext->Info.Address.Device;
uint8_t fn = ext->Info.Address.Function;
uint16_t control = PciRawRead16(bus, dev, fn, cap + 2u);
uint32_t size = (control & 0x7FFu) + 1u;
if (count > size) return NTLSTATUS_NOT_SUPPORTED;
uint32_t table = PciRawRead32(bus, dev, fn, cap + 4u);
uint32_t bir = table & 7u, offset = table & ~7u;
if (bir >= PCI_MAX_BARS) return NTLSTATUS_DEVICE_ERROR;
PCI_BAR bar;
KSTATUS st = PciGetBar(pdo, (uint8_t)bir, &bar);
if (!KSUCCESS(st) || (bar.Type != PciBarMemory32 && bar.Type != PciBarMemory64) ||
bar.Length < offset || count > (bar.Length - offset) / 16u)
return NTLSTATUS_NOT_SUPPORTED;
uint16_t command = PciRawRead16(bus, dev, fn, PCI_REG_COMMAND_STATUS);
if (!(command & PCI_COMMAND_MEMORY_SPACE)) {
DbgPrint("pci: MSI-X requires enabled memory decoding at %02x:%02x.%u\n",
bus, dev, fn);
return NTLSTATUS_DEVICE_ERROR;
}
if (!ext->MsixTable) {
volatile uint8_t* mapped = (volatile uint8_t*)0;
uint64_t mappedLength = 0;
st = PciMapBar(pdo, (uint8_t)bir,
NTL_DDK_PAGE_PRESENT | NTL_DDK_PAGE_WRITE | NTL_DDK_PAGE_CACHE_UC | NTL_DDK_PAGE_NX,
(void**)&mapped, &mappedLength);
if (!KSUCCESS(st)) return st;
ext->MsixTable = mapped;
ext->MsixMappedLength = mappedLength;
ext->MsixBarIndex = (uint8_t)bir;
}
// A persistent per-PDO mapping prevents repeated BAR allocations on reconnect.
if (ext->MsixBarIndex != bir || ext->MsixMappedLength < offset ||
count > (ext->MsixMappedLength - offset) / 16u)
return NTLSTATUS_DEVICE_ERROR;
volatile uint8_t* mapped = ext->MsixTable;
// Mask the function and turn off stale firmware MSI before programming MSI-X.
PciRawWrite16(bus, dev, fn, cap + 2u, (control | 0x4000u) & ~0x8000u);
uint8_t msiCap = PciFindCapability(ext, PCI_CAP_ID_MSI);
if (msiCap) {
uint16_t msiControl = PciRawRead16(bus, dev, fn, msiCap + 2u);
PciRawWrite16(bus, dev, fn, msiCap + 2u,
msiControl & (uint16_t)~PCI_MSI_CTRL_ENABLE);
}
for (uint32_t i = 0; i < count; i++) {
st = KeInterruptReserveMessage(requests[i].Affinity, requests[i].Routine,
requests[i].Context, &requests[i].Interrupt);
if (!KSUCCESS(st)) goto failed;
NTL_DDK_MSI_MESSAGE msg;
st = KeInterruptComposeMessage(requests[i].Interrupt, &msg);
if (!KSUCCESS(st)) goto failed;
st = PciBindMessage(pdo, &requests[i], 1u, cap, offset + 16u * i);
if (!KSUCCESS(st)) goto failed;
volatile uint32_t* entry = (volatile uint32_t*)(mapped + offset + 16u * i);
entry[3] = 1u;
entry[0] = (uint32_t)msg.Address;
entry[1] = (uint32_t)(msg.Address >> 32);
entry[2] = msg.Data;
entry[3] = 0u;
// Read back the entry to drain posted MMIO writes before enabling MSI-X.
(void)entry[3];
}
PciRawWrite16(bus, dev, fn, cap + 2u, (control | 0x8000u) & ~0x4000u);
(void)PciRawRead16(bus, dev, fn, cap + 2u);
PciRawWrite16(bus, dev, fn, PCI_REG_COMMAND_STATUS, command | PCI_COMMAND_INTX_DISABLE);
for (uint32_t i = 0; i < count; i++) {
st = KeInterruptActivateMessage(requests[i].Interrupt);
if (!KSUCCESS(st)) goto failed;
}
return NTLSTATUS_SUCCESS;
failed:
PciRawWrite16(bus, dev, fn, cap + 2u, control & ~0x8000u);
for (uint32_t i = 0; i < count; i++) {
if (requests[i].Interrupt) {
KeInterruptDisconnect(requests[i].Interrupt);
requests[i].Interrupt = (KE_INTERRUPT*)0;
}
if (requests[i].BusContext) {
MmFreePool(requests[i].BusContext);
requests[i].BusContext = 0;
}
}
return st;
}
static KSTATUS PciConnectMsi(DEVICE_OBJECT* pdo, PCI_PDO_EXTENSION* ext,
PCI_INTERRUPT_REQUEST* request) {
uint8_t cap = PciFindCapability(ext, PCI_CAP_ID_MSI);
if (!cap) return NTLSTATUS_NOT_SUPPORTED;
uint8_t bus = ext->Info.Address.Bus, dev = ext->Info.Address.Device;
uint8_t fn = ext->Info.Address.Function;
KSTATUS st = KeInterruptReserveMessage(request->Affinity, request->Routine,
request->Context, &request->Interrupt);
if (!KSUCCESS(st)) return st;
NTL_DDK_MSI_MESSAGE msg;
st = KeInterruptComposeMessage(request->Interrupt, &msg);
if (!KSUCCESS(st)) goto failed;
st = PciBindMessage(pdo, request, 0u, cap, 0);
if (!KSUCCESS(st)) goto failed;
uint8_t msixCap = PciFindCapability(ext, PCI_CAP_ID_MSIX);
if (msixCap) {
uint16_t msixControl = PciRawRead16(bus, dev, fn, msixCap + 2u);
PciRawWrite16(bus, dev, fn, msixCap + 2u,
(msixControl | 0x4000u) & (uint16_t)~0x8000u);
}
uint16_t control = PciRawRead16(bus, dev, fn, cap + 2u);
bool is64 = (control & PCI_MSI_CTRL_64BIT) != 0;
bool pvm = (control & PCI_MSI_CTRL_PVM) != 0;
PciRawWrite32(bus, dev, fn, cap + 4u, (uint32_t)msg.Address);
if (is64) {
PciRawWrite32(bus, dev, fn, cap + 8u, (uint32_t)(msg.Address >> 32));
PciRawWrite16(bus, dev, fn, cap + 12u, (uint16_t)msg.Data);
if (pvm) PciRawWrite32(bus, dev, fn, cap + 16u, 0);
} else {
PciRawWrite16(bus, dev, fn, cap + 8u, (uint16_t)msg.Data);
if (pvm) PciRawWrite32(bus, dev, fn, cap + 12u, 0);
}
control = (control & ~(uint16_t)PCI_MSI_CTRL_MME_MASK) | PCI_MSI_CTRL_ENABLE;
PciRawWrite16(bus, dev, fn, cap + 2u, control);
uint16_t command = PciRawRead16(bus, dev, fn, PCI_REG_COMMAND_STATUS);
PciRawWrite16(bus, dev, fn, PCI_REG_COMMAND_STATUS, command | PCI_COMMAND_INTX_DISABLE);
st = KeInterruptActivateMessage(request->Interrupt);
if (!KSUCCESS(st)) goto failed;
return NTLSTATUS_SUCCESS;
failed:
{
uint16_t previous = PciRawRead16(bus, dev, fn, cap + 2u);
PciRawWrite16(bus, dev, fn, cap + 2u,
previous & (uint16_t)~PCI_MSI_CTRL_ENABLE);
}
KeInterruptDisconnect(request->Interrupt);
request->Interrupt = (KE_INTERRUPT*)0;
if (request->BusContext) {
MmFreePool(request->BusContext);
request->BusContext = 0;
}
return st;
}
__declspec(dllexport) KSTATUS PciConnectInterrupts(DEVICE_OBJECT* pdo,
PCI_INTERRUPT_REQUEST* requests, uint32_t count, bool* usingMessages) {
PCI_PDO_EXTENSION* ext;
if (!PciIsPdo(pdo, &ext) || !requests || !count || !usingMessages)
return NTLSTATUS_INVALID_PARAMETER;
*usingMessages = false;
for (uint32_t i = 0; i < count; i++) {
if (!requests[i].Routine) return NTLSTATUS_INVALID_PARAMETER;
requests[i].Interrupt = (KE_INTERRUPT*)0;
requests[i].BusContext = 0;
}
KSTATUS st = PciConnectMsix(pdo, ext, requests, count);
if (KSUCCESS(st)) { *usingMessages = true; return st; }
if (count > 1u) return st;
st = PciConnectMsi(pdo, ext, requests);
if (KSUCCESS(st)) { *usingMessages = true; return st; }
uint8_t line = ext->Info.InterruptLine;
uint8_t pin = ext->Info.InterruptPin;
if (pin < 1u || pin > 4u || line == 0u || line == 0xFFu) {
DbgPrint("pci: INTx resource unavailable for %02x:%02x.%u pin=%u line=%u\n",
ext->Info.Address.Bus, ext->Info.Address.Device,
ext->Info.Address.Function, pin, line);
return NTLSTATUS_NOT_FOUND;
}
// The Interrupt Line register is a firmware hint until PCI _PRT routing is available.
DbgPrint("pci: INTx legacy route %02x:%02x.%u pin=%u line=%u\n",
ext->Info.Address.Bus, ext->Info.Address.Device,
ext->Info.Address.Function, pin, line);
if (line < 16u)
st = KeInterruptConnectIsa(line, 0x0Fu, requests[0].Affinity,
requests[0].Routine, requests[0].Context, &requests[0].Interrupt);
else
st = KeInterruptConnectGsi(line, 0x0Fu, requests[0].Affinity,
requests[0].Routine, requests[0].Context, &requests[0].Interrupt);
if (KSUCCESS(st)) {
uint16_t command = PciRawRead16(ext->Info.Address.Bus,
ext->Info.Address.Device, ext->Info.Address.Function, PCI_REG_COMMAND_STATUS);
PciRawWrite16(ext->Info.Address.Bus, ext->Info.Address.Device,
ext->Info.Address.Function, PCI_REG_COMMAND_STATUS,
command & (uint16_t)~PCI_COMMAND_INTX_DISABLE);
}
return st;
}
__declspec(dllexport) void PciDisconnectInterrupts(DEVICE_OBJECT* pdo,
PCI_INTERRUPT_REQUEST* requests, uint32_t count) {
PCI_PDO_EXTENSION* ext;
if (!PciIsPdo(pdo, &ext) || !requests) return;
// Close every route before disabling PCI delivery so an affinity update
// cannot resume the device after its disconnect has begun.
for (uint32_t i = 0; i < count; i++)
if (requests[i].Interrupt) KeInterruptBeginDisconnect(requests[i].Interrupt);
uint8_t bus = ext->Info.Address.Bus, dev = ext->Info.Address.Device;
uint8_t fn = ext->Info.Address.Function;
uint8_t msi = PciFindCapability(ext, PCI_CAP_ID_MSI);
uint8_t msix = PciFindCapability(ext, PCI_CAP_ID_MSIX);
if (msi) {
uint16_t control = PciRawRead16(bus, dev, fn, msi + 2u);
PciRawWrite16(bus, dev, fn, msi + 2u, control & ~PCI_MSI_CTRL_ENABLE);
}
if (msix) {
uint16_t control = PciRawRead16(bus, dev, fn, msix + 2u);
PciRawWrite16(bus, dev, fn, msix + 2u, (control | 0x4000u) & ~0x8000u);
}
uint16_t command = PciRawRead16(bus, dev, fn, PCI_REG_COMMAND_STATUS);
PciRawWrite16(bus, dev, fn, PCI_REG_COMMAND_STATUS, command | PCI_COMMAND_INTX_DISABLE);
for (uint32_t i = 0; i < count; i++) {
if (requests[i].Interrupt) {
KeInterruptDisconnect(requests[i].Interrupt);
requests[i].Interrupt = (KE_INTERRUPT*)0;
}
if (requests[i].BusContext) {
MmFreePool(requests[i].BusContext);
requests[i].BusContext = 0;
}
}
}
static KSTATUS DriverInitialize(NTL_MODULE* module) {
(void)module;
+4 -1
View File
@@ -37,10 +37,13 @@
#define PCI_MSI_CTRL_64BIT 0x0080u
#define PCI_MSI_CTRL_PVM 0x0100u
#define PCI_IRQ_VECTOR_BASE 0x20u
typedef struct PCI_PDO_EXTENSION {
PCI_DEVICE_INFO Info;
PCI_BAR Bars[PCI_MAX_BARS];
uint8_t CapabilityOffset;
// The MSI-X table is mapped once for the lifetime of its PCI PDO.
volatile uint8_t* MsixTable;
uint64_t MsixMappedLength;
uint8_t MsixBarIndex;
} PCI_PDO_EXTENSION;
+8
View File
@@ -0,0 +1,8 @@
TARGETNAME=pci
TARGETPATH=obj
TARGETTYPE=DRIVER
FLAVOR=DRIVER
EXTRA_CFLAGS=/DPCI_SYS_BUILD
TARGETLIBS="$(BASEDIR)\bin\kernel.lib" "$(BASEDIR)\bin\libc.lib" "$(BASEDIR)\bin\ntlddk.lib" "$(BASEDIR)\bin\printf.lib"
EXTRA_LFLAGS=/NOENTRY /IMPLIB:"$(BASEDIR)\bin\pci.lib"
SOURCES=@/code/drivers/bus/pci/pci.c