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

+119 -12
View File
@@ -4,6 +4,9 @@
#include <kernel/io_dma.h>
#include <kernel/ke_audio.h>
#include <kernel/ke_irq.h>
#include <kernel/ke_vectors.h>
#include <kernel/ke_sched.h>
#include <kernel/ke_irql.h>
#include <kernel/mm_pte.h>
static const HAL_API* gHal;
@@ -14,6 +17,10 @@ void IoInitializeDdk(const HAL_API* hal, uintptr_t physicalWindowBase) {
gPhysicalWindowBase = physicalWindowBase;
}
__declspec(dllexport) uintptr_t KeCurrentThreadIdentity(void) {
return (uintptr_t)KeGetCurrentThread();
}
__declspec(dllexport) uint64_t KeQueryTicks(void) {
return gHal && gHal->Timer.QueryTicks ? gHal->Timer.QueryTicks() : 0;
}
@@ -30,18 +37,6 @@ __declspec(dllexport) void KePciWriteConfig32(uint16_t segment, uint8_t bus, uin
if (gHal && gHal->Pci.Write32) gHal->Pci.Write32(segment, bus, device, function, offset, value);
}
__declspec(dllexport) KSTATUS KeIrqComposeMsiMessage(uint8_t irq, NTL_DDK_MSI_MESSAGE* out) {
if (!gHal || !out || irq >= 24u || !gHal->InterruptController.ComposeMsi)
return NTLSTATUS_INVALID_PARAMETER;
HAL_MSI_MESSAGE message;
KSTATUS status = gHal->InterruptController.ComposeMsi((uint8_t)(0x20u + irq), &message);
if (!KSUCCESS(status)) return status;
out->Address = message.Address;
out->Data = message.Data;
out->Reserved = 0;
return NTLSTATUS_SUCCESS;
}
__declspec(dllexport) void* MmDdkPhysToVirt(uint64_t physicalAddress) {
if (!gPhysicalWindowBase || physicalAddress > UINTPTR_MAX - gPhysicalWindowBase)
return (void*)0;
@@ -53,6 +48,118 @@ __declspec(dllexport) KSTATUS MmDdkMapPage(uintptr_t virtualAddress, uint64_t ph
mode == NtlDdkMapReplaceExisting ? MmPteMapReplaceExisting : MmPteMapFailIfPresent);
}
// Each slot is a recyclable 2 MiB VA reservation; no pool allocation is needed
// when reserving a device mapping. This aperture stays separate from PCI BARs.
#define DDK_IO_VA_BASE 0xFFFF980000000000ULL
#define DDK_IO_SLOT_SIZE (2ULL * 1024ULL * 1024ULL)
#define DDK_IO_SLOT_COUNT 256u
typedef struct DDK_IO_MAPPING {
uint8_t State;
uint32_t Pages;
uintptr_t Offset;
size_t Length;
} DDK_IO_MAPPING;
static SPINLOCK gDdkIoMapLock = SPINLOCK_INIT;
static DDK_IO_MAPPING gDdkIoMaps[DDK_IO_SLOT_COUNT];
// The caller owns the mapping until an exact-length unmap completes.
__declspec(dllexport) KSTATUS MmDdkMapIoMemory(uint64_t physicalAddress, size_t length, void** outVirtual) {
if (!outVirtual) return NTLSTATUS_INVALID_PARAMETER;
*outVirtual = NULL;
if (!KeCanWait()) return NTLSTATUS_NOT_SUPPORTED;
if (!length || physicalAddress > UINT64_MAX - length) return NTLSTATUS_INVALID_PARAMETER;
uintptr_t offset = (uintptr_t)(physicalAddress & (PAGE_SIZE - 1u));
if (length > DDK_IO_SLOT_SIZE - offset) return NTLSTATUS_INVALID_PARAMETER;
uint32_t pages = (uint32_t)((offset + length + PAGE_SIZE - 1u) / PAGE_SIZE);
if (pages == 0 || pages > DDK_IO_SLOT_SIZE / PAGE_SIZE) return NTLSTATUS_INVALID_PARAMETER;
// Reject a UC alias of RAM already covered by the firmware's WB/WC
// direct map. Real device registers have no direct mapping or an UC one.
for (uint32_t i = 0; i < pages; i++) {
uint64_t frame = (physicalAddress - offset) + (uint64_t)i * PAGE_SIZE;
if (gPhysicalWindowBase && frame <= UINTPTR_MAX - gPhysicalWindowBase) {
PHYSICAL_ADDRESS existing = 0;
uint64_t existingFlags = 0;
if (KSUCCESS(MmPteQueryPage(gPhysicalWindowBase + (uintptr_t)frame,
&existing, &existingFlags))) {
if ((existing & PAGE_MASK) != frame ||
(existingFlags & PAGE_CACHE_MASK) != PAGE_CACHE_UC)
return NTLSTATUS_NOT_SUPPORTED;
}
}
}
uintptr_t flags = KeAcquireSpinlock(&gDdkIoMapLock);
uint32_t slot;
for (slot = 0; slot < DDK_IO_SLOT_COUNT; slot++) {
if (!gDdkIoMaps[slot].State) {
gDdkIoMaps[slot].State = 1;
gDdkIoMaps[slot].Length = length;
gDdkIoMaps[slot].Offset = offset;
gDdkIoMaps[slot].Pages = pages;
break;
}
}
KeReleaseSpinlock(&gDdkIoMapLock, flags);
if (slot == DDK_IO_SLOT_COUNT) return NTLSTATUS_NO_MEMORY;
uintptr_t base = (uintptr_t)(DDK_IO_VA_BASE + (uint64_t)slot * DDK_IO_SLOT_SIZE);
uint64_t physBase = physicalAddress - offset;
uint32_t mapped = 0;
KSTATUS status = NTLSTATUS_SUCCESS;
for (; mapped < pages; mapped++) {
status = MmPteMapPage(base + (uintptr_t)mapped * PAGE_SIZE,
physBase + (uint64_t)mapped * PAGE_SIZE,
PAGE_PRESENT | PAGE_WRITE | PAGE_CACHE_UC | PAGE_NX,
MmPteMapFailIfPresent);
if (!KSUCCESS(status)) break;
}
if (mapped != pages) {
while (mapped) (void)MmPteUnmapPage(base + (uintptr_t)(--mapped) * PAGE_SIZE);
flags = KeAcquireSpinlock(&gDdkIoMapLock);
gDdkIoMaps[slot].State = 0;
KeReleaseSpinlock(&gDdkIoMapLock, flags);
return status;
}
flags = KeAcquireSpinlock(&gDdkIoMapLock);
gDdkIoMaps[slot].State = 2;
KeReleaseSpinlock(&gDdkIoMapLock, flags);
*outVirtual = (void*)(base + offset);
return NTLSTATUS_SUCCESS;
}
__declspec(dllexport) KSTATUS MmDdkUnmapIoMemory(void* virtualAddress, size_t length) {
if (!KeCanWait()) return NTLSTATUS_NOT_SUPPORTED;
if (!virtualAddress || !length) return NTLSTATUS_INVALID_PARAMETER;
uintptr_t address = (uintptr_t)virtualAddress;
if (address < DDK_IO_VA_BASE ||
(uint64_t)(address - DDK_IO_VA_BASE) >= DDK_IO_SLOT_SIZE * DDK_IO_SLOT_COUNT)
return NTLSTATUS_INVALID_PARAMETER;
uint32_t slot = (uint32_t)((address - DDK_IO_VA_BASE) / DDK_IO_SLOT_SIZE);
uintptr_t base = (uintptr_t)(DDK_IO_VA_BASE + (uint64_t)slot * DDK_IO_SLOT_SIZE);
uintptr_t flags = KeAcquireSpinlock(&gDdkIoMapLock);
DDK_IO_MAPPING* map = &gDdkIoMaps[slot];
if (map->State != 2 || map->Length != length || address != base + map->Offset) {
KeReleaseSpinlock(&gDdkIoMapLock, flags);
return NTLSTATUS_INVALID_PARAMETER;
}
map->State = 3;
uint32_t pages = map->Pages;
KeReleaseSpinlock(&gDdkIoMapLock, flags);
KSTATUS result = NTLSTATUS_SUCCESS;
for (uint32_t i = 0; i < pages; i++) {
KSTATUS status = MmPteUnmapPage(base + (uintptr_t)i * PAGE_SIZE);
if (!KSUCCESS(status)) result = status;
}
flags = KeAcquireSpinlock(&gDdkIoMapLock);
// Preserve the slot after a failed unmap to prevent stale PTE reuse.
if (KSUCCESS(result)) map->State = 0;
KeReleaseSpinlock(&gDdkIoMapLock, flags);
return result;
}
__declspec(dllexport) KSTATUS IoDmaGetAdapter(struct DEVICE_OBJECT* device, const IO_DMA_REQUIREMENTS* requirements, IO_DMA_ADAPTER** outAdapter) {
return IoGetDmaDdk()->GetAdapter(device, requirements, outAdapter);
}