add system time, clean up pci into pci.sys, clean up syscall names, fix USERAPC1 typo

This commit is contained in:
maksw committed 2026-06-11 18:11:59 +02:00
1 parent c1a291c4c9
commit e41bf6e2c0
64 files changed
+4514 -2220

No files matched your search

Binary file not shown.
Binary file not shown.
+20
View File
@@ -650,6 +650,26 @@ EFI_STATUS EFIAPI UefiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable
bi->Magic = BOOT_INFO_MAGIC;
AsciiStrCpyS(bi->CommandLine, 64, ps.commandLine);
EFI_TIME fwTime;
if (!EFI_ERROR(gRT->GetTime(&fwTime, NULL)) &&
fwTime.Year >= 1970 && fwTime.Month >= 1 && fwTime.Month <= 12 &&
fwTime.Day >= 1 && fwTime.Day <= 31 && fwTime.Hour <= 23 &&
fwTime.Minute <= 59 && fwTime.Second <= 59 &&
fwTime.Nanosecond < 1000000000U) {
bi->BootTime.Year = fwTime.Year;
bi->BootTime.Month = fwTime.Month;
bi->BootTime.Day = fwTime.Day;
bi->BootTime.Hour = fwTime.Hour;
bi->BootTime.Minute = fwTime.Minute;
bi->BootTime.Second = fwTime.Second;
bi->BootTime.Daylight = fwTime.Daylight;
bi->BootTime.Nanosecond = fwTime.Nanosecond;
bi->BootTime.TimeZoneMinutes = fwTime.TimeZone;
bi->BootTime.Flags = BOOT_TIME_FLAG_VALID | BOOT_TIME_FLAG_UEFI;
if (fwTime.TimeZone != EFI_UNSPECIFIED_TIMEZONE)
bi->BootTime.Flags |= BOOT_TIME_FLAG_TZ_KNOWN;
}
// Build PML4.
gPml4 = AllocPage(NULL);
+29 -12
View File
@@ -18,19 +18,24 @@ typedef struct Driver_Target {
const char *obj_dir;
const char *sources;
const char *cflags;
const char *libs;
} Driver_Target;
#define DRIVER_TARGET(name_, obj_dir_, sources_) { (name_), (obj_dir_), (sources_), CFLAGS_LITERAL }
#define DRIVER_TARGET_FLAGS(name_, obj_dir_, sources_, cflags_) { (name_), (obj_dir_), (sources_), (cflags_) }
#define DRIVER_TARGET(name_, obj_dir_, sources_) { (name_), (obj_dir_), (sources_), CFLAGS_LITERAL, "" }
#define DRIVER_TARGET_LIBS(name_, obj_dir_, sources_, libs_) { (name_), (obj_dir_), (sources_), CFLAGS_LITERAL, (libs_) }
#define DRIVER_TARGET_FLAGS(name_, obj_dir_, sources_, cflags_) { (name_), (obj_dir_), (sources_), (cflags_), "" }
static const Driver_Target PCI_BUS_DRIVER =
DRIVER_TARGET_FLAGS("pci", "obj\\drivers\\pci", "code\\drivers\\bus\\pci\\pci.c", CFLAGS_LITERAL " /DPCI_SYS_BUILD");
static const Driver_Target STANDALONE_DRIVERS[] = {
DRIVER_TARGET("ps2", "obj\\drivers\\ps2", "code\\drivers\\input\\ps2\\ps2.c code\\drivers\\input\\ps2\\ps2_i8042.c"),
DRIVER_TARGET("ide", "obj\\drivers\\ide", "code\\drivers\\storage\\ide\\ide.c code\\drivers\\storage\\ide\\ide_bus.c"),
DRIVER_TARGET("ahci", "obj\\drivers\\ahci", "code\\drivers\\storage\\ahci\\ahci.c code\\drivers\\storage\\ahci\\ahci_port.c"),
DRIVER_TARGET_LIBS("ata", "obj\\drivers\\ata", "code\\drivers\\storage\\ata\\ata.c", "bin\\pci.lib"),
DRIVER_TARGET_LIBS("ahci", "obj\\drivers\\ahci", "code\\drivers\\storage\\ahci\\ahci.c code\\drivers\\storage\\ahci\\ahci_port.c", "bin\\pci.lib"),
DRIVER_TARGET("fat32", "obj\\drivers\\fat32", "code\\drivers\\fs\\fat32\\fat32.c code\\drivers\\fs\\fat32\\fat32_mount.c"),
DRIVER_TARGET("usb", "obj\\drivers\\usb", "code\\drivers\\bus\\usb\\usb.c code\\drivers\\bus\\usb\\usb_bus.c code\\drivers\\bus\\usb\\usb_composite.c code\\drivers\\bus\\usb\\usb_core.c code\\drivers\\bus\\usb\\usb_xhci.c code\\drivers\\bus\\usb\\usb_hid.c code\\drivers\\bus\\usb\\usb_storage.c code\\drivers\\bus\\usb\\usb_hub.c"),
DRIVER_TARGET("rtl816x", "obj\\drivers\\rtl816x", "code\\drivers\\net\\rtl816x\\rtl816x.c code\\drivers\\net\\rtl816x\\rtl816x_pci.c"),
DRIVER_TARGET("rtl8139", "obj\\drivers\\rtl8139", "code\\drivers\\net\\rtl8139\\rtl8139.c code\\drivers\\net\\rtl8139\\rtl8139_pci.c"),
DRIVER_TARGET_LIBS("usb", "obj\\drivers\\usb", "code\\drivers\\bus\\usb\\usb.c code\\drivers\\bus\\usb\\usb_bus.c code\\drivers\\bus\\usb\\usb_composite.c code\\drivers\\bus\\usb\\usb_core.c code\\drivers\\bus\\usb\\usb_xhci.c code\\drivers\\bus\\usb\\usb_hid.c code\\drivers\\bus\\usb\\usb_storage.c code\\drivers\\bus\\usb\\usb_hub.c", "bin\\pci.lib"),
DRIVER_TARGET_LIBS("rtl816x", "obj\\drivers\\rtl816x", "code\\drivers\\net\\rtl816x\\rtl816x.c", "bin\\pci.lib"),
DRIVER_TARGET_LIBS("rtl8139", "obj\\drivers\\rtl8139", "code\\drivers\\net\\rtl8139\\rtl8139.c", "bin\\pci.lib"),
};
void create_layout() {
@@ -42,6 +47,7 @@ void create_layout() {
"obj\\tcpserve", "obj\\udp", "obj\\resolve", "obj\\ping", "obj\\doom", "obj\\video"
};
for (size_t i = 0; i < NOB_ARRAY_LEN(dirs); i++) nob_mkdir_if_not_exists(dirs[i]);
nob_mkdir_if_not_exists(PCI_BUS_DRIVER.obj_dir);
for (size_t i = 0; i < NOB_ARRAY_LEN(STANDALONE_DRIVERS); i++) nob_mkdir_if_not_exists(STANDALONE_DRIVERS[i].obj_dir);
}
@@ -108,7 +114,17 @@ int main(int argc, char **argv) {
if (!run_sync(core_tasks[i])) return 1;
}
// 3. Parallel Phase (Drivers and Applications)
// 3. Driver dependency phase. pci.sys owns PCI enumeration and exports
// bin\pci.lib, so it must be built before PCI function drivers link.
nob_log(NOB_INFO, "--- Building Bus Drivers ---");
const char *pci_cmd = nob_temp_sprintf(
"cl %s /MP /c /Fo%s\\ %s && link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /OUT:bin\\%s.sys /IMPLIB:bin\\%s.lib /ENTRY:DriverEntry bin\\hal.lib bin\\kernel.lib obj\\printf.obj obj\\libc.obj %s\\*.obj",
PCI_BUS_DRIVER.cflags, PCI_BUS_DRIVER.obj_dir, PCI_BUS_DRIVER.sources,
PCI_BUS_DRIVER.name, PCI_BUS_DRIVER.name, PCI_BUS_DRIVER.obj_dir
);
if (!run_sync(pci_cmd)) return 1;
// 4. Parallel Phase (Drivers and Applications)
nob_log(NOB_INFO, "--- Compiling Drivers and Apps in Parallel ---");
Nob_Procs procs = {0};
@@ -117,8 +133,9 @@ int main(int argc, char **argv) {
for (size_t i = 0; i < NOB_ARRAY_LEN(STANDALONE_DRIVERS); i++) {
const Driver_Target *driver = &STANDALONE_DRIVERS[i];
const char *cmd = nob_temp_sprintf(
"cl %s /MP /c /Fo%s\\ %s && link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /OUT:bin\\%s.sys /ENTRY:DriverEntry bin\\hal.lib bin\\kernel.lib obj\\libc.obj %s\\*.obj",
driver->cflags, driver->obj_dir, driver->sources, driver->name, driver->obj_dir
"cl %s /MP /c /Fo%s\\ %s && link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /OUT:bin\\%s.sys /ENTRY:DriverEntry bin\\hal.lib bin\\kernel.lib %s obj\\libc.obj %s\\*.obj",
driver->cflags, driver->obj_dir, driver->sources, driver->name,
driver->libs ? driver->libs : "", driver->obj_dir
);
nob_da_append(&procs, run_async(cmd));
}
@@ -199,8 +216,8 @@ int main(int argc, char **argv) {
{"bin\\win32.dll", "Z:\\system\\win32.dll"}, {"bin\\posix.dll", "Z:\\system\\posix.dll"},
{"code\\settings.ini", "Z:\\system\\settings.ini"}, {"bin\\init.exe", "Z:\\system\\init.exe"},
{"bin\\ps2.sys", "Z:\\drivers\\ps2.sys"}, {"bin\\ide.sys", "Z:\\drivers\\ide.sys"},
{"bin\\ahci.sys", "Z:\\drivers\\ahci.sys"},
{"bin\\pci.sys", "Z:\\drivers\\pci.sys"}, {"bin\\ps2.sys", "Z:\\drivers\\ps2.sys"},
{"bin\\ata.sys", "Z:\\drivers\\ata.sys"}, {"bin\\ahci.sys", "Z:\\drivers\\ahci.sys"},
{"bin\\fat32.sys", "Z:\\drivers\\fat32.sys"}, {"bin\\lwip.sys", "Z:\\drivers\\lwip.sys"},
{"bin\\usb.sys", "Z:\\drivers\\usb.sys"}, {"bin\\rtl816x.sys", "Z:\\drivers\\rtl816x.sys"},
{"bin\\rtl8139.sys", "Z:\\drivers\\rtl8139.sys"}, {"code\\drivers\\drivers.ini", "Z:\\drivers\\drivers.ini"},
+603
View File
@@ -0,0 +1,603 @@
// pci.c - PCI bus driver, PDO enumerator, and exported PCI DDI
#include "pci.h"
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <common/printf.h>
#include <ntlite/ddi/hal_api.h>
#include <ntlite/ddi/io_driver.h>
#include <kernel/mm_virt.h>
#include <kernel/ke_debug.h>
#include <kernel/ke_irp.h>
#include <kernel/hal/hal_apic.h>
int _fltused; // MSVC floating-point helper anchor required by printf.obj
static const HAL_API* gHal;
static DRIVER_OBJECT gPciDriver;
static uint32_t gPciDeviceCount;
static bool PciIsPdo(DEVICE_OBJECT* pdo, PCI_PDO_EXTENSION** outExt) {
if (!pdo || pdo->Type != DeviceObjectPhysical || pdo->u.Pdo.BusType != IoBusPci)
return false;
PCI_PDO_EXTENSION* ext = (PCI_PDO_EXTENSION*)pdo->DeviceExtension;
if (!ext) return false;
if (outExt) *outExt = ext;
return true;
}
static uint32_t PciRawRead32(uint8_t bus, uint8_t dev, uint8_t fn, uint16_t offset) {
if (!gHal || offset > 0xFCu) return 0xFFFFFFFFu;
return gHal->Pci.Read32(0, bus, dev, fn, offset & 0xFCu);
}
static void PciRawWrite32(uint8_t bus, uint8_t dev, uint8_t fn, uint16_t offset, uint32_t value) {
if (!gHal || offset > 0xFCu) return;
gHal->Pci.Write32(0, bus, dev, fn, offset & 0xFCu, value);
}
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));
}
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));
}
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;
uint32_t old = PciRawRead32(bus, dev, fn, aligned);
old &= ~(0xFFu << shift);
old |= ((uint32_t)value << shift);
PciRawWrite32(bus, dev, fn, aligned, old);
}
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;
uint32_t old = PciRawRead32(bus, dev, fn, aligned);
old &= ~(0xFFFFu << shift);
old |= ((uint32_t)value << shift);
PciRawWrite32(bus, dev, fn, aligned, old);
}
static uint64_t PciBarSizeFromMask(uint64_t mask, uint64_t baseMask) {
uint64_t sizeMask = mask & baseMask;
if (!sizeMask || sizeMask == baseMask)
return 0;
return (~sizeMask + 1u) & baseMask;
}
static uint8_t PciHeaderBarCount(uint8_t headerType) {
switch (headerType & PCI_HEADER_TYPE_MASK) {
case 0x00: return 6;
case 0x01: return 2;
case 0x02: return 1;
default: return 0;
}
}
static void PciDecodeBars(PCI_PDO_EXTENSION* ext) {
uint8_t barCount = PciHeaderBarCount(ext->Info.HeaderType);
for (uint8_t i = 0; i < PCI_MAX_BARS; i++) {
ext->Bars[i].Type = PciBarUnused;
ext->Bars[i].Index = i;
}
// Size BARs with I/O and memory decoding disabled so all-ones probes do
// not accidentally alias a live resource. Restore policy immediately;
// PciEnableDevice() is the only exported path that changes command bits.
uint16_t savedCommand = PciRawRead16(ext->Info.Address.Bus,
ext->Info.Address.Device,
ext->Info.Address.Function,
PCI_REG_COMMAND_STATUS);
uint16_t disabledCommand = (uint16_t)(savedCommand &
(uint16_t)~(PCI_COMMAND_IO_SPACE | PCI_COMMAND_MEMORY_SPACE));
if (disabledCommand != savedCommand) {
PciRawWrite16(ext->Info.Address.Bus,
ext->Info.Address.Device,
ext->Info.Address.Function,
PCI_REG_COMMAND_STATUS,
disabledCommand);
}
for (uint8_t i = 0; i < barCount && i < PCI_MAX_BARS; i++) {
uint16_t reg = (uint16_t)(PCI_REG_BAR0 + i * 4u);
uint32_t original = PciRawRead32(ext->Info.Address.Bus,
ext->Info.Address.Device,
ext->Info.Address.Function,
reg);
if (original == 0 || original == 0xFFFFFFFFu)
continue;
PCI_BAR* bar = &ext->Bars[i];
bar->Index = i;
bar->Length = 0;
bar->Prefetchable = false;
if (original & 0x1u) {
PciRawWrite32(ext->Info.Address.Bus,
ext->Info.Address.Device,
ext->Info.Address.Function,
reg,
0xFFFFFFFFu);
uint32_t maskLo = PciRawRead32(ext->Info.Address.Bus,
ext->Info.Address.Device,
ext->Info.Address.Function,
reg);
PciRawWrite32(ext->Info.Address.Bus,
ext->Info.Address.Device,
ext->Info.Address.Function,
reg,
original);
bar->Type = PciBarIo;
bar->Base = (uint64_t)(original & ~0x3u);
bar->Length = PciBarSizeFromMask((uint64_t)maskLo, 0xFFFFFFFCull);
continue;
}
uint32_t memType = (original >> 1) & 0x3u;
bar->Prefetchable = (original & 0x8u) != 0;
if (memType == 0x2u && i + 1u < barCount && i + 1u < PCI_MAX_BARS) {
uint16_t regHi = (uint16_t)(reg + 4u);
uint32_t originalHi = PciRawRead32(ext->Info.Address.Bus,
ext->Info.Address.Device,
ext->Info.Address.Function,
regHi);
PciRawWrite32(ext->Info.Address.Bus,
ext->Info.Address.Device,
ext->Info.Address.Function,
reg,
0xFFFFFFFFu);
PciRawWrite32(ext->Info.Address.Bus,
ext->Info.Address.Device,
ext->Info.Address.Function,
regHi,
0xFFFFFFFFu);
uint32_t maskLo = PciRawRead32(ext->Info.Address.Bus,
ext->Info.Address.Device,
ext->Info.Address.Function,
reg);
uint32_t maskHi = PciRawRead32(ext->Info.Address.Bus,
ext->Info.Address.Device,
ext->Info.Address.Function,
regHi);
PciRawWrite32(ext->Info.Address.Bus,
ext->Info.Address.Device,
ext->Info.Address.Function,
reg,
original);
PciRawWrite32(ext->Info.Address.Bus,
ext->Info.Address.Device,
ext->Info.Address.Function,
regHi,
originalHi);
bar->Type = PciBarMemory64;
bar->Base = ((uint64_t)originalHi << 32) | (uint64_t)(original & ~0xFu);
uint64_t mask = ((uint64_t)maskHi << 32) | (uint64_t)(maskLo & ~0xFu);
bar->Length = PciBarSizeFromMask(mask, 0xFFFFFFFFFFFFFFF0ull);
i++;
ext->Bars[i].Type = PciBarUnused;
ext->Bars[i].Index = i;
} else {
PciRawWrite32(ext->Info.Address.Bus,
ext->Info.Address.Device,
ext->Info.Address.Function,
reg,
0xFFFFFFFFu);
uint32_t maskLo = PciRawRead32(ext->Info.Address.Bus,
ext->Info.Address.Device,
ext->Info.Address.Function,
reg);
PciRawWrite32(ext->Info.Address.Bus,
ext->Info.Address.Device,
ext->Info.Address.Function,
reg,
original);
bar->Type = PciBarMemory32;
bar->Base = (uint64_t)(original & ~0xFu);
bar->Length = PciBarSizeFromMask((uint64_t)maskLo, 0xFFFFFFF0ull);
}
}
if (disabledCommand != savedCommand) {
PciRawWrite16(ext->Info.Address.Bus,
ext->Info.Address.Device,
ext->Info.Address.Function,
PCI_REG_COMMAND_STATUS,
savedCommand);
}
}
static uint8_t PciFindCapabilityOffset(PCI_PDO_EXTENSION* ext) {
uint16_t status = (uint16_t)(PciRawRead32(ext->Info.Address.Bus,
ext->Info.Address.Device,
ext->Info.Address.Function,
PCI_REG_COMMAND_STATUS) >> 16);
if ((status & PCI_STATUS_CAP_LIST) == 0)
return 0;
uint8_t cap = PciRawRead8(ext->Info.Address.Bus,
ext->Info.Address.Device,
ext->Info.Address.Function,
PCI_REG_CAP_PTR) & 0xFCu;
return cap;
}
static void PciMakeIds(const PCI_DEVICE_INFO* info, IO_DEVICE_ID* ids, char storage[][IO_MAX_DEVICE_ID_CHARS], size_t* outCount) {
size_t count = 0;
snprintf(storage[count], IO_MAX_DEVICE_ID_CHARS,
"PCI\\VEN_%04X&DEV_%04X&REV_%02X",
info->VendorId, info->DeviceId, info->RevisionId);
ids[count].BusType = IoBusPci;
ids[count].Id = SysSvFromCstr(storage[count]);
count++;
snprintf(storage[count], IO_MAX_DEVICE_ID_CHARS,
"PCI\\VEN_%04X&DEV_%04X",
info->VendorId, info->DeviceId);
ids[count].BusType = IoBusPci;
ids[count].Id = SysSvFromCstr(storage[count]);
count++;
snprintf(storage[count], IO_MAX_DEVICE_ID_CHARS,
"PCI\\CC_%02X%02X%02X",
info->ClassCode, info->Subclass, info->ProgIf);
ids[count].BusType = IoBusPci;
ids[count].Id = SysSvFromCstr(storage[count]);
count++;
snprintf(storage[count], IO_MAX_DEVICE_ID_CHARS,
"PCI\\CC_%02X%02X",
info->ClassCode, info->Subclass);
ids[count].BusType = IoBusPci;
ids[count].Id = SysSvFromCstr(storage[count]);
count++;
snprintf(storage[count], IO_MAX_DEVICE_ID_CHARS,
"PCI\\CC_%02X",
info->ClassCode);
ids[count].BusType = IoBusPci;
ids[count].Id = SysSvFromCstr(storage[count]);
count++;
*outCount = count;
}
static KSTATUS PciCreatePdo(uint8_t bus, uint8_t dev, uint8_t fn) {
uint32_t id = PciRawRead32(bus, dev, fn, PCI_REG_VENDOR_DEVICE);
uint16_t vendor = (uint16_t)(id & 0xFFFFu);
if (vendor == PCI_VENDOR_INVALID)
return STATUS_NOT_FOUND;
uint32_t classReg = PciRawRead32(bus, dev, fn, PCI_REG_REVISION_CLASS);
uint32_t hdrReg = PciRawRead32(bus, dev, fn, PCI_REG_HEADER_TYPE);
uint32_t irqReg = PciRawRead32(bus, dev, fn, PCI_REG_INTERRUPT_LINE_PIN);
uint32_t subsysReg = PciRawRead32(bus, dev, fn, PCI_REG_SUBSYSTEM);
PCI_DEVICE_INFO info;
memset(&info, 0, sizeof(info));
info.Address.Segment = 0;
info.Address.Bus = bus;
info.Address.Device = dev;
info.Address.Function = fn;
info.VendorId = vendor;
info.DeviceId = (uint16_t)(id >> 16);
info.SubsystemVendorId = (uint16_t)(subsysReg & 0xFFFFu);
info.SubsystemId = (uint16_t)(subsysReg >> 16);
info.RevisionId = (uint8_t)(classReg & 0xFFu);
info.ProgIf = (uint8_t)((classReg >> 8) & 0xFFu);
info.Subclass = (uint8_t)((classReg >> 16) & 0xFFu);
info.ClassCode = (uint8_t)((classReg >> 24) & 0xFFu);
info.HeaderType = (uint8_t)((hdrReg >> 16) & 0xFFu);
info.InterruptLine = (uint8_t)(irqReg & 0xFFu);
info.InterruptPin = (uint8_t)((irqReg >> 8) & 0xFFu);
IO_DEVICE_ID ids[5];
char idStorage[5][IO_MAX_DEVICE_ID_CHARS];
size_t idCount = 0;
PciMakeIds(&info, ids, idStorage, &idCount);
DEVICE_OBJECT* pdo = (DEVICE_OBJECT*)0;
KSTATUS st = IoCreatePhysicalDevice(&gPciDriver,
(DEVICE_OBJECT*)0,
ids,
idCount,
sizeof(PCI_PDO_EXTENSION),
&pdo);
if (!KSUCCESS(st))
return st;
PCI_PDO_EXTENSION* ext = (PCI_PDO_EXTENSION*)pdo->DeviceExtension;
memset(ext, 0, sizeof(*ext));
ext->Info = info;
PciDecodeBars(ext);
ext->CapabilityOffset = PciFindCapabilityOffset(ext);
pdo->u.Pdo.DeviceContext = ext;
char name[IO_MAX_DEVICE_NAME_CHARS];
snprintf(name, sizeof(name), "pci-%04X:%02X:%02X.%u",
info.Address.Segment, info.Address.Bus, info.Address.Device, info.Address.Function);
IoSetDeviceName(pdo, SysSvFromCstr(name));
st = IoRegisterPhysicalDevice(pdo);
if (!KSUCCESS(st)) {
IoDeleteDevice(pdo);
return st;
}
gPciDeviceCount++;
DbgPrint("pci: %v ven=%04x dev=%04x class=%02x%02x%02x irq=%u\n",
pdo->Name,
info.VendorId,
info.DeviceId,
info.ClassCode,
info.Subclass,
info.ProgIf,
info.InterruptLine);
return STATUS_SUCCESS;
}
static void PciEnumerateBus(void) {
for (uint32_t bus = 0; bus < 256u; bus++) {
for (uint32_t dev = 0; dev < 32u; dev++) {
uint32_t id0 = PciRawRead32((uint8_t)bus, (uint8_t)dev, 0, PCI_REG_VENDOR_DEVICE);
if ((uint16_t)(id0 & 0xFFFFu) == PCI_VENDOR_INVALID)
continue;
uint8_t headerType = PciRawRead8((uint8_t)bus, (uint8_t)dev, 0, PCI_REG_HEADER_TYPE + 2u);
uint8_t fnLimit = (headerType & PCI_HEADER_TYPE_MULTI) ? 8u : 1u;
for (uint8_t fn = 0; fn < fnLimit; fn++) {
KSTATUS st = PciCreatePdo((uint8_t)bus, (uint8_t)dev, fn);
if (!KSUCCESS(st) && st != STATUS_NOT_FOUND) {
DbgPrint("pci: failed to create PDO for %02x:%02x.%u st=0x%x\n",
bus, dev, fn, st);
}
}
}
}
}
static KSTATUS PciDispatchPnp(DEVICE_OBJECT* device, IRP* irp) {
if (!device || !irp) return STATUS_INVALID_PARAMETER;
IO_STACK_LOCATION* ios = IoGetCurrentIrpStackLocation(irp);
if (!ios || ios->MajorFunction != IRP_MJ_PNP) return STATUS_INVALID_PARAMETER;
switch ((IO_PNP_MINOR_FUNCTION)ios->MinorFunction) {
case IRP_MN_START_DEVICE:
device->PnpState = DevicePnpStarted;
return STATUS_SUCCESS;
case IRP_MN_QUERY_REMOVE_DEVICE:
case IRP_MN_CANCEL_REMOVE_DEVICE:
case IRP_MN_SURPRISE_REMOVAL:
case IRP_MN_REMOVE_DEVICE:
return STATUS_NOT_SUPPORTED;
default:
return STATUS_NOT_SUPPORTED;
}
}
__declspec(dllexport) uint32_t PciDriverAbiVersion(void) {
return 1u;
}
__declspec(dllexport) KSTATUS PciGetDeviceInfo(DEVICE_OBJECT* pdo, PCI_DEVICE_INFO* outInfo) {
PCI_PDO_EXTENSION* ext;
if (!outInfo || !PciIsPdo(pdo, &ext)) return STATUS_INVALID_PARAMETER;
*outInfo = ext->Info;
return STATUS_SUCCESS;
}
__declspec(dllexport) KSTATUS PciReadConfig8(DEVICE_OBJECT* pdo, uint16_t offset, uint8_t* outValue) {
PCI_PDO_EXTENSION* ext;
if (!outValue || offset > 0xFFu || !PciIsPdo(pdo, &ext)) return STATUS_INVALID_PARAMETER;
*outValue = PciRawRead8(ext->Info.Address.Bus, ext->Info.Address.Device, ext->Info.Address.Function, offset);
return STATUS_SUCCESS;
}
__declspec(dllexport) KSTATUS PciReadConfig16(DEVICE_OBJECT* pdo, uint16_t offset, uint16_t* outValue) {
PCI_PDO_EXTENSION* ext;
if (!outValue || offset > 0xFEu || !PciIsPdo(pdo, &ext)) return STATUS_INVALID_PARAMETER;
*outValue = PciRawRead16(ext->Info.Address.Bus, ext->Info.Address.Device, ext->Info.Address.Function, offset);
return STATUS_SUCCESS;
}
__declspec(dllexport) KSTATUS PciReadConfig32(DEVICE_OBJECT* pdo, uint16_t offset, uint32_t* outValue) {
PCI_PDO_EXTENSION* ext;
if (!outValue || offset > 0xFCu || !PciIsPdo(pdo, &ext)) return STATUS_INVALID_PARAMETER;
*outValue = PciRawRead32(ext->Info.Address.Bus, ext->Info.Address.Device, ext->Info.Address.Function, offset);
return STATUS_SUCCESS;
}
__declspec(dllexport) KSTATUS PciWriteConfig8(DEVICE_OBJECT* pdo, uint16_t offset, uint8_t value) {
PCI_PDO_EXTENSION* ext;
if (offset > 0xFFu || !PciIsPdo(pdo, &ext)) return STATUS_INVALID_PARAMETER;
PciRawWrite8(ext->Info.Address.Bus, ext->Info.Address.Device, ext->Info.Address.Function, offset, value);
return STATUS_SUCCESS;
}
__declspec(dllexport) KSTATUS PciWriteConfig16(DEVICE_OBJECT* pdo, uint16_t offset, uint16_t value) {
PCI_PDO_EXTENSION* ext;
if (offset > 0xFEu || !PciIsPdo(pdo, &ext)) return STATUS_INVALID_PARAMETER;
PciRawWrite16(ext->Info.Address.Bus, ext->Info.Address.Device, ext->Info.Address.Function, offset, value);
return STATUS_SUCCESS;
}
__declspec(dllexport) KSTATUS PciWriteConfig32(DEVICE_OBJECT* pdo, uint16_t offset, uint32_t value) {
PCI_PDO_EXTENSION* ext;
if (offset > 0xFCu || !PciIsPdo(pdo, &ext)) return STATUS_INVALID_PARAMETER;
PciRawWrite32(ext->Info.Address.Bus, ext->Info.Address.Device, ext->Info.Address.Function, offset, value);
return STATUS_SUCCESS;
}
__declspec(dllexport) KSTATUS PciGetBar(DEVICE_OBJECT* pdo, uint8_t index, PCI_BAR* outBar) {
PCI_PDO_EXTENSION* ext;
if (!outBar || index >= PCI_MAX_BARS || !PciIsPdo(pdo, &ext)) return STATUS_INVALID_PARAMETER;
if (ext->Bars[index].Type == PciBarUnused) return STATUS_NOT_FOUND;
*outBar = ext->Bars[index];
return STATUS_SUCCESS;
}
__declspec(dllexport) KSTATUS PciMapBar(DEVICE_OBJECT* pdo, uint8_t index, uint64_t pageFlags, void** outVirtual, uint64_t* outLength) {
PCI_BAR bar;
if (!outVirtual) return STATUS_INVALID_PARAMETER;
KSTATUS st = PciGetBar(pdo, index, &bar);
if (!KSUCCESS(st)) return st;
if (bar.Type != PciBarMemory32 && bar.Type != PciBarMemory64)
return STATUS_NOT_SUPPORTED;
if (!bar.Length)
return STATUS_DEVICE_ERROR;
uint64_t flags = pageFlags ? pageFlags : (PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE);
uint64_t pageBase = bar.Base & ~(uint64_t)(PAGE_SIZE - 1u);
uint64_t pageEnd = (bar.Base + bar.Length + PAGE_SIZE - 1u) & ~(uint64_t)(PAGE_SIZE - 1u);
for (uint64_t phys = pageBase; phys < pageEnd; phys += PAGE_SIZE) {
uintptr_t virt = (uintptr_t)gHal->PhysToVirt(phys);
st = MmMapPage(virt, phys, flags, MmMapFailIfPresent);
if (st == STATUS_ALREADY_EXISTS)
st = MmSetPageProtect(virt, PAGE_SIZE, flags);
if (!KSUCCESS(st))
return st;
}
*outVirtual = (void*)((uintptr_t)gHal->PhysToVirt(pageBase) + (uintptr_t)(bar.Base - pageBase));
if (outLength) *outLength = bar.Length;
return STATUS_SUCCESS;
}
__declspec(dllexport) KSTATUS PciEnableDevice(DEVICE_OBJECT* pdo, uint32_t flags) {
PCI_PDO_EXTENSION* ext;
if (!PciIsPdo(pdo, &ext)) return STATUS_INVALID_PARAMETER;
uint16_t cmd = PciRawRead16(ext->Info.Address.Bus,
ext->Info.Address.Device,
ext->Info.Address.Function,
PCI_REG_COMMAND_STATUS);
if (flags & PCI_ENABLE_IO) cmd |= PCI_COMMAND_IO_SPACE;
if (flags & PCI_ENABLE_MEMORY) cmd |= PCI_COMMAND_MEMORY_SPACE;
if (flags & PCI_ENABLE_BUSMASTER) cmd |= PCI_COMMAND_BUS_MASTER;
if (flags & PCI_ENABLE_INTX) cmd &= (uint16_t)~PCI_COMMAND_INTX_DISABLE;
if (flags & PCI_DISABLE_INTX) cmd |= PCI_COMMAND_INTX_DISABLE;
PciRawWrite16(ext->Info.Address.Bus,
ext->Info.Address.Device,
ext->Info.Address.Function,
PCI_REG_COMMAND_STATUS,
cmd);
return STATUS_SUCCESS;
}
__declspec(dllexport) KSTATUS PciGetInterrupt(DEVICE_OBJECT* pdo, uint8_t* outIrq) {
PCI_PDO_EXTENSION* ext;
if (!outIrq || !PciIsPdo(pdo, &ext)) return STATUS_INVALID_PARAMETER;
if (ext->Info.InterruptLine == 0xFFu) return STATUS_NOT_FOUND;
*outIrq = ext->Info.InterruptLine;
return STATUS_SUCCESS;
}
static uint8_t PciFindCapability(PCI_PDO_EXTENSION* ext, uint8_t capId) {
if (!ext || !ext->CapabilityOffset)
return 0;
uint8_t cap = ext->CapabilityOffset & 0xFCu;
for (uint32_t guard = 0; cap && guard < 48u; guard++) {
uint32_t hdr = PciRawRead32(ext->Info.Address.Bus,
ext->Info.Address.Device,
ext->Info.Address.Function,
cap);
uint8_t id = (uint8_t)(hdr & 0xFFu);
uint8_t next = (uint8_t)((hdr >> 8) & 0xFCu);
if (id == capId)
return cap;
cap = next;
}
return 0;
}
__declspec(dllexport) KSTATUS PciEnableMsi(DEVICE_OBJECT* pdo, uint8_t irqSlot) {
PCI_PDO_EXTENSION* ext;
if (!PciIsPdo(pdo, &ext))
return STATUS_INVALID_PARAMETER;
if (irqSlot >= 24u)
return STATUS_INVALID_PARAMETER;
uint8_t cap = PciFindCapability(ext, PCI_CAP_ID_MSI);
if (!cap)
return STATUS_NOT_SUPPORTED;
uint32_t bspLapic = HalGetBspLapicId();
if (!HalApicUsingX2Apic() && bspLapic >= 256u)
return STATUS_NOT_SUPPORTED;
if (HalApicUsingX2Apic() && bspLapic >= 256u) {
// Extended x2APIC MSI destinations need interrupt-remapping awareness.
return STATUS_NOT_SUPPORTED;
}
uint8_t bus = ext->Info.Address.Bus;
uint8_t 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;
uint8_t vector = (uint8_t)(PCI_IRQ_VECTOR_BASE + irqSlot);
uint32_t address = PCI_MSI_ADDRESS_BASE | ((bspLapic & 0xFFu) << 12);
uint16_t data = vector;
PciRawWrite32(bus, dev, fn, (uint16_t)(cap + 4u), address);
if (is64) {
PciRawWrite32(bus, dev, fn, (uint16_t)(cap + 8u), 0);
PciRawWrite16(bus, dev, fn, (uint16_t)(cap + 12u), data);
if (pvm)
PciRawWrite32(bus, dev, fn, (uint16_t)(cap + 16u), 0);
} else {
PciRawWrite16(bus, dev, fn, (uint16_t)(cap + 8u), data);
if (pvm)
PciRawWrite32(bus, dev, fn, (uint16_t)(cap + 12u), 0);
}
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 dest=%u %s\n",
bus, dev, fn, cap, vector, irqSlot, bspLapic, is64 ? "64-bit" : "32-bit");
return STATUS_SUCCESS;
}
KSTATUS DriverEntry(const HAL_API* hal) {
if (!hal) return STATUS_INVALID_PARAMETER;
gHal = hal;
gPciDeviceCount = 0;
IoInitializeDriverObject(&gPciDriver, SYS_SV_LITERAL("pci"));
gPciDriver.MajorFunction[IRP_MJ_PNP] = PciDispatchPnp;
KSTATUS st = IoRegisterDriverObject(&gPciDriver);
if (!KSUCCESS(st)) return st;
DbgPrint("pci: DriverEntry ABI=%u\n", PciDriverAbiVersion());
PciEnumerateBus();
DbgPrint("pci: enumeration complete, devices=%u\n", gPciDeviceCount);
return STATUS_SUCCESS;
}
+45
View File
@@ -0,0 +1,45 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <ntlite/ddi/pci.h>
#define PCI_MAX_BARS 6u
#define PCI_VENDOR_INVALID 0xFFFFu
#define PCI_REG_VENDOR_DEVICE 0x00u
#define PCI_REG_COMMAND_STATUS 0x04u
#define PCI_REG_REVISION_CLASS 0x08u
#define PCI_REG_HEADER_TYPE 0x0Cu
#define PCI_REG_BAR0 0x10u
#define PCI_REG_SUBSYSTEM 0x2Cu
#define PCI_REG_CAP_PTR 0x34u
#define PCI_REG_INTERRUPT_LINE_PIN 0x3Cu
#define PCI_COMMAND_IO_SPACE 0x0001u
#define PCI_COMMAND_MEMORY_SPACE 0x0002u
#define PCI_COMMAND_BUS_MASTER 0x0004u
#define PCI_COMMAND_INTX_DISABLE 0x0400u
#define PCI_HEADER_TYPE_MASK 0x7Fu
#define PCI_HEADER_TYPE_MULTI 0x80u
#define PCI_STATUS_CAP_LIST 0x0010u
#define PCI_CAP_ID_MSI 0x05u
#define PCI_CAP_ID_MSIX 0x11u
#define PCI_MSI_CTRL_ENABLE 0x0001u
#define PCI_MSI_CTRL_MME_MASK 0x0070u
#define PCI_MSI_CTRL_64BIT 0x0080u
#define PCI_MSI_CTRL_PVM 0x0100u
#define PCI_MSI_ADDRESS_BASE 0xFEE00000u
#define PCI_IRQ_VECTOR_BASE 0x20u
typedef struct PCI_PDO_EXTENSION {
PCI_DEVICE_INFO Info;
PCI_BAR Bars[PCI_MAX_BARS];
uint8_t CapabilityOffset;
} PCI_PDO_EXTENSION;
+28 -60
View File
@@ -1,8 +1,17 @@
// usb.c - USB bus driver entry point and PCI controller discovery.
// usb.c - USB bus driver entry point and host-controller driver registration.
#include "usb.h"
XHCI_CONTROLLER gXhci;
bool gHaveXhci = false;
DRIVER_OBJECT gXhciDriver;
const HAL_API* gUsbHal;
static const IO_DEVICE_ID gXhciIds[] = {
{ IoBusPci, { "PCI\\CC_0C0330", sizeof("PCI\\CC_0C0330") - 1 } },
};
static const IO_DRIVER_ID_TABLE gXhciIdTable = {
gXhciIds,
sizeof(gXhciIds) / sizeof(gXhciIds[0]),
};
const char* UsbControllerName(uint8_t progIf) {
switch (progIf) {
@@ -14,66 +23,19 @@ const char* UsbControllerName(uint8_t progIf) {
}
}
void UsbDiscoverControllers(const HAL_API* hal) {
uint32_t found = 0;
uint32_t xhciOk = 0;
for (uint16_t bus = 0; bus < 256; bus++) {
for (uint8_t dev = 0; dev < 32; dev++) {
for (uint8_t fn = 0; fn < 8; fn++) {
uint32_t vd = hal->Pci.Read32((uint8_t)bus, dev, fn, PCI_REG_VENDOR_DEVICE);
if ((vd & 0xFFFFu) == PCI_VENDOR_INVALID)
continue;
uint32_t classReg = hal->Pci.Read32((uint8_t)bus, dev, fn, PCI_REG_CLASS);
uint8_t classCode = (uint8_t)(classReg >> 24);
uint8_t subclass = (uint8_t)(classReg >> 16);
uint8_t progIf = (uint8_t)(classReg >> 8);
if (classCode != PCI_CLASS_SERIAL_BUS || subclass != PCI_SUBCLASS_USB)
continue;
USB_BAR bar0;
bool hasBar0 = UsbReadBar(hal, (uint8_t)bus, dev, fn, 0, &bar0);
uint32_t rawBar0 = hal->Pci.Read32((uint8_t)bus, dev, fn, PCI_REG_BAR0);
uint32_t rawBar1 = hal->Pci.Read32((uint8_t)bus, dev, fn, PCI_REG_BAR0 + 4u);
uint8_t irq = hal->Pci.GetIrqLine((uint8_t)bus, dev, fn);
DbgPrint("usb: found %s controller at %u:%u.%u vendor=%04x device=%04x irq=%u bar0raw=%08x bar1raw=%08x",
UsbControllerName(progIf),
bus, dev, fn,
vd & 0xFFFFu, vd >> 16,
irq, rawBar0, rawBar1);
if (hasBar0 && bar0.Kind == UsbBarMmio) {
DbgPrint(" mmio=0x%016llX\n", (unsigned long long)bar0.Base);
} else if (hasBar0 && bar0.Kind == UsbBarIo) {
DbgPrint(" io=0x%016llX\n", (unsigned long long)bar0.Base);
} else {
DbgPrint(" no-bar0\n");
}
if (progIf == PCI_PROGIF_XHCI) {
KSTATUS st = XhciInitialise(hal, (uint8_t)bus, dev, fn,
(uint16_t)(vd & 0xFFFFu),
(uint16_t)(vd >> 16));
if (KSUCCESS(st) || st == STATUS_ALREADY_EXISTS) xhciOk++;
else DbgPrint("usb: xHCI init failed st=0x%x\n", st);
}
found++;
}
}
}
if (!found)
DbgPrint("usb: no PCI USB controllers discovered\n");
else
DbgPrint("usb: discovery complete; controllers=%u xhci_initialised=%u\n", found, xhciOk);
static KSTATUS UsbInitializeXhciDriver(void) {
memset(&gXhciDriver, 0, sizeof(gXhciDriver));
IoInitializeDriverObject(&gXhciDriver, SYS_SV_LITERAL("xhci"));
gXhciDriver.IdTable = &gXhciIdTable;
gXhciDriver.DriverAddDevice = XhciAddDevice;
gXhciDriver.MajorFunction[IRP_MJ_PNP] = XhciDispatchPnp;
return IoRegisterDriverObject(&gXhciDriver);
}
KSTATUS DriverEntry(const HAL_API* hal) {
if (!hal) return STATUS_INVALID_PARAMETER;
DbgPrint("usb: discovery starting\n");
DbgPrint("usb: driver loading\n");
gUsbHal = hal;
KSTATUS st = UsbInitializeBusModel();
if (!KSUCCESS(st)) {
@@ -105,6 +67,12 @@ KSTATUS DriverEntry(const HAL_API* hal) {
return st;
}
UsbDiscoverControllers(hal);
st = UsbInitializeXhciDriver();
if (!KSUCCESS(st)) {
DbgPrint("usb: xHCI driver initialisation failed st=0x%x\n", st);
return st;
}
DbgPrint("usb: driver initialized\n");
return STATUS_SUCCESS;
}
+14 -31
View File
@@ -10,6 +10,7 @@
#include <ntlite/ddi/hal_api.h>
#include <ntlite/ddi/input_device.h>
#include <ntlite/ddi/io_driver.h>
#include <ntlite/ddi/pci.h>
#include <ntlite/status.h>
#include <kernel/ke_debug.h>
#include <kernel/ke_irq.h>
@@ -32,17 +33,9 @@ static __inline void UsbTrace(const char* fmt, ...) { (void)fmt; }
#endif
#define PCI_VENDOR_INVALID 0xFFFFu
#define PCI_CLASS_SERIAL_BUS 0x0Cu
#define PCI_SUBCLASS_USB 0x03u
#define PCI_PROGIF_XHCI 0x30u
#define PCI_REG_VENDOR_DEVICE 0x00u
#define PCI_REG_COMMAND 0x04u
#define PCI_REG_CLASS 0x08u
#define PCI_REG_BAR0 0x10u
#define PCI_COMMAND_MEMORY (1u << 1)
#define PCI_COMMAND_MASTER (1u << 2)
#define PCI_COMMAND_INTX_DISABLE (1u << 10)
#define XHCI_CAP_CAPLENGTH 0x00u
#define XHCI_CAP_HCSPARAMS1 0x04u
@@ -212,7 +205,6 @@ static __inline void UsbTrace(const char* fmt, ...) { (void)fmt; }
#define XHCI_RING_TRBS 256u
#define XHCI_EVENT_TRBS 256u
#define XHCI_DCBAA_ENTRIES 256u
#define XHCI_MMIO_FLOOR_BYTES 0x10000u
#define XHCI_MAX_SCRATCHPADS 1024u
#define XHCI_MAX_TRACKED_SLOTS 64u
#define XHCI_MAX_ROOT_PORTS 255u
@@ -347,19 +339,6 @@ typedef struct USB_TRACKED_INTERFACE {
USB_ENDPOINT_DESCRIPTOR Endpoints[USB_MAX_TRACKED_ENDPOINTS];
} USB_TRACKED_INTERFACE;
typedef enum USB_BAR_KIND {
UsbBarNone,
UsbBarIo,
UsbBarMmio
} USB_BAR_KIND;
typedef struct USB_BAR {
USB_BAR_KIND Kind;
uint64_t Base;
uint8_t Index;
} USB_BAR;
typedef enum USB_DEVICE_STATE {
UsbDeviceAttached = 0,
UsbDevicePowered,
@@ -422,7 +401,7 @@ struct USB_HCD {
const USB_HCD_OPERATIONS* Operations;
void* ControllerContext;
DRIVER_OBJECT* DriverObject;
DEVICE_OBJECT* ControllerPdo;
DEVICE_OBJECT* ControllerDevice;
DEVICE_OBJECT* RootHubPdo;
void* RootHubContext;
uint8_t ControllerIndex;
@@ -488,10 +467,9 @@ struct USB_URB {
};
typedef enum USB_PDO_KIND {
UsbPdoController = 1,
UsbPdoRootHub = 1,
UsbPdoDevice = 2,
UsbPdoInterface = 3,
UsbPdoRootHub = 4,
} USB_PDO_KIND;
typedef struct USB_PDO_EXTENSION {
@@ -779,7 +757,13 @@ typedef struct XHCI_WAIT_TARGET {
} XHCI_WAIT_TARGET;
typedef struct XHCI_CONTROLLER {
uint32_t Magic;
const HAL_API* Hal;
DEVICE_OBJECT* Fdo;
DEVICE_OBJECT* Pdo;
DEVICE_OBJECT* LowerDevice;
PCI_DEVICE_INFO PciInfo;
PCI_BAR MmioBar;
uint8_t Bus;
uint8_t Dev;
uint8_t Fn;
@@ -845,13 +829,13 @@ typedef struct XHCI_CONTROLLER {
} XHCI_CONTROLLER;
extern XHCI_CONTROLLER gXhci;
extern bool gHaveXhci;
extern DRIVER_OBJECT gUsbStorageDriver;
extern DRIVER_OBJECT gUsbBusDriver;
extern DRIVER_OBJECT gUsbCompositeDriver;
extern DRIVER_OBJECT gUsbHidDriver;
extern DRIVER_OBJECT gUsbHubDriver;
extern DRIVER_OBJECT gXhciDriver;
extern const HAL_API* gUsbHal;
KSTATUS UsbInitializeBusModel(void);
KSTATUS UsbInitializeCompositeDriver(void);
@@ -865,7 +849,6 @@ void UsbInitializeHcd(USB_HCD* hcd,
void* controllerContext,
uint8_t controllerIndex,
uint8_t maxRootPorts);
KSTATUS UsbCreateControllerPdo(USB_HCD* hcd, uint16_t vendor, uint16_t device);
KSTATUS UsbCreateRootHubPdo(USB_HCD* hcd);
KSTATUS UsbRemoveDeviceObjectChildren(DEVICE_OBJECT* parent, bool surprise);
KSTATUS UsbRemovePdoSubtree(DEVICE_OBJECT* pdo, bool surprise);
@@ -899,8 +882,6 @@ void XhciWrite64(volatile uint8_t* base, uint32_t reg, uint64_t value);
void UsbDelayUs(const HAL_API* hal, uint32_t us);
bool UsbWaitSet32(const HAL_API* hal, volatile uint8_t* base, uint32_t reg, uint32_t mask, uint32_t timeoutUs);
bool UsbWaitClear32(const HAL_API* hal, volatile uint8_t* base, uint32_t reg, uint32_t mask, uint32_t timeoutUs);
bool UsbReadBar(const HAL_API* hal, uint8_t bus, uint8_t dev, uint8_t fn, uint8_t index, USB_BAR* out);
KSTATUS UsbMapMmio(const HAL_API* hal, uint64_t physBase, uint32_t bytes, volatile uint8_t** outMmio);
void* UsbDmaAllocPages(XHCI_CONTROLLER* xhci, size_t pages, PHYSICAL_ADDRESS* outPhys);
uint16_t XhciScratchpadCount(uint32_t hcs2);
uint32_t XhciTrbType(const XHCI_TRB* trb);
@@ -1014,4 +995,6 @@ KSTATUS UsbHubScheduleRootScan(USB_HCD* hcd);
void UsbHubQueueRootPortChange(USB_HCD* hcd, uint8_t port);
void UsbHubQueueExternalPortChange(USB_HUB_EXTENSION* hub, uint8_t port);
extern const USB_HCD_OPERATIONS gXhciHcdOperations;
KSTATUS XhciInitialise(const HAL_API* hal, uint8_t bus, uint8_t dev, uint8_t fn, uint16_t vendor, uint16_t device);
KSTATUS XhciStartController(XHCI_CONTROLLER* xhci);
KSTATUS XhciAddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDeviceObject);
KSTATUS XhciDispatchPnp(DEVICE_OBJECT* device, IRP* irp);
+2 -44
View File
@@ -177,16 +177,6 @@ static void UsbFormatComposite(char* buf, size_t cap) {
UsbIdAppendLiteral(buf, cap, &pos, "USB\\COMPOSITE");
}
static void UsbFormatPciXhci(char* buf, size_t cap, uint16_t vendor, uint16_t device) {
size_t pos = 0;
if (cap) buf[0] = '\0';
UsbIdAppendLiteral(buf, cap, &pos, "PCI\\VEN_");
UsbIdAppendHex(buf, cap, &pos, vendor, 4);
UsbIdAppendLiteral(buf, cap, &pos, "&DEV_");
UsbIdAppendHex(buf, cap, &pos, device, 4);
UsbIdAppendLiteral(buf, cap, &pos, "&CC_0C0330");
}
static void UsbFormatRootHub(char* buf, size_t cap) {
size_t pos = 0;
if (cap) buf[0] = '\0';
@@ -273,38 +263,6 @@ void UsbInitializeHcd(USB_HCD* hcd,
hcd->MaxRootPorts = maxRootPorts;
}
KSTATUS UsbCreateControllerPdo(USB_HCD* hcd, uint16_t vendor, uint16_t device) {
if (!hcd) return STATUS_INVALID_PARAMETER;
if (hcd->ControllerPdo) return STATUS_ALREADY_EXISTS;
IO_DEVICE_ID ids[2];
char idbuf[2][USB_MAX_DEVICE_ID_TEXT];
UsbFormatPciXhci(idbuf[0], USB_MAX_DEVICE_ID_TEXT, vendor, device);
{
size_t pos = 0;
idbuf[1][0] = '\0';
UsbIdAppendLiteral(idbuf[1], USB_MAX_DEVICE_ID_TEXT, &pos, "PCI\\CC_0C0330");
}
ids[0] = (IO_DEVICE_ID){ IoBusPci, UsbIdFromBuffer(idbuf[0]) };
ids[1] = (IO_DEVICE_ID){ IoBusPci, UsbIdFromBuffer(idbuf[1]) };
DEVICE_OBJECT* pdo = (DEVICE_OBJECT*)0;
KSTATUS st = IoCreatePhysicalDevice(&gUsbBusDriver, (DEVICE_OBJECT*)0, ids, 2, sizeof(USB_PDO_EXTENSION), &pdo);
if (!KSUCCESS(st)) return st;
(void)IoSetDeviceName(pdo, SYS_SV_LITERAL("xhci-controller"));
USB_PDO_EXTENSION* ext = (USB_PDO_EXTENSION*)pdo->DeviceExtension;
ext->Kind = UsbPdoController;
ext->Hcd = hcd;
hcd->ControllerPdo = pdo;
st = IoRegisterPhysicalDevice(pdo);
if (!KSUCCESS(st) && st != STATUS_ALREADY_EXISTS)
return st;
return STATUS_SUCCESS;
}
KSTATUS UsbCreateRootHubPdo(USB_HCD* hcd) {
if (!hcd) return STATUS_INVALID_PARAMETER;
if (hcd->RootHubPdo) return STATUS_ALREADY_EXISTS;
@@ -318,7 +276,7 @@ KSTATUS UsbCreateRootHubPdo(USB_HCD* hcd) {
DEVICE_OBJECT* pdo = (DEVICE_OBJECT*)0;
KSTATUS st = IoCreatePhysicalDevice(&gUsbBusDriver,
hcd->ControllerPdo,
hcd->ControllerDevice,
ids,
2,
sizeof(USB_PDO_EXTENSION),
@@ -376,7 +334,7 @@ KSTATUS UsbCreateDevicePdo(USB_HCD* hcd, XHCI_DEVICE* xdev, DEVICE_OBJECT* paren
DEVICE_OBJECT* pdo = (DEVICE_OBJECT*)0;
KSTATUS st = IoCreatePhysicalDevice(&gUsbBusDriver,
parent ? parent : (hcd->RootHubPdo ? hcd->RootHubPdo : hcd->ControllerPdo),
parent ? parent : (hcd->RootHubPdo ? hcd->RootHubPdo : hcd->ControllerDevice),
ids,
idCount,
sizeof(USB_PDO_EXTENSION),
+1 -1
View File
@@ -242,7 +242,7 @@ KSTATUS XhciDiscoverAndSetConfiguration(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev,
if (!dev->UsbPdo) {
st = UsbCreateDevicePdo(&xhci->Hcd, dev,
dev->ParentDeviceObject ? dev->ParentDeviceObject :
(xhci->Hcd.RootHubPdo ? xhci->Hcd.RootHubPdo : xhci->Hcd.ControllerPdo));
(xhci->Hcd.RootHubPdo ? xhci->Hcd.RootHubPdo : xhci->Hcd.ControllerDevice));
if (!KSUCCESS(st)) {
DbgPrint("usb: create device PDO slot=%u failed st=0x%x\n", dev->SlotId, st);
return st;
+183 -136
View File
@@ -74,62 +74,6 @@ bool UsbWaitClear32(const HAL_API* hal, volatile uint8_t* base, uint32_t reg,
}
bool UsbReadBar(const HAL_API* hal, uint8_t bus, uint8_t dev, uint8_t fn,
uint8_t index, USB_BAR* out) {
uint8_t reg = (uint8_t)(PCI_REG_BAR0 + index * 4u);
uint32_t lo = hal->Pci.Read32(bus, dev, fn, reg);
out->Kind = UsbBarNone;
out->Base = 0;
out->Index = index;
if (lo == 0 || lo == 0xFFFFFFFFu)
return false;
if (lo & 1u) {
out->Kind = UsbBarIo;
out->Base = (uint64_t)(lo & ~0x3u);
return out->Base != 0;
}
uint64_t base = (uint64_t)(lo & ~0xFu);
uint32_t type = (lo >> 1) & 0x3u;
if (type == 0x2u && index < 5) {
uint32_t hi = hal->Pci.Read32(bus, dev, fn, (uint8_t)(reg + 4u));
base |= ((uint64_t)hi << 32);
}
out->Kind = UsbBarMmio;
out->Base = base;
return base != 0;
}
KSTATUS UsbMapMmio(const HAL_API* hal, uint64_t physBase,
uint32_t bytes, volatile uint8_t** outMmio) {
uint64_t pageBase = physBase & PAGE_MASK;
uint64_t pageOff = physBase - pageBase;
uint32_t total = UsbAlignUp32((uint32_t)pageOff + bytes, (uint32_t)PAGE_SIZE);
uint32_t pages = total / (uint32_t)PAGE_SIZE;
for (uint32_t i = 0; i < pages; i++) {
PHYSICAL_ADDRESS phys = pageBase + (uint64_t)i * PAGE_SIZE;
uintptr_t virt = (uintptr_t)hal->PhysToVirt(phys);
KSTATUS st = MmMapPage(virt, phys, PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE, MmMapFailIfPresent);
if (st == STATUS_ALREADY_EXISTS)
st = MmSetPageProtect(virt, PAGE_SIZE, PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE);
if (!KSUCCESS(st)) {
DbgPrint("usb: xHCI MmMapPage failed phys=0x%016llX st=0x%x\n",
(unsigned long long)phys, st);
return st;
}
}
*outMmio = (volatile uint8_t*)((uintptr_t)hal->PhysToVirt(pageBase) + pageOff);
return STATUS_SUCCESS;
}
void* UsbDmaAllocPages(XHCI_CONTROLLER* xhci, size_t pages,
PHYSICAL_ADDRESS* outPhys) {
if (!outPhys || pages == 0)
@@ -617,19 +561,39 @@ void XhciEventDpcRoutine(KDPC* dpc, void* context,
}
#define XHCI_CONTROLLER_MAGIC 0x58484349u /* XHCI */
#define XHCI_MAX_CONTROLLERS 8u
static XHCI_CONTROLLER* gXhciControllers[XHCI_MAX_CONTROLLERS];
static uint32_t gXhciControllerCount;
static KSTATUS XhciRegisterController(XHCI_CONTROLLER* xhci) {
if (!xhci) return STATUS_INVALID_PARAMETER;
for (uint32_t i = 0; i < gXhciControllerCount; i++) {
if (gXhciControllers[i] == xhci)
return STATUS_SUCCESS;
}
if (gXhciControllerCount >= XHCI_MAX_CONTROLLERS)
return STATUS_NO_MEMORY;
gXhciControllers[gXhciControllerCount++] = xhci;
return STATUS_SUCCESS;
}
void XhciIsr(void) {
XHCI_CONTROLLER* xhci = &gXhci;
if (!xhci->Running || !xhci->Op || !xhci->Runtime)
return;
for (uint32_t i = 0; i < gXhciControllerCount; i++) {
XHCI_CONTROLLER* xhci = gXhciControllers[i];
if (!xhci || !xhci->Running || !xhci->Op || !xhci->Runtime)
continue;
uint32_t status = XhciRead32(xhci->Op, XHCI_OP_USBSTS);
if (!(status & (XHCI_USBSTS_EINT | XHCI_USBSTS_PCD | XHCI_USBSTS_HSE | XHCI_USBSTS_HCE)))
return;
uint32_t status = XhciRead32(xhci->Op, XHCI_OP_USBSTS);
if (!(status & (XHCI_USBSTS_EINT | XHCI_USBSTS_PCD | XHCI_USBSTS_HSE | XHCI_USBSTS_HCE)))
continue;
xhci->InterruptCount++;
XhciWrite32(xhci->Op, XHCI_OP_USBSTS, status & XHCI_USBSTS_CLEAR_MASK);
XhciAckInterrupter0(xhci);
KeInsertQueueDpc(&xhci->EventDpc, (void*)0, (void*)0);
xhci->InterruptCount++;
XhciWrite32(xhci->Op, XHCI_OP_USBSTS, status & XHCI_USBSTS_CLEAR_MASK);
XhciAckInterrupter0(xhci);
KeInsertQueueDpc(&xhci->EventDpc, (void*)0, (void*)0);
}
}
@@ -1872,65 +1836,67 @@ const USB_HCD_OPERATIONS gXhciHcdOperations = {
XhciHcdAllocateDma,
};
KSTATUS XhciInitialise(const HAL_API* hal,
uint8_t bus, uint8_t dev, uint8_t fn,
uint16_t vendor, uint16_t device) {
if (gHaveXhci) {
DbgPrint("usb: additional xHCI controller at %u:%u.%u ignored for now\n",
bus, dev, fn);
return STATUS_ALREADY_EXISTS;
KSTATUS XhciStartController(XHCI_CONTROLLER* xhci) {
if (!xhci || xhci->Magic != XHCI_CONTROLLER_MAGIC || !xhci->Pdo || !xhci->Fdo)
return STATUS_INVALID_PARAMETER;
if (xhci->Running)
return STATUS_SUCCESS;
KSTATUS st = PciGetDeviceInfo(xhci->Pdo, &xhci->PciInfo);
if (!KSUCCESS(st)) {
DbgPrint("usb: xHCI PciGetDeviceInfo failed st=0x%x\n", st);
return st;
}
USB_BAR bar;
if (!UsbReadBar(hal, bus, dev, fn, 0, &bar) || bar.Kind != UsbBarMmio) {
DbgPrint("usb: xHCI controller has no usable MMIO BAR0\n");
xhci->Bus = xhci->PciInfo.Address.Bus;
xhci->Dev = xhci->PciInfo.Address.Device;
xhci->Fn = xhci->PciInfo.Address.Function;
st = PciGetBar(xhci->Pdo, 0, &xhci->MmioBar);
if (!KSUCCESS(st)) {
DbgPrint("usb: xHCI PCI %02x:%02x.%x BAR0 missing st=0x%x\n",
xhci->Bus, xhci->Dev, xhci->Fn, st);
return st;
}
if (xhci->MmioBar.Type != PciBarMemory32 && xhci->MmioBar.Type != PciBarMemory64) {
DbgPrint("usb: xHCI PCI %02x:%02x.%x BAR0 is not MMIO type=%u\n",
xhci->Bus, xhci->Dev, xhci->Fn, xhci->MmioBar.Type);
return STATUS_DEVICE_ERROR;
}
st = PciGetInterrupt(xhci->Pdo, &xhci->Irq);
if (!KSUCCESS(st)) {
DbgPrint("usb: xHCI PciGetInterrupt failed st=0x%x\n", st);
return st;
}
if (xhci->Irq == 0xFFu) {
DbgPrint("usb: xHCI PCI %02x:%02x.%x has no INTx IRQ; MSI is not in pci.sys yet\n",
xhci->Bus, xhci->Dev, xhci->Fn);
return STATUS_NOT_SUPPORTED;
}
memset(&gXhci, 0, sizeof(gXhci));
XHCI_CONTROLLER* xhci = &gXhci;
KeInitializeDpc(&xhci->EventDpc, XhciEventDpcRoutine, xhci);
xhci->Hal = hal;
xhci->Bus = bus;
xhci->Dev = dev;
xhci->Fn = fn;
xhci->Irq = hal->Pci.GetIrqLine(bus, dev, fn);
xhci->MmioPhys = bar.Base;
uint32_t pciCmd = hal->Pci.Read32(bus, dev, fn, PCI_REG_COMMAND);
pciCmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
hal->Pci.Write32(bus, dev, fn, PCI_REG_COMMAND, pciCmd);
if (xhci->Irq == 0xFFu) {
uint8_t msiIrq = 0xFFu;
KSTATUS irqSt = KeIrqAllocateMsiVector(&msiIrq);
if (!KSUCCESS(irqSt)) {
DbgPrint("usb: xHCI has no PCI INTx IRQ line and MSI vector allocation failed st=0x%x\n",
irqSt);
return irqSt;
}
if (!hal->Pci.EnableMsi) {
DbgPrint("usb: xHCI has no PCI INTx IRQ line and HAL MSI support is unavailable\n");
return STATUS_NOT_SUPPORTED;
}
irqSt = hal->Pci.EnableMsi(bus, dev, fn, msiIrq);
if (!KSUCCESS(irqSt)) {
DbgPrint("usb: xHCI has no PCI INTx IRQ line and MSI enable failed st=0x%x\n",
irqSt);
return irqSt;
}
xhci->Irq = msiIrq;
xhci->UsingMsi = true;
DbgPrint("usb: xHCI using MSI irqslot=%u vector=0x%02x\n",
xhci->Irq, 0x20u + xhci->Irq);
} else {
pciCmd = hal->Pci.Read32(bus, dev, fn, PCI_REG_COMMAND);
pciCmd &= ~PCI_COMMAND_INTX_DISABLE;
hal->Pci.Write32(bus, dev, fn, PCI_REG_COMMAND, pciCmd);
st = PciEnableDevice(xhci->Pdo,
PCI_ENABLE_MEMORY |
PCI_ENABLE_BUSMASTER |
PCI_ENABLE_INTX);
if (!KSUCCESS(st)) {
DbgPrint("usb: xHCI PciEnableDevice failed st=0x%x\n", st);
return st;
}
KSTATUS st = UsbMapMmio(hal, xhci->MmioPhys, PAGE_SIZE, &xhci->Mmio);
if (!KSUCCESS(st)) return st;
xhci->MmioPhys = xhci->MmioBar.Base;
uint64_t mappedLength = 0;
st = PciMapBar(xhci->Pdo,
0,
PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE,
(void**)&xhci->Mmio,
&mappedLength);
if (!KSUCCESS(st)) {
DbgPrint("usb: xHCI PciMapBar(BAR0) failed st=0x%x\n", st);
return st;
}
xhci->MmioBytes = (mappedLength > 0xFFFFFFFFull) ? 0xFFFFFFFFu : (uint32_t)mappedLength;
xhci->Cap = xhci->Mmio;
uint32_t cap0 = XhciRead32(xhci->Cap, XHCI_CAP_CAPLENGTH);
@@ -1954,32 +1920,29 @@ KSTATUS XhciInitialise(const HAL_API* hal,
return STATUS_DEVICE_ERROR;
}
UsbInitializeHcd(&xhci->Hcd, &gXhciHcdOperations, xhci, 0, xhci->MaxPorts);
KSTATUS hcdPdoStatus = UsbCreateControllerPdo(&xhci->Hcd, vendor, device);
if (!KSUCCESS(hcdPdoStatus)) {
DbgPrint("usb: xHCI controller PDO creation failed st=0x%x\n", hcdPdoStatus);
return hcdPdoStatus;
}
uint32_t portEnd = xhci->CapLength + XHCI_OP_PORT_BASE +
(uint32_t)xhci->MaxPorts * XHCI_OP_PORT_STRIDE;
uint32_t needBytes = portEnd;
if (xhci->DbOff + 0x100u > needBytes) needBytes = xhci->DbOff + 0x100u;
if (xhci->RtsOff + 0x1000u > needBytes) needBytes = xhci->RtsOff + 0x1000u;
if (needBytes < XHCI_MMIO_FLOOR_BYTES) needBytes = XHCI_MMIO_FLOOR_BYTES;
needBytes = UsbAlignUp32(needBytes, (uint32_t)PAGE_SIZE);
if (xhci->MmioBytes < needBytes) {
DbgPrint("usb: xHCI BAR0 too small length=0x%x need=0x%x dboff=0x%x rtsoff=0x%x ports=%u\n",
xhci->MmioBytes, needBytes, xhci->DbOff, xhci->RtsOff, xhci->MaxPorts);
return STATUS_DEVICE_ERROR;
}
st = UsbMapMmio(hal, xhci->MmioPhys, needBytes, &xhci->Mmio);
if (!KSUCCESS(st)) return st;
xhci->MmioBytes = needBytes;
xhci->Cap = xhci->Mmio;
xhci->Op = xhci->Mmio + xhci->CapLength;
xhci->Runtime = xhci->Mmio + xhci->RtsOff;
xhci->Doorbells = xhci->Mmio + xhci->DbOff;
DbgPrint("usb: xHCI init %u:%u.%u vendor=%04x device=%04x irq=%u%s mmio=0x%016llX caplen=%u version=%04x\n",
bus, dev, fn, vendor, device, xhci->Irq,
xhci->UsingMsi ? "(msi)" : "",
UsbInitializeHcd(&xhci->Hcd, &gXhciHcdOperations, xhci, 0, xhci->MaxPorts);
xhci->Hcd.ControllerDevice = xhci->Fdo;
DbgPrint("usb: xHCI init %02x:%02x.%x vendor=%04x device=%04x irq=%u mmio=0x%016llX caplen=%u version=%04x\n",
xhci->Bus, xhci->Dev, xhci->Fn,
xhci->PciInfo.VendorId, xhci->PciInfo.DeviceId,
xhci->Irq,
(unsigned long long)xhci->MmioPhys, xhci->CapLength, xhci->Version);
DbgPrint("usb: xHCI caps slots=%u intrs=%u ports=%u ctx=%u scratchpads=%u hcs2=%08x hcc1=%08x dboff=0x%x rtsoff=0x%x pagesize=%08x\n",
xhci->MaxSlots, xhci->MaxIntrs, xhci->MaxPorts, xhci->ContextBytes,
@@ -2021,12 +1984,18 @@ KSTATUS XhciInitialise(const HAL_API* hal,
return st;
}
st = XhciRegisterController(xhci);
if (!KSUCCESS(st)) {
DbgPrint("usb: xHCI controller registry full st=0x%x\n", st);
return st;
}
KeIrqRegister(xhci->Irq, XhciIsr);
XhciEnableInterrupts(xhci);
xhci->InterruptsEnabled = true;
xhci->Fdo->PnpState = DevicePnpStarted;
KeInsertQueueDpc(&xhci->EventDpc, (void*)0, (void*)0);
DbgPrint("usb: xHCI ISR registered on IRQ %u%s; event ring handled by DPC\n",
xhci->Irq, xhci->UsingMsi ? "(msi)" : "");
DbgPrint("usb: xHCI ISR registered on IRQ %u; event ring handled by DPC\n", xhci->Irq);
st = UsbHubScheduleRootScan(&xhci->Hcd);
if (!KSUCCESS(st))
@@ -2034,8 +2003,86 @@ KSTATUS XhciInitialise(const HAL_API* hal,
else
DbgPrint("usb: root hub initial scan queued asynchronously\n");
gHaveXhci = true;
DbgPrint("usb: xHCI host controller initialised; HID boot input active=%u mass-storage will arrive through hotplug\n",
xhci->HidDeviceCount);
return STATUS_SUCCESS;
}
KSTATUS XhciDispatchPnp(DEVICE_OBJECT* device, IRP* irp) {
if (!device || !irp || !device->DeviceExtension)
return STATUS_INVALID_PARAMETER;
XHCI_CONTROLLER* xhci = (XHCI_CONTROLLER*)device->DeviceExtension;
if (xhci->Magic != XHCI_CONTROLLER_MAGIC)
return STATUS_INVALID_PARAMETER;
IO_STACK_LOCATION* ios = IoGetCurrentIrpStackLocation(irp);
if (!ios) return STATUS_INVALID_PARAMETER;
switch ((IO_PNP_MINOR_FUNCTION)ios->MinorFunction) {
case IRP_MN_START_DEVICE:
return XhciStartController(xhci);
case IRP_MN_QUERY_REMOVE_DEVICE:
device->PnpState = DevicePnpRemovePending;
return STATUS_SUCCESS;
case IRP_MN_CANCEL_REMOVE_DEVICE:
device->PnpState = xhci->Running ? DevicePnpStarted : DevicePnpNotStarted;
return STATUS_SUCCESS;
case IRP_MN_SURPRISE_REMOVAL:
device->PnpState = DevicePnpSurpriseRemoved;
xhci->Running = false;
xhci->InterruptsEnabled = false;
if (xhci->Op) {
uint32_t cmd = XhciRead32(xhci->Op, XHCI_OP_USBCMD);
XhciWrite32(xhci->Op, XHCI_OP_USBCMD, cmd & ~XHCI_USBCMD_RS);
}
if (xhci->Hcd.RootHubPdo)
(void)UsbRemovePdoSubtree(xhci->Hcd.RootHubPdo, true);
return STATUS_SUCCESS;
case IRP_MN_REMOVE_DEVICE:
device->PnpState = DevicePnpDeleted;
xhci->Running = false;
xhci->InterruptsEnabled = false;
if (xhci->Hcd.RootHubPdo)
(void)UsbRemovePdoSubtree(xhci->Hcd.RootHubPdo, true);
IoDetachDevice(device);
IoDeleteDevice(device);
return STATUS_SUCCESS;
default:
return IoForwardIrpToLower(device, irp);
}
}
KSTATUS XhciAddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDeviceObject) {
if (!driver || !physicalDeviceObject || physicalDeviceObject->Type != DeviceObjectPhysical)
return STATUS_INVALID_PARAMETER;
DEVICE_OBJECT* fdo = (DEVICE_OBJECT*)0;
KSTATUS st = IoCreateDevice(driver, sizeof(XHCI_CONTROLLER), &fdo);
if (!KSUCCESS(st))
return st;
(void)IoSetDeviceName(fdo, SYS_SV_LITERAL("xhci-controller"));
XHCI_CONTROLLER* xhci = (XHCI_CONTROLLER*)fdo->DeviceExtension;
memset(xhci, 0, sizeof(*xhci));
xhci->Magic = XHCI_CONTROLLER_MAGIC;
xhci->Hal = gUsbHal;
xhci->Fdo = fdo;
xhci->Pdo = physicalDeviceObject;
xhci->Irq = 0xFFu;
KeInitializeDpc(&xhci->EventDpc, XhciEventDpcRoutine, xhci);
xhci->LowerDevice = IoAttachDeviceToDeviceStack(fdo, physicalDeviceObject);
if (!xhci->LowerDevice) {
IoDeleteDevice(fdo);
return STATUS_FAILURE;
}
DbgPrint("usb: xHCI FDO attached to %v\n", physicalDeviceObject->Name);
return STATUS_SUCCESS;
}
+3 -1
View File
@@ -1,10 +1,12 @@
[boot]
pci.sys
ps2.sys
ide.sys
ahci.sys
ata.sys
usb.sys
fat32.sys
[runtime]
lwip.sys
rtl8139.sys
rtl816x.sys
+274 -28
View File
@@ -101,6 +101,8 @@ typedef struct {
#define ATTR_DIRECTORY 0x10
#define ATTR_ARCHIVE 0x20
#define ATTR_LFN 0x0F
#define FAT_NTRES_BASE_LOWER 0x08u
#define FAT_NTRES_EXT_LOWER 0x10u
#define FAT32_EOC 0x0FFFFFF8u
#define FAT32_EOC_MARK 0x0FFFFFFFu
#define FAT32_FREE 0x00000000u
@@ -343,34 +345,186 @@ static void FreeClusterChain(FAT32_VOL *v, uint32_t start) {
}
// ---------------------------------------------------------------------------
// DIRENT update helpers
// FAT timestamp and DIRENT metadata helpers
// ---------------------------------------------------------------------------
static KSTATUS DirentUpdateSize(FAT32_VOL *v, uint64_t lba,
uint32_t offset, uint32_t size) {
typedef struct FAT32_ENCODED_TIME {
uint16_t Date;
uint16_t Time;
uint8_t CreateTimeTenth;
} FAT32_ENCODED_TIME;
typedef struct FAT32_DIRENT_UPDATE {
uint32_t Flags;
uint32_t Size;
uint32_t FirstCluster;
FAT32_ENCODED_TIME Timestamp;
} FAT32_DIRENT_UPDATE;
#define FAT32_DIRENT_UPDATE_SIZE 0x00000001u
#define FAT32_DIRENT_UPDATE_FIRST_CLUSTER 0x00000002u
#define FAT32_DIRENT_UPDATE_CREATE_TIME 0x00000004u
#define FAT32_DIRENT_UPDATE_WRITE_TIME 0x00000008u
#define FAT32_DIRENT_UPDATE_ACCESS_DATE 0x00000010u
static int FatIsLeapYear(uint32_t year) {
return ((year % 4u) == 0u && (year % 100u) != 0u) || ((year % 400u) == 0u);
}
static uint32_t FatDaysInMonth(uint32_t year, uint32_t month) {
static const uint8_t days[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
if (month < 1u || month > 12u) return 31u;
if (month == 2u && FatIsLeapYear(year)) return 29u;
return days[month - 1u];
}
static uint64_t FatCalendarToEpochSeconds(uint32_t year, uint32_t month, uint32_t day,
uint32_t hour, uint32_t minute, uint32_t second) {
uint64_t days = 0;
for (uint32_t y = 1970u; y < year; y++)
days += FatIsLeapYear(y) ? 366u : 365u;
for (uint32_t m = 1u; m < month; m++)
days += FatDaysInMonth(year, m);
days += day - 1u;
return (((days * 24u) + hour) * 60u + minute) * 60u + second;
}
static uint8_t FatDayOfWeek(uint32_t year, uint32_t month, uint32_t day) {
uint64_t epoch = FatCalendarToEpochSeconds(year, month, day, 0, 0, 0);
return (uint8_t)(((epoch / 86400u) + 4u) % 7u);
}
static uint16_t FatEncodeDate(const SYS_SYSTEM_TIME* t) {
uint32_t year = t && t->Year ? t->Year : 1980u;
uint32_t month = t && t->Month ? t->Month : 1u;
uint32_t day = t && t->Day ? t->Day : 1u;
if (year < 1980u) year = 1980u;
if (year > 2107u) year = 2107u;
if (month < 1u) month = 1u;
if (month > 12u) month = 12u;
uint32_t dim = FatDaysInMonth(year, month);
if (day < 1u) day = 1u;
if (day > dim) day = dim;
return (uint16_t)(((year - 1980u) << 9) | (month << 5) | day);
}
static uint16_t FatEncodeTime(const SYS_SYSTEM_TIME* t) {
uint32_t hour = t ? t->Hour : 0u;
uint32_t minute = t ? t->Minute : 0u;
uint32_t second = t ? t->Second : 0u;
if (hour > 23u) hour = 23u;
if (minute > 59u) minute = 59u;
if (second > 59u) second = 59u;
return (uint16_t)((hour << 11) | (minute << 5) | (second / 2u));
}
static uint8_t FatEncodeCreateTimeTenth(const SYS_SYSTEM_TIME* t) {
uint32_t second = t ? t->Second : 0u;
uint32_t ms = t ? t->Millisecond : 0u;
if (second > 59u) second = 59u;
if (ms > 999u) ms = 999u;
uint32_t v = ((second & 1u) * 100u) + (ms / 10u);
if (v > 199u) v = 199u;
return (uint8_t)v;
}
static void FatQueryEncodedTime(FAT32_ENCODED_TIME* out) {
SYS_SYSTEM_TIME now;
memset(&now, 0, sizeof(now));
if (KeQuerySystemTime(&now) != STATUS_SUCCESS) {
now.Year = 1980;
now.Month = 1;
now.Day = 1;
}
out->Date = FatEncodeDate(&now);
out->Time = FatEncodeTime(&now);
out->CreateTimeTenth = FatEncodeCreateTimeTenth(&now);
}
static void FatDecodeDateTime(uint16_t date, uint16_t time, uint8_t createTenth,
SYS_SYSTEM_TIME* out) {
memset(out, 0, sizeof(*out));
uint32_t year = 1980u + ((date >> 9) & 0x7Fu);
uint32_t month = (date >> 5) & 0x0Fu;
uint32_t day = date & 0x1Fu;
uint32_t hour = (time >> 11) & 0x1Fu;
uint32_t minute = (time >> 5) & 0x3Fu;
uint32_t second = (time & 0x1Fu) * 2u;
if (date == 0 || month < 1u || month > 12u) { year = 1980u; month = 1u; day = 1u; }
uint32_t dim = FatDaysInMonth(year, month);
if (day < 1u) day = 1u;
if (day > dim) day = dim;
if (hour > 23u) hour = 23u;
if (minute > 59u) minute = 59u;
if (second > 58u) second = 58u;
if (createTenth >= 100u && second < 59u) second++;
out->Year = (uint16_t)year;
out->Month = (uint8_t)month;
out->Day = (uint8_t)day;
out->Hour = (uint8_t)hour;
out->Minute = (uint8_t)minute;
out->Second = (uint8_t)second;
out->Millisecond = (uint16_t)((createTenth % 100u) * 10u);
out->DayOfWeek = FatDayOfWeek(year, month, day);
out->Flags = SYS_TIME_FLAG_VALID;
out->EpochSeconds = FatCalendarToEpochSeconds(year, month, day, hour, minute, second);
}
static void FatDecodeAccessDate(uint16_t date, SYS_SYSTEM_TIME* out) {
FatDecodeDateTime(date, 0, 0, out);
}
static KSTATUS DirentUpdateMetadata(FAT32_VOL *v, uint64_t lba,
uint32_t offset,
const FAT32_DIRENT_UPDATE* update) {
if (!v || !update || !update->Flags) return STATUS_INVALID_PARAMETER;
uint8_t *sec = (uint8_t *)MmAllocatePool(v->BytesPerSector);
if (!sec) return STATUS_NO_MEMORY;
KSTATUS s = ReadSectors(v, lba, 1, sec);
if (KSUCCESS(s)) {
((DIRENT *)(sec + offset))->FileSize = size;
DIRENT *d = (DIRENT *)(sec + offset);
if (update->Flags & FAT32_DIRENT_UPDATE_SIZE)
d->FileSize = update->Size;
if (update->Flags & FAT32_DIRENT_UPDATE_FIRST_CLUSTER) {
d->FirstClusterHi = (uint16_t)(update->FirstCluster >> 16);
d->FirstClusterLo = (uint16_t)(update->FirstCluster & 0xFFFF);
}
if (update->Flags & FAT32_DIRENT_UPDATE_CREATE_TIME) {
d->CrtTimeTenth = update->Timestamp.CreateTimeTenth;
d->CrtTime = update->Timestamp.Time;
d->CrtDate = update->Timestamp.Date;
}
if (update->Flags & FAT32_DIRENT_UPDATE_WRITE_TIME) {
d->WrtTime = update->Timestamp.Time;
d->WrtDate = update->Timestamp.Date;
}
if (update->Flags & FAT32_DIRENT_UPDATE_ACCESS_DATE)
d->LastAccDate = update->Timestamp.Date;
s = WriteSectors(v, lba, 1, sec);
}
MmFreePool(sec);
return s;
}
static KSTATUS DirentUpdateSize(FAT32_VOL *v, uint64_t lba,
uint32_t offset, uint32_t size) {
FAT32_DIRENT_UPDATE u;
memset(&u, 0, sizeof(u));
FatQueryEncodedTime(&u.Timestamp);
u.Flags = FAT32_DIRENT_UPDATE_SIZE | FAT32_DIRENT_UPDATE_WRITE_TIME;
u.Size = size;
return DirentUpdateMetadata(v, lba, offset, &u);
}
static KSTATUS DirentUpdateFirstCluster(FAT32_VOL *v, uint64_t lba,
uint32_t offset, uint32_t cluster) {
uint8_t *sec = (uint8_t *)MmAllocatePool(v->BytesPerSector);
if (!sec) return STATUS_NO_MEMORY;
KSTATUS s = ReadSectors(v, lba, 1, sec);
if (KSUCCESS(s)) {
DIRENT *d = (DIRENT *)(sec + offset);
d->FirstClusterHi = (uint16_t)(cluster >> 16);
d->FirstClusterLo = (uint16_t)(cluster & 0xFFFF);
s = WriteSectors(v, lba, 1, sec);
}
MmFreePool(sec);
return s;
FAT32_DIRENT_UPDATE u;
memset(&u, 0, sizeof(u));
u.Flags = FAT32_DIRENT_UPDATE_FIRST_CLUSTER;
u.FirstCluster = cluster;
return DirentUpdateMetadata(v, lba, offset, &u);
}
// ---------------------------------------------------------------------------
@@ -467,14 +621,67 @@ static int FatNameIsStructurallyShort83V(SYS_STRING_VIEW name) {
return baseLen >= 1 && baseLen <= 8 && extLen <= 3;
}
// Creation uses LFN when needed for structure, or when lowercase would be lost.
static int FatNameNeedsLfnForCreateV(SYS_STRING_VIEW name) {
if (!FatNameIsStructurallyShort83V(name)) return 1;
for (size_t i = 0; i < name.Length; i++)
static int FatComponentHasLowerV(SYS_STRING_VIEW name, size_t start, size_t end) {
for (size_t i = start; i < end; i++)
if (FatIsLowerChar(name.Data[i])) return 1;
return 0;
}
static int FatComponentHasUpperV(SYS_STRING_VIEW name, size_t start, size_t end) {
for (size_t i = start; i < end; i++)
if (name.Data[i] >= 'A' && name.Data[i] <= 'Z') return 1;
return 0;
}
static void FatSplitShortNameV(SYS_STRING_VIEW name, size_t* baseEnd,
size_t* extStart, size_t* extEnd) {
size_t dot = (size_t)-1;
for (size_t i = 0; i < name.Length; i++)
if (name.Data[i] == '.') dot = i;
if (dot == (size_t)-1) {
*baseEnd = name.Length;
*extStart = name.Length;
*extEnd = name.Length;
} else {
*baseEnd = dot;
*extStart = dot + 1u;
*extEnd = name.Length;
}
}
// Creation uses LFN only when the spelling cannot be represented by a short
// entry, or when mixed-case 8.3 spelling would be lost. Plain lowercase
// 8.3 names are represented with FAT's NT case bits, not VFAT LFN entries.
static int FatNameNeedsLfnForCreateV(SYS_STRING_VIEW name) {
if (!FatNameIsStructurallyShort83V(name)) return 1;
size_t baseEnd, extStart, extEnd;
FatSplitShortNameV(name, &baseEnd, &extStart, &extEnd);
int baseLower = FatComponentHasLowerV(name, 0, baseEnd);
int baseUpper = FatComponentHasUpperV(name, 0, baseEnd);
int extLower = FatComponentHasLowerV(name, extStart, extEnd);
int extUpper = FatComponentHasUpperV(name, extStart, extEnd);
if ((baseLower && baseUpper) || (extLower && extUpper)) return 1;
return 0;
}
static uint8_t FatShortNameCaseFlagsV(SYS_STRING_VIEW name) {
if (!FatNameIsStructurallyShort83V(name)) return 0;
size_t baseEnd, extStart, extEnd;
FatSplitShortNameV(name, &baseEnd, &extStart, &extEnd);
uint8_t flags = 0;
if (FatComponentHasLowerV(name, 0, baseEnd) &&
!FatComponentHasUpperV(name, 0, baseEnd))
flags |= FAT_NTRES_BASE_LOWER;
if (extStart < extEnd &&
FatComponentHasLowerV(name, extStart, extEnd) &&
!FatComponentHasUpperV(name, extStart, extEnd))
flags |= FAT_NTRES_EXT_LOWER;
return flags;
}
static uint8_t LfnChecksum(const char name8[8], const char ext3[3]) {
uint8_t sum = 0;
for (int i = 0; i < 11; i++) {
@@ -1218,9 +1425,17 @@ KSTATUS Fat32Write(IO_FILESYSTEM *fs, void *fileCtx,
MmFreePool(runBuf);
uint64_t newEnd = offset + written;
if (newEnd > f->FileSize) {
f->FileSize = (uint32_t)newEnd;
DirentUpdateSize(v, f->DirentLba, f->DirentOffset, f->FileSize);
if (written > 0) {
FAT32_DIRENT_UPDATE u;
memset(&u, 0, sizeof(u));
FatQueryEncodedTime(&u.Timestamp);
u.Flags = FAT32_DIRENT_UPDATE_WRITE_TIME;
if (newEnd > f->FileSize) {
f->FileSize = (uint32_t)newEnd;
u.Flags |= FAT32_DIRENT_UPDATE_SIZE;
u.Size = f->FileSize;
}
DirentUpdateMetadata(v, f->DirentLba, f->DirentOffset, &u);
}
*bytesWritten = written;
@@ -1316,6 +1531,17 @@ KSTATUS Fat32Create(IO_FILESYSTEM *fs, SYS_STRING_VIEW path, void **fileCtx) {
memcpy(d->Name, shortName, 8);
memcpy(d->Ext, shortExt, 3);
d->Attr = ATTR_ARCHIVE;
d->Reserved = FatShortNameCaseFlagsV(filenameView);
{
FAT32_ENCODED_TIME now;
FatQueryEncodedTime(&now);
d->CrtTimeTenth = now.CreateTimeTenth;
d->CrtTime = now.Time;
d->CrtDate = now.Date;
d->LastAccDate = now.Date;
d->WrtTime = now.Time;
d->WrtDate = now.Date;
}
s = WriteSectors(v, clusterLba, v->SectorsPerCluster, clusterBuf);
MmFreePool(clusterBuf);
@@ -1340,7 +1566,13 @@ KSTATUS Fat32Truncate(IO_FILESYSTEM *fs, void *fileCtx, uint64_t newSize) {
(void)fs;
FAT32_FILE *f = (FAT32_FILE *)fileCtx;
FAT32_VOL *v = f->Vol;
if ((uint32_t)newSize == f->FileSize) return STATUS_SUCCESS;
if ((uint32_t)newSize == f->FileSize) {
FAT32_DIRENT_UPDATE u;
memset(&u, 0, sizeof(u));
FatQueryEncodedTime(&u.Timestamp);
u.Flags = FAT32_DIRENT_UPDATE_WRITE_TIME;
return DirentUpdateMetadata(v, f->DirentLba, f->DirentOffset, &u);
}
if (newSize == 0) {
if (f->StartCluster >= 2) {
@@ -1495,6 +1727,8 @@ KSTATUS Fat32ReadDir(IO_FILESYSTEM *fs, void *dirCtx, KDIR_ENTRY *out) {
if (e->Attr == ATTR_LFN) { LfnAppend(ctx->LfnBuf, (LFN_ENTRY *)e); ctx->HasLfn = 1; continue; }
if (e->Attr & 0x08 && !(e->Attr & ATTR_DIRECTORY)) { ctx->HasLfn = 0; memset(ctx->LfnBuf, 0, sizeof(ctx->LfnBuf)); continue; }
memset(out, 0, sizeof(*out));
if (ctx->HasLfn && ctx->LfnBuf[0]) {
size_t len = strlen(ctx->LfnBuf);
if (len >= KDIR_NAME_MAX) len = KDIR_NAME_MAX - 1;
@@ -1513,7 +1747,11 @@ KSTATUS Fat32ReadDir(IO_FILESYSTEM *fs, void *dirCtx, KDIR_ENTRY *out) {
memcpy(out->Name, name83, len); out->Name[len] = '\0';
}
out->Attr = e->Attr; out->FileSize = e->FileSize;
out->Attr = e->Attr;
out->FileSize = e->FileSize;
FatDecodeDateTime(e->CrtDate, e->CrtTime, e->CrtTimeTenth, &out->CreateTime);
FatDecodeAccessDate(e->LastAccDate, &out->LastAccessTime);
FatDecodeDateTime(e->WrtDate, e->WrtTime, 0, &out->LastWriteTime);
ctx->HasLfn = 0; memset(ctx->LfnBuf, 0, sizeof(ctx->LfnBuf));
return STATUS_SUCCESS;
}
@@ -1993,10 +2231,18 @@ static void Fat32AsyncWriteIrpComplete(IRP* irp, void* completeCtx) {
static void Fat32AsyncWriteSubmitNext(FAT32_ASYNC_RW* ctx) {
if (ctx->Remaining == 0) {
uint64_t newEnd = ctx->Offset + ctx->Done;
if (newEnd > ctx->File->FileSize) {
ctx->File->FileSize = (uint32_t)newEnd;
DirentUpdateSize(ctx->Vol, ctx->File->DirentLba,
ctx->File->DirentOffset, ctx->File->FileSize);
if (ctx->Done > 0) {
FAT32_DIRENT_UPDATE u;
memset(&u, 0, sizeof(u));
FatQueryEncodedTime(&u.Timestamp);
u.Flags = FAT32_DIRENT_UPDATE_WRITE_TIME;
if (newEnd > ctx->File->FileSize) {
ctx->File->FileSize = (uint32_t)newEnd;
u.Flags |= FAT32_DIRENT_UPDATE_SIZE;
u.Size = ctx->File->FileSize;
}
DirentUpdateMetadata(ctx->Vol, ctx->File->DirentLba,
ctx->File->DirentOffset, &u);
}
Fat32AsyncFinish(ctx, STATUS_SUCCESS, ctx->Done);
return;
+1
View File
@@ -14,6 +14,7 @@
#include <kernel/ke_semaphore.h>
#include <kernel/ke_thread.h>
#include <kernel/ke_sched.h>
#include <kernel/ke_time.h>
typedef struct FAT32_VOL_S FAT32_VOL;
+276 -50
View File
@@ -2,8 +2,19 @@
#include "rtl8139.h"
const HAL_API* gHal;
RTL8139_DEVICE gDevice;
bool gDevicePresent = false;
static DRIVER_OBJECT gRtl8139Driver;
static RTL8139_DEVICE* gRtl8139Devices[RTL8139_MAX_DEVICES];
static uint32_t gRtl8139DeviceCount;
static SPINLOCK gRtl8139RegistryLock = SPINLOCK_INIT;
static const IO_DEVICE_ID gRtl8139Ids[] = {
{ IoBusPci, { "PCI\\VEN_10EC&DEV_8139", sizeof("PCI\\VEN_10EC&DEV_8139") - 1 } },
};
static const IO_DRIVER_ID_TABLE gRtl8139IdTable = {
gRtl8139Ids,
sizeof(gRtl8139Ids) / sizeof(gRtl8139Ids[0]),
};
static __forceinline void Rtl8139MemoryBarrier(void) {
_ReadWriteBarrier();
@@ -201,19 +212,68 @@ static void Rtl8139DpcRoutine(KDPC* dpc, void* context, void* systemArgument1, v
DbgPrint("RTL8139: interrupt error bits=0x%04x\n", status);
}
static KSTATUS Rtl8139RegisterDevice(RTL8139_DEVICE* r) {
if (!r) return STATUS_INVALID_PARAMETER;
uintptr_t flags = KeAcquireSpinlock(&gRtl8139RegistryLock);
for (uint32_t i = 0; i < gRtl8139DeviceCount; i++) {
if (gRtl8139Devices[i] == r) {
KeReleaseSpinlock(&gRtl8139RegistryLock, flags);
return STATUS_SUCCESS;
}
}
if (gRtl8139DeviceCount >= RTL8139_MAX_DEVICES) {
KeReleaseSpinlock(&gRtl8139RegistryLock, flags);
return STATUS_NO_MEMORY;
}
gRtl8139Devices[gRtl8139DeviceCount++] = r;
KeReleaseSpinlock(&gRtl8139RegistryLock, flags);
return STATUS_SUCCESS;
}
static void Rtl8139UnregisterDevice(RTL8139_DEVICE* r) {
if (!r) return;
uintptr_t flags = KeAcquireSpinlock(&gRtl8139RegistryLock);
for (uint32_t i = 0; i < gRtl8139DeviceCount; i++) {
if (gRtl8139Devices[i] == r) {
gRtl8139Devices[i] = gRtl8139Devices[gRtl8139DeviceCount - 1u];
gRtl8139Devices[gRtl8139DeviceCount - 1u] = (RTL8139_DEVICE*)0;
gRtl8139DeviceCount--;
break;
}
}
KeReleaseSpinlock(&gRtl8139RegistryLock, flags);
}
static void Rtl8139Isr(void) {
if (!gDevicePresent)
return;
RTL8139_DEVICE* snapshot[RTL8139_MAX_DEVICES];
uint32_t count = 0;
RTL8139_DEVICE* r = &gDevice;
uint16_t status = Rtl8139Read16(r, RTL8139_REG_ISR);
status &= RTL8139_INTR_ENABLES;
if (!status || status == 0xFFFFu)
return;
uintptr_t flags = KeAcquireSpinlock(&gRtl8139RegistryLock);
count = gRtl8139DeviceCount;
if (count > RTL8139_MAX_DEVICES)
count = RTL8139_MAX_DEVICES;
for (uint32_t i = 0; i < count; i++)
snapshot[i] = gRtl8139Devices[i];
KeReleaseSpinlock(&gRtl8139RegistryLock, flags);
Rtl8139Write16(r, RTL8139_REG_ISR, status);
r->PendingIsr |= status;
KeInsertQueueDpc(&r->Dpc, (void*)0, (void*)0);
for (uint32_t i = 0; i < count; i++) {
RTL8139_DEVICE* r = snapshot[i];
if (!r || !r->Started || r->Removed || r->SurpriseRemoved)
continue;
uint16_t status = Rtl8139Read16(r, RTL8139_REG_ISR);
status &= RTL8139_INTR_ENABLES;
if (!status || status == 0xFFFFu)
continue;
Rtl8139Write16(r, RTL8139_REG_ISR, status);
r->PendingIsr |= status;
KeInsertQueueDpc(&r->Dpc, (void*)0, (void*)0);
}
}
static KSTATUS Rtl8139SendFrame(NET_DEVICE* device, const void* frame, size_t length) {
@@ -252,76 +312,242 @@ static KSTATUS Rtl8139SendFrame(NET_DEVICE* device, const void* frame, size_t le
return STATUS_SUCCESS;
}
static KSTATUS Rtl8139Initialize(const HAL_API* hal) {
gHal = hal;
memset(&gDevice, 0, sizeof(gDevice));
gDevice.TxLock = (SPINLOCK)SPINLOCK_INIT;
static KSTATUS Rtl8139SelectRegisterBar(RTL8139_DEVICE* r) {
if (!r || !r->Pdo)
return STATUS_INVALID_PARAMETER;
if (!gHal->Pci.FindDevice(RTL8139_VENDOR_REALTEK, RTL8139_DEVICE_ID,
&gDevice.Bus, &gDevice.Dev, &gDevice.Fn)) {
DbgPrint("RTL8139: no PCI device 10ec:8139 found; skipping\n");
PCI_BAR best;
PCI_BAR fallback;
memset(&best, 0, sizeof(best));
memset(&fallback, 0, sizeof(fallback));
best.Type = PciBarUnused;
fallback.Type = PciBarUnused;
for (uint8_t i = 0; i < 6; i++) {
PCI_BAR bar;
KSTATUS st = PciGetBar(r->Pdo, i, &bar);
if (!KSUCCESS(st))
continue;
if (bar.Type == PciBarMemory32 || bar.Type == PciBarMemory64) {
best = bar;
break;
}
if (bar.Type == PciBarIo && fallback.Type == PciBarUnused)
fallback = bar;
}
if (best.Type == PciBarUnused)
best = fallback;
if (best.Type == PciBarMemory32 || best.Type == PciBarMemory64) {
KSTATUS st = PciMapBar(r->Pdo,
best.Index,
PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE,
(void**)&r->Mmio,
&r->RegisterBytes);
if (!KSUCCESS(st))
return st;
r->RegisterBar = best;
r->UseMmio = true;
DbgPrint("RTL8139: BAR%u MMIO base=0x%016llX len=0x%llx virt=0x%016llX\n",
best.Index,
(unsigned long long)best.Base,
(unsigned long long)r->RegisterBytes,
r->Mmio);
return STATUS_SUCCESS;
}
DbgPrint("RTL8139: found Realtek PCI device 10ec:8139 at %u:%u.%u\n",
gDevice.Bus, gDevice.Dev, gDevice.Fn);
if (best.Type == PciBarIo) {
if (best.Base > 0xFFFFu)
return STATUS_NOT_SUPPORTED;
KSTATUS st = Rtl8139SelectRegisterBar(&gDevice);
r->RegisterBar = best;
r->RegisterBytes = best.Length;
r->IoBase = (uint16_t)best.Base;
r->UseMmio = false;
DbgPrint("RTL8139: BAR%u I/O base=0x%04x len=0x%llx\n",
best.Index,
r->IoBase,
(unsigned long long)r->RegisterBytes);
return STATUS_SUCCESS;
}
return STATUS_NOT_FOUND;
}
static KSTATUS Rtl8139StartDevice(RTL8139_DEVICE* r) {
if (!r || r->Magic != RTL8139_DEVICE_MAGIC || !r->Pdo || !r->Fdo)
return STATUS_INVALID_PARAMETER;
if (r->Started)
return STATUS_SUCCESS;
KSTATUS st = PciGetDeviceInfo(r->Pdo, &r->PciInfo);
if (!KSUCCESS(st)) {
DbgPrint("RTL8139: PciGetDeviceInfo failed: 0x%x\n", st);
return st;
}
DbgPrint("RTL8139: controller at PCI %02x:%02x.%x vendor=%04x device=%04x\n",
r->PciInfo.Address.Bus,
r->PciInfo.Address.Device,
r->PciInfo.Address.Function,
r->PciInfo.VendorId,
r->PciInfo.DeviceId);
st = Rtl8139SelectRegisterBar(r);
if (!KSUCCESS(st)) {
DbgPrint("RTL8139: no usable register BAR (0x%x)\n", st);
return st;
}
Rtl8139EnablePci(&gDevice);
gDevice.Irq = hal->Pci.GetIrqLine(gDevice.Bus, gDevice.Dev, gDevice.Fn);
if (gDevice.Irq == 0xFFu) {
DbgPrint("RTL8139: no legacy PCI IRQ line wired\n");
return STATUS_NOT_SUPPORTED;
st = PciEnableDevice(r->Pdo,
PCI_ENABLE_BUSMASTER |
PCI_ENABLE_INTX |
(r->UseMmio ? PCI_ENABLE_MEMORY : PCI_ENABLE_IO));
if (!KSUCCESS(st)) {
DbgPrint("RTL8139: PciEnableDevice failed: 0x%x\n", st);
return st;
}
// Wake, reset, then read the station address.
Rtl8139Write8(&gDevice, RTL8139_REG_CONFIG1, 0x00);
st = Rtl8139Reset(&gDevice);
st = PciGetInterrupt(r->Pdo, &r->Irq);
if (!KSUCCESS(st) || r->Irq == 0xFFu) {
DbgPrint("RTL8139: no legacy PCI IRQ line wired\n");
return KSUCCESS(st) ? STATUS_NOT_SUPPORTED : st;
}
Rtl8139Write8(r, RTL8139_REG_CONFIG1, 0x00);
st = Rtl8139Reset(r);
if (!KSUCCESS(st)) {
DbgPrint("RTL8139: reset timed out\n");
return st;
}
Rtl8139ReadMac(&gDevice);
Rtl8139ReadMac(r);
DbgPrint("RTL8139: MAC %02x:%02x:%02x:%02x:%02x:%02x irq=%u\n",
gDevice.NetDevice.HardwareAddress[0], gDevice.NetDevice.HardwareAddress[1],
gDevice.NetDevice.HardwareAddress[2], gDevice.NetDevice.HardwareAddress[3],
gDevice.NetDevice.HardwareAddress[4], gDevice.NetDevice.HardwareAddress[5],
gDevice.Irq);
r->NetDevice.HardwareAddress[0], r->NetDevice.HardwareAddress[1],
r->NetDevice.HardwareAddress[2], r->NetDevice.HardwareAddress[3],
r->NetDevice.HardwareAddress[4], r->NetDevice.HardwareAddress[5],
r->Irq);
st = Rtl8139AllocateDma(&gDevice);
st = Rtl8139AllocateDma(r);
if (!KSUCCESS(st))
return st;
KeInitializeDpc(&gDevice.Dpc, Rtl8139DpcRoutine, &gDevice);
KeInitializeDpc(&r->Dpc, Rtl8139DpcRoutine, r);
gDevice.NetDevice.Mtu = NET_MTU_ETHERNET;
gDevice.NetDevice.DriverContext = &gDevice;
gDevice.NetDevice.SendFrame = Rtl8139SendFrame;
r->NetDevice.Mtu = NET_MTU_ETHERNET;
r->NetDevice.DriverContext = r;
r->NetDevice.SendFrame = Rtl8139SendFrame;
Rtl8139ProgramHardware(&gDevice);
gDevicePresent = true;
KeIrqRegister(gDevice.Irq, Rtl8139Isr);
st = NetRegisterDevice(&gDevice.NetDevice);
st = Rtl8139RegisterDevice(r);
if (!KSUCCESS(st))
return st;
DbgPrint("RTL8139: initialized; RX/TX enabled on IRQ %u\n", gDevice.Irq);
KeIrqRegister(r->Irq, Rtl8139Isr);
r->Started = true;
Rtl8139ProgramHardware(r);
r->Fdo->PnpState = DevicePnpStarted;
st = NetRegisterDevice(&r->NetDevice);
if (!KSUCCESS(st)) {
Rtl8139Write16(r, RTL8139_REG_IMR, 0);
r->Started = false;
Rtl8139UnregisterDevice(r);
return st;
}
DbgPrint("RTL8139: initialized; RX/TX enabled on IRQ %u\n", r->Irq);
return STATUS_SUCCESS;
}
KSTATUS Rtl8139DispatchPnp(DEVICE_OBJECT* device, IRP* irp) {
if (!device || !irp || !device->DeviceExtension)
return STATUS_INVALID_PARAMETER;
RTL8139_DEVICE* r = (RTL8139_DEVICE*)device->DeviceExtension;
if (r->Magic != RTL8139_DEVICE_MAGIC)
return STATUS_INVALID_PARAMETER;
IO_STACK_LOCATION* ios = IoGetCurrentIrpStackLocation(irp);
if (!ios || ios->MajorFunction != IRP_MJ_PNP)
return STATUS_INVALID_PARAMETER;
switch ((IO_PNP_MINOR_FUNCTION)ios->MinorFunction) {
case IRP_MN_START_DEVICE:
return Rtl8139StartDevice(r);
case IRP_MN_QUERY_REMOVE_DEVICE:
case IRP_MN_CANCEL_REMOVE_DEVICE:
return STATUS_SUCCESS;
case IRP_MN_SURPRISE_REMOVAL:
r->SurpriseRemoved = true;
device->PnpState = DevicePnpSurpriseRemoved;
if (r->Started)
Rtl8139Write16(r, RTL8139_REG_IMR, 0);
return STATUS_SUCCESS;
case IRP_MN_REMOVE_DEVICE:
r->Removed = true;
device->PnpState = DevicePnpDeleted;
if (r->Started)
Rtl8139Write16(r, RTL8139_REG_IMR, 0);
Rtl8139UnregisterDevice(r);
IoDetachDevice(device);
IoDeleteDevice(device);
return STATUS_SUCCESS;
default:
return IoForwardIrpToLower(device, irp);
}
}
KSTATUS Rtl8139AddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDeviceObject) {
if (!driver || !physicalDeviceObject || physicalDeviceObject->Type != DeviceObjectPhysical)
return STATUS_INVALID_PARAMETER;
DEVICE_OBJECT* fdo = (DEVICE_OBJECT*)0;
KSTATUS st = IoCreateDevice(driver, sizeof(RTL8139_DEVICE), &fdo);
if (!KSUCCESS(st))
return st;
(void)IoSetDeviceName(fdo, SYS_SV_LITERAL("rtl8139"));
RTL8139_DEVICE* r = (RTL8139_DEVICE*)fdo->DeviceExtension;
memset(r, 0, sizeof(*r));
r->Magic = RTL8139_DEVICE_MAGIC;
r->Fdo = fdo;
r->Pdo = physicalDeviceObject;
r->Irq = 0xFFu;
r->TxLock = (SPINLOCK)SPINLOCK_INIT;
r->LowerDevice = IoAttachDeviceToDeviceStack(fdo, physicalDeviceObject);
if (!r->LowerDevice) {
IoDeleteDevice(fdo);
return STATUS_FAILURE;
}
DbgPrint("RTL8139: FDO attached to %v\n", physicalDeviceObject->Name);
return STATUS_SUCCESS;
}
KSTATUS DriverEntry(const HAL_API* hal) {
if (!hal)
return STATUS_INVALID_PARAMETER;
DbgPrint("RTL8139: driver loading...\n");
KSTATUS st = Rtl8139Initialize(hal);
gHal = hal;
gRtl8139DeviceCount = 0;
memset(&gRtl8139Driver, 0, sizeof(gRtl8139Driver));
IoInitializeDriverObject(&gRtl8139Driver, SYS_SV_LITERAL("rtl8139"));
gRtl8139Driver.IdTable = &gRtl8139IdTable;
gRtl8139Driver.DriverAddDevice = Rtl8139AddDevice;
gRtl8139Driver.MajorFunction[IRP_MJ_PNP] = Rtl8139DispatchPnp;
KSTATUS st = IoRegisterDriverObject(&gRtl8139Driver);
if (!KSUCCESS(st))
DbgPrint("RTL8139: init failed: 0x%x\n", st);
DbgPrint("RTL8139: IoRegisterDriverObject failed: 0x%x\n", st);
return st;
}
+20 -29
View File
@@ -8,6 +8,8 @@
#include <intrin.h>
#include <ntlite/ddi/hal_api.h>
#include <ntlite/ddi/io_driver.h>
#include <ntlite/ddi/pci.h>
#include <ntlite/status.h>
#include <kernel/ke_debug.h>
#include <kernel/ke_irq.h>
@@ -20,12 +22,7 @@
#define RTL8139_VENDOR_REALTEK 0x10ECu
#define RTL8139_DEVICE_ID 0x8139u
#define PCI_REG_COMMAND 0x04u
#define PCI_REG_BAR0 0x10u
#define PCI_COMMAND_IO (1u << 0)
#define PCI_COMMAND_MEMORY (1u << 1)
#define PCI_COMMAND_MASTER (1u << 2)
#define PCI_COMMAND_INTX_DISABLE (1u << 10)
#define RTL8139_DEVICE_MAGIC 0x81390001u
#define RTL8139_REG_IDR0 0x00u
#define RTL8139_REG_MAR0 0x08u
@@ -91,30 +88,29 @@
#define RTL8139_RX_ALLOC_SIZE (RTL8139_RX_RING_SIZE + RTL8139_RX_PAD + RTL8139_RX_GUARD)
#define RTL8139_RX_PAGES ((RTL8139_RX_ALLOC_SIZE + 4095u) / 4096u)
#define RTL8139_TX_PAGES (((RTL8139_TX_SLOTS * RTL8139_TX_BUF_SIZE) + 4095u) / 4096u)
#define RTL8139_MMIO_PAGES 1u
#define RTL8139_RX_WIRE_MAX (NET_ETHERNET_MAX_FRAME + 4u)
#define RTL8139_RX_WIRE_MAX (NET_ETHERNET_MAX_FRAME + 4u)
#define RTL8139_REG_TSD(slot) (RTL8139_REG_TSD0 + ((slot) * 4u))
#define RTL8139_REG_TSAD(slot) (RTL8139_REG_TSAD0 + ((slot) * 4u))
typedef enum RTL8139_BAR_KIND {
Rtl8139BarNone = 0,
Rtl8139BarIo,
Rtl8139BarMmio,
} RTL8139_BAR_KIND;
typedef struct RTL8139_BAR {
RTL8139_BAR_KIND Kind;
uint64_t Base;
uint8_t Index;
} RTL8139_BAR;
#define RTL8139_MAX_DEVICES 8u
typedef struct RTL8139_DEVICE {
uint8_t Bus;
uint8_t Dev;
uint8_t Fn;
uint32_t Magic;
DEVICE_OBJECT* Fdo;
DEVICE_OBJECT* Pdo;
DEVICE_OBJECT* LowerDevice;
PCI_DEVICE_INFO PciInfo;
PCI_BAR RegisterBar;
uint64_t RegisterBytes;
uint8_t Irq;
bool Started;
bool Removed;
bool SurpriseRemoved;
bool UseMmio;
volatile uint8_t* Mmio;
uint16_t IoBase;
@@ -134,12 +130,7 @@ typedef struct RTL8139_DEVICE {
NET_DEVICE NetDevice;
} RTL8139_DEVICE;
extern const HAL_API* gHal;
extern RTL8139_DEVICE gDevice;
extern bool gDevicePresent;
bool Rtl8139ReadBar(uint8_t bus, uint8_t dev, uint8_t fn, uint8_t index, RTL8139_BAR* out);
KSTATUS Rtl8139MapMmio(uint64_t physBase, volatile uint8_t** outMmio);
KSTATUS Rtl8139SelectRegisterBar(RTL8139_DEVICE* r);
void Rtl8139EnablePci(RTL8139_DEVICE* r);
KSTATUS Rtl8139AddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDeviceObject);
KSTATUS Rtl8139DispatchPnp(DEVICE_OBJECT* device, IRP* irp);
+2 -112
View File
@@ -1,112 +1,2 @@
// rtl8139_pci.c - PCI BAR/MMIO front-end for rtl8139.
#include "rtl8139.h"
bool Rtl8139ReadBar(uint8_t bus, uint8_t dev, uint8_t fn, uint8_t index, RTL8139_BAR* out) {
uint8_t reg = (uint8_t)(PCI_REG_BAR0 + index * 4u);
uint32_t lo = gHal->Pci.Read32(bus, dev, fn, reg);
out->Kind = Rtl8139BarNone;
out->Base = 0;
out->Index = index;
if (lo == 0 || lo == 0xFFFFFFFFu)
return false;
if (lo & 1u) {
uint32_t base = lo & ~0x3u;
if (!base) return false;
out->Kind = Rtl8139BarIo;
out->Base = base;
return true;
}
uint64_t base = (uint64_t)(lo & ~0xFu);
uint32_t type = (lo >> 1) & 0x3u;
if (type == 0x2u && index < 5) {
uint32_t hi = gHal->Pci.Read32(bus, dev, fn, (uint8_t)(reg + 4u));
base |= ((uint64_t)hi << 32);
}
if (!base) return false;
out->Kind = Rtl8139BarMmio;
out->Base = base;
return true;
}
KSTATUS Rtl8139MapMmio(uint64_t physBase, volatile uint8_t** outMmio) {
uint64_t pageBase = physBase & PAGE_MASK;
uint64_t pageOff = physBase - pageBase;
for (uint32_t i = 0; i < RTL8139_MMIO_PAGES; i++) {
PHYSICAL_ADDRESS phys = pageBase + (uint64_t)i * PAGE_SIZE;
uintptr_t virt = (uintptr_t)gHal->PhysToVirt(phys);
KSTATUS st = MmMapPage(virt, phys, PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE, MmMapFailIfPresent);
if (st == STATUS_ALREADY_EXISTS)
st = MmSetPageProtect(virt, PAGE_SIZE, PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE);
if (!KSUCCESS(st))
return st;
}
*outMmio = (volatile uint8_t*)((uintptr_t)gHal->PhysToVirt(pageBase) + pageOff);
return STATUS_SUCCESS;
}
KSTATUS Rtl8139SelectRegisterBar(RTL8139_DEVICE* r) {
RTL8139_BAR best = { Rtl8139BarNone, 0, 0 };
RTL8139_BAR fallback = { Rtl8139BarNone, 0, 0 };
for (uint8_t i = 0; i < 6; i++) {
RTL8139_BAR bar;
if (!Rtl8139ReadBar(r->Bus, r->Dev, r->Fn, i, &bar))
continue;
if (bar.Kind == Rtl8139BarMmio) {
best = bar;
break;
}
if (bar.Kind == Rtl8139BarIo && fallback.Kind == Rtl8139BarNone)
fallback = bar;
if (bar.Kind == Rtl8139BarMmio) {
uint32_t lo = gHal->Pci.Read32(r->Bus, r->Dev, r->Fn, (uint8_t)(PCI_REG_BAR0 + i * 4u));
if (((lo >> 1) & 0x3u) == 0x2u)
i++;
}
}
if (best.Kind == Rtl8139BarNone)
best = fallback;
if (best.Kind == Rtl8139BarMmio) {
KSTATUS st = Rtl8139MapMmio(best.Base, &r->Mmio);
if (!KSUCCESS(st))
return st;
r->UseMmio = true;
DbgPrint("RTL8139: BAR%u MMIO base=0x%016llX virt=0x%016llX\n",
best.Index, (unsigned long long)best.Base, r->Mmio);
return STATUS_SUCCESS;
}
if (best.Kind == Rtl8139BarIo) {
if (best.Base > 0xFFFFu)
return STATUS_NOT_SUPPORTED;
r->IoBase = (uint16_t)best.Base;
r->UseMmio = false;
DbgPrint("RTL8139: BAR%u I/O base=0x%04x\n", best.Index, r->IoBase);
return STATUS_SUCCESS;
}
return STATUS_NOT_FOUND;
}
void Rtl8139EnablePci(RTL8139_DEVICE* r) {
uint32_t cmd = gHal->Pci.Read32(r->Bus, r->Dev, r->Fn, PCI_REG_COMMAND);
cmd |= PCI_COMMAND_MASTER;
if (r->UseMmio) cmd |= PCI_COMMAND_MEMORY;
else cmd |= PCI_COMMAND_IO;
cmd &= ~PCI_COMMAND_INTX_DISABLE;
gHal->Pci.Write32(r->Bus, r->Dev, r->Fn, PCI_REG_COMMAND, cmd);
}
// rtl8139_pci.c intentionally empty.
// PCI enumeration, BAR decoding, mapping, and command-register policy now live in pci.sys.
+283 -64
View File
@@ -1,9 +1,21 @@
// rtl816x.c - packet I/O, interrupt, and DriverEntry path.
// rtl816x.c - rtl8168/rtl8169 packet I/O, interrupt, and PCI function-driver path.
#include "rtl816x.h"
const HAL_API* gHal;
RTL816X_DEVICE gDevice;
bool gDevicePresent = false;
static DRIVER_OBJECT gRtl816xDriver;
static RTL816X_DEVICE* gRtl816xDevices[RTL816X_MAX_DEVICES];
static uint32_t gRtl816xDeviceCount;
static SPINLOCK gRtl816xRegistryLock = SPINLOCK_INIT;
static const IO_DEVICE_ID gRtl816xIds[] = {
{ IoBusPci, { "PCI\\VEN_10EC&DEV_8168", sizeof("PCI\\VEN_10EC&DEV_8168") - 1 } },
{ IoBusPci, { "PCI\\VEN_10EC&DEV_8169", sizeof("PCI\\VEN_10EC&DEV_8169") - 1 } },
};
static const IO_DRIVER_ID_TABLE gRtl816xIdTable = {
gRtl816xIds,
sizeof(gRtl816xIds) / sizeof(gRtl816xIds[0]),
};
static __forceinline void RtlMemoryBarrier(void) {
_ReadWriteBarrier();
@@ -44,11 +56,6 @@ static void RtlWrite32(RTL816X_DEVICE* r, uint32_t reg, uint32_t value) {
else __outdword((unsigned short)(r->IoBase + reg), value);
}
static KSTATUS RtlReset(RTL816X_DEVICE* r) {
RtlWrite8(r, RTL_REG_CHIP_CMD, RTL_CMD_RESET);
for (uint32_t i = 0; i < 1000; i++) {
@@ -116,14 +123,11 @@ static void RtlInitDescriptors(RTL816X_DEVICE* r) {
}
static void RtlProgramHardware(RTL816X_DEVICE* r) {
// Unlock the 9346-style config register window while programming.
RtlWrite8(r, RTL_REG_CFG9346, 0xC0);
// Disable interrupts while rings are being installed.
RtlWrite16(r, RTL_REG_INTR_MASK, 0);
RtlWrite16(r, RTL_REG_INTR_STAT, 0xFFFFu);
// DMA ring base addresses.
RtlWrite32(r, RTL_REG_TNPDS_LO, (uint32_t)r->TxRingPhys);
RtlWrite32(r, RTL_REG_TNPDS_HI, (uint32_t)(r->TxRingPhys >> 32));
RtlWrite32(r, RTL_REG_THPDS_LO, (uint32_t)r->TxRingPhys);
@@ -131,7 +135,6 @@ static void RtlProgramHardware(RTL816X_DEVICE* r) {
RtlWrite32(r, RTL_REG_RDSAR_LO, (uint32_t)r->RxRingPhys);
RtlWrite32(r, RTL_REG_RDSAR_HI, (uint32_t)(r->RxRingPhys >> 32));
// Plain packet mode. Keep C+ features mostly disabled for bring-up.
RtlWrite16(r, RTL_REG_CPLUS_CMD, RtlRead16(r, RTL_REG_CPLUS_CMD) & ~(uint16_t)0x00E0u);
RtlWrite16(r, RTL_REG_RX_MAXSIZE, RTL_BUF_SIZE);
@@ -141,10 +144,8 @@ static void RtlProgramHardware(RTL816X_DEVICE* r) {
RtlMemoryBarrier();
// Enable receiver and transmitter.
RtlWrite8(r, RTL_REG_CHIP_CMD, RTL_CMD_RX_ENABLE | RTL_CMD_TX_ENABLE);
// Lock config space again and enable selected interrupts.
RtlWrite8(r, RTL_REG_CFG9346, 0x00);
RtlWrite16(r, RTL_REG_INTR_STAT, 0xFFFFu);
RtlWrite16(r, RTL_REG_INTR_MASK, RTL_INTR_ENABLES);
@@ -164,8 +165,6 @@ static void RtlHandleRx(RTL816X_DEVICE* r) {
len >= NET_ETHERNET_HEADER_LENGTH && len <= RTL_RX_WIRE_MAX;
if (good) {
// Realtek reports the Ethernet FCS in the descriptor length on many
// chips. Remove it when present so upper layers see a normal frame.
if (len > 4)
len -= 4;
if (len > NET_ETHERNET_MAX_FRAME) {
@@ -195,6 +194,9 @@ static void RtlDpcRoutine(KDPC* dpc, void* context, void* systemArgument1, void*
(void)systemArgument2;
RTL816X_DEVICE* r = (RTL816X_DEVICE*)context;
if (!r || r->Removed || r->SurpriseRemoved)
return;
uint16_t status = (uint16_t)r->PendingIsr;
r->PendingIsr = 0;
@@ -210,18 +212,68 @@ static void RtlDpcRoutine(KDPC* dpc, void* context, void* systemArgument1, void*
DbgPrint("RTL816X: interrupt status error bits=0x%04x\n", status);
}
static KSTATUS RtlRegisterDevice(RTL816X_DEVICE* r) {
if (!r) return STATUS_INVALID_PARAMETER;
uintptr_t flags = KeAcquireSpinlock(&gRtl816xRegistryLock);
for (uint32_t i = 0; i < gRtl816xDeviceCount; i++) {
if (gRtl816xDevices[i] == r) {
KeReleaseSpinlock(&gRtl816xRegistryLock, flags);
return STATUS_SUCCESS;
}
}
if (gRtl816xDeviceCount >= RTL816X_MAX_DEVICES) {
KeReleaseSpinlock(&gRtl816xRegistryLock, flags);
return STATUS_NO_MEMORY;
}
gRtl816xDevices[gRtl816xDeviceCount++] = r;
KeReleaseSpinlock(&gRtl816xRegistryLock, flags);
return STATUS_SUCCESS;
}
static void RtlUnregisterDevice(RTL816X_DEVICE* r) {
if (!r) return;
uintptr_t flags = KeAcquireSpinlock(&gRtl816xRegistryLock);
for (uint32_t i = 0; i < gRtl816xDeviceCount; i++) {
if (gRtl816xDevices[i] == r) {
gRtl816xDevices[i] = gRtl816xDevices[gRtl816xDeviceCount - 1u];
gRtl816xDevices[gRtl816xDeviceCount - 1u] = (RTL816X_DEVICE*)0;
gRtl816xDeviceCount--;
break;
}
}
KeReleaseSpinlock(&gRtl816xRegistryLock, flags);
}
static void RtlIsr(void) {
if (!gDevicePresent)
return;
RTL816X_DEVICE* snapshot[RTL816X_MAX_DEVICES];
uint32_t count = 0;
RTL816X_DEVICE* r = &gDevice;
uint16_t status = RtlRead16(r, RTL_REG_INTR_STAT);
if (!status || status == 0xFFFFu)
return;
uintptr_t flags = KeAcquireSpinlock(&gRtl816xRegistryLock);
count = gRtl816xDeviceCount;
if (count > RTL816X_MAX_DEVICES)
count = RTL816X_MAX_DEVICES;
for (uint32_t i = 0; i < count; i++)
snapshot[i] = gRtl816xDevices[i];
KeReleaseSpinlock(&gRtl816xRegistryLock, flags);
RtlWrite16(r, RTL_REG_INTR_STAT, status);
r->PendingIsr |= status;
KeInsertQueueDpc(&r->Dpc, (void*)0, (void*)0);
for (uint32_t i = 0; i < count; i++) {
RTL816X_DEVICE* r = snapshot[i];
if (!r || !r->Started || r->Removed || r->SurpriseRemoved)
continue;
uint16_t status = RtlRead16(r, RTL_REG_INTR_STAT);
status &= RTL_INTR_ENABLES;
if (!status || status == 0xFFFFu)
continue;
RtlWrite16(r, RTL_REG_INTR_STAT, status);
r->PendingIsr |= status;
KeInsertQueueDpc(&r->Dpc, (void*)0, (void*)0);
}
}
static KSTATUS RtlSendFrame(NET_DEVICE* device, const void* frame, size_t length) {
@@ -233,8 +285,8 @@ static KSTATUS RtlSendFrame(NET_DEVICE* device, const void* frame, size_t length
return STATUS_INVALID_PARAMETER;
RTL816X_DEVICE* r = (RTL816X_DEVICE*)device->DriverContext;
if (!r)
return STATUS_INVALID_PARAMETER;
if (!r || !r->Started || r->Removed || r->SurpriseRemoved)
return STATUS_OBJECT_DEAD;
uintptr_t flags = KeAcquireSpinlock(&r->TxLock);
uint32_t index = r->TxIndex;
@@ -263,75 +315,242 @@ static KSTATUS RtlSendFrame(NET_DEVICE* device, const void* frame, size_t length
return STATUS_SUCCESS;
}
static KSTATUS RtlInitialize(const HAL_API* hal) {
gHal = hal;
memset(&gDevice, 0, sizeof(gDevice));
gDevice.TxLock = (SPINLOCK)SPINLOCK_INIT;
static KSTATUS RtlSelectRegisterBar(RTL816X_DEVICE* r) {
if (!r || !r->Pdo)
return STATUS_INVALID_PARAMETER;
uint16_t deviceId;
if (!RtlFindDevice(&gDevice.Bus, &gDevice.Dev, &gDevice.Fn, &deviceId)) {
DbgPrint("RTL816X: no RTL8168/RTL8169 PCI device found; skipping\n");
PCI_BAR best;
PCI_BAR fallback;
memset(&best, 0, sizeof(best));
memset(&fallback, 0, sizeof(fallback));
best.Type = PciBarUnused;
fallback.Type = PciBarUnused;
for (uint8_t i = 0; i < 6; i++) {
PCI_BAR bar;
KSTATUS st = PciGetBar(r->Pdo, i, &bar);
if (!KSUCCESS(st))
continue;
if (bar.Type == PciBarMemory32 || bar.Type == PciBarMemory64) {
best = bar;
break;
}
if (bar.Type == PciBarIo && fallback.Type == PciBarUnused)
fallback = bar;
}
if (best.Type == PciBarUnused)
best = fallback;
if (best.Type == PciBarMemory32 || best.Type == PciBarMemory64) {
KSTATUS st = PciMapBar(r->Pdo,
best.Index,
PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE,
(void**)&r->Mmio,
&r->RegisterBytes);
if (!KSUCCESS(st))
return st;
r->RegisterBar = best;
r->UseMmio = true;
DbgPrint("RTL816X: BAR%u MMIO base=0x%016llX len=0x%llx virt=0x%016llX\n",
best.Index,
(unsigned long long)best.Base,
(unsigned long long)r->RegisterBytes,
r->Mmio);
return STATUS_SUCCESS;
}
gDevice.DeviceId = deviceId;
DbgPrint("RTL816X: found Realtek PCI device 10ec:%04x at %u:%u.%u\n",
deviceId, gDevice.Bus, gDevice.Dev, gDevice.Fn);
if (best.Type == PciBarIo) {
if (best.Base > 0xFFFFu)
return STATUS_NOT_SUPPORTED;
KSTATUS st = RtlSelectRegisterBar(&gDevice);
r->RegisterBar = best;
r->RegisterBytes = best.Length;
r->IoBase = (uint16_t)best.Base;
r->UseMmio = false;
DbgPrint("RTL816X: BAR%u I/O base=0x%04x len=0x%llx\n",
best.Index,
r->IoBase,
(unsigned long long)r->RegisterBytes);
return STATUS_SUCCESS;
}
return STATUS_NOT_FOUND;
}
static KSTATUS RtlStartDevice(RTL816X_DEVICE* r) {
if (!r || r->Magic != RTL816X_DEVICE_MAGIC || !r->Pdo || !r->Fdo)
return STATUS_INVALID_PARAMETER;
if (r->Started)
return STATUS_SUCCESS;
KSTATUS st = PciGetDeviceInfo(r->Pdo, &r->PciInfo);
if (!KSUCCESS(st)) {
DbgPrint("RTL816X: PciGetDeviceInfo failed: 0x%x\n", st);
return st;
}
DbgPrint("RTL816X: controller at PCI %02x:%02x.%x vendor=%04x device=%04x\n",
r->PciInfo.Address.Bus,
r->PciInfo.Address.Device,
r->PciInfo.Address.Function,
r->PciInfo.VendorId,
r->PciInfo.DeviceId);
st = RtlSelectRegisterBar(r);
if (!KSUCCESS(st)) {
DbgPrint("RTL816X: no usable register BAR (0x%x)\n", st);
return st;
}
RtlEnablePci(&gDevice);
gDevice.Irq = hal->Pci.GetIrqLine(gDevice.Bus, gDevice.Dev, gDevice.Fn);
if (gDevice.Irq == 0xFFu) {
DbgPrint("RTL816X: no legacy PCI IRQ line wired\n");
return STATUS_NOT_SUPPORTED;
st = PciEnableDevice(r->Pdo,
PCI_ENABLE_BUSMASTER |
PCI_ENABLE_INTX |
(r->UseMmio ? PCI_ENABLE_MEMORY : PCI_ENABLE_IO));
if (!KSUCCESS(st)) {
DbgPrint("RTL816X: PciEnableDevice failed: 0x%x\n", st);
return st;
}
st = RtlReset(&gDevice);
st = PciGetInterrupt(r->Pdo, &r->Irq);
if (!KSUCCESS(st) || r->Irq == 0xFFu) {
DbgPrint("RTL816X: no legacy PCI IRQ line wired\n");
return KSUCCESS(st) ? STATUS_NOT_SUPPORTED : st;
}
st = RtlReset(r);
if (!KSUCCESS(st)) {
DbgPrint("RTL816X: reset timed out\n");
return st;
}
RtlReadMac(&gDevice);
RtlReadMac(r);
DbgPrint("RTL816X: MAC %02x:%02x:%02x:%02x:%02x:%02x irq=%u\n",
gDevice.NetDevice.HardwareAddress[0], gDevice.NetDevice.HardwareAddress[1],
gDevice.NetDevice.HardwareAddress[2], gDevice.NetDevice.HardwareAddress[3],
gDevice.NetDevice.HardwareAddress[4], gDevice.NetDevice.HardwareAddress[5],
gDevice.Irq);
r->NetDevice.HardwareAddress[0], r->NetDevice.HardwareAddress[1],
r->NetDevice.HardwareAddress[2], r->NetDevice.HardwareAddress[3],
r->NetDevice.HardwareAddress[4], r->NetDevice.HardwareAddress[5],
r->Irq);
st = RtlAllocateDma(&gDevice);
st = RtlAllocateDma(r);
if (!KSUCCESS(st))
return st;
RtlInitDescriptors(&gDevice);
KeInitializeDpc(&gDevice.Dpc, RtlDpcRoutine, &gDevice);
RtlInitDescriptors(r);
KeInitializeDpc(&r->Dpc, RtlDpcRoutine, r);
gDevice.NetDevice.Mtu = NET_MTU_ETHERNET;
gDevice.NetDevice.DriverContext = &gDevice;
gDevice.NetDevice.SendFrame = RtlSendFrame;
RtlProgramHardware(&gDevice);
r->NetDevice.Mtu = NET_MTU_ETHERNET;
r->NetDevice.DriverContext = r;
r->NetDevice.SendFrame = RtlSendFrame;
gDevicePresent = true;
KeIrqRegister(gDevice.Irq, RtlIsr);
st = NetRegisterDevice(&gDevice.NetDevice);
st = RtlRegisterDevice(r);
if (!KSUCCESS(st))
return st;
DbgPrint("RTL816X: initialized; RX/TX enabled on IRQ %u\n", gDevice.Irq);
KeIrqRegister(r->Irq, RtlIsr);
r->Started = true;
RtlProgramHardware(r);
r->Fdo->PnpState = DevicePnpStarted;
st = NetRegisterDevice(&r->NetDevice);
if (!KSUCCESS(st)) {
RtlWrite16(r, RTL_REG_INTR_MASK, 0);
r->Started = false;
RtlUnregisterDevice(r);
return st;
}
DbgPrint("RTL816X: initialized; RX/TX enabled on IRQ %u\n", r->Irq);
return STATUS_SUCCESS;
}
KSTATUS Rtl816xDispatchPnp(DEVICE_OBJECT* device, IRP* irp) {
if (!device || !irp || !device->DeviceExtension)
return STATUS_INVALID_PARAMETER;
RTL816X_DEVICE* r = (RTL816X_DEVICE*)device->DeviceExtension;
if (r->Magic != RTL816X_DEVICE_MAGIC)
return STATUS_INVALID_PARAMETER;
IO_STACK_LOCATION* ios = IoGetCurrentIrpStackLocation(irp);
if (!ios || ios->MajorFunction != IRP_MJ_PNP)
return STATUS_INVALID_PARAMETER;
switch ((IO_PNP_MINOR_FUNCTION)ios->MinorFunction) {
case IRP_MN_START_DEVICE:
return RtlStartDevice(r);
case IRP_MN_QUERY_REMOVE_DEVICE:
case IRP_MN_CANCEL_REMOVE_DEVICE:
return STATUS_SUCCESS;
case IRP_MN_SURPRISE_REMOVAL:
r->SurpriseRemoved = true;
device->PnpState = DevicePnpSurpriseRemoved;
if (r->Started)
RtlWrite16(r, RTL_REG_INTR_MASK, 0);
return STATUS_SUCCESS;
case IRP_MN_REMOVE_DEVICE:
r->Removed = true;
device->PnpState = DevicePnpDeleted;
if (r->Started)
RtlWrite16(r, RTL_REG_INTR_MASK, 0);
RtlUnregisterDevice(r);
IoDetachDevice(device);
IoDeleteDevice(device);
return STATUS_SUCCESS;
default:
return IoForwardIrpToLower(device, irp);
}
}
KSTATUS Rtl816xAddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDeviceObject) {
if (!driver || !physicalDeviceObject || physicalDeviceObject->Type != DeviceObjectPhysical)
return STATUS_INVALID_PARAMETER;
DEVICE_OBJECT* fdo = (DEVICE_OBJECT*)0;
KSTATUS st = IoCreateDevice(driver, sizeof(RTL816X_DEVICE), &fdo);
if (!KSUCCESS(st))
return st;
(void)IoSetDeviceName(fdo, SYS_SV_LITERAL("rtl816x"));
RTL816X_DEVICE* r = (RTL816X_DEVICE*)fdo->DeviceExtension;
memset(r, 0, sizeof(*r));
r->Magic = RTL816X_DEVICE_MAGIC;
r->Fdo = fdo;
r->Pdo = physicalDeviceObject;
r->Irq = 0xFFu;
r->TxLock = (SPINLOCK)SPINLOCK_INIT;
r->LowerDevice = IoAttachDeviceToDeviceStack(fdo, physicalDeviceObject);
if (!r->LowerDevice) {
IoDeleteDevice(fdo);
return STATUS_FAILURE;
}
DbgPrint("RTL816X: FDO attached to %v\n", physicalDeviceObject->Name);
return STATUS_SUCCESS;
}
KSTATUS DriverEntry(const HAL_API* hal) {
if (!hal)
return STATUS_INVALID_PARAMETER;
DbgPrint("RTL816X: driver loading...\n");
KSTATUS st = RtlInitialize(hal);
gHal = hal;
gRtl816xDeviceCount = 0;
memset(&gRtl816xDriver, 0, sizeof(gRtl816xDriver));
IoInitializeDriverObject(&gRtl816xDriver, SYS_SV_LITERAL("rtl816x"));
gRtl816xDriver.IdTable = &gRtl816xIdTable;
gRtl816xDriver.DriverAddDevice = Rtl816xAddDevice;
gRtl816xDriver.MajorFunction[IRP_MJ_PNP] = Rtl816xDispatchPnp;
KSTATUS st = IoRegisterDriverObject(&gRtl816xDriver);
if (!KSUCCESS(st))
DbgPrint("RTL816X: init failed: 0x%x\n", st);
DbgPrint("RTL816X: IoRegisterDriverObject failed: 0x%x\n", st);
return st;
}
+20 -33
View File
@@ -1,4 +1,4 @@
// rtl816x.h - shared rtl816x driver internals.
// rtl816x.h - shared rtl8168/rtl8169 driver internals.
#pragma once
#include <stdint.h>
@@ -8,6 +8,8 @@
#include <intrin.h>
#include <ntlite/ddi/hal_api.h>
#include <ntlite/ddi/io_driver.h>
#include <ntlite/ddi/pci.h>
#include <ntlite/status.h>
#include <kernel/ke_debug.h>
#include <kernel/ke_irq.h>
@@ -21,13 +23,8 @@
#define RTL_DEVICE_8168 0x8168u
#define RTL_DEVICE_8169 0x8169u
#define PCI_REG_COMMAND 0x04u
#define PCI_REG_BAR0 0x10u
#define PCI_REG_IRQ 0x3Cu
#define PCI_COMMAND_IO (1u << 0)
#define PCI_COMMAND_MEMORY (1u << 1)
#define PCI_COMMAND_MASTER (1u << 2)
#define PCI_COMMAND_INTX_DISABLE (1u << 10)
#define RTL816X_DEVICE_MAGIC 0x81690001u
#define RTL816X_MAX_DEVICES 8u
#define RTL_REG_MAC0 0x00u
#define RTL_REG_MAR0 0x08u
@@ -99,7 +96,6 @@
#define RTL_RING_PAGES 1u
#define RTL_RXBUF_PAGES ((RTL_RX_COUNT * RTL_BUF_SIZE + 4095u) / 4096u)
#define RTL_TXBUF_PAGES ((RTL_TX_COUNT * RTL_BUF_SIZE + 4095u) / 4096u)
#define RTL_MMIO_PAGES 1u
#pragma pack(push, 1)
typedef struct RTL_DESC {
@@ -110,24 +106,21 @@ typedef struct RTL_DESC {
} RTL_DESC;
#pragma pack(pop)
typedef enum RTL_BAR_KIND {
RtlBarNone = 0,
RtlBarIo,
RtlBarMmio,
} RTL_BAR_KIND;
typedef struct RTL_BAR {
RTL_BAR_KIND Kind;
uint64_t Base;
uint8_t Index;
} RTL_BAR;
typedef struct RTL816X_DEVICE {
uint8_t Bus;
uint8_t Dev;
uint8_t Fn;
uint32_t Magic;
DEVICE_OBJECT* Fdo;
DEVICE_OBJECT* Pdo;
DEVICE_OBJECT* LowerDevice;
PCI_DEVICE_INFO PciInfo;
PCI_BAR RegisterBar;
uint64_t RegisterBytes;
uint8_t Irq;
uint16_t DeviceId;
bool Started;
bool Removed;
bool SurpriseRemoved;
bool UseMmio;
volatile uint8_t* Mmio;
@@ -152,13 +145,7 @@ typedef struct RTL816X_DEVICE {
NET_DEVICE NetDevice;
} RTL816X_DEVICE;
extern const HAL_API* gHal;
extern RTL816X_DEVICE gDevice;
extern bool gDevicePresent;
bool RtlFindDevice(uint8_t* outBus, uint8_t* outDev, uint8_t* outFn, uint16_t* outDeviceId);
bool RtlReadBar(uint8_t bus, uint8_t dev, uint8_t fn, uint8_t index, RTL_BAR* out);
KSTATUS RtlMapMmio(uint64_t physBase, volatile uint8_t** outMmio);
KSTATUS RtlSelectRegisterBar(RTL816X_DEVICE* r);
void RtlEnablePci(RTL816X_DEVICE* r);
KSTATUS Rtl816xAddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDeviceObject);
KSTATUS Rtl816xDispatchPnp(DEVICE_OBJECT* device, IRP* irp);
-126
View File
@@ -1,126 +0,0 @@
// rtl816x_pci.c - PCI BAR/MMIO front-end for rtl816x.
#include "rtl816x.h"
bool RtlFindDevice(uint8_t* outBus, uint8_t* outDev, uint8_t* outFn, uint16_t* outDeviceId) {
if (gHal->Pci.FindDevice(RTL_VENDOR_REALTEK, RTL_DEVICE_8168, outBus, outDev, outFn)) {
*outDeviceId = RTL_DEVICE_8168;
return true;
}
if (gHal->Pci.FindDevice(RTL_VENDOR_REALTEK, RTL_DEVICE_8169, outBus, outDev, outFn)) {
*outDeviceId = RTL_DEVICE_8169;
return true;
}
return false;
}
bool RtlReadBar(uint8_t bus, uint8_t dev, uint8_t fn, uint8_t index, RTL_BAR* out) {
uint8_t reg = (uint8_t)(PCI_REG_BAR0 + index * 4u);
uint32_t lo = gHal->Pci.Read32(bus, dev, fn, reg);
out->Kind = RtlBarNone;
out->Base = 0;
out->Index = index;
if (lo == 0 || lo == 0xFFFFFFFFu)
return false;
if (lo & 1u) {
uint32_t base = lo & ~0x3u;
if (!base) return false;
out->Kind = RtlBarIo;
out->Base = base;
return true;
}
uint64_t base = (uint64_t)(lo & ~0xFu);
uint32_t type = (lo >> 1) & 0x3u;
if (type == 0x2u && index < 5) {
uint32_t hi = gHal->Pci.Read32(bus, dev, fn, (uint8_t)(reg + 4u));
base |= ((uint64_t)hi << 32);
}
if (!base) return false;
out->Kind = RtlBarMmio;
out->Base = base;
return true;
}
KSTATUS RtlMapMmio(uint64_t physBase, volatile uint8_t** outMmio) {
uint64_t pageBase = physBase & PAGE_MASK;
uint64_t pageOff = physBase - pageBase;
for (uint32_t i = 0; i < RTL_MMIO_PAGES; i++) {
PHYSICAL_ADDRESS phys = pageBase + (uint64_t)i * PAGE_SIZE;
uintptr_t virt = (uintptr_t)gHal->PhysToVirt(phys);
KSTATUS st = MmMapPage(virt, phys, PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE, MmMapFailIfPresent);
if (st == STATUS_ALREADY_EXISTS)
st = MmSetPageProtect(virt, PAGE_SIZE, PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE);
if (!KSUCCESS(st))
return st;
}
*outMmio = (volatile uint8_t*)((uintptr_t)gHal->PhysToVirt(pageBase) + pageOff);
return STATUS_SUCCESS;
}
KSTATUS RtlSelectRegisterBar(RTL816X_DEVICE* r) {
RTL_BAR best = { RtlBarNone, 0, 0 };
RTL_BAR fallback = { RtlBarNone, 0, 0 };
for (uint8_t i = 0; i < 6; i++) {
RTL_BAR bar;
if (!RtlReadBar(r->Bus, r->Dev, r->Fn, i, &bar))
continue;
if (bar.Kind == RtlBarMmio) {
best = bar;
break;
}
if (bar.Kind == RtlBarIo && fallback.Kind == RtlBarNone)
fallback = bar;
// Skip the high dword of 64-bit memory BARs.
if (bar.Kind == RtlBarMmio) {
uint32_t lo = gHal->Pci.Read32(r->Bus, r->Dev, r->Fn, (uint8_t)(PCI_REG_BAR0 + i * 4u));
if (((lo >> 1) & 0x3u) == 0x2u)
i++;
}
}
if (best.Kind == RtlBarNone)
best = fallback;
if (best.Kind == RtlBarMmio) {
KSTATUS st = RtlMapMmio(best.Base, &r->Mmio);
if (!KSUCCESS(st))
return st;
r->UseMmio = true;
DbgPrint("RTL816X: BAR%u MMIO base=0x%016llX virt=0x%016llX\n",
best.Index, (unsigned long long)best.Base, r->Mmio);
return STATUS_SUCCESS;
}
if (best.Kind == RtlBarIo) {
if (best.Base > 0xFFFFu)
return STATUS_NOT_SUPPORTED;
r->IoBase = (uint16_t)best.Base;
r->UseMmio = false;
DbgPrint("RTL816X: BAR%u I/O base=0x%04x\n", best.Index, r->IoBase);
return STATUS_SUCCESS;
}
return STATUS_NOT_FOUND;
}
void RtlEnablePci(RTL816X_DEVICE* r) {
uint32_t cmd = gHal->Pci.Read32(r->Bus, r->Dev, r->Fn, PCI_REG_COMMAND);
cmd |= PCI_COMMAND_MASTER;
if (r->UseMmio) cmd |= PCI_COMMAND_MEMORY;
else cmd |= PCI_COMMAND_IO;
cmd &= ~PCI_COMMAND_INTX_DISABLE;
gHal->Pci.Write32(r->Bus, r->Dev, r->Fn, PCI_REG_COMMAND, cmd);
}
+246 -104
View File
@@ -2,17 +2,26 @@
#include "ahci.h"
const HAL_API *g_hal;
HBA_MEM *g_hba;
uint8_t g_irq;
DRIVER_OBJECT g_driver;
AHCI_DRIVE g_drives[MAX_AHCI_DRIVES];
int g_driveCount;
static AHCI_CONTROLLER* g_controllers[MAX_AHCI_CONTROLLERS];
static int g_controllerCount;
static uint8_t g_nextDiskIndex;
static const IO_DEVICE_ID g_ahciIds[] = {
{ IoBusPci, { "PCI\\CC_010601", sizeof("PCI\\CC_010601") - 1 } },
};
static const IO_DRIVER_ID_TABLE g_ahciIdTable = {
g_ahciIds,
sizeof(g_ahciIds) / sizeof(g_ahciIds[0]),
};
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
static KSTATUS AhciStartController(AHCI_CONTROLLER* ctl);
// Accessors for port structure memory at known offsets from structVirt/Phys
static inline HBA_CMD_HEADER *cmd_list(AHCI_DRIVE *drv) {
@@ -166,29 +175,34 @@ static void AhciCompletionDpc(KDPC *dpc, void *context,
// ---------------------------------------------------------------------------
static void AhciIsr(void) {
if (!g_hba) return;
for (int c = 0; c < g_controllerCount; c++) {
AHCI_CONTROLLER* ctl = g_controllers[c];
if (!ctl || !ctl->hba || ctl->removed)
continue;
// GHC.IS tells us which ports are pending.
uint32_t pending = g_hba->is;
if (!pending) return;
// GHC.IS tells us which ports are pending for this HBA.
uint32_t pending = ctl->hba->is;
if (!pending)
continue;
for (int i = 0; i < g_driveCount; i++) {
AHCI_DRIVE *drv = &g_drives[i];
uint32_t portBit = (1u << drv->portNo);
if (!(pending & portBit)) continue;
for (int i = 0; i < ctl->driveCount; i++) {
AHCI_DRIVE *drv = &ctl->drives[i];
uint32_t portBit = (1u << drv->portNo);
if (!(pending & portBit)) continue;
// Capture and clear port IS before queueing the bottom half. The
// waiter reads lastIs to check for errors without racing the next
// command. OR in case hardware reports multiple causes before the
// DPC releases the worker.
uint32_t portIs = drv->port->is;
drv->port->is = portIs; // W1C - write back to clear
drv->lastIs |= portIs;
// Capture and clear port IS before queueing the bottom half. The
// waiter reads lastIs to check for errors without racing the next
// command. OR in case hardware reports multiple causes before the
// DPC releases the worker.
uint32_t portIs = drv->port->is;
drv->port->is = portIs; // W1C - write back to clear
drv->lastIs |= portIs;
// Clear the HBA-level bit.
g_hba->is = portBit;
// Clear the HBA-level bit.
ctl->hba->is = portBit;
KeInsertQueueDpc(&drv->completionDpc, (void *)0, (void *)0);
KeInsertQueueDpc(&drv->completionDpc, (void *)0, (void *)0);
}
}
}
@@ -441,7 +455,7 @@ static void AhciCancelReleaseRemoveLock(IRP* irp, void* context) {
IoReleaseRemoveLock(&drv->removeLock, irp);
}
static KSTATUS AhciDispatchPnp(DEVICE_OBJECT* device, IRP* irp) {
static KSTATUS AhciDispatchDrivePnp(DEVICE_OBJECT* device, IRP* irp) {
if (!device || !irp) return STATUS_INVALID_PARAMETER;
AHCI_DRIVE* drv = (AHCI_DRIVE*)device->DeviceExtension;
if (!drv) return STATUS_INVALID_PARAMETER;
@@ -478,6 +492,71 @@ static KSTATUS AhciDispatchPnp(DEVICE_OBJECT* device, IRP* irp) {
}
}
static KSTATUS AhciDispatchControllerPnp(DEVICE_OBJECT* device, IRP* irp) {
if (!device || !irp) return STATUS_INVALID_PARAMETER;
AHCI_CONTROLLER* ctl = (AHCI_CONTROLLER*)device->DeviceExtension;
if (!ctl || ctl->magic != AHCI_CONTROLLER_MAGIC)
return STATUS_INVALID_PARAMETER;
IO_STACK_LOCATION* ios = IoGetCurrentIrpStackLocation(irp);
if (!ios || ios->MajorFunction != IRP_MJ_PNP)
return STATUS_INVALID_PARAMETER;
switch ((IO_PNP_MINOR_FUNCTION)ios->MinorFunction) {
case IRP_MN_START_DEVICE:
if (ctl->started) {
device->PnpState = DevicePnpStarted;
return STATUS_SUCCESS;
}
return AhciStartController(ctl);
case IRP_MN_QUERY_REMOVE_DEVICE:
device->PnpState = DevicePnpRemovePending;
return STATUS_SUCCESS;
case IRP_MN_CANCEL_REMOVE_DEVICE:
device->PnpState = DevicePnpStarted;
return STATUS_SUCCESS;
case IRP_MN_SURPRISE_REMOVAL:
ctl->surpriseRemoved = true;
device->PnpState = DevicePnpSurpriseRemoved;
for (int i = 0; i < ctl->driveCount; i++) {
AHCI_DRIVE* drv = &ctl->drives[i];
drv->surpriseRemoved = true;
IrpQueueCancelAllEx(&drv->irpQueue, STATUS_OBJECT_DEAD, AhciCancelReleaseRemoveLock, drv);
}
return STATUS_SUCCESS;
case IRP_MN_REMOVE_DEVICE:
ctl->removed = true;
device->PnpState = DevicePnpDeleted;
for (int i = 0; i < ctl->driveCount; i++) {
AHCI_DRIVE* drv = &ctl->drives[i];
drv->removed = true;
IrpQueueCancelAllEx(&drv->irpQueue, STATUS_OBJECT_DEAD, AhciCancelReleaseRemoveLock, drv);
}
IoDetachDevice(device);
IoDeleteDevice(device);
return STATUS_SUCCESS;
default:
return STATUS_NOT_SUPPORTED;
}
}
static KSTATUS AhciDispatchPnp(DEVICE_OBJECT* device, IRP* irp) {
if (!device || !device->DeviceExtension)
return STATUS_INVALID_PARAMETER;
uint32_t magic = *(uint32_t*)device->DeviceExtension;
if (magic == AHCI_CONTROLLER_MAGIC)
return AhciDispatchControllerPnp(device, irp);
if (magic == AHCI_DRIVE_MAGIC)
return AhciDispatchDrivePnp(device, irp);
return STATUS_INVALID_PARAMETER;
}
// AhciWorker - kernel thread, one per drive.
// Dequeues IRPs and executes them one at a time using the existing
// single-slot interrupt-driven path. Completion fires the IRP's event
@@ -548,80 +627,101 @@ static void AhciWorker(uintptr_t arg) {
#define PORT_IE_ERRORS (PORT_IS_TFES | PORT_IS_HBFS | PORT_IS_HBDS | PORT_IS_IFS)
#define PORT_IE_ALL (PORT_IE_NORMAL | PORT_IE_ERRORS)
KSTATUS AhciInitialize(const HAL_API *hal) {
g_hal = hal;
g_driveCount = 0;
memset(&g_driver, 0, sizeof(g_driver));
IoInitializeDriverObject(&g_driver, SYS_SV_LITERAL("ahci"));
g_driver.MajorFunction[IRP_MJ_READ] = AhciDispatchReadWrite;
g_driver.MajorFunction[IRP_MJ_WRITE] = AhciDispatchReadWrite;
g_driver.MajorFunction[IRP_MJ_PNP] = AhciDispatchPnp;
// -----------------------------------------------------------------------
// Locate AHCI controller via PCI class scan
// -----------------------------------------------------------------------
uint8_t pciBus, pciDev, pciFn;
if (!hal->Pci.FindClass(PCI_AHCI_CLASS, PCI_AHCI_SUBCLASS,
&pciBus, &pciDev, &pciFn)) {
DbgPrint("AHCI: no AHCI controller found\n");
return STATUS_NOT_FOUND;
static KSTATUS AhciRegisterController(AHCI_CONTROLLER* ctl) {
if (!ctl) return STATUS_INVALID_PARAMETER;
for (int i = 0; i < g_controllerCount; i++) {
if (g_controllers[i] == ctl)
return STATUS_SUCCESS;
}
DbgPrint("AHCI: controller at PCI %02x:%02x.%x\n", pciBus, pciDev, pciFn);
if (g_controllerCount >= MAX_AHCI_CONTROLLERS)
return STATUS_NO_MEMORY;
g_controllers[g_controllerCount++] = ctl;
return STATUS_SUCCESS;
}
// -----------------------------------------------------------------------
// Enable Bus Master + Memory Space in PCI command register
// -----------------------------------------------------------------------
uint32_t cmd = hal->Pci.Read32(pciBus, pciDev, pciFn, PCI_CMD_REG);
cmd |= (PCI_CMD_BUSMASTER | PCI_CMD_MEMSPACE); cmd &= ~(1 << 10); cmd |= (1 << 2);
hal->Pci.Write32(pciBus, pciDev, pciFn, PCI_CMD_REG, cmd);
static KSTATUS AhciStartController(AHCI_CONTROLLER* ctl) {
if (!ctl || ctl->magic != AHCI_CONTROLLER_MAGIC || !ctl->pdo || !ctl->fdo)
return STATUS_INVALID_PARAMETER;
// -----------------------------------------------------------------------
// Read PCI IRQ line
// -----------------------------------------------------------------------
g_irq = hal->Pci.GetIrqLine(pciBus, pciDev, pciFn);
if (g_irq == 0xFF) {
if (ctl->started)
return STATUS_SUCCESS;
KSTATUS st = PciGetDeviceInfo(ctl->pdo, &ctl->pciInfo);
if (!KSUCCESS(st)) {
DbgPrint("AHCI: PciGetDeviceInfo failed: 0x%x\n", st);
return st;
}
DbgPrint("AHCI: controller at PCI %02x:%02x.%x vendor=%04x device=%04x\n",
ctl->pciInfo.Address.Bus,
ctl->pciInfo.Address.Device,
ctl->pciInfo.Address.Function,
ctl->pciInfo.VendorId,
ctl->pciInfo.DeviceId);
st = PciGetInterrupt(ctl->pdo, &ctl->irq);
if (!KSUCCESS(st) || ctl->irq == 0xFF) {
DbgPrint("AHCI: no PCI IRQ wired - cannot use interrupt-driven mode\n");
return STATUS_NOT_SUPPORTED;
return KSUCCESS(st) ? STATUS_NOT_SUPPORTED : st;
}
DbgPrint("AHCI: PCI IRQ line = %u\n", (unsigned)g_irq);
DbgPrint("AHCI: PCI IRQ line = %u\n", (unsigned)ctl->irq);
// -----------------------------------------------------------------------
// Read ABAR (BAR5) and map as uncacheable
// -----------------------------------------------------------------------
uint32_t bar5 = hal->Pci.Read32(pciBus, pciDev, pciFn, PCI_BAR5_REG);
uint64_t abarPhys = (uint64_t)(bar5 & ~0xFFFu);
KSTATUS st = ahci_map_mmio(abarPhys);
if (!KSUCCESS(st)) return st;
st = PciGetBar(ctl->pdo, AHCI_PCI_BAR_ABAR, &ctl->abar);
if (!KSUCCESS(st)) {
DbgPrint("AHCI: BAR5/ABAR not present (0x%x)\n", st);
return st;
}
if (ctl->abar.Type != PciBarMemory32 && ctl->abar.Type != PciBarMemory64) {
DbgPrint("AHCI: BAR5/ABAR is not MMIO (type=%u)\n", ctl->abar.Type);
return STATUS_DEVICE_ERROR;
}
g_hba = (HBA_MEM *)hal->PhysToVirt(abarPhys);
DbgPrint("AHCI: ABAR phys=0x%016llX version=0x%08x\n",
(unsigned long long)abarPhys, g_hba->vs);
st = PciMapBar(ctl->pdo,
AHCI_PCI_BAR_ABAR,
PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE,
(void**)&ctl->hba,
&ctl->abarLength);
if (!KSUCCESS(st)) {
DbgPrint("AHCI: PciMapBar(BAR5) failed: 0x%x\n", st);
return st;
}
// -----------------------------------------------------------------------
// HBA reset + BIOS handoff (also enables GHC.IE)
// -----------------------------------------------------------------------
st = hba_reset(g_hba);
if (!KSUCCESS(st)) return st;
st = PciEnableDevice(ctl->pdo,
PCI_ENABLE_MEMORY |
PCI_ENABLE_BUSMASTER |
PCI_ENABLE_INTX);
if (!KSUCCESS(st)) {
DbgPrint("AHCI: PciEnableDevice failed: 0x%x\n", st);
return st;
}
// -----------------------------------------------------------------------
// Log capability summary
// -----------------------------------------------------------------------
uint32_t cap = g_hba->cap;
DbgPrint("AHCI: ABAR phys=0x%016llX len=0x%llx version=0x%08x\n",
(unsigned long long)ctl->abar.Base,
(unsigned long long)ctl->abarLength,
ctl->hba->vs);
st = hba_reset(ctl->hba);
if (!KSUCCESS(st))
return st;
uint32_t cap = ctl->hba->cap;
uint32_t nPorts = (cap & 0x1F) + 1;
uint32_t nSlots = ((cap >> 8) & 0x1F) + 1;
bool s64a = !!(cap & (1u << 31));
DbgPrint("AHCI: cap=0x%08x ports=%u slots=%u 64bit=%d\n",
cap, nPorts, nSlots, (int)s64a);
// -----------------------------------------------------------------------
// Enumerate implemented ports
// -----------------------------------------------------------------------
uint32_t pi = g_hba->pi;
for (uint32_t portno = 0; portno < 32 && g_driveCount < MAX_AHCI_DRIVES; portno++) {
st = AhciRegisterController(ctl);
if (!KSUCCESS(st)) {
DbgPrint("AHCI: controller registry full (0x%x)\n", st);
return st;
}
uint32_t pi = ctl->hba->pi;
for (uint32_t portno = 0; portno < 32 && ctl->driveCount < MAX_AHCI_DRIVES; portno++) {
if (!(pi & (1u << portno))) continue;
HBA_PORT *port = &g_hba->ports[portno];
HBA_PORT *port = &ctl->hba->ports[portno];
// Phase 1: physical link check
if (!port_link_up(port)) {
@@ -631,9 +731,11 @@ KSTATUS AhciInitialize(const HAL_API *hal) {
DbgPrint("AHCI: port %u: link up, initializing...\n", portno);
int driveIdx = g_driveCount;
AHCI_DRIVE *drv = &g_drives[driveIdx];
int driveIdx = ctl->driveCount;
AHCI_DRIVE *drv = &ctl->drives[driveIdx];
memset(drv, 0, sizeof(*drv));
drv->magic = AHCI_DRIVE_MAGIC;
drv->controller = ctl;
drv->port = port;
drv->portNo = (uint8_t)portno;
@@ -689,7 +791,7 @@ KSTATUS AhciInitialize(const HAL_API *hal) {
}
DbgPrint("AHCI: drive %d: %llu sectors (%llu MB)\n",
driveIdx,
g_nextDiskIndex,
(unsigned long long)drv->sectorCount,
(unsigned long long)(drv->sectorCount / 2048));
@@ -701,7 +803,7 @@ KSTATUS AhciInitialize(const HAL_API *hal) {
// Phase 8: create and register a disk DEVICE_OBJECT.
st = IoCreateDevice(&g_driver, 0, &drv->deviceObject);
if (!KSUCCESS(st)) {
DbgPrint("AHCI: drive %d: IoCreateDevice failed (0x%x)\n", driveIdx, st);
DbgPrint("AHCI: drive %d: IoCreateDevice failed (0x%x)\n", g_nextDiskIndex, st);
continue;
}
drv->deviceObject->DeviceExtension = drv;
@@ -709,12 +811,14 @@ KSTATUS AhciInitialize(const HAL_API *hal) {
drv->deviceObject->u.Disk.SectorSize = 512;
drv->deviceObject->AlignmentRequirement = 512;
st = IoRegisterDiskDevice((uint8_t)driveIdx, drv->deviceObject);
uint8_t diskIndex = g_nextDiskIndex;
st = IoRegisterDiskDevice(diskIndex, drv->deviceObject);
if (KSUCCESS(st)) {
DbgPrint("AHCI: drive %d registered\n", driveIdx);
g_driveCount++;
DbgPrint("AHCI: drive %u registered\n", diskIndex);
ctl->driveCount++;
g_nextDiskIndex++;
} else {
DbgPrint("AHCI: IoRegisterDiskDevice(%d) failed (0x%x)\n", driveIdx, st);
DbgPrint("AHCI: IoRegisterDiskDevice(%u) failed (0x%x)\n", diskIndex, st);
IoDeleteDevice(drv->deviceObject);
drv->deviceObject = (DEVICE_OBJECT*)0;
continue;
@@ -726,33 +830,71 @@ KSTATUS AhciInitialize(const HAL_API *hal) {
st = KeCreateKernelThread((uintptr_t)AhciWorker, (uintptr_t)drv,
PriorityHigh, &drv->workerThread);
if (!KSUCCESS(st)) {
DbgPrint("AHCI: drive %d: worker thread create failed (0x%x)\n",
driveIdx, st);
DbgPrint("AHCI: drive %u: worker thread create failed (0x%x)\n",
diskIndex, st);
// Fatal for this device: all disk access is IRP-based now, so
// leave the device registered but clearly fail during testing.
}
}
if (g_driveCount == 0) {
DbgPrint("AHCI: no drives found\n");
return STATUS_NOT_FOUND;
if (ctl->driveCount == 0)
DbgPrint("AHCI: no drives found on PCI %02x:%02x.%x\n",
ctl->pciInfo.Address.Bus,
ctl->pciInfo.Address.Device,
ctl->pciInfo.Address.Function);
KeIrqRegister(ctl->irq, AhciIsr);
ctl->started = true;
ctl->fdo->PnpState = DevicePnpStarted;
DbgPrint("AHCI: ISR registered on IRQ %u; controller drives=%d\n",
(unsigned)ctl->irq, ctl->driveCount);
return STATUS_SUCCESS;
}
static KSTATUS AhciAddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDeviceObject) {
if (!driver || !physicalDeviceObject || physicalDeviceObject->Type != DeviceObjectPhysical)
return STATUS_INVALID_PARAMETER;
DEVICE_OBJECT* fdo = (DEVICE_OBJECT*)0;
KSTATUS st = IoCreateDevice(driver, sizeof(AHCI_CONTROLLER), &fdo);
if (!KSUCCESS(st))
return st;
AHCI_CONTROLLER* ctl = (AHCI_CONTROLLER*)fdo->DeviceExtension;
memset(ctl, 0, sizeof(*ctl));
ctl->magic = AHCI_CONTROLLER_MAGIC;
ctl->fdo = fdo;
ctl->pdo = physicalDeviceObject;
ctl->irq = 0xFF;
(void)IoSetDeviceName(fdo, SYS_SV_LITERAL("ahci-controller"));
ctl->lowerDevice = IoAttachDeviceToDeviceStack(fdo, physicalDeviceObject);
if (!ctl->lowerDevice) {
IoDeleteDevice(fdo);
return STATUS_FAILURE;
}
// -----------------------------------------------------------------------
// Register the ISR. All ports on this HBA share one PCI IRQ line.
// Do this after all drives are initialised so the ISR sees valid state.
// -----------------------------------------------------------------------
KeIrqRegister(g_irq, AhciIsr);
DbgPrint("AHCI: ISR registered on IRQ %u; initialised %d drive(s)\n",
(unsigned)g_irq, g_driveCount);
DbgPrint("AHCI: FDO attached to %v\n", physicalDeviceObject->Name);
return STATUS_SUCCESS;
}
KSTATUS DriverEntry(const HAL_API *hal) {
DbgPrint("AHCI: driver loading...\n");
KSTATUS st = AhciInitialize(hal);
g_hal = hal;
g_controllerCount = 0;
g_nextDiskIndex = 0;
memset(&g_driver, 0, sizeof(g_driver));
IoInitializeDriverObject(&g_driver, SYS_SV_LITERAL("ahci"));
g_driver.IdTable = &g_ahciIdTable;
g_driver.DriverAddDevice = AhciAddDevice;
g_driver.MajorFunction[IRP_MJ_READ] = AhciDispatchReadWrite;
g_driver.MajorFunction[IRP_MJ_WRITE] = AhciDispatchReadWrite;
g_driver.MajorFunction[IRP_MJ_PNP] = AhciDispatchPnp;
KSTATUS st = IoRegisterDriverObject(&g_driver);
if (!KSUCCESS(st))
DbgPrint("AHCI: init failed: 0x%x\n", st);
DbgPrint("AHCI: IoRegisterDriverObject failed: 0x%x\n", st);
return st;
}
+31 -12
View File
@@ -5,6 +5,7 @@
#include <stdbool.h>
#include <string.h>
#include <ntlite/ddi/io_driver.h>
#include <ntlite/ddi/pci.h>
#include <kernel/mm_phys.h>
#include <kernel/mm_virt.h>
#include <kernel/ke_debug.h>
@@ -223,13 +224,12 @@ typedef volatile struct {
// Constants
// ---------------------------------------------------------------------------
// PCI
#define PCI_AHCI_CLASS 0x01
#define PCI_AHCI_SUBCLASS 0x06
#define PCI_CMD_REG 0x04
#define PCI_BAR5_REG 0x24
#define PCI_CMD_BUSMASTER (1 << 2)
#define PCI_CMD_MEMSPACE (1 << 1)
// PCI/AHCI binding. PCI enumeration, BAR decoding, interrupt line
// discovery, and command-register policy are owned by pci.sys.
#define AHCI_PCI_BAR_ABAR 5u
#define AHCI_CONTROLLER_MAGIC 0x41484349u // 'AHCI'
#define AHCI_DRIVE_MAGIC 0x41484452u // 'AHDR'
#define MAX_AHCI_CONTROLLERS 8
// GHC register bits
#define GHC_AE (1u << 31) // AHCI Enable
@@ -314,8 +314,12 @@ typedef volatile struct {
// We map 8 pages (32KB) without probing the BAR size.
#define AHCI_MMIO_PAGES 8
typedef struct AHCI_CONTROLLER AHCI_CONTROLLER;
// Per-drive context
typedef struct {
uint32_t magic; // AHCI_DRIVE_MAGIC
AHCI_CONTROLLER* controller; // owning AHCI controller FDO extension
HBA_PORT *port; // MMIO port registers (virtual)
uint64_t sectorCount; // Total LBA sectors on device
uint8_t portNo; // Physical port index (for ISR dispatch)
@@ -358,15 +362,30 @@ typedef struct {
// volatile uint32_t prevSact; // previous port->sact snapshot
} AHCI_DRIVE;
struct AHCI_CONTROLLER {
uint32_t magic; // AHCI_CONTROLLER_MAGIC
DEVICE_OBJECT* fdo;
DEVICE_OBJECT* pdo;
DEVICE_OBJECT* lowerDevice;
PCI_DEVICE_INFO pciInfo;
PCI_BAR abar;
HBA_MEM* hba;
uint64_t abarLength;
uint8_t irq;
AHCI_DRIVE drives[MAX_AHCI_DRIVES];
int driveCount;
bool started;
bool surpriseRemoved;
bool removed;
};
extern const HAL_API *g_hal;
extern HBA_MEM *g_hba;
extern uint8_t g_irq;
extern DRIVER_OBJECT g_driver;
extern AHCI_DRIVE g_drives[MAX_AHCI_DRIVES];
extern int g_driveCount;
KSTATUS ahci_map_mmio(uint64_t physBase);
KSTATUS ahci_map_mmio(uint64_t physBase, uint64_t length);
void port_stop(HBA_PORT *port);
void port_start(HBA_PORT *port);
KSTATUS hba_reset(HBA_MEM *hba);
+8 -4
View File
@@ -1,9 +1,13 @@
// ahci_port.c - AHCI MMIO mapping, HBA reset, and port link bring-up helpers.
#include "ahci.h"
KSTATUS ahci_map_mmio(uint64_t physBase) {
for (int i = 0; i < AHCI_MMIO_PAGES; i++) {
uint64_t phys = physBase + (uint64_t)i * 4096;
KSTATUS ahci_map_mmio(uint64_t physBase, uint64_t length) {
if (length == 0)
length = AHCI_MMIO_PAGES * 4096ull;
uint64_t pageBase = physBase & ~(uint64_t)(PAGE_SIZE - 1u);
uint64_t pageEnd = (physBase + length + PAGE_SIZE - 1u) & ~(uint64_t)(PAGE_SIZE - 1u);
int pageIndex = 0;
for (uint64_t phys = pageBase; phys < pageEnd; phys += PAGE_SIZE, pageIndex++) {
uintptr_t virt = (uintptr_t)g_hal->PhysToVirt(phys);
uint64_t flags = PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE;
KSTATUS st = MmMapPage(virt, phys, flags, MmMapFailIfPresent);
@@ -15,7 +19,7 @@ KSTATUS ahci_map_mmio(uint64_t physBase) {
}
if (!KSUCCESS(st)) {
DbgPrint("AHCI: MmMapPage failed for page %d (phys=0x%016llX, st=0x%x)\n",
i, (unsigned long long)phys, st);
pageIndex, (unsigned long long)phys, st);
return st;
}
}
+686
View File
@@ -0,0 +1,686 @@
// ata.c - PCI IDE / ATA disk driver.
#include "ata.h"
const HAL_API* gAtaHal;
static DRIVER_OBJECT gAtaDriver;
static ATA_CONTROLLER* gAtaControllers[ATA_MAX_CONTROLLERS];
static uint32_t gAtaControllerCount;
static const IO_DEVICE_ID gAtaIds[] = {
{ IoBusPci, { "PCI\\CC_0101", sizeof("PCI\\CC_0101") - 1 } },
};
static const IO_DRIVER_ID_TABLE gAtaIdTable = {
gAtaIds,
sizeof(gAtaIds) / sizeof(gAtaIds[0]),
};
static uint8_t AtaIn8(ATA_CHANNEL* ch, uint8_t reg) {
return __inbyte((unsigned short)(ch->CommandBase + reg));
}
static uint16_t AtaIn16(ATA_CHANNEL* ch, uint8_t reg) {
return __inword((unsigned short)(ch->CommandBase + reg));
}
static void AtaOut8(ATA_CHANNEL* ch, uint8_t reg, uint8_t value) {
__outbyte((unsigned short)(ch->CommandBase + reg), value);
}
static void AtaOut16(ATA_CHANNEL* ch, uint8_t reg, uint16_t value) {
__outword((unsigned short)(ch->CommandBase + reg), value);
}
static uint8_t AtaAltStatus(ATA_CHANNEL* ch) {
return __inbyte((unsigned short)(ch->ControlBase + ATA_REG_ALT_STATUS));
}
static void AtaDeviceControl(ATA_CHANNEL* ch, uint8_t value) {
__outbyte((unsigned short)(ch->ControlBase + ATA_REG_DEVICE_CONTROL), value);
}
static void AtaDelay400ns(ATA_CHANNEL* ch) {
(void)AtaAltStatus(ch);
(void)AtaAltStatus(ch);
(void)AtaAltStatus(ch);
(void)AtaAltStatus(ch);
}
static KSTATUS AtaWaitNotBusy(ATA_CHANNEL* ch) {
for (uint32_t i = 0; i < ATA_POLL_LIMIT; i++) {
if (!(AtaIn8(ch, ATA_REG_STATUS) & ATA_STATUS_BSY))
return STATUS_SUCCESS;
KeYield();
}
return STATUS_TIMEOUT;
}
static KSTATUS AtaWaitDrq(ATA_CHANNEL* ch) {
for (uint32_t i = 0; i < ATA_POLL_LIMIT; i++) {
uint8_t st = AtaIn8(ch, ATA_REG_STATUS);
if (st & ATA_STATUS_ERR)
return STATUS_DEVICE_ERROR;
if (st & ATA_STATUS_DF)
return STATUS_DEVICE_ERROR;
if (!(st & ATA_STATUS_BSY) && (st & ATA_STATUS_DRQ))
return STATUS_SUCCESS;
KeYield();
}
return STATUS_TIMEOUT;
}
static void AtaSelectDrive(ATA_DEVICE* dev) {
ATA_CHANNEL* ch = dev->Channel;
AtaOut8(ch, ATA_REG_DRIVE_HEAD, (uint8_t)(0xA0u | (dev->Drive ? 0x10u : 0u)));
AtaDelay400ns(ch);
}
static KSTATUS AtaIdentify(ATA_DEVICE* dev) {
ATA_CHANNEL* ch = dev->Channel;
uint16_t ident[256];
memset(ident, 0, sizeof(ident));
KSTATUS st = KeWaitSemaphore(ch->Lock);
if (!KSUCCESS(st))
return st;
AtaSelectDrive(dev);
AtaOut8(ch, ATA_REG_SECTOR_COUNT, 0);
AtaOut8(ch, ATA_REG_LBA0, 0);
AtaOut8(ch, ATA_REG_LBA1, 0);
AtaOut8(ch, ATA_REG_LBA2, 0);
AtaOut8(ch, ATA_REG_COMMAND, ATA_CMD_IDENTIFY_DEVICE);
AtaDelay400ns(ch);
uint8_t status = AtaIn8(ch, ATA_REG_STATUS);
if (status == 0) {
KeSignalSemaphore(ch->Lock);
return STATUS_NOT_FOUND;
}
st = AtaWaitNotBusy(ch);
if (!KSUCCESS(st)) {
KeSignalSemaphore(ch->Lock);
return st;
}
if (AtaIn8(ch, ATA_REG_LBA1) != 0 || AtaIn8(ch, ATA_REG_LBA2) != 0) {
KeSignalSemaphore(ch->Lock);
return STATUS_NOT_SUPPORTED; // ATAPI or non-ATA signature.
}
st = AtaWaitDrq(ch);
if (!KSUCCESS(st)) {
KeSignalSemaphore(ch->Lock);
return st;
}
for (uint32_t i = 0; i < 256; i++)
ident[i] = AtaIn16(ch, ATA_REG_DATA);
KeSignalSemaphore(ch->Lock);
if (!(ident[ATA_IDENT_CAPABILITIES] & ATA_IDENT_LBA_SUPPORTED))
return STATUS_NOT_SUPPORTED;
dev->SupportsLba48 = (ident[ATA_IDENT_COMMAND_SETS] & ATA_IDENT_LBA48_SUPPORTED) != 0;
if (dev->SupportsLba48) {
uint64_t sectors = 0;
sectors |= (uint64_t)ident[100];
sectors |= (uint64_t)ident[101] << 16;
sectors |= (uint64_t)ident[102] << 32;
sectors |= (uint64_t)ident[103] << 48;
dev->SectorCount = sectors;
} else {
dev->SectorCount = ((uint32_t)ident[ATA_IDENT_LBA28_SECTORS_HI] << 16) |
ident[ATA_IDENT_LBA28_SECTORS_LO];
}
return dev->SectorCount ? STATUS_SUCCESS : STATUS_NOT_FOUND;
}
static KSTATUS AtaProgramLba(ATA_DEVICE* dev, uint64_t lba, uint16_t count, bool write) {
ATA_CHANNEL* ch = dev->Channel;
if (dev->SupportsLba48) {
AtaOut8(ch, ATA_REG_DRIVE_HEAD, (uint8_t)(0x40u | (dev->Drive ? 0x10u : 0u)));
AtaOut8(ch, ATA_REG_SECTOR_COUNT, (uint8_t)(count >> 8));
AtaOut8(ch, ATA_REG_LBA0, (uint8_t)(lba >> 24));
AtaOut8(ch, ATA_REG_LBA1, (uint8_t)(lba >> 32));
AtaOut8(ch, ATA_REG_LBA2, (uint8_t)(lba >> 40));
AtaOut8(ch, ATA_REG_SECTOR_COUNT, (uint8_t)count);
AtaOut8(ch, ATA_REG_LBA0, (uint8_t)lba);
AtaOut8(ch, ATA_REG_LBA1, (uint8_t)(lba >> 8));
AtaOut8(ch, ATA_REG_LBA2, (uint8_t)(lba >> 16));
AtaOut8(ch, ATA_REG_COMMAND, write ? ATA_CMD_WRITE_SECTORS_EXT : ATA_CMD_READ_SECTORS_EXT);
return STATUS_SUCCESS;
}
if (lba > 0x0FFFFFFFULL || count > 256)
return STATUS_INVALID_PARAMETER;
AtaOut8(ch, ATA_REG_DRIVE_HEAD, (uint8_t)(0xE0u | (dev->Drive ? 0x10u : 0u) | ((lba >> 24) & 0x0Fu)));
AtaOut8(ch, ATA_REG_SECTOR_COUNT, (uint8_t)count);
AtaOut8(ch, ATA_REG_LBA0, (uint8_t)lba);
AtaOut8(ch, ATA_REG_LBA1, (uint8_t)(lba >> 8));
AtaOut8(ch, ATA_REG_LBA2, (uint8_t)(lba >> 16));
AtaOut8(ch, ATA_REG_COMMAND, write ? ATA_CMD_WRITE_SECTORS : ATA_CMD_READ_SECTORS);
return STATUS_SUCCESS;
}
static KSTATUS AtaReadPio(ATA_DEVICE* dev, uint64_t lba, uint32_t count, void* buffer) {
if (!dev || !buffer)
return STATUS_INVALID_PARAMETER;
if (count == 0)
return STATUS_SUCCESS;
if (lba + count > dev->SectorCount)
return STATUS_INVALID_PARAMETER;
ATA_CHANNEL* ch = dev->Channel;
uint16_t* out = (uint16_t*)buffer;
KSTATUS st = KeWaitSemaphore(ch->Lock);
if (!KSUCCESS(st))
return st;
while (count > 0) {
uint16_t batch = (count > 256u) ? 256u : (uint16_t)count;
uint16_t encodedCount = (!dev->SupportsLba48 && batch == 256u) ? 0u : batch;
AtaSelectDrive(dev);
st = AtaWaitNotBusy(ch);
if (!KSUCCESS(st)) break;
st = AtaProgramLba(dev, lba, encodedCount, false);
if (!KSUCCESS(st)) break;
for (uint32_t s = 0; s < batch; s++) {
st = AtaWaitDrq(ch);
if (!KSUCCESS(st)) break;
for (uint32_t w = 0; w < ATA_SECTOR_SIZE / 2u; w++)
*out++ = AtaIn16(ch, ATA_REG_DATA);
}
if (!KSUCCESS(st)) break;
lba += batch;
count -= batch;
}
KeSignalSemaphore(ch->Lock);
return st;
}
static KSTATUS AtaFlush(ATA_DEVICE* dev) {
ATA_CHANNEL* ch = dev->Channel;
KSTATUS st = AtaWaitNotBusy(ch);
if (!KSUCCESS(st))
return st;
AtaOut8(ch, ATA_REG_COMMAND, dev->SupportsLba48 ? ATA_CMD_CACHE_FLUSH_EXT : ATA_CMD_CACHE_FLUSH);
return AtaWaitNotBusy(ch);
}
static KSTATUS AtaWritePio(ATA_DEVICE* dev, uint64_t lba, uint32_t count, const void* buffer) {
if (!dev || !buffer)
return STATUS_INVALID_PARAMETER;
if (count == 0)
return STATUS_SUCCESS;
if (lba + count > dev->SectorCount)
return STATUS_INVALID_PARAMETER;
ATA_CHANNEL* ch = dev->Channel;
const uint16_t* in = (const uint16_t*)buffer;
KSTATUS st = KeWaitSemaphore(ch->Lock);
if (!KSUCCESS(st))
return st;
while (count > 0) {
uint16_t batch = (count > 256u) ? 256u : (uint16_t)count;
uint16_t encodedCount = (!dev->SupportsLba48 && batch == 256u) ? 0u : batch;
AtaSelectDrive(dev);
st = AtaWaitNotBusy(ch);
if (!KSUCCESS(st)) break;
st = AtaProgramLba(dev, lba, encodedCount, true);
if (!KSUCCESS(st)) break;
for (uint32_t s = 0; s < batch; s++) {
st = AtaWaitDrq(ch);
if (!KSUCCESS(st)) break;
for (uint32_t w = 0; w < ATA_SECTOR_SIZE / 2u; w++)
AtaOut16(ch, ATA_REG_DATA, *in++);
}
if (!KSUCCESS(st)) break;
st = AtaFlush(dev);
if (!KSUCCESS(st)) break;
lba += batch;
count -= batch;
}
KeSignalSemaphore(ch->Lock);
return st;
}
static KSTATUS AtaGetIrpReadWrite(IRP* irp, bool* outWrite, uint64_t* outLba,
uint32_t* outSectors, void** outBuffer) {
if (!irp || !outWrite || !outLba || !outSectors || !outBuffer)
return STATUS_INVALID_PARAMETER;
IO_STACK_LOCATION* ios = IoGetCurrentIrpStackLocation(irp);
if (!ios) return STATUS_INVALID_PARAMETER;
if (ios->MajorFunction != IRP_MJ_READ && ios->MajorFunction != IRP_MJ_WRITE)
return STATUS_INVALID_PARAMETER;
if ((ios->Parameters.ReadWrite.ByteOffset & 511ull) ||
(ios->Parameters.ReadWrite.Length & 511u))
return STATUS_INVALID_PARAMETER;
if (!irp->UserBuffer || ios->Parameters.ReadWrite.Length == 0)
return STATUS_INVALID_PARAMETER;
*outWrite = (ios->MajorFunction == IRP_MJ_WRITE);
*outLba = ios->Parameters.ReadWrite.ByteOffset >> 9;
*outSectors = ios->Parameters.ReadWrite.Length >> 9;
*outBuffer = irp->UserBuffer;
return STATUS_SUCCESS;
}
static void AtaWorker(uintptr_t arg) {
ATA_DEVICE* dev = (ATA_DEVICE*)arg;
if (!dev)
return;
while (true) {
KeWaitSemaphore(dev->IrpQueue.Semaphore);
IRP* irp = IrpQueueDequeue(&dev->IrpQueue);
if (!irp)
continue;
bool write = false;
uint64_t lba = 0;
uint32_t sectors = 0;
void* buffer = (void*)0;
KSTATUS st = AtaGetIrpReadWrite(irp, &write, &lba, &sectors, &buffer);
if (KSUCCESS(st)) {
if (lba + sectors > dev->SectorCount)
st = STATUS_INVALID_PARAMETER;
else
st = write ? AtaWritePio(dev, lba, sectors, buffer)
: AtaReadPio(dev, lba, sectors, buffer);
}
IoReleaseRemoveLock(&dev->RemoveLock, irp);
IoCompleteRequest(irp, st, KSUCCESS(st) ? ((size_t)sectors * ATA_SECTOR_SIZE) : 0);
}
}
KSTATUS AtaDispatchReadWrite(DEVICE_OBJECT* device, IRP* irp) {
if (!device || !irp || !device->DeviceExtension)
return STATUS_INVALID_PARAMETER;
ATA_DEVICE* dev = (ATA_DEVICE*)device->DeviceExtension;
if (dev->Magic != ATA_DEVICE_MAGIC || !dev->Present)
return STATUS_INVALID_PARAMETER;
KSTATUS st = IoAcquireRemoveLock(&dev->RemoveLock, irp);
if (!KSUCCESS(st))
return st;
bool write = false;
uint64_t lba = 0;
uint32_t sectors = 0;
void* buffer = (void*)0;
st = AtaGetIrpReadWrite(irp, &write, &lba, &sectors, &buffer);
(void)write;
(void)buffer;
if (!KSUCCESS(st) || lba + sectors > dev->SectorCount) {
IoReleaseRemoveLock(&dev->RemoveLock, irp);
return KSUCCESS(st) ? STATUS_INVALID_PARAMETER : st;
}
irp->Status = STATUS_FAILURE;
irp->Information = 0;
IrpQueueEnqueue(&dev->IrpQueue, irp);
return STATUS_PENDING;
}
static uint8_t AtaFindFreeDiskIndex(void) {
for (uint8_t i = 0; i < 8; i++) {
if (!IoDiskDevicePresent(i))
return i;
}
return 0xFFu;
}
static uint16_t AtaBarIoBase(ATA_CONTROLLER* ctl, uint8_t barIndex, uint16_t fallback) {
PCI_BAR bar;
KSTATUS st = PciGetBar(ctl->Pdo, barIndex, &bar);
if (KSUCCESS(st) && bar.Type == PciBarIo && bar.Base && bar.Base <= 0xFFFFu)
return (uint16_t)bar.Base;
return fallback;
}
static KSTATUS AtaInitChannel(ATA_CONTROLLER* ctl, uint8_t index) {
ATA_CHANNEL* ch = &ctl->Channels[index];
memset(ch, 0, sizeof(*ch));
ch->Controller = ctl;
ch->Index = index;
if (index == 0) {
ch->CommandBase = AtaBarIoBase(ctl, 0, ATA_PRIMARY_LEGACY_CMD_BASE);
ch->ControlBase = AtaBarIoBase(ctl, 1, ATA_PRIMARY_LEGACY_CTL_BASE);
ch->Irq = ATA_PRIMARY_LEGACY_IRQ;
} else {
ch->CommandBase = AtaBarIoBase(ctl, 2, ATA_SECONDARY_LEGACY_CMD_BASE);
ch->ControlBase = AtaBarIoBase(ctl, 3, ATA_SECONDARY_LEGACY_CTL_BASE);
ch->Irq = ATA_SECONDARY_LEGACY_IRQ;
}
if (ctl->PciInfo.ProgIf & (index == 0 ? 0x01u : 0x04u)) {
uint8_t irq = 0xFFu;
if (KSUCCESS(PciGetInterrupt(ctl->Pdo, &irq)) && irq != 0xFFu)
ch->Irq = irq;
ch->NativeMode = true;
}
KSTATUS st = KeSemaphoreCreate(1, 1, &ch->Lock);
if (!KSUCCESS(st))
return st;
AtaDeviceControl(ch, 0x02u); // nIEN: polled I/O for now.
DbgPrint("ATA: channel %u cmd=0x%04x ctl=0x%04x irq=%u mode=%s\n",
index,
ch->CommandBase,
ch->ControlBase,
ch->Irq,
ch->NativeMode ? "native" : "compat");
return STATUS_SUCCESS;
}
static KSTATUS AtaRegisterDisk(ATA_DEVICE* dev) {
DEVICE_OBJECT* disk = (DEVICE_OBJECT*)0;
KSTATUS st = IoCreateDevice(&gAtaDriver, 0, &disk);
if (!KSUCCESS(st))
return st;
disk->DeviceExtension = dev;
disk->u.Disk.SectorCount = dev->SectorCount;
disk->u.Disk.SectorSize = ATA_SECTOR_SIZE;
disk->AlignmentRequirement = ATA_SECTOR_SIZE;
(void)IoSetDeviceName(disk, SYS_SV_LITERAL("ata-disk"));
uint8_t index = AtaFindFreeDiskIndex();
if (index == 0xFFu) {
IoDeleteDevice(disk);
return STATUS_NO_MEMORY;
}
st = IoRegisterDiskDevice(index, disk);
if (!KSUCCESS(st)) {
IoDeleteDevice(disk);
return st;
}
dev->DeviceObject = disk;
dev->DiskIndex = index;
DbgPrint("ATA: drive %u registered channel=%u %s sectors=%llu (%llu MB)\n",
index,
dev->Channel->Index,
dev->Drive ? "slave" : "master",
(unsigned long long)dev->SectorCount,
(unsigned long long)(dev->SectorCount / 2048));
return STATUS_SUCCESS;
}
static KSTATUS AtaProbeDrive(ATA_CONTROLLER* ctl, ATA_CHANNEL* ch, uint8_t drive) {
ATA_DEVICE* dev = &ch->Devices[drive];
memset(dev, 0, sizeof(*dev));
dev->Magic = ATA_DEVICE_MAGIC;
dev->Controller = ctl;
dev->Channel = ch;
dev->Drive = drive;
dev->DiskIndex = 0xFFu;
KSTATUS st = AtaIdentify(dev);
if (!KSUCCESS(st))
return st;
st = IoInitializeRemoveLock(&dev->RemoveLock);
if (!KSUCCESS(st))
return st;
SEMAPHORE* sem = (SEMAPHORE*)0;
st = KeSemaphoreCreate(0, 0x7FFFFFFF, &sem);
if (!KSUCCESS(st))
return st;
IrpQueueInit(&dev->IrpQueue, sem);
dev->Present = true;
st = AtaRegisterDisk(dev);
if (!KSUCCESS(st)) {
dev->Present = false;
return st;
}
st = KeCreateKernelThread((uintptr_t)AtaWorker, (uintptr_t)dev,
PriorityHigh, &dev->WorkerThread);
if (!KSUCCESS(st))
DbgPrint("ATA: drive %u worker thread create failed (0x%x)\n", dev->DiskIndex, st);
return STATUS_SUCCESS;
}
static KSTATUS AtaRegisterController(ATA_CONTROLLER* ctl) {
if (!ctl) return STATUS_INVALID_PARAMETER;
for (uint32_t i = 0; i < gAtaControllerCount; i++) {
if (gAtaControllers[i] == ctl)
return STATUS_SUCCESS;
}
if (gAtaControllerCount >= ATA_MAX_CONTROLLERS)
return STATUS_NO_MEMORY;
gAtaControllers[gAtaControllerCount++] = ctl;
return STATUS_SUCCESS;
}
static KSTATUS AtaStartController(ATA_CONTROLLER* ctl) {
if (!ctl || ctl->Magic != ATA_CONTROLLER_MAGIC || !ctl->Pdo || !ctl->Fdo)
return STATUS_INVALID_PARAMETER;
if (ctl->Started)
return STATUS_SUCCESS;
KSTATUS st = PciGetDeviceInfo(ctl->Pdo, &ctl->PciInfo);
if (!KSUCCESS(st)) {
DbgPrint("ATA: PciGetDeviceInfo failed: 0x%x\n", st);
return st;
}
DbgPrint("ATA: controller at PCI %02x:%02x.%x vendor=%04x device=%04x progif=%02x\n",
ctl->PciInfo.Address.Bus,
ctl->PciInfo.Address.Device,
ctl->PciInfo.Address.Function,
ctl->PciInfo.VendorId,
ctl->PciInfo.DeviceId,
ctl->PciInfo.ProgIf);
st = PciEnableDevice(ctl->Pdo, PCI_ENABLE_IO | PCI_ENABLE_INTX);
if (!KSUCCESS(st)) {
DbgPrint("ATA: PciEnableDevice failed: 0x%x\n", st);
return st;
}
st = AtaRegisterController(ctl);
if (!KSUCCESS(st))
return st;
for (uint8_t chIndex = 0; chIndex < ATA_CHANNEL_COUNT; chIndex++) {
ATA_CHANNEL* ch = &ctl->Channels[chIndex];
st = AtaInitChannel(ctl, chIndex);
if (!KSUCCESS(st)) {
DbgPrint("ATA: channel %u init failed (0x%x)\n", chIndex, st);
continue;
}
for (uint8_t drive = 0; drive < ATA_DRIVES_PER_CHANNEL; drive++) {
st = AtaProbeDrive(ctl, ch, drive);
if (KSUCCESS(st))
ctl->DeviceCount++;
}
}
if (ctl->DeviceCount == 0)
DbgPrint("ATA: no ATA disks found on PCI %02x:%02x.%x\n",
ctl->PciInfo.Address.Bus,
ctl->PciInfo.Address.Device,
ctl->PciInfo.Address.Function);
ctl->Started = true;
ctl->Fdo->PnpState = DevicePnpStarted;
return STATUS_SUCCESS;
}
static void AtaCancelReleaseRemoveLock(IRP* irp, void* context) {
ATA_DEVICE* dev = (ATA_DEVICE*)context;
if (dev)
IoReleaseRemoveLock(&dev->RemoveLock, irp);
}
static void AtaRemoveControllerDevices(ATA_CONTROLLER* ctl, IO_DEVICE_CHANGE change) {
if (!ctl) return;
for (uint8_t c = 0; c < ATA_CHANNEL_COUNT; c++) {
ATA_CHANNEL* ch = &ctl->Channels[c];
for (uint8_t d = 0; d < ATA_DRIVES_PER_CHANNEL; d++) {
ATA_DEVICE* dev = &ch->Devices[d];
if (!dev->Present)
continue;
IrpQueueCancelAllEx(&dev->IrpQueue, STATUS_OBJECT_DEAD, AtaCancelReleaseRemoveLock, dev);
if (dev->DiskIndex != 0xFFu) {
if (change == IoDeviceSurpriseRemoved)
IoNotifyDiskSurpriseRemoved(dev->DiskIndex);
else
IoUnregisterDiskDevice(dev->DiskIndex);
dev->DiskIndex = 0xFFu;
}
dev->Present = false;
}
}
}
KSTATUS AtaDispatchPnp(DEVICE_OBJECT* device, IRP* irp) {
if (!device || !irp || !device->DeviceExtension)
return STATUS_INVALID_PARAMETER;
ATA_CONTROLLER* ctl = (ATA_CONTROLLER*)device->DeviceExtension;
if (ctl->Magic == ATA_CONTROLLER_MAGIC) {
IO_STACK_LOCATION* ios = IoGetCurrentIrpStackLocation(irp);
if (!ios || ios->MajorFunction != IRP_MJ_PNP)
return STATUS_INVALID_PARAMETER;
switch ((IO_PNP_MINOR_FUNCTION)ios->MinorFunction) {
case IRP_MN_START_DEVICE:
return AtaStartController(ctl);
case IRP_MN_QUERY_REMOVE_DEVICE:
case IRP_MN_CANCEL_REMOVE_DEVICE:
return STATUS_SUCCESS;
case IRP_MN_SURPRISE_REMOVAL:
ctl->SurpriseRemoved = true;
device->PnpState = DevicePnpSurpriseRemoved;
AtaRemoveControllerDevices(ctl, IoDeviceSurpriseRemoved);
return STATUS_SUCCESS;
case IRP_MN_REMOVE_DEVICE:
ctl->Removed = true;
device->PnpState = DevicePnpDeleted;
AtaRemoveControllerDevices(ctl, IoDeviceRemoved);
IoDetachDevice(device);
IoDeleteDevice(device);
return STATUS_SUCCESS;
default:
return IoForwardIrpToLower(device, irp);
}
}
ATA_DEVICE* dev = (ATA_DEVICE*)device->DeviceExtension;
if (dev->Magic == ATA_DEVICE_MAGIC) {
IO_STACK_LOCATION* ios = IoGetCurrentIrpStackLocation(irp);
if (!ios || ios->MajorFunction != IRP_MJ_PNP)
return STATUS_INVALID_PARAMETER;
switch ((IO_PNP_MINOR_FUNCTION)ios->MinorFunction) {
case IRP_MN_START_DEVICE:
device->PnpState = DevicePnpStarted;
return STATUS_SUCCESS;
case IRP_MN_QUERY_REMOVE_DEVICE:
case IRP_MN_CANCEL_REMOVE_DEVICE:
return STATUS_SUCCESS;
case IRP_MN_SURPRISE_REMOVAL:
device->PnpState = DevicePnpSurpriseRemoved;
dev->Present = false;
IrpQueueCancelAllEx(&dev->IrpQueue, STATUS_OBJECT_DEAD, AtaCancelReleaseRemoveLock, dev);
return STATUS_SUCCESS;
case IRP_MN_REMOVE_DEVICE:
device->PnpState = DevicePnpDeleted;
dev->Present = false;
IrpQueueCancelAllEx(&dev->IrpQueue, STATUS_OBJECT_DEAD, AtaCancelReleaseRemoveLock, dev);
IoReleaseRemoveLockAndWait(&dev->RemoveLock, irp);
IoDeleteDevice(device);
dev->DeviceObject = (DEVICE_OBJECT*)0;
return STATUS_SUCCESS;
default:
return STATUS_NOT_SUPPORTED;
}
}
return STATUS_INVALID_PARAMETER;
}
KSTATUS AtaAddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDeviceObject) {
if (!driver || !physicalDeviceObject || physicalDeviceObject->Type != DeviceObjectPhysical)
return STATUS_INVALID_PARAMETER;
DEVICE_OBJECT* fdo = (DEVICE_OBJECT*)0;
KSTATUS st = IoCreateDevice(driver, sizeof(ATA_CONTROLLER), &fdo);
if (!KSUCCESS(st))
return st;
(void)IoSetDeviceName(fdo, SYS_SV_LITERAL("ata-controller"));
ATA_CONTROLLER* ctl = (ATA_CONTROLLER*)fdo->DeviceExtension;
memset(ctl, 0, sizeof(*ctl));
ctl->Magic = ATA_CONTROLLER_MAGIC;
ctl->Fdo = fdo;
ctl->Pdo = physicalDeviceObject;
ctl->LowerDevice = IoAttachDeviceToDeviceStack(fdo, physicalDeviceObject);
if (!ctl->LowerDevice) {
IoDeleteDevice(fdo);
return STATUS_FAILURE;
}
DbgPrint("ATA: FDO attached to %v\n", physicalDeviceObject->Name);
return STATUS_SUCCESS;
}
KSTATUS DriverEntry(const HAL_API* hal) {
if (!hal)
return STATUS_INVALID_PARAMETER;
DbgPrint("ATA: driver loading...\n");
gAtaHal = hal;
gAtaControllerCount = 0;
memset(&gAtaDriver, 0, sizeof(gAtaDriver));
IoInitializeDriverObject(&gAtaDriver, SYS_SV_LITERAL("ata"));
gAtaDriver.IdTable = &gAtaIdTable;
gAtaDriver.DriverAddDevice = AtaAddDevice;
gAtaDriver.MajorFunction[IRP_MJ_READ] = AtaDispatchReadWrite;
gAtaDriver.MajorFunction[IRP_MJ_WRITE] = AtaDispatchReadWrite;
gAtaDriver.MajorFunction[IRP_MJ_PNP] = AtaDispatchPnp;
KSTATUS st = IoRegisterDriverObject(&gAtaDriver);
if (!KSUCCESS(st))
DbgPrint("ATA: IoRegisterDriverObject failed: 0x%x\n", st);
return st;
}
+130
View File
@@ -0,0 +1,130 @@
// ata.h - PCI IDE / ATA driver internals.
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <intrin.h>
#include <ntlite/ddi/hal_api.h>
#include <ntlite/ddi/io_driver.h>
#include <ntlite/ddi/pci.h>
#include <ntlite/status.h>
#include <kernel/ke_debug.h>
#include <kernel/ke_irp.h>
#include <kernel/ke_sched.h>
#include <kernel/ke_semaphore.h>
#include <kernel/ke_thread.h>
#include <kernel/mm_phys.h>
#include <kernel/mm_virt.h>
#define ATA_CONTROLLER_MAGIC 0x41544143u // ATAC
#define ATA_DEVICE_MAGIC 0x41544144u // ATAD
#define ATA_MAX_CONTROLLERS 8u
#define ATA_CHANNEL_COUNT 2u
#define ATA_DRIVES_PER_CHANNEL 2u
#define ATA_MAX_DEVICES_PER_CTL (ATA_CHANNEL_COUNT * ATA_DRIVES_PER_CHANNEL)
#define ATA_PRIMARY_LEGACY_CMD_BASE 0x1F0u
#define ATA_PRIMARY_LEGACY_CTL_BASE 0x3F6u
#define ATA_PRIMARY_LEGACY_IRQ 14u
#define ATA_SECONDARY_LEGACY_CMD_BASE 0x170u
#define ATA_SECONDARY_LEGACY_CTL_BASE 0x376u
#define ATA_SECONDARY_LEGACY_IRQ 15u
#define ATA_REG_DATA 0x00u
#define ATA_REG_ERROR 0x01u
#define ATA_REG_FEATURES 0x01u
#define ATA_REG_SECTOR_COUNT 0x02u
#define ATA_REG_LBA0 0x03u
#define ATA_REG_LBA1 0x04u
#define ATA_REG_LBA2 0x05u
#define ATA_REG_DRIVE_HEAD 0x06u
#define ATA_REG_STATUS 0x07u
#define ATA_REG_COMMAND 0x07u
#define ATA_REG_ALT_STATUS 0x00u
#define ATA_REG_DEVICE_CONTROL 0x00u
#define ATA_STATUS_ERR 0x01u
#define ATA_STATUS_DRQ 0x08u
#define ATA_STATUS_DF 0x20u
#define ATA_STATUS_DRDY 0x40u
#define ATA_STATUS_BSY 0x80u
#define ATA_CMD_READ_SECTORS 0x20u
#define ATA_CMD_WRITE_SECTORS 0x30u
#define ATA_CMD_CACHE_FLUSH 0xE7u
#define ATA_CMD_IDENTIFY_DEVICE 0xECu
#define ATA_CMD_READ_SECTORS_EXT 0x24u
#define ATA_CMD_WRITE_SECTORS_EXT 0x34u
#define ATA_CMD_CACHE_FLUSH_EXT 0xEAu
#define ATA_IDENT_CAPABILITIES 49u
#define ATA_IDENT_COMMAND_SETS 83u
#define ATA_IDENT_LBA28_SECTORS_LO 60u
#define ATA_IDENT_LBA28_SECTORS_HI 61u
#define ATA_IDENT_LBA48_SECTORS 100u
#define ATA_IDENT_LBA_SUPPORTED (1u << 9)
#define ATA_IDENT_LBA48_SUPPORTED (1u << 10)
#define ATA_SECTOR_SIZE 512u
#define ATA_POLL_LIMIT 100000u
struct ATA_CONTROLLER;
struct ATA_CHANNEL;
typedef struct ATA_DEVICE {
uint32_t Magic;
struct ATA_CONTROLLER* Controller;
struct ATA_CHANNEL* Channel;
DEVICE_OBJECT* DeviceObject;
uint8_t Drive; // 0=master, 1=slave
uint8_t DiskIndex;
bool Present;
bool SupportsLba48;
uint64_t SectorCount;
IRP_QUEUE IrpQueue;
SEMAPHORE* IrpSemaphore;
IO_REMOVE_LOCK RemoveLock;
THREAD* WorkerThread;
} ATA_DEVICE;
typedef struct ATA_CHANNEL {
struct ATA_CONTROLLER* Controller;
uint8_t Index;
uint16_t CommandBase;
uint16_t ControlBase;
uint8_t Irq;
bool NativeMode;
SEMAPHORE* Lock;
ATA_DEVICE Devices[ATA_DRIVES_PER_CHANNEL];
} ATA_CHANNEL;
typedef struct ATA_CONTROLLER {
uint32_t Magic;
DEVICE_OBJECT* Fdo;
DEVICE_OBJECT* Pdo;
DEVICE_OBJECT* LowerDevice;
PCI_DEVICE_INFO PciInfo;
bool Started;
bool Removed;
bool SurpriseRemoved;
ATA_CHANNEL Channels[ATA_CHANNEL_COUNT];
uint8_t DeviceCount;
} ATA_CONTROLLER;
extern const HAL_API* gAtaHal;
KSTATUS AtaAddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDeviceObject);
KSTATUS AtaDispatchPnp(DEVICE_OBJECT* device, IRP* irp);
KSTATUS AtaDispatchReadWrite(DEVICE_OBJECT* device, IRP* irp);
-531
View File
@@ -1,531 +0,0 @@
// ide.c - IDE/ATA disk I/O path and DriverEntry.
#include "ide.h"
// ---------------------------------------------------------------------------
// Module state
// ---------------------------------------------------------------------------
const HAL_API *gHal;
DRIVER_OBJECT gDriver;
DEVICE_OBJECT *gDevice = NULL;
bool gDmaEnabled = false;
uint64_t gSectorCount = 0;
bool gSupportsLba48 = false;
// DMA hardware state
uint16_t gBmBase = 0; // Bus Master I/O base port (BAR4 & ~3)
PRD *gPrdtVirt = NULL; // kernel VA of PRDT page
uint32_t gPrdtPhys = 0; // 32-bit physical address of PRDT
// Async worker synchronisation
IRP_QUEUE gIrpQueue;
SEMAPHORE *gIrpSemaphore = NULL;
EVENT *gDmaEvent = NULL; // auto-reset; DPC signals after each xfer
KDPC gDmaDpc; // bottom half for DMA completion
IO_REMOVE_LOCK gRemoveLock;
bool gSurpriseRemoved = false;
bool gRemoved = false;
// ---------------------------------------------------------------------------
// Bus Master I/O helpers
// ---------------------------------------------------------------------------
static inline uint8_t BmRead8 (uint8_t reg) { return __inbyte (gBmBase + reg); }
static inline void BmWrite8 (uint8_t reg, uint8_t v) { __outbyte (gBmBase + reg, v); }
static inline void BmWrite32(uint8_t reg, uint32_t v) { __outdword(gBmBase + reg, v); }
// ---------------------------------------------------------------------------
// PIO polling helpers (unchanged)
// ---------------------------------------------------------------------------
static void IdeWait(void) {
while (__inbyte(IDE_STATUS) & IDE_BUSY)
KeYield();
}
static KSTATUS IdeWaitData(void) {
for (int i = 0; i < 4; i++) __inbyte(IDE_ALT); // 400 ns delay
while (true) {
uint8_t st = __inbyte(IDE_STATUS);
if (st & IDE_ERR_F) return STATUS_DEVICE_ERROR;
if (!(st & IDE_BUSY) && (st & IDE_DRQ)) return STATUS_SUCCESS;
KeYield();
}
}
// ---------------------------------------------------------------------------
// PIO read/write — sync fallback when DMA is unavailable
// ---------------------------------------------------------------------------
static KSTATUS IdeRead(void *ctx, uint64_t lba, uint32_t count, void *buf) {
(void)ctx;
if (lba + count > gSectorCount) return STATUS_INVALID_PARAMETER;
uint16_t *p = (uint16_t *)buf;
for (uint32_t i = 0; i < count; i++, lba++) {
IdeWait();
if (gSupportsLba48) {
__outbyte(IDE_DRIVE, 0x40);
__outbyte(IDE_SECCNT, 0);
__outbyte(IDE_LBA0, (lba >> 24) & 0xFF);
__outbyte(IDE_LBA1, (lba >> 32) & 0xFF);
__outbyte(IDE_LBA2, (lba >> 40) & 0xFF);
__outbyte(IDE_SECCNT, 1);
__outbyte(IDE_LBA0, (uint8_t)lba);
__outbyte(IDE_LBA1, (uint8_t)(lba >> 8));
__outbyte(IDE_LBA2, (uint8_t)(lba >> 16));
__outbyte(IDE_CMD, CMD_READ_EXT);
} else {
__outbyte(IDE_DRIVE, 0xE0 | ((lba >> 24) & 0xF));
__outbyte(IDE_SECCNT, 1);
__outbyte(IDE_LBA0, (uint8_t)lba);
__outbyte(IDE_LBA1, (uint8_t)(lba >> 8));
__outbyte(IDE_LBA2, (uint8_t)(lba >> 16));
__outbyte(IDE_CMD, 0x20);
}
if (IdeWaitData() != STATUS_SUCCESS) return STATUS_DEVICE_ERROR;
for (int w = 0; w < 256; w++) *p++ = __inword(IDE_DATA);
}
return STATUS_SUCCESS;
}
static KSTATUS IdeWrite(void *ctx, uint64_t lba, uint32_t count, const void *buf) {
(void)ctx;
if (lba + count > gSectorCount) return STATUS_INVALID_PARAMETER;
const uint16_t *p = (const uint16_t *)buf;
for (uint32_t i = 0; i < count; i++, lba++) {
IdeWait();
if (gSupportsLba48) {
__outbyte(IDE_DRIVE, 0x40);
__outbyte(IDE_SECCNT, 0);
__outbyte(IDE_LBA0, (lba >> 24) & 0xFF);
__outbyte(IDE_LBA1, (lba >> 32) & 0xFF);
__outbyte(IDE_LBA2, (lba >> 40) & 0xFF);
__outbyte(IDE_SECCNT, 1);
__outbyte(IDE_LBA0, (uint8_t)lba);
__outbyte(IDE_LBA1, (uint8_t)(lba >> 8));
__outbyte(IDE_LBA2, (uint8_t)(lba >> 16));
__outbyte(IDE_CMD, CMD_WRITE_EXT);
} else {
__outbyte(IDE_DRIVE, 0xE0 | ((lba >> 24) & 0xF));
__outbyte(IDE_SECCNT, 1);
__outbyte(IDE_LBA0, (uint8_t)lba);
__outbyte(IDE_LBA1, (uint8_t)(lba >> 8));
__outbyte(IDE_LBA2, (uint8_t)(lba >> 16));
__outbyte(IDE_CMD, 0x30);
}
IdeWait();
for (int w = 0; w < 256; w++) __outword(IDE_DATA, *p++);
__outbyte(IDE_ALT, 0); // flush write cache
if (IdeWaitData() != STATUS_SUCCESS) return STATUS_DEVICE_ERROR;
}
return STATUS_SUCCESS;
}
// ---------------------------------------------------------------------------
// BuildPrdt — fill gPrdtVirt[] for a transfer.
//
// Walks the virtual buffer in page-aligned chunks, looks up each chunk's
// physical address via MmGetPhysicalAddress, and coalesces adjacent physical
// pages into a single PRD entry where possible. This is correct regardless of
// whether the pool gave us physically contiguous pages.
//
// Constraints enforced:
// - Each PRD entry covers at most one 4 KB physical page (never crosses
// a page boundary), so the physical address is valid for the whole chunk.
// - Total byte count per entry is ≤ 64 KB (the PRD limit).
// - Physical address must fit in 32 bits (BM IDE hardware limit).
//
// Returns the number of PRD entries written, or 0 on error.
// ---------------------------------------------------------------------------
static uint32_t BuildPrdt(void *virtBuf, uint32_t byteLen) {
uint32_t nPrd = 0;
uintptr_t va = (uintptr_t)virtBuf;
uint32_t remain = byteLen;
while (remain > 0) {
if (nPrd >= PRDT_MAX_ENTRIES) {
DbgPrint("IDE DMA: transfer too large for PRDT (%u entries)\n", nPrd);
return 0;
}
// Bytes from va to the end of its 4 KB page (never straddles a page).
uint32_t pageOff = (uint32_t)(va & 0xFFF);
uint32_t inPage = 0x1000 - pageOff;
uint32_t chunk = (remain < inPage) ? remain : inPage;
PHYSICAL_ADDRESS phys = MmGetPhysicalAddress(va);
if (phys >> 32) {
// Physical address above 4 GB — BM IDE's 32-bit PRDT can't reach it.
DbgPrint("IDE DMA: buffer page at VA 0x%016llX has phys 0x%016llX > 4 GB\n",
(uint64_t)va, (uint64_t)phys);
return 0;
}
uint32_t phys32 = (uint32_t)phys;
// Try to coalesce with the previous PRD entry if the physical regions
// are adjacent and the combined size stays within the 64 KB limit.
if (nPrd > 0) {
PRD *prev = &gPrdtVirt[nPrd - 1];
uint32_t prevSz = prev->byteCount ? prev->byteCount : 0x10000u;
uint32_t prevEnd = prev->physAddr + prevSz;
uint32_t combined = prevSz + chunk;
if (prevEnd == phys32 && combined <= 0x10000u) {
prev->byteCount = (uint16_t)(combined == 0x10000u ? 0u : combined);
va += chunk;
remain -= chunk;
continue;
}
}
gPrdtVirt[nPrd].physAddr = phys32;
gPrdtVirt[nPrd].byteCount = (uint16_t)(chunk == 0x10000u ? 0u : chunk);
gPrdtVirt[nPrd].flags = 0;
nPrd++;
va += chunk;
remain -= chunk;
}
if (nPrd > 0)
gPrdtVirt[nPrd - 1].flags |= PRD_EOT;
return nPrd;
}
// ---------------------------------------------------------------------------
// IDE DMA completion DPC. The ISR owns hardware acknowledgement; this bottom
// half wakes the worker outside hard IRQ/DIRQL context.
// ---------------------------------------------------------------------------
void IdeDmaCompletionDpc(KDPC *dpc, void *context,
void *systemArgument1, void *systemArgument2) {
(void)dpc;
(void)context;
(void)systemArgument1;
(void)systemArgument2;
if (gDmaEvent)
KeSignalEvent(gDmaEvent);
}
// ---------------------------------------------------------------------------
// IDE ISR (IRQ 14 — primary channel)
//
// Must be fast — runs with interrupts disabled. We only clear the hardware
// interrupt bits here and queue a DPC to wake the worker thread.
// The worker reads the final status and fires IRP completion hooks.
// ---------------------------------------------------------------------------
void IdeIsr(void) {
uint8_t bmSt = BmRead8(BM_STATUS_REG);
if (!(bmSt & BM_STATUS_IRQ))
return; // not our interrupt (spurious or secondary channel)
// Stop the Bus Master engine.
BmWrite8(BM_CMD_REG, 0x00);
// Clear interrupt and error sticky bits (write-1-to-clear).
BmWrite8(BM_STATUS_REG, BM_STATUS_IRQ | BM_STATUS_ERROR);
// Read IDE status and alt-status to fully acknowledge the device interrupt.
(void)__inbyte(IDE_ALT);
(void)__inbyte(IDE_STATUS);
// Wake happens in the DPC. gDmaEvent is auto-reset so exactly one waiter
// is released when the bottom half runs.
KeInsertQueueDpc(&gDmaDpc, (void *)0, (void *)0);
}
// ---------------------------------------------------------------------------
// IdeDmaRw — program the hardware and block until the ISR completes it.
//
// Called exclusively from IdeWorker. Has full control of the IDE/BM
// registers; no other thread touches them while the worker is running.
// Falls back to PIO inline if BuildPrdt fails (address space issue).
// ---------------------------------------------------------------------------
static KSTATUS IdeDmaRw(uint64_t lba, uint32_t count, void *buf, bool write) {
uint32_t byteLen = count * 512u;
uint32_t nPrd = BuildPrdt(buf, byteLen);
if (nPrd == 0) {
// Graceful inline PIO fallback for awkward buffers.
DbgPrint("IDE DMA: BuildPrdt failed — falling back to PIO\n");
return write ? IdeWrite(NULL, lba, count, buf)
: IdeRead (NULL, lba, count, buf);
}
// ---- Program Bus Master -----------------------------------------------
// Load PRDT physical address.
BmWrite32(BM_PRDT_REG, gPrdtPhys);
// Clear any leftover interrupt/error bits from the previous transfer.
BmWrite8(BM_STATUS_REG, BM_STATUS_IRQ | BM_STATUS_ERROR);
// Set direction: BM_CMD_READ = disk→memory; 0 = memory→disk.
// Do NOT set BM_CMD_START yet — spec says program ATA regs first.
BmWrite8(BM_CMD_REG, write ? 0x00 : BM_CMD_READ);
// ---- Program ATA registers -------------------------------------------
IdeWait();
if (gSupportsLba48) {
__outbyte(IDE_DRIVE, 0x40);
__outbyte(IDE_SECCNT, (uint8_t)(count >> 8)); // sector count high byte
__outbyte(IDE_LBA0, (uint8_t)(lba >> 24));
__outbyte(IDE_LBA1, (uint8_t)(lba >> 32));
__outbyte(IDE_LBA2, (uint8_t)(lba >> 40));
__outbyte(IDE_SECCNT, (uint8_t)count); // sector count low byte
__outbyte(IDE_LBA0, (uint8_t)lba);
__outbyte(IDE_LBA1, (uint8_t)(lba >> 8));
__outbyte(IDE_LBA2, (uint8_t)(lba >> 16));
__outbyte(IDE_CMD, write ? CMD_WRITE_DMA_EXT : CMD_READ_DMA_EXT);
} else {
__outbyte(IDE_DRIVE, 0xE0 | ((lba >> 24) & 0xF));
__outbyte(IDE_SECCNT, (uint8_t)count);
__outbyte(IDE_LBA0, (uint8_t)lba);
__outbyte(IDE_LBA1, (uint8_t)(lba >> 8));
__outbyte(IDE_LBA2, (uint8_t)(lba >> 16));
__outbyte(IDE_CMD, write ? CMD_WRITE_DMA : CMD_READ_DMA);
}
// ---- Start DMA --------------------------------------------------------
// Set Start bit. Direction bit is already set from above.
BmWrite8(BM_CMD_REG, (write ? 0x00 : BM_CMD_READ) | BM_CMD_START);
// Block the worker thread until the ISR fires.
KeWaitForEvent(gDmaEvent, 0);
// ---- Read result -------------------------------------------------------
// ISR already stopped the BM engine and cleared BM_STATUS_IRQ.
// We still need to check BM_STATUS_ERROR and IDE_ERR_F.
uint8_t bmSt = BmRead8(BM_STATUS_REG);
uint8_t ideSt = __inbyte(IDE_STATUS);
if (bmSt & BM_STATUS_ERROR) {
DbgPrint("IDE DMA: BM error (bmStatus=0x%02x, ideStatus=0x%02x, ideErr=0x%02x)\n",
bmSt, ideSt, __inbyte(IDE_ERR));
return STATUS_DEVICE_ERROR;
}
if (ideSt & IDE_ERR_F) {
DbgPrint("IDE DMA: ATA error (ideStatus=0x%02x, ideErr=0x%02x)\n",
ideSt, __inbyte(IDE_ERR));
return STATUS_DEVICE_ERROR;
}
return STATUS_SUCCESS;
}
static KSTATUS IdeGetIrpReadWrite(IRP* irp, bool* outWrite, uint64_t* outLba,
uint32_t* outSectors, void** outBuffer) {
if (!irp || !outWrite || !outLba || !outSectors || !outBuffer)
return STATUS_INVALID_PARAMETER;
IO_STACK_LOCATION* ios = IoGetCurrentIrpStackLocation(irp);
if (!ios) return STATUS_INVALID_PARAMETER;
if (ios->MajorFunction != IRP_MJ_READ && ios->MajorFunction != IRP_MJ_WRITE)
return STATUS_INVALID_PARAMETER;
if ((ios->Parameters.ReadWrite.ByteOffset & 511ull) ||
(ios->Parameters.ReadWrite.Length & 511u))
return STATUS_INVALID_PARAMETER;
if (!irp->UserBuffer || ios->Parameters.ReadWrite.Length == 0)
return STATUS_INVALID_PARAMETER;
*outWrite = (ios->MajorFunction == IRP_MJ_WRITE);
*outLba = ios->Parameters.ReadWrite.ByteOffset >> 9;
*outSectors = ios->Parameters.ReadWrite.Length >> 9;
*outBuffer = irp->UserBuffer;
return STATUS_SUCCESS;
}
// ---------------------------------------------------------------------------
// IdeWorker — kernel thread, one per IDE controller.
//
// Blocks on gIrpSemaphore. Each IrpQueueEnqueue increments it by one, so
// the worker wakes once per submitted IRP. Mirrors AhciWorker exactly.
// ---------------------------------------------------------------------------
void IdeWorker(uintptr_t arg) {
(void)arg;
while (true) {
KeWaitSemaphore(gIrpSemaphore);
IRP *irp = IrpQueueDequeue(&gIrpQueue);
if (!irp)
continue;
bool write = false;
uint64_t lba = 0;
uint32_t sectors = 0;
void* buffer = (void*)0;
KSTATUS st = IdeGetIrpReadWrite(irp, &write, &lba, &sectors, &buffer);
if (KSUCCESS(st)) {
if (lba + sectors > gSectorCount)
st = STATUS_INVALID_PARAMETER;
else
st = IdeDmaRw(lba, sectors, buffer, write);
}
IoReleaseRemoveLock(&gRemoveLock, irp);
IoCompleteRequest(irp, st, KSUCCESS(st) ? ((size_t)sectors * 512u) : 0);
}
}
// ---------------------------------------------------------------------------
// IdeDispatchReadWrite — DEVICE_OBJECT dispatch entry for disk IRPs.
//
// If DMA is online, the IRP is queued to the worker and completed later.
// If DMA is unavailable, the IRP is completed inline through the PIO path.
// Either way, accepted IRPs return STATUS_PENDING and complete through
// IoCompleteRequest().
// ---------------------------------------------------------------------------
static KSTATUS IdeDispatchReadWrite(DEVICE_OBJECT *device, IRP *irp) {
(void)device;
KSTATUS st = IoAcquireRemoveLock(&gRemoveLock, irp);
if (!KSUCCESS(st))
return st;
bool write = false;
uint64_t lba = 0;
uint32_t sectors = 0;
void* buffer = (void*)0;
st = IdeGetIrpReadWrite(irp, &write, &lba, &sectors, &buffer);
if (!KSUCCESS(st) || lba + sectors > gSectorCount) {
IoReleaseRemoveLock(&gRemoveLock, irp);
return KSUCCESS(st) ? STATUS_INVALID_PARAMETER : st;
}
irp->Status = STATUS_FAILURE;
irp->Information = 0;
if (gDmaEnabled) {
IrpQueueEnqueue(&gIrpQueue, irp);
return STATUS_PENDING;
}
st = write ? IdeWrite(NULL, lba, sectors, buffer)
: IdeRead (NULL, lba, sectors, buffer);
IoReleaseRemoveLock(&gRemoveLock, irp);
IoCompleteRequest(irp, st, KSUCCESS(st) ? ((size_t)sectors * 512u) : 0);
return STATUS_PENDING;
}
static void IdeCancelReleaseRemoveLock(IRP* irp, void* context) {
(void)context;
IoReleaseRemoveLock(&gRemoveLock, irp);
}
static KSTATUS IdeDispatchPnp(DEVICE_OBJECT* device, IRP* irp) {
if (!device || !irp) return STATUS_INVALID_PARAMETER;
IO_STACK_LOCATION* ios = IoGetCurrentIrpStackLocation(irp);
if (!ios || ios->MajorFunction != IRP_MJ_PNP)
return STATUS_INVALID_PARAMETER;
switch ((IO_PNP_MINOR_FUNCTION)ios->MinorFunction) {
case IRP_MN_START_DEVICE:
device->PnpState = DevicePnpStarted;
return STATUS_SUCCESS;
case IRP_MN_QUERY_REMOVE_DEVICE:
device->PnpState = DevicePnpRemovePending;
return STATUS_SUCCESS;
case IRP_MN_CANCEL_REMOVE_DEVICE:
device->PnpState = DevicePnpStarted;
return STATUS_SUCCESS;
case IRP_MN_SURPRISE_REMOVAL:
gSurpriseRemoved = true;
device->PnpState = DevicePnpSurpriseRemoved;
IrpQueueCancelAllEx(&gIrpQueue, STATUS_OBJECT_DEAD, IdeCancelReleaseRemoveLock, (void*)0);
return STATUS_SUCCESS;
case IRP_MN_REMOVE_DEVICE:
gRemoved = true;
device->PnpState = DevicePnpDeleted;
IrpQueueCancelAllEx(&gIrpQueue, STATUS_OBJECT_DEAD, IdeCancelReleaseRemoveLock, (void*)0);
IoReleaseRemoveLockAndWait(&gRemoveLock, irp);
IoDeleteDevice(device);
gDevice = (DEVICE_OBJECT*)0;
return STATUS_SUCCESS;
default:
return STATUS_NOT_SUPPORTED;
}
}
// ---------------------------------------------------------------------------
// IdeDmaInit — locate the PCI IDE controller, grab BAR4, allocate the PRDT,
// create sync objects, and register IRQ 14.
//
// Returns true on success. On any failure, logs a message and returns false;
// dispatch will complete IRPs inline through PIO.
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// DriverEntry
// ---------------------------------------------------------------------------
KSTATUS DriverEntry(const HAL_API *hal) {
DbgPrint("IDE: Init\n");
gHal = hal;
// ---- IDENTIFY drive (same as before) ----------------------------------
__outbyte(IDE_DRIVE, 0xA0);
for (int i = 0; i < 4; i++) __inbyte(IDE_ALT);
__outbyte(IDE_SECCNT, 0);
__outbyte(IDE_LBA0, 0);
__outbyte(IDE_LBA1, 0);
__outbyte(IDE_LBA2, 0);
__outbyte(IDE_CMD, CMD_IDENT);
if (__inbyte(IDE_STATUS) == 0) {
DbgPrint("IDE: No drive on primary channel\n");
return STATUS_NOT_FOUND;
}
int timeout = 10000;
while (__inbyte(IDE_STATUS) & IDE_BUSY) {
if (--timeout == 0) return STATUS_DEVICE_ERROR;
KeYield();
}
if (__inbyte(IDE_LBA1) != 0 || __inbyte(IDE_LBA2) != 0) {
DbgPrint("IDE: Not a standard ATA drive (ATAPI?)\n");
return STATUS_NOT_SUPPORTED;
}
timeout = 10000;
while (true) {
uint8_t st = __inbyte(IDE_STATUS);
if (st & IDE_ERR_F) return STATUS_DEVICE_ERROR;
if (st & IDE_DRQ) break;
if (--timeout == 0) return STATUS_DEVICE_ERROR;
KeYield();
}
uint16_t ident[256];
for (int i = 0; i < 256; i++) ident[i] = __inword(IDE_DATA);
gSupportsLba48 = (ident[83] & (1 << 10)) != 0;
if (gSupportsLba48) {
gSectorCount = *(uint64_t *)&ident[100];
DbgPrint("IDE: LBA48, %llu sectors\n", gSectorCount);
} else {
gSectorCount = ((uint32_t)ident[61] << 16) | ident[60];
DbgPrint("IDE: LBA28, %u sectors\n", (uint32_t)gSectorCount);
}
if (gSectorCount == 0) return STATUS_NOT_FOUND;
// ---- Register definitive DEVICE_OBJECT --------------------------------
memset(&gDriver, 0, sizeof(gDriver));
IoInitializeDriverObject(&gDriver, SYS_SV_LITERAL("ide"));
gDriver.MajorFunction[IRP_MJ_READ] = IdeDispatchReadWrite;
gDriver.MajorFunction[IRP_MJ_WRITE] = IdeDispatchReadWrite;
gDriver.MajorFunction[IRP_MJ_PNP] = IdeDispatchPnp;
KSTATUS st = IoInitializeRemoveLock(&gRemoveLock);
if (!KSUCCESS(st)) return st;
st = IoCreateDevice(&gDriver, 0, &gDevice);
if (!KSUCCESS(st)) return st;
gDevice->u.Disk.SectorCount = gSectorCount;
gDevice->u.Disk.SectorSize = 512;
gDevice->AlignmentRequirement = 512;
// ---- Try to initialise Bus Master DMA ---------------------------------
gDmaEnabled = IdeDmaInit();
DbgPrint("IDE: Registered (%s)\n", gDmaEnabled ? "DMA" : "PIO fallback");
return IoRegisterDiskDevice(0, gDevice);
}
-102
View File
@@ -1,102 +0,0 @@
// ide.h - shared IDE/ATA driver internals.
#pragma once
#include <stdint.h>
#include <string.h>
#include <intrin.h>
#include <ntlite/ddi/io_driver.h>
#include <ntlite/ddi/hal_api.h>
#include <kernel/ke_debug.h>
#include <kernel/ke_sched.h>
#include <kernel/ke_irp.h>
#include <kernel/ke_event.h>
#include <kernel/ke_semaphore.h>
#include <kernel/ke_thread.h>
#include <kernel/ke_irq.h>
#include <kernel/ke_dpc.h>
#include <kernel/mm_phys.h>
#include <kernel/mm_virt.h>
// ---------------------------------------------------------------------------
// IDE register map (primary channel, base 0x1F0)
// ---------------------------------------------------------------------------
#define IDE_DATA 0x1F0
#define IDE_ERR 0x1F1
#define IDE_SECCNT 0x1F2
#define IDE_LBA0 0x1F3
#define IDE_LBA1 0x1F4
#define IDE_LBA2 0x1F5
#define IDE_DRIVE 0x1F6
#define IDE_STATUS 0x1F7
#define IDE_CMD 0x1F7
#define IDE_ALT 0x3F6
#define IDE_BUSY 0x80
#define IDE_READY 0x40
#define IDE_ERR_F 0x01
#define IDE_DRQ 0x08
// ATA commands
#define CMD_READ_EXT 0x24 // PIO 48-bit read
#define CMD_WRITE_EXT 0x34 // PIO 48-bit write
#define CMD_READ_DMA_EXT 0x25 // DMA 48-bit read
#define CMD_WRITE_DMA_EXT 0x35 // DMA 48-bit write
#define CMD_READ_DMA 0xC8 // DMA 28-bit read
#define CMD_WRITE_DMA 0xCA // DMA 28-bit write
#define CMD_IDENT 0xEC
// IDE primary IRQ
#define IDE_IRQ_PRIMARY 14
// ---------------------------------------------------------------------------
// Bus Master IDE register offsets (relative to gBmBase, primary channel)
// ---------------------------------------------------------------------------
#define BM_CMD_REG 0x00 // command
#define BM_STATUS_REG 0x02 // status
#define BM_PRDT_REG 0x04 // PRDT physical address (32-bit)
// BM_CMD_REG bits
#define BM_CMD_START 0x01 // start DMA transfer
#define BM_CMD_READ 0x08 // 1 = disk→memory (read), 0 = memory→disk (write)
// BM_STATUS_REG bits
#define BM_STATUS_ACTIVE 0x01 // DMA active
#define BM_STATUS_ERROR 0x02 // DMA error (write 1 to clear)
#define BM_STATUS_IRQ 0x04 // interrupt pending (write 1 to clear)
// ---------------------------------------------------------------------------
// Physical Region Descriptor (PRDT entry, 8 bytes)
// The PRDT itself must not cross a 64 KB boundary and must be 4-byte aligned.
// We allocate a full page so both constraints are trivially satisfied.
// ---------------------------------------------------------------------------
#pragma pack(push, 1)
typedef struct {
uint32_t physAddr; // physical base of this memory region
uint16_t byteCount; // byte count; 0 means 64 KB
uint16_t flags; // bit 15: End Of Table
} PRD;
#pragma pack(pop)
#define PRD_EOT 0x8000u
// 512 entries × 8 bytes = 4096 bytes = exactly one page; supports 512×64 KB = 32 MB
#define PRDT_MAX_ENTRIES 512
extern const HAL_API *gHal;
extern DRIVER_OBJECT gDriver;
extern DEVICE_OBJECT *gDevice;
extern bool gDmaEnabled;
extern uint64_t gSectorCount;
extern bool gSupportsLba48;
extern uint16_t gBmBase;
extern PRD *gPrdtVirt;
extern uint32_t gPrdtPhys;
extern IRP_QUEUE gIrpQueue;
extern SEMAPHORE *gIrpSemaphore;
extern EVENT *gDmaEvent;
extern KDPC gDmaDpc;
void IdeDmaCompletionDpc(KDPC *dpc, void *context, void *systemArgument1, void *systemArgument2);
void IdeIsr(void);
void IdeWorker(uintptr_t arg);
bool IdeDmaInit(void);
-87
View File
@@ -1,87 +0,0 @@
// ide_bus.c - Bus-master IDE PCI/DMA initialisation.
#include "ide.h"
bool IdeDmaInit(void) {
// ---- Find PCI IDE controller (class 0x01, subclass 0x01) --------------
uint8_t bus, dev, fn;
if (!gHal->Pci.FindClass(0x01, 0x01, &bus, &dev, &fn)) {
DbgPrint("IDE DMA: No PCI IDE controller found — using PIO\n");
return false;
}
// ---- Read BAR4 (Bus Master base, I/O space) ---------------------------
// PCI config offset 0x20. Bit 0 must be 1 for I/O BAR.
uint32_t bar4 = gHal->Pci.Read32(bus, dev, fn, 0x20);
if (!(bar4 & 0x1)) {
DbgPrint("IDE DMA: BAR4 is a memory BAR (0x%08x) — unexpected, using PIO\n", bar4);
return false;
}
uint16_t bmBase = (uint16_t)(bar4 & 0xFFFC);
if (bmBase == 0) {
DbgPrint("IDE DMA: BAR4 is zero (firmware didn't assign it) — using PIO\n");
return false;
}
DbgPrint("IDE DMA: Bus Master base = 0x%04X (bus %u, dev %u, fn %u)\n",
bmBase, bus, dev, fn);
// ---- Enable Bus Mastering in PCI Command register (bit 2) ------------
uint32_t pciCmd = gHal->Pci.Read32(bus, dev, fn, 0x04);
gHal->Pci.Write32(bus, dev, fn, 0x04, pciCmd | (1u << 2));
// ---- Allocate PRDT page (must be 32-bit physical, 4-byte aligned) ----
PHYSICAL_ADDRESS prdtPhys = MmAllocateContiguous(1);
if (!prdtPhys) {
DbgPrint("IDE DMA: Failed to allocate PRDT page\n");
return false;
}
if (prdtPhys >> 32) {
// MmAllocateContiguous returned memory above 4 GB — BM IDE can't
// address it. This shouldn't happen on normal x86 systems with early
// boot allocations but we check defensively.
DbgPrint("IDE DMA: PRDT page is above 4 GB (0x%016llX) — using PIO\n",
(uint64_t)prdtPhys);
return false;
}
void *prdtVirt = gHal->PhysToVirt(prdtPhys);
DbgPrint("IDE DMA: PRDT at phys 0x%08x, virt 0x%016llX\n", (uint32_t)prdtPhys, prdtVirt);
// ---- Create synchronisation objects ------------------------------------
SEMAPHORE *sem = NULL;
if (!KSUCCESS(KeSemaphoreCreate(0, 0x7FFFFFFF, &sem))) {
DbgPrint("IDE DMA: Failed to create IRP semaphore\n");
return false;
}
EVENT *dmaEv = NULL;
if (!KSUCCESS(KeEventCreate(EventAutoReset, 0, &dmaEv))) {
DbgPrint("IDE DMA: Failed to create DMA completion event\n");
return false;
}
// ---- Commit module state -----------------------------------------------
gBmBase = bmBase;
gPrdtPhys = (uint32_t)prdtPhys;
gPrdtVirt = (PRD *)prdtVirt;
gIrpSemaphore = sem;
gDmaEvent = dmaEv;
KeInitializeDpc(&gDmaDpc, IdeDmaCompletionDpc, (void *)0);
IrpQueueInit(&gIrpQueue, sem);
// ---- Register IRQ 14 --------------------------------------------------
KeIrqRegister(IDE_IRQ_PRIMARY, IdeIsr);
DbgPrint("IDE DMA: IRQ %u registered\n", IDE_IRQ_PRIMARY);
// ---- Spawn worker thread -----------------------------------------------
KSTATUS st = KeCreateKernelThread((uintptr_t)IdeWorker, 0,
PriorityHigh, (THREAD **)NULL);
if (!KSUCCESS(st)) {
DbgPrint("IDE DMA: Worker thread creation failed (0x%x)\n", st);
// Not fatal for init — the PRDT/IRQ are live but async callers will
// never get completions. Better to surface the failure clearly.
return false;
}
DbgPrint("IDE DMA: Init complete\n");
return true;
}
+11 -2
View File
@@ -12,6 +12,8 @@ void HalScreenInitialize(void* (*AllocatePool)(size_t size), uintptr_t fb, int w
HAL_SCREEN* out);
KSTATUS HalTimerInitialize(uintptr_t lapicPhys, uintptr_t hpetPhys, HAL_TIMER *out);
void HalPciInitialize(HAL_PCI* out);
void HalRtcInitialize(HAL_RTC* out);
void HalRtcSetCenturyRegister(uint8_t centuryRegister);
extern void HalSetDebugEnabled(int v);
// Defined in mm_virt.c - HAL needs it for MMIO window access.
@@ -117,6 +119,7 @@ static void *HalPhysToVirt(uint64_t phys) {
#define FADT_X_DSDT_OFFSET 140u
#define FADT_X_PM1A_CNT_BLK_OFFSET 172u
#define FADT_X_PM1B_CNT_BLK_OFFSET 184u
#define FADT_CENTURY_OFFSET 108u
#pragma pack(push, 1)
typedef struct {
@@ -312,8 +315,13 @@ static void ParseFadt(const ACPISDTHeader* header) {
if (!dsdtPhys)
dsdtPhys = AcpiReadU32(fadt, len, FADT_DSDT_OFFSET);
HalDbgPrint("HAL: FADT PM1a_CNT=0x%04x PM1b_CNT=0x%04x DSDT=0x%016llx\n",
gPm1aCntBlk, gPm1bCntBlk, dsdtPhys);
uint8_t centuryRegister = 0;
if (FADT_CENTURY_OFFSET < len)
centuryRegister = *((const uint8_t*)fadt + FADT_CENTURY_OFFSET);
HalRtcSetCenturyRegister(centuryRegister);
HalDbgPrint("HAL: FADT PM1a_CNT=0x%04x PM1b_CNT=0x%04x DSDT=0x%016llx RTC_CENTURY=0x%02x\n",
gPm1aCntBlk, gPm1bCntBlk, dsdtPhys, centuryRegister);
if (dsdtPhys) {
const ACPISDTHeader* dsdt = (const ACPISDTHeader*)(dsdtPhys + gPhysBase);
@@ -550,6 +558,7 @@ __declspec(dllexport) KSTATUS HalInitialize(const HAL_INIT_PARAMS* initParams) {
KSTATUS ts = HalTimerInitialize(gLapicPhys, gHpetPhys, &gApi.Timer);
if (!KSUCCESS(ts)) HalDbgPrint("HAL: HPET unavailable, using fallback\n");
HalRtcInitialize(&gApi.Rtc);
HalPciInitialize(&gApi.Pci);
gApi.Intc.RouteIrq = HalApicRouteIrq;
gApi.Intc.MaskIrq = HalApicMaskIrq;
+22 -156
View File
@@ -1,178 +1,44 @@
// hal_pci.c - PCI configuration space via Mechanism 1 port I/O
// hal_pci.c - raw PCI configuration access via legacy Mechanism 1 port I/O
#include <stdint.h>
#include <ntlite/ddi/hal_api.h>
#include <kernel/hal/hal_apic.h>
#include <kernel/hal/hal_debug.h>
#define PCI_CONFIG_ADDR 0xCF8
#define PCI_CONFIG_DATA 0xCFC
#define PCI_REG_COMMAND_STATUS 0x04u
#define PCI_REG_CAP_PTR 0x34u
#define PCI_STATUS_CAP_LIST (1u << 20)
#define PCI_COMMAND_INTX_DISABLE (1u << 10)
#define PCI_CAP_ID_MSI 0x05u
#define PCI_CAP_ID_MSIX 0x11u
#define PCI_MSI_CTRL_ENABLE (1u << 0)
#define PCI_MSI_CTRL_MME_MASK (7u << 4)
#define PCI_MSI_CTRL_64BIT (1u << 7)
#define PCI_MSI_CTRL_PVM (1u << 8)
#define PCI_MSI_ADDRESS_BASE 0xFEE00000u
#define PCI_IRQ_VECTOR_BASE 0x20u
static uint32_t MakeAddr(uint8_t bus, uint8_t dev, uint8_t fn, uint8_t reg) {
static uint32_t MakeAddr(uint8_t bus, uint8_t dev, uint8_t fn, uint16_t offset) {
return 0x80000000UL
| ((uint32_t)bus << 16)
| ((uint32_t)(dev & 0x1F) << 11)
| ((uint32_t)(fn & 0x07) << 8)
| (reg & 0xFC);
| ((uint32_t)offset & 0xFCu);
}
static uint32_t PciRead32(uint8_t bus, uint8_t dev, uint8_t fn, uint8_t reg) {
__outdword(PCI_CONFIG_ADDR, MakeAddr(bus, dev, fn, reg));
static uint32_t PciRead32(uint16_t segment,
uint8_t bus,
uint8_t dev,
uint8_t fn,
uint16_t offset) {
if (segment != 0 || offset > 0xFCu)
return 0xFFFFFFFFu;
__outdword(PCI_CONFIG_ADDR, MakeAddr(bus, dev, fn, offset));
return __indword(PCI_CONFIG_DATA);
}
static void PciWrite32(uint8_t bus, uint8_t dev, uint8_t fn,
uint8_t reg, uint32_t val) {
__outdword(PCI_CONFIG_ADDR, MakeAddr(bus, dev, fn, reg));
__outdword(PCI_CONFIG_DATA, val);
}
static void PciWrite32(uint16_t segment,
uint8_t bus,
uint8_t dev,
uint8_t fn,
uint16_t offset,
uint32_t value) {
if (segment != 0 || offset > 0xFCu)
return;
static uint8_t PciRead8(uint8_t bus, uint8_t dev, uint8_t fn, uint8_t reg) {
uint32_t v = PciRead32(bus, dev, fn, reg);
return (uint8_t)(v >> ((reg & 3u) * 8u));
}
static uint16_t PciRead16(uint8_t bus, uint8_t dev, uint8_t fn, uint8_t reg) {
uint32_t v = PciRead32(bus, dev, fn, reg);
return (uint16_t)(v >> ((reg & 2u) * 8u));
}
static void PciWrite16(uint8_t bus, uint8_t dev, uint8_t fn, uint8_t reg, uint16_t value) {
uint8_t aligned = reg & ~3u;
uint32_t shift = (reg & 2u) * 8u;
uint32_t old = PciRead32(bus, dev, fn, aligned);
old &= ~(0xFFFFu << shift);
old |= ((uint32_t)value << shift);
PciWrite32(bus, dev, fn, aligned, old);
}
static bool PciFindDevice(uint16_t vendor, uint16_t device,
uint8_t* outBus, uint8_t* outDev, uint8_t* outFn) {
for (int bus = 0; bus < 256; bus++)
for (int dev = 0; dev < 32; dev++)
for (int fn = 0; fn < 8; fn++) {
uint32_t id = PciRead32((uint8_t)bus, (uint8_t)dev, (uint8_t)fn, 0);
if ((id & 0xFFFF) == vendor && (id >> 16) == device) {
*outBus = (uint8_t)bus; *outDev = (uint8_t)dev; *outFn = (uint8_t)fn;
return true;
}
}
return false;
}
static bool PciFindClass(uint8_t classCode, uint8_t subclass,
uint8_t* outBus, uint8_t* outDev, uint8_t* outFn) {
for (int bus = 0; bus < 256; bus++)
for (int dev = 0; dev < 32; dev++)
for (int fn = 0; fn < 8; fn++) {
uint32_t id = PciRead32((uint8_t)bus,(uint8_t)dev,(uint8_t)fn,0);
if ((id & 0xFFFF) == 0xFFFF) continue; // no device
uint32_t cc = PciRead32((uint8_t)bus,(uint8_t)dev,(uint8_t)fn,8);
if (((cc >> 24) & 0xFF) == classCode &&
((cc >> 16) & 0xFF) == subclass) {
*outBus = (uint8_t)bus; *outDev = (uint8_t)dev; *outFn = (uint8_t)fn;
return true;
}
}
return false;
}
static uint8_t PciGetIrqLine(uint8_t bus, uint8_t dev, uint8_t fn) {
// PCI config register 0x3C: byte 0 = IRQ line, byte 1 = IRQ pin
uint32_t val = PciRead32(bus, dev, fn, 0x3C);
return (uint8_t)(val & 0xFF); // 0xFF = not connected
}
static uint8_t PciFindCapability(uint8_t bus, uint8_t dev, uint8_t fn, uint8_t capId) {
uint32_t status = PciRead32(bus, dev, fn, PCI_REG_COMMAND_STATUS);
if ((status & PCI_STATUS_CAP_LIST) == 0)
return 0;
uint8_t cap = PciRead8(bus, dev, fn, PCI_REG_CAP_PTR) & 0xFCu;
for (uint32_t guard = 0; cap && guard < 48u; guard++) {
uint32_t hdr = PciRead32(bus, dev, fn, cap);
uint8_t id = (uint8_t)(hdr & 0xFFu);
uint8_t next = (uint8_t)((hdr >> 8) & 0xFCu);
if (id == capId)
return cap;
cap = next;
}
return 0;
}
static KSTATUS PciEnableMsi(uint8_t bus, uint8_t dev, uint8_t fn, uint8_t irqSlot) {
if (irqSlot >= 24u)
return STATUS_INVALID_PARAMETER;
uint8_t cap = PciFindCapability(bus, dev, fn, PCI_CAP_ID_MSI);
if (!cap) {
HalDbgPrint("PCI %u:%u.%u: MSI capability not present\n", bus, dev, fn);
return STATUS_NOT_SUPPORTED;
}
uint32_t bspLapic = HalGetBspLapicId();
if (!HalApicUsingX2Apic() && bspLapic >= 256u)
return STATUS_NOT_SUPPORTED;
if (HalApicUsingX2Apic() && bspLapic >= 256u) {
// Extended x2APIC MSI destinations need interrupt-remapping awareness.
// Keep the first MSI implementation xAPIC-compatible and explicit.
HalDbgPrint("PCI %u:%u.%u: MSI x2APIC destination %u not supported yet\n",
bus, dev, fn, bspLapic);
return STATUS_NOT_SUPPORTED;
}
uint16_t control = PciRead16(bus, dev, fn, (uint8_t)(cap + 2u));
bool is64 = (control & PCI_MSI_CTRL_64BIT) != 0;
bool pvm = (control & PCI_MSI_CTRL_PVM) != 0;
uint8_t vector = (uint8_t)(PCI_IRQ_VECTOR_BASE + irqSlot);
uint32_t address = PCI_MSI_ADDRESS_BASE | ((bspLapic & 0xFFu) << 12);
uint16_t data = vector;
PciWrite32(bus, dev, fn, (uint8_t)(cap + 4u), address);
if (is64) {
PciWrite32(bus, dev, fn, (uint8_t)(cap + 8u), 0);
PciWrite16(bus, dev, fn, (uint8_t)(cap + 12u), data);
if (pvm)
PciWrite32(bus, dev, fn, (uint8_t)(cap + 16u), 0);
} else {
PciWrite16(bus, dev, fn, (uint8_t)(cap + 8u), data);
if (pvm)
PciWrite32(bus, dev, fn, (uint8_t)(cap + 12u), 0);
}
control &= (uint16_t)~PCI_MSI_CTRL_MME_MASK; // enable exactly one message
control |= PCI_MSI_CTRL_ENABLE;
PciWrite16(bus, dev, fn, (uint8_t)(cap + 2u), control);
uint32_t cmd = PciRead32(bus, dev, fn, PCI_REG_COMMAND_STATUS);
cmd |= PCI_COMMAND_INTX_DISABLE;
PciWrite32(bus, dev, fn, PCI_REG_COMMAND_STATUS, cmd);
HalDbgPrint("PCI %u:%u.%u: MSI enabled cap=0x%02x vector=0x%02x irqslot=%u dest=%u %s\n",
bus, dev, fn, cap, vector, irqSlot, bspLapic, is64 ? "64-bit" : "32-bit");
return STATUS_SUCCESS;
__outdword(PCI_CONFIG_ADDR, MakeAddr(bus, dev, fn, offset));
__outdword(PCI_CONFIG_DATA, value);
}
void HalPciInitialize(HAL_PCI* out) {
out->Read32 = PciRead32;
out->Write32 = PciWrite32;
out->FindDevice = PciFindDevice;
out->FindClass = PciFindClass;
out->GetIrqLine = PciGetIrqLine;
out->EnableMsi = PciEnableMsi;
}
+163
View File
@@ -0,0 +1,163 @@
// hal_rtc.c - legacy CMOS RTC fallback clock
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <intrin.h>
#include <ntlite/status.h>
#include <ntlite/ddi/hal_api.h>
#include <kernel/hal/hal_debug.h>
#define CMOS_INDEX_PORT 0x70
#define CMOS_DATA_PORT 0x71
#define RTC_REG_SECONDS 0x00
#define RTC_REG_MINUTES 0x02
#define RTC_REG_HOURS 0x04
#define RTC_REG_WEEKDAY 0x06
#define RTC_REG_DAY 0x07
#define RTC_REG_MONTH 0x08
#define RTC_REG_YEAR 0x09
#define RTC_REG_STATUS_A 0x0A
#define RTC_REG_STATUS_B 0x0B
static uint8_t gCenturyRegister;
static uint8_t RtcRead(uint8_t reg) {
__outbyte(CMOS_INDEX_PORT, (uint8_t)(reg | 0x80u)); // keep NMI masked while selecting.
return __inbyte(CMOS_DATA_PORT);
}
static bool RtcUpdateInProgress(void) {
return (RtcRead(RTC_REG_STATUS_A) & 0x80u) != 0;
}
static uint8_t RtcBcdToBinary(uint8_t value) {
return (uint8_t)(((value >> 4) * 10u) + (value & 0x0Fu));
}
static bool RtcReadStable(HAL_RTC_TIME* out) {
if (!out) return false;
uint8_t sec1 = 0, min1 = 0, hour1 = 0, day1 = 0, month1 = 0, year1 = 0, century1 = 0;
uint8_t sec2 = 0, min2 = 0, hour2 = 0, day2 = 0, month2 = 0, year2 = 0, century2 = 0;
bool stable = false;
for (uint32_t tries = 0; tries < 100000u; tries++) {
while (RtcUpdateInProgress()) _mm_pause();
sec1 = RtcRead(RTC_REG_SECONDS);
min1 = RtcRead(RTC_REG_MINUTES);
hour1 = RtcRead(RTC_REG_HOURS);
day1 = RtcRead(RTC_REG_DAY);
month1 = RtcRead(RTC_REG_MONTH);
year1 = RtcRead(RTC_REG_YEAR);
century1 = gCenturyRegister ? RtcRead(gCenturyRegister) : 0;
while (RtcUpdateInProgress()) _mm_pause();
sec2 = RtcRead(RTC_REG_SECONDS);
min2 = RtcRead(RTC_REG_MINUTES);
hour2 = RtcRead(RTC_REG_HOURS);
day2 = RtcRead(RTC_REG_DAY);
month2 = RtcRead(RTC_REG_MONTH);
year2 = RtcRead(RTC_REG_YEAR);
century2 = gCenturyRegister ? RtcRead(gCenturyRegister) : 0;
if (sec1 == sec2 && min1 == min2 && hour1 == hour2 && day1 == day2 &&
month1 == month2 && year1 == year2 && century1 == century2) {
stable = true;
break;
}
}
if (!stable) return false;
uint8_t statusB = RtcRead(RTC_REG_STATUS_B);
bool binary = (statusB & 0x04u) != 0;
bool hour24 = (statusB & 0x02u) != 0;
bool pm = (!hour24 && (hour1 & 0x80u) != 0);
if (!binary) {
sec1 = RtcBcdToBinary(sec1);
min1 = RtcBcdToBinary(min1);
hour1 = (uint8_t)((hour1 & 0x80u) | RtcBcdToBinary((uint8_t)(hour1 & 0x7Fu)));
day1 = RtcBcdToBinary(day1);
month1 = RtcBcdToBinary(month1);
year1 = RtcBcdToBinary(year1);
if (gCenturyRegister) century1 = RtcBcdToBinary(century1);
}
if (!hour24) {
hour1 = (uint8_t)(hour1 & 0x7Fu);
if (pm && hour1 < 12u) hour1 = (uint8_t)(hour1 + 12u);
if (!pm && hour1 == 12u) hour1 = 0;
}
uint16_t year;
if (gCenturyRegister && century1) {
year = (uint16_t)((uint16_t)century1 * 100u + year1);
} else {
year = (uint16_t)((year1 < 70u) ? (2000u + year1) : (1900u + year1));
}
out->Year = year;
out->Month = month1;
out->Day = day1;
out->Hour = hour1;
out->Minute = min1;
out->Second = sec1;
out->Nanosecond = 0;
out->Flags = HAL_RTC_TIME_FLAG_VALID | HAL_RTC_TIME_FLAG_RTC;
out->Reserved = 0;
return true;
}
static bool RtcLeapYear(uint16_t year) {
return ((year % 4u) == 0u && (year % 100u) != 0u) || ((year % 400u) == 0u);
}
static uint8_t RtcDaysInMonth(uint16_t year, uint8_t month) {
static const uint8_t days[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
if (month < 1u || month > 12u) return 0;
if (month == 2u && RtcLeapYear(year)) return 29;
return days[month - 1u];
}
static bool RtcValid(const HAL_RTC_TIME* t) {
if (!t) return false;
if (t->Year < 1970u || t->Year > 9999u) return false;
if (t->Month < 1u || t->Month > 12u) return false;
uint8_t dim = RtcDaysInMonth(t->Year, t->Month);
if (t->Day < 1u || t->Day > dim) return false;
if (t->Hour > 23u || t->Minute > 59u || t->Second > 59u) return false;
return true;
}
static KSTATUS HalRtcQueryTime(HAL_RTC_TIME* outTime) {
if (!outTime) return STATUS_INVALID_PARAMETER;
HAL_RTC_TIME t;
memset(&t, 0, sizeof(t));
if (!RtcReadStable(&t) || !RtcValid(&t))
return STATUS_DEVICE_ERROR;
*outTime = t;
return STATUS_SUCCESS;
}
void HalRtcSetCenturyRegister(uint8_t centuryRegister) {
gCenturyRegister = centuryRegister;
}
void HalRtcInitialize(HAL_RTC* out) {
if (!out) return;
out->QueryTime = HalRtcQueryTime;
HAL_RTC_TIME t;
if (HalRtcQueryTime(&t) == STATUS_SUCCESS) {
HalDbgPrint("HAL: RTC %04u-%02u-%02u %02u:%02u:%02u century-reg=0x%02x\n",
t.Year, t.Month, t.Day, t.Hour, t.Minute, t.Second,
gCenturyRegister);
} else {
HalDbgPrint("HAL: RTC unavailable or invalid\n");
}
}
+1 -1
View File
@@ -43,7 +43,7 @@ typedef struct SYS_USER_APC_FRAME_K {
uint64_t SystemArgument2;
} SYS_USER_APC_FRAME_K;
#define SYS_USER_APC_FRAME_MAGIC 0x3143504152555355ULL /* "USURAPC1" little-ish */
#define SYS_USER_APC_FRAME_MAGIC 0x3143504152455355ULL /* "USERAPC1" little-ish */
struct KUSER_APC {
LIST_ENTRY Link;
+11
View File
@@ -0,0 +1,11 @@
#pragma once
#include <ntlite/status.h>
#include <ntlite/time.h>
typedef struct BOOT_INFO BOOT_INFO;
typedef struct HAL_API HAL_API;
void KeTimeInitialize(const BOOT_INFO* bootInfo, const HAL_API* hal);
KSTATUS KeTimeReloadSettings(void);
__declspec(dllexport) KSTATUS KeQuerySystemTime(SYS_SYSTEM_TIME* outTime);
__declspec(dllexport) uint64_t KeQueryUnixTimeSeconds(void);
+94 -93
View File
@@ -6,97 +6,98 @@
// R10, R11 = args 4-5 (loaded by SYSCALL_STUB6)
// RAX = return value
#define SYS_EXIT_PROCESS 0
#define SYS_EXIT_THREAD 1
#define SYS_CREATE_PROCESS 2
#define SYS_WAIT_FOR_PROCESS 3
#define SYS_GET_PROCESS_EXIT_CODE 4
#define SYS_KILL_PROCESS 5
#define SYS_GET_PROCESS_LIST 6
#define SYS_GET_PROCESS_PID 7
#define SYS_CREATE_THREAD 8
#define SYS_WAIT_THREAD 9
#define SYS_GET_CURRENT_TID 10
#define SYS_GET_CURRENT_PID 11
#define SYS_SET_THREAD_PRIORITY 12
#define SYS_YIELD 13
#define SYS_SLEEP 14
#define SYS_SET_USER_APC_DISPATCHER 15
#define SYS_APC_RETURN 16
#define SYS_VM_ALLOC 17
#define SYS_VM_FREE 18
#define SYS_VM_PROTECT 19
#define SYS_VM_QUERY 20
#define SYS_CLOSE_HANDLE 21
#define SYS_MUTEX_CREATE 22
#define SYS_MUTEX_ACQUIRE 23
#define SYS_MUTEX_TRY_ACQUIRE 24
#define SYS_MUTEX_RELEASE 25
#define SYS_SEM_CREATE 26
#define SYS_SEM_WAIT 27
#define SYS_SEM_TRY_WAIT 28
#define SYS_SEM_SIGNAL 29
#define SYS_EVENT_CREATE 30
#define SYS_EVENT_SIGNAL 31
#define SYS_EVENT_CLEAR 32
#define SYS_EVENT_WAIT 33
#define SYS_QUEUE_CREATE 34
#define SYS_QUEUE_SEND 35
#define SYS_QUEUE_RECV 36
#define SYS_PUBLISH_QUEUE 37
#define SYS_OPEN_NAMED_QUEUE 38
#define SYS_QUEUE_DUPLICATE 39
#define SYS_NAMED_QUEUE_OWNER_PID 40
#define SYS_OPEN_FILE 41
#define SYS_CREATE_FILE 42
#define SYS_READ_FILE 43
#define SYS_WRITE_FILE 44
#define SYS_READ_FILE_ASYNC 45
#define SYS_WRITE_FILE_ASYNC 46
#define SYS_CANCEL_IO 47
#define SYS_SEEK_FILE 48
#define SYS_GET_FILE_POS 49
#define SYS_GET_FILE_SIZE 50
#define SYS_TRUNCATE_FILE 51
#define SYS_DELETE_FILE 52
#define SYS_RENAME_FILE 53
#define SYS_OPEN_DIR 54
#define SYS_READ_DIR 55
#define SYS_CREATE_DIR 56
#define SYS_REMOVE_DIR 57
#define SYS_SET_CWD 58
#define SYS_GET_CWD 59
#define SYS_WRITE_CONSOLE 60
#define SYS_SCREEN_BLIT 61
#define SYS_SCREEN_CLEAR 62
#define SYS_SCREEN_GET_SIZE 63
#define SYS_SCREEN_PUT_CHAR 64
#define SYS_KB_POLL 65
#define SYS_KB_IS_KEY_DOWN 66
#define SYS_KB_READ_CHAR 67
#define SYS_KB_READ_KEY 68
#define SYS_KB_GET_MODIFIERS 69
#define SYS_MOUSE_POLL 70
#define SYS_MOUSE_READ 71
#define SYS_MOUSE_GET_POS 72
#define SYS_GET_TICK 73
#define SYS_DEBUG_PRINT 74
#define SYS_QUERY_TRAP_FRAME 75
#define SYS_SOCKET 76
#define SYS_BIND 77
#define SYS_LISTEN 78
#define SYS_ACCEPT 79
#define SYS_CONNECT 80
#define SYS_SEND 81
#define SYS_RECV 82
#define SYS_SHUTDOWN 83
#define SYS_SEND_TO 84
#define SYS_RECV_FROM 85
#define SYS_RESOLVE_HOST 86
#define SYS_SET_SOCKET_OPTION 87
#define SYS_GET_SOCKET_OPTION 88
#define SYS_POLL 89
#define SYS_GET_MEMORY_STATUS 90
#define SYS_QUERY_KERNEL_STATS 91
#define SYS_EXIT_PROCESS 0
#define SYS_EXIT_THREAD 1
#define SYS_CREATE_PROCESS 2
#define SYS_WAIT_FOR_PROCESS 3
#define SYS_GET_PROCESS_EXIT_CODE 4
#define SYS_KILL_PROCESS 5
#define SYS_GET_PROCESS_LIST 6
#define SYS_GET_PROCESS_PID 7
#define SYS_CREATE_THREAD 8
#define SYS_WAIT_THREAD 9
#define SYS_GET_CURRENT_TID 10
#define SYS_GET_CURRENT_PID 11
#define SYS_SET_THREAD_PRIORITY 12
#define SYS_YIELD 13
#define SYS_SLEEP 14
#define SYS_SET_USER_APC_DISPATCHER 15
#define SYS_APC_RETURN 16
#define SYS_ALLOC_VM 17
#define SYS_FREE_VM 18
#define SYS_PROTECT_VM 19
#define SYS_QUERY_VM 20
#define SYS_CLOSE_HANDLE 21
#define SYS_CREATE_MUTEX 22
#define SYS_ACQUIRE_MUTEX 23
#define SYS_TRY_ACQUIRE_MUTEX 24
#define SYS_RELEASE_MUTEX 25
#define SYS_CREATE_SEM 26
#define SYS_WAIT_SEM 27
#define SYS_TRY_WAIT_SEM 28
#define SYS_SIGNAL_SEM 29
#define SYS_CREATE_EVENT 30
#define SYS_SIGNAL_EVENT 31
#define SYS_CLEAR_EVENT 32
#define SYS_WAIT_EVENT 33
#define SYS_CREATE_QUEUE 34
#define SYS_SEND_QUEUE 35
#define SYS_RECV_QUEUE 36
#define SYS_PUBLISH_QUEUE 37
#define SYS_OPEN_NAMED_QUEUE 38
#define SYS_DUPLICATE_QUEUE 39
#define SYS_GET_NAMED_QUEUE_OWNER_PID 40
#define SYS_OPEN_FILE 41
#define SYS_CREATE_FILE 42
#define SYS_READ_FILE 43
#define SYS_WRITE_FILE 44
#define SYS_READ_FILE_ASYNC 45
#define SYS_WRITE_FILE_ASYNC 46
#define SYS_CANCEL_IO 47
#define SYS_SEEK_FILE 48
#define SYS_GET_FILE_POS 49
#define SYS_GET_FILE_SIZE 50
#define SYS_TRUNCATE_FILE 51
#define SYS_DELETE_FILE 52
#define SYS_RENAME_FILE 53
#define SYS_OPEN_DIR 54
#define SYS_READ_DIR 55
#define SYS_CREATE_DIR 56
#define SYS_REMOVE_DIR 57
#define SYS_SET_CWD 58
#define SYS_GET_CWD 59
#define SYS_WRITE_CONSOLE 60
#define SYS_BLIT_SCREEN 61
#define SYS_CLEAR_SCREEN 62
#define SYS_GET_SCREEN_SIZE 63
#define SYS_PUT_SCREEN_CHAR 64
#define SYS_POLL_KEYBOARD 65
#define SYS_IS_KEY_DOWN 66
#define SYS_READ_KEYBOARD_CHAR 67
#define SYS_READ_KEY 68
#define SYS_GET_KEY_MODIFIERS 69
#define SYS_POLL_MOUSE 70
#define SYS_READ_MOUSE 71
#define SYS_GET_MOUSE_POS 72
#define SYS_GET_TICK 73
#define SYS_PRINT_DEBUG 74
#define SYS_QUERY_TRAP_FRAME 75
#define SYS_CREATE_SOCKET 76
#define SYS_BIND_SOCKET 77
#define SYS_LISTEN_SOCKET 78
#define SYS_ACCEPT_SOCKET 79
#define SYS_CONNECT_SOCKET 80
#define SYS_SEND_SOCKET 81
#define SYS_RECV_SOCKET 82
#define SYS_SHUTDOWN_SOCKET 83
#define SYS_SEND_TO_SOCKET 84
#define SYS_RECV_FROM_SOCKET 85
#define SYS_RESOLVE_HOST 86
#define SYS_SET_SOCKET_OPTION 87
#define SYS_GET_SOCKET_OPTION 88
#define SYS_POLL 89
#define SYS_GET_MEMORY_STATUS 90
#define SYS_QUERY_KERNEL_STATS 91
#define SYS_GET_SYSTEM_TIME 92
#define SYS_MAX 92
#define SYS_MAX 93
+104 -88
View File
@@ -61,6 +61,7 @@
#include <kernel/net_socket.h>
#include <kernel/ke_trap.h>
#include <kernel/ke_input.h>
#include <kernel/ke_time.h>
#include <ntlite/syscall.h>
// ---------------------------------------------------------------------------
@@ -499,7 +500,7 @@ static uint64_t SyscallVmQuery(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_MUTEX_CREATE (11) a0 = *handleOut
// SYS_CREATE_MUTEX (11) a0 = *handleOut
// ---------------------------------------------------------------------------
static uint64_t SyscallMutexCreate(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -520,7 +521,7 @@ static uint64_t SyscallMutexCreate(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_MUTEX_ACQUIRE (12) a0 = handle
// SYS_ACQUIRE_MUTEX (12) a0 = handle
// ---------------------------------------------------------------------------
static uint64_t SyscallMutexAcquire(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -533,7 +534,7 @@ static uint64_t SyscallMutexAcquire(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_MUTEX_TRY_ACQUIRE (13) a0 = handle
// SYS_TRY_ACQUIRE_MUTEX (13) a0 = handle
// ---------------------------------------------------------------------------
static uint64_t SyscallMutexTryAcquire(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -546,7 +547,7 @@ static uint64_t SyscallMutexTryAcquire(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_MUTEX_RELEASE (14) a0 = handle
// SYS_RELEASE_MUTEX (14) a0 = handle
// ---------------------------------------------------------------------------
static uint64_t SyscallMutexRelease(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -559,7 +560,7 @@ static uint64_t SyscallMutexRelease(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_SEM_CREATE (15) a0=initial a1=max a2=*handleOut
// SYS_CREATE_SEM (15) a0=initial a1=max a2=*handleOut
// ---------------------------------------------------------------------------
static uint64_t SyscallSemCreate(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -580,7 +581,7 @@ static uint64_t SyscallSemCreate(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_SEM_WAIT (16) a0 = handle
// SYS_WAIT_SEM (16) a0 = handle
// ---------------------------------------------------------------------------
static uint64_t SyscallSemWait(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -593,7 +594,7 @@ static uint64_t SyscallSemWait(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_SEM_TRY_WAIT (17) a0 = handle
// SYS_TRY_WAIT_SEM (17) a0 = handle
// ---------------------------------------------------------------------------
static uint64_t SyscallSemTryWait(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -606,7 +607,7 @@ static uint64_t SyscallSemTryWait(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_SEM_SIGNAL (18) a0 = handle
// SYS_SIGNAL_SEM (18) a0 = handle
// ---------------------------------------------------------------------------
static uint64_t SyscallSemSignal(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -619,7 +620,7 @@ static uint64_t SyscallSemSignal(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_EVENT_CREATE (19) a0=type a1=initialState a2=*handleOut
// SYS_CREATE_EVENT (19) a0=type a1=initialState a2=*handleOut
// ---------------------------------------------------------------------------
static uint64_t SyscallEventCreate(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -640,7 +641,7 @@ static uint64_t SyscallEventCreate(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_EVENT_SIGNAL (20) a0 = handle
// SYS_SIGNAL_EVENT (20) a0 = handle
// ---------------------------------------------------------------------------
static uint64_t SyscallEventSignal(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -653,7 +654,7 @@ static uint64_t SyscallEventSignal(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_EVENT_CLEAR (21) a0 = handle
// SYS_CLEAR_EVENT (21) a0 = handle
// ---------------------------------------------------------------------------
static uint64_t SyscallEventClear(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -666,7 +667,7 @@ static uint64_t SyscallEventClear(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_EVENT_WAIT a0 = handle, a1 = alertable
// SYS_WAIT_EVENT a0 = handle, a1 = alertable
// ---------------------------------------------------------------------------
static uint64_t SyscallEventWait(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -685,7 +686,7 @@ static uint64_t SyscallEventWait(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_QUEUE_CREATE (23) a0 = *handleOut
// SYS_CREATE_QUEUE (23) a0 = *handleOut
// ---------------------------------------------------------------------------
static uint64_t SyscallQueueCreate(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -706,7 +707,7 @@ static uint64_t SyscallQueueCreate(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_QUEUE_SEND (24) a0=handle a1=*msg a2=blocking
// SYS_SEND_QUEUE (24) a0=handle a1=*msg a2=blocking
// ---------------------------------------------------------------------------
static uint64_t SyscallQueueSend(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -725,7 +726,7 @@ static uint64_t SyscallQueueSend(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_QUEUE_RECV (25) a0=handle a1=*msg a2=blocking
// SYS_RECV_QUEUE (25) a0=handle a1=*msg a2=blocking
// ---------------------------------------------------------------------------
static uint64_t SyscallQueueRecv(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -1203,7 +1204,7 @@ static uint64_t SyscallGetFileSize(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_SCREEN_BLIT (36) a0=x a1=y a2=w a3=h a4=*pixels
// SYS_BLIT_SCREEN (36) a0=x a1=y a2=w a3=h a4=*pixels
// ---------------------------------------------------------------------------
static uint64_t SyscallScreenBlit(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -1233,7 +1234,7 @@ static uint64_t SyscallScreenBlit(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_SCREEN_CLEAR (37) a0=color
// SYS_CLEAR_SCREEN (37) a0=color
// ---------------------------------------------------------------------------
static uint64_t SyscallScreenClear(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -1244,7 +1245,7 @@ static uint64_t SyscallScreenClear(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_SCREEN_GET_SIZE (38) a0=*widthOut a1=*heightOut
// SYS_GET_SCREEN_SIZE (38) a0=*widthOut a1=*heightOut
// ---------------------------------------------------------------------------
static uint64_t SyscallScreenGetSize(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -1264,7 +1265,7 @@ static uint64_t SyscallScreenGetSize(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_SCREEN_PUT_CHAR (39) a0=c a1=x a2=y a3=fg a4=bg
// SYS_PUT_SCREEN_CHAR (39) a0=c a1=x a2=y a3=fg a4=bg
// ---------------------------------------------------------------------------
static uint64_t SyscallScreenPutChar(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -1276,7 +1277,7 @@ static uint64_t SyscallScreenPutChar(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_KB_POLL (64) -> next INPUT_KEY or INPUT_KEY_NONE
// SYS_POLL_KEYBOARD (64) -> next INPUT_KEY or INPUT_KEY_NONE
// ---------------------------------------------------------------------------
static uint64_t SyscallKbPoll(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -1285,7 +1286,7 @@ static uint64_t SyscallKbPoll(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_KB_IS_KEY_DOWN (65) a0=INPUT_KEY -> 1 or 0
// SYS_IS_KEY_DOWN (65) a0=INPUT_KEY -> 1 or 0
// ---------------------------------------------------------------------------
static uint64_t SyscallKbIsKeyDown(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -1294,7 +1295,7 @@ static uint64_t SyscallKbIsKeyDown(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_KB_READ_CHAR (66) -> char (blocks, yields while waiting)
// SYS_READ_KEYBOARD_CHAR (66) -> char (blocks, yields while waiting)
// ---------------------------------------------------------------------------
static uint64_t SyscallKbReadChar(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -1304,7 +1305,7 @@ static uint64_t SyscallKbReadChar(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_KB_READ_KEY (67) -> INPUT_KEY (blocks, yields while waiting)
// SYS_READ_KEY (67) -> INPUT_KEY (blocks, yields while waiting)
// ---------------------------------------------------------------------------
static uint64_t SyscallKbReadKey(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -1314,7 +1315,7 @@ static uint64_t SyscallKbReadKey(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_KB_GET_MODIFIERS (68) -> uint32_t INPUT_MOD_* flags
// SYS_GET_KEY_MODIFIERS (68) -> uint32_t INPUT_MOD_* flags
// ---------------------------------------------------------------------------
static uint64_t SyscallKbGetModifiers(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -1323,7 +1324,7 @@ static uint64_t SyscallKbGetModifiers(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_MOUSE_POLL (69) -> 1 or 0
// SYS_POLL_MOUSE (69) -> 1 or 0
// ---------------------------------------------------------------------------
static uint64_t SyscallMousePoll(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -1332,7 +1333,7 @@ static uint64_t SyscallMousePoll(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_MOUSE_READ (70) a0=*dx a1=*dy a2=*buttons -> 1 or 0
// SYS_READ_MOUSE (70) a0=*dx a1=*dy a2=*buttons -> 1 or 0
// ---------------------------------------------------------------------------
static uint64_t SyscallMouseRead(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -1350,7 +1351,7 @@ static uint64_t SyscallMouseRead(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_MOUSE_GET_POS (71) a0=*x a1=*y
// SYS_GET_MOUSE_POS (71) a0=*x a1=*y
// ---------------------------------------------------------------------------
static uint64_t SyscallMouseGetPos(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -1374,13 +1375,27 @@ static uint64_t SyscallGetTick(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_DEBUG_PRINT (49) a0=*str
// SYS_GET_SYSTEM_TIME a0=*SYS_SYSTEM_TIME
// ---------------------------------------------------------------------------
static uint64_t SyscallGetSystemTime(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
if (!a0) return STATUS_INVALID_PARAMETER;
SYS_SYSTEM_TIME t;
KSTATUS s = KeQuerySystemTime(&t);
if (!KSUCCESS(s)) return s;
return CopyToUser((void*)(uintptr_t)a0, &t, sizeof(t));
}
// ---------------------------------------------------------------------------
// SYS_PRINT_DEBUG (49) a0=*str
// ---------------------------------------------------------------------------
static uint64_t SyscallDebugPrint(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
SYS_DEBUG_PRINT_REQUEST req;
SYS_PRINT_DEBUG_REQUEST req;
KSTATUS s = KiCopyUserRequest(a0, &req, sizeof(req));
if (!KSUCCESS(s)) return s;
if (req.Text.Length == 0) return STATUS_SUCCESS;
@@ -1593,7 +1608,7 @@ static uint64_t SyscallGetProcessExitCode(uint64_t a0, uint64_t a1, uint64_t a2,
// ---------------------------------------------------------------------------
// SYS_WRITE_CONSOLE (53) a0=*buf a1=len
// Writes user console text in white; distinct from green SYS_DEBUG_PRINT.
// Writes user console text in white; distinct from green SYS_PRINT_DEBUG.
// ---------------------------------------------------------------------------
static uint64_t SyscallWriteConsole(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -1922,7 +1937,7 @@ static uint64_t SyscallOpenNamedQueue(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_QUEUE_DUPLICATE (62) a0=handle a1=targetPid a2=*handleOut
// SYS_DUPLICATE_QUEUE (62) a0=handle a1=targetPid a2=*handleOut
//
// Looks up the QUEUE behind 'handle' in the CALLER's table, then allocates
// a new handle for the same object in the TARGET process's table.
@@ -1959,11 +1974,11 @@ static uint64_t SyscallQueueDuplicate(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_NAMED_QUEUE_OWNER_PID (63) a0=*name a1=*pidOut
// SYS_GET_NAMED_QUEUE_OWNER_PID (63) a0=*name a1=*pidOut
//
// Returns the ProcessId of whoever published the named queue.
// Lets a client get the publisher's PID so it can duplicate one of its
// own handles into that process via SYS_QUEUE_DUPLICATE.
// own handles into that process via SYS_DUPLICATE_QUEUE.
// ---------------------------------------------------------------------------
static uint64_t SyscallNamedQueueOwnerPid(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -2151,7 +2166,7 @@ typedef struct SYS_MEMORY_STATUS_K {
#define SYS_POLL_MAX_FDS 64u
// ---------------------------------------------------------------------------
// SYS_SOCKET a0=domain a1=type a2=protocol a3=*handleOut
// SYS_CREATE_SOCKET a0=domain a1=type a2=protocol a3=*handleOut
// ---------------------------------------------------------------------------
static uint64_t SyscallSocket(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -2178,7 +2193,7 @@ static uint64_t SyscallSocket(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_BIND a0=socketHandle a1=*SYS_SOCKET_ADDRESS_IPV4 a2=addressSize
// SYS_BIND_SOCKET a0=socketHandle a1=*SYS_SOCKET_ADDRESS_IPV4 a2=addressSize
// ---------------------------------------------------------------------------
static uint64_t SyscallBind(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -2199,7 +2214,7 @@ static uint64_t SyscallBind(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_LISTEN a0=socketHandle a1=backlog
// SYS_LISTEN_SOCKET a0=socketHandle a1=backlog
// ---------------------------------------------------------------------------
static uint64_t SyscallListen(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -2214,7 +2229,7 @@ static uint64_t SyscallListen(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_ACCEPT a0=listenSocket a1=*remoteAddressOut(optional)
// SYS_ACCEPT_SOCKET a0=listenSocket a1=*remoteAddressOut(optional)
// a2=*remoteAddressSizeInOut(optional) a3=*acceptedHandleOut
// ---------------------------------------------------------------------------
static uint64_t SyscallAccept(uint64_t a0, uint64_t a1, uint64_t a2,
@@ -2271,7 +2286,7 @@ static uint64_t SyscallAccept(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_CONNECT a0=socketHandle a1=*SYS_SOCKET_ADDRESS_IPV4 a2=addressSize
// SYS_CONNECT_SOCKET a0=socketHandle a1=*SYS_SOCKET_ADDRESS_IPV4 a2=addressSize
// ---------------------------------------------------------------------------
static uint64_t SyscallConnect(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -2292,7 +2307,7 @@ static uint64_t SyscallConnect(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_SEND a0=socketHandle a1=*buffer a2=length a3=flags a4=*sentOut(optional)
// SYS_SEND_SOCKET a0=socketHandle a1=*buffer a2=length a3=flags a4=*sentOut(optional)
// ---------------------------------------------------------------------------
static uint64_t SyscallSend(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -2328,7 +2343,7 @@ static uint64_t SyscallSend(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_RECV a0=socketHandle a1=*buffer a2=length a3=flags a4=*receivedOut(optional)
// SYS_RECV_SOCKET a0=socketHandle a1=*buffer a2=length a3=flags a4=*receivedOut(optional)
// ---------------------------------------------------------------------------
static uint64_t SyscallRecv(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -2365,7 +2380,7 @@ static uint64_t SyscallRecv(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_SHUTDOWN a0=socketHandle a1=SYS_SHUTDOWN_*
// SYS_SHUTDOWN_SOCKET a0=socketHandle a1=SYS_SHUTDOWN_SOCKET_*
// ---------------------------------------------------------------------------
static uint64_t SyscallShutdown(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -2380,7 +2395,7 @@ static uint64_t SyscallShutdown(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_SEND_TO a0=socketHandle a1=*SYS_SOCKET_SEND_TO_REQUEST
// SYS_SEND_TO_SOCKET a0=socketHandle a1=*SYS_SOCKET_SEND_TO_REQUEST
// ---------------------------------------------------------------------------
static uint64_t SyscallSendTo(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -2423,7 +2438,7 @@ static uint64_t SyscallSendTo(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_RECV_FROM a0=socketHandle a1=*SYS_SOCKET_RECV_FROM_REQUEST
// SYS_RECV_FROM_SOCKET a0=socketHandle a1=*SYS_SOCKET_RECV_FROM_REQUEST
// ---------------------------------------------------------------------------
static uint64_t SyscallRecvFrom(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
@@ -2797,30 +2812,30 @@ static const SYSCALL_HANDLER gSyscallTable[SYS_MAX] = {
/* 14 SYS_SLEEP */ SyscallSleep,
/* 15 SYS_SET_USER_APC_DISPATCHER */ SyscallSetUserApcDispatcher,
/* 16 SYS_APC_RETURN */ SyscallApcReturn,
/* 17 SYS_VM_ALLOC */ SyscallVmAlloc,
/* 18 SYS_VM_FREE */ SyscallVmFree,
/* 19 SYS_VM_PROTECT */ SyscallVmProtect,
/* 20 SYS_VM_QUERY */ SyscallVmQuery,
/* 17 SYS_ALLOC_VM */ SyscallVmAlloc,
/* 18 SYS_FREE_VM */ SyscallVmFree,
/* 19 SYS_PROTECT_VM */ SyscallVmProtect,
/* 20 SYS_QUERY_VM */ SyscallVmQuery,
/* 21 SYS_CLOSE_HANDLE */ SyscallCloseHandle,
/* 22 SYS_MUTEX_CREATE */ SyscallMutexCreate,
/* 23 SYS_MUTEX_ACQUIRE */ SyscallMutexAcquire,
/* 24 SYS_MUTEX_TRY_ACQUIRE */ SyscallMutexTryAcquire,
/* 25 SYS_MUTEX_RELEASE */ SyscallMutexRelease,
/* 26 SYS_SEM_CREATE */ SyscallSemCreate,
/* 27 SYS_SEM_WAIT */ SyscallSemWait,
/* 28 SYS_SEM_TRY_WAIT */ SyscallSemTryWait,
/* 29 SYS_SEM_SIGNAL */ SyscallSemSignal,
/* 30 SYS_EVENT_CREATE */ SyscallEventCreate,
/* 31 SYS_EVENT_SIGNAL */ SyscallEventSignal,
/* 32 SYS_EVENT_CLEAR */ SyscallEventClear,
/* 33 SYS_EVENT_WAIT */ SyscallEventWait,
/* 34 SYS_QUEUE_CREATE */ SyscallQueueCreate,
/* 35 SYS_QUEUE_SEND */ SyscallQueueSend,
/* 36 SYS_QUEUE_RECV */ SyscallQueueRecv,
/* 22 SYS_CREATE_MUTEX */ SyscallMutexCreate,
/* 23 SYS_ACQUIRE_MUTEX */ SyscallMutexAcquire,
/* 24 SYS_TRY_ACQUIRE_MUTEX */ SyscallMutexTryAcquire,
/* 25 SYS_RELEASE_MUTEX */ SyscallMutexRelease,
/* 26 SYS_CREATE_SEM */ SyscallSemCreate,
/* 27 SYS_WAIT_SEM */ SyscallSemWait,
/* 28 SYS_TRY_WAIT_SEM */ SyscallSemTryWait,
/* 29 SYS_SIGNAL_SEM */ SyscallSemSignal,
/* 30 SYS_CREATE_EVENT */ SyscallEventCreate,
/* 31 SYS_SIGNAL_EVENT */ SyscallEventSignal,
/* 32 SYS_CLEAR_EVENT */ SyscallEventClear,
/* 33 SYS_WAIT_EVENT */ SyscallEventWait,
/* 34 SYS_CREATE_QUEUE */ SyscallQueueCreate,
/* 35 SYS_SEND_QUEUE */ SyscallQueueSend,
/* 36 SYS_RECV_QUEUE */ SyscallQueueRecv,
/* 37 SYS_PUBLISH_QUEUE */ SyscallPublishQueue,
/* 38 SYS_OPEN_NAMED_QUEUE */ SyscallOpenNamedQueue,
/* 39 SYS_QUEUE_DUPLICATE */ SyscallQueueDuplicate,
/* 40 SYS_NAMED_QUEUE_OWNER_PID */ SyscallNamedQueueOwnerPid,
/* 39 SYS_DUPLICATE_QUEUE */ SyscallQueueDuplicate,
/* 40 SYS_GET_NAMED_QUEUE_OWNER_PID */ SyscallNamedQueueOwnerPid,
/* 41 SYS_OPEN_FILE */ SyscallOpenFile,
/* 42 SYS_CREATE_FILE */ SyscallCreateFile,
/* 43 SYS_READ_FILE */ SyscallReadFile,
@@ -2841,37 +2856,38 @@ static const SYSCALL_HANDLER gSyscallTable[SYS_MAX] = {
/* 58 SYS_SET_CWD */ SyscallSetCwd,
/* 59 SYS_GET_CWD */ SyscallGetCwd,
/* 60 SYS_WRITE_CONSOLE */ SyscallWriteConsole,
/* 61 SYS_SCREEN_BLIT */ SyscallScreenBlit,
/* 62 SYS_SCREEN_CLEAR */ SyscallScreenClear,
/* 63 SYS_SCREEN_GET_SIZE */ SyscallScreenGetSize,
/* 64 SYS_SCREEN_PUT_CHAR */ SyscallScreenPutChar,
/* 65 SYS_KB_POLL */ SyscallKbPoll,
/* 66 SYS_KB_IS_KEY_DOWN */ SyscallKbIsKeyDown,
/* 67 SYS_KB_READ_CHAR */ SyscallKbReadChar,
/* 68 SYS_KB_READ_KEY */ SyscallKbReadKey,
/* 69 SYS_KB_GET_MODIFIERS */ SyscallKbGetModifiers,
/* 70 SYS_MOUSE_POLL */ SyscallMousePoll,
/* 71 SYS_MOUSE_READ */ SyscallMouseRead,
/* 72 SYS_MOUSE_GET_POS */ SyscallMouseGetPos,
/* 61 SYS_BLIT_SCREEN */ SyscallScreenBlit,
/* 62 SYS_CLEAR_SCREEN */ SyscallScreenClear,
/* 63 SYS_GET_SCREEN_SIZE */ SyscallScreenGetSize,
/* 64 SYS_PUT_SCREEN_CHAR */ SyscallScreenPutChar,
/* 65 SYS_POLL_KEYBOARD */ SyscallKbPoll,
/* 66 SYS_IS_KEY_DOWN */ SyscallKbIsKeyDown,
/* 67 SYS_READ_KEYBOARD_CHAR */ SyscallKbReadChar,
/* 68 SYS_READ_KEY */ SyscallKbReadKey,
/* 69 SYS_GET_KEY_MODIFIERS */ SyscallKbGetModifiers,
/* 70 SYS_POLL_MOUSE */ SyscallMousePoll,
/* 71 SYS_READ_MOUSE */ SyscallMouseRead,
/* 72 SYS_GET_MOUSE_POS */ SyscallMouseGetPos,
/* 73 SYS_GET_TICK */ SyscallGetTick,
/* 74 SYS_DEBUG_PRINT */ SyscallDebugPrint,
/* 74 SYS_PRINT_DEBUG */ SyscallDebugPrint,
/* 75 SYS_QUERY_TRAP_FRAME */ SyscallQueryTrapFrame,
/* 76 SYS_SOCKET */ SyscallSocket,
/* 77 SYS_BIND */ SyscallBind,
/* 78 SYS_LISTEN */ SyscallListen,
/* 79 SYS_ACCEPT */ SyscallAccept,
/* 80 SYS_CONNECT */ SyscallConnect,
/* 81 SYS_SEND */ SyscallSend,
/* 82 SYS_RECV */ SyscallRecv,
/* 83 SYS_SHUTDOWN */ SyscallShutdown,
/* 84 SYS_SEND_TO */ SyscallSendTo,
/* 85 SYS_RECV_FROM */ SyscallRecvFrom,
/* 76 SYS_CREATE_SOCKET */ SyscallSocket,
/* 77 SYS_BIND_SOCKET */ SyscallBind,
/* 78 SYS_LISTEN_SOCKET */ SyscallListen,
/* 79 SYS_ACCEPT_SOCKET */ SyscallAccept,
/* 80 SYS_CONNECT_SOCKET */ SyscallConnect,
/* 81 SYS_SEND_SOCKET */ SyscallSend,
/* 82 SYS_RECV_SOCKET */ SyscallRecv,
/* 83 SYS_SHUTDOWN_SOCKET */ SyscallShutdown,
/* 84 SYS_SEND_TO_SOCKET */ SyscallSendTo,
/* 85 SYS_RECV_FROM_SOCKET */ SyscallRecvFrom,
/* 86 SYS_RESOLVE_HOST */ SyscallResolveHost,
/* 87 SYS_SET_SOCKET_OPTION */ SyscallSetSocketOption,
/* 88 SYS_GET_SOCKET_OPTION */ SyscallGetSocketOption,
/* 89 SYS_POLL */ SyscallPoll,
/* 90 SYS_GET_MEMORY_STATUS */ SyscallGetMemoryStatus,
/* 91 SYS_QUERY_KERNEL_STATS */ SyscallQueryKernelStats
/* 91 SYS_QUERY_KERNEL_STATS */ SyscallQueryKernelStats,
/* 92 SYS_GET_SYSTEM_TIME */ SyscallGetSystemTime
};
// ---------------------------------------------------------------------------
+500
View File
@@ -0,0 +1,500 @@
// ke_time.c - kernel wall-clock time service
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <ntlite/status.h>
#include <ntlite/boot_info.h>
#include <ntlite/ddi/hal_api.h>
#include <kernel/ke_time.h>
#include <kernel/ke_debug.h>
#include <kernel/ke_settings.h>
#define KE_TIME_FALLBACK_YEAR 2024u
#define KE_TIME_FALLBACK_MONTH 1u
#define KE_TIME_FALLBACK_DAY 1u
#define KE_TZ_UNSPECIFIED SYS_TIME_UNSPECIFIED_TZ
#define KE_CE_STANDARD_OFFSET 60
#define KE_DST_OFFSET_DELTA 60
typedef enum KE_DST_RULE {
KeDstRuleNone = 0,
KeDstRuleAlways,
KeDstRuleCentralEurope,
} KE_DST_RULE;
typedef struct KE_TIME_ZONE_POLICY {
int16_t StandardOffsetMinutes; // minutes east of UTC.
KE_DST_RULE DstRule;
bool TimeZoneKnown;
} KE_TIME_ZONE_POLICY;
typedef enum KE_HARDWARE_CLOCK_MODE {
KeHardwareClockUtc = 0,
KeHardwareClockLocal,
} KE_HARDWARE_CLOCK_MODE;
static const HAL_API* gTimeHal;
static uint64_t gSourceRawEpochSeconds;
static int16_t gSourceTimeZoneMinutes;
static bool gSourceTimeZoneKnown;
static uint32_t gSourceNanosecond;
static uint64_t gSourceTickMicroseconds;
static uint64_t gBaseUtcEpochSeconds;
static uint64_t gBaseTickMicroseconds;
static uint16_t gSourceFlags;
static KE_TIME_ZONE_POLICY gTimeZonePolicy = {
KE_CE_STANDARD_OFFSET,
KeDstRuleCentralEurope,
true,
};
static KE_HARDWARE_CLOCK_MODE gHardwareClockMode = KeHardwareClockUtc;
static bool KiIsLeapYear(uint32_t year) {
return ((year % 4u) == 0u && (year % 100u) != 0u) || ((year % 400u) == 0u);
}
static uint32_t KiDaysInMonth(uint32_t year, uint32_t month) {
static const uint8_t days[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
if (month == 2u && KiIsLeapYear(year)) return 29u;
if (month < 1u || month > 12u) return 0u;
return days[month - 1u];
}
static bool KiValidCalendar(uint32_t year, uint32_t month, uint32_t day,
uint32_t hour, uint32_t minute, uint32_t second,
uint32_t nanosecond) {
if (year < 1970u || year > 9999u) return false;
if (month < 1u || month > 12u) return false;
uint32_t dim = KiDaysInMonth(year, month);
if (day < 1u || day > dim) return false;
if (hour > 23u || minute > 59u || second > 59u) return false;
if (nanosecond >= 1000000000u) return false;
return true;
}
static uint64_t KiDaysBeforeYear(uint32_t year) {
uint64_t days = 0;
for (uint32_t y = 1970u; y < year; y++)
days += KiIsLeapYear(y) ? 366u : 365u;
return days;
}
static uint64_t KiCalendarToEpochSeconds(uint32_t year, uint32_t month, uint32_t day,
uint32_t hour, uint32_t minute, uint32_t second) {
uint64_t days = KiDaysBeforeYear(year);
for (uint32_t m = 1u; m < month; m++)
days += KiDaysInMonth(year, m);
days += (uint64_t)(day - 1u);
return (((days * 24u) + hour) * 60u + minute) * 60u + second;
}
static void KiEpochSecondsToCalendar(uint64_t epochSeconds, SYS_SYSTEM_TIME* out) {
uint64_t days = epochSeconds / 86400u;
uint32_t sod = (uint32_t)(epochSeconds % 86400u);
uint32_t year = 1970u;
for (;;) {
uint32_t diy = KiIsLeapYear(year) ? 366u : 365u;
if (days < diy) break;
days -= diy;
year++;
}
uint32_t month = 1u;
for (;;) {
uint32_t dim = KiDaysInMonth(year, month);
if (days < dim) break;
days -= dim;
month++;
}
uint64_t totalDays = epochSeconds / 86400u;
out->Year = (uint16_t)year;
out->Month = (uint8_t)month;
out->Day = (uint8_t)(days + 1u);
out->Hour = (uint8_t)(sod / 3600u);
out->Minute = (uint8_t)((sod / 60u) % 60u);
out->Second = (uint8_t)(sod % 60u);
out->DayOfWeek = (uint8_t)((totalDays + 4u) % 7u); // 1970-01-01 was Thursday.
}
static uint32_t KiDayOfWeek(uint32_t year, uint32_t month, uint32_t day) {
uint64_t epoch = KiCalendarToEpochSeconds(year, month, day, 0, 0, 0);
return (uint32_t)(((epoch / 86400u) + 4u) % 7u);
}
static uint32_t KiLastSundayOfMonth(uint32_t year, uint32_t month) {
uint32_t last = KiDaysInMonth(year, month);
uint32_t dow = KiDayOfWeek(year, month, last); // Sunday == 0.
return last - dow;
}
static bool KiCentralEuropeDstActiveUtc(uint64_t utcEpochSeconds) {
SYS_SYSTEM_TIME utc;
memset(&utc, 0, sizeof(utc));
KiEpochSecondsToCalendar(utcEpochSeconds, &utc);
uint32_t startDay = KiLastSundayOfMonth(utc.Year, 3u);
uint32_t endDay = KiLastSundayOfMonth(utc.Year, 10u);
uint64_t startUtc = KiCalendarToEpochSeconds(utc.Year, 3u, startDay, 1u, 0u, 0u);
uint64_t endUtc = KiCalendarToEpochSeconds(utc.Year, 10u, endDay, 1u, 0u, 0u);
return utcEpochSeconds >= startUtc && utcEpochSeconds < endUtc;
}
static int16_t KiOffsetForUtcEpoch(uint64_t utcEpochSeconds, bool* daylight) {
int32_t offset = gTimeZonePolicy.StandardOffsetMinutes;
bool dst = false;
if (gTimeZonePolicy.DstRule == KeDstRuleAlways) {
dst = true;
} else if (gTimeZonePolicy.DstRule == KeDstRuleCentralEurope) {
dst = KiCentralEuropeDstActiveUtc(utcEpochSeconds);
}
if (dst) offset += KE_DST_OFFSET_DELTA;
if (daylight) *daylight = dst;
return (int16_t)offset;
}
static uint64_t KiLocalEpochToUtc(uint64_t localEpochSeconds, int16_t offsetMinutes) {
uint64_t offsetSeconds = (uint64_t)((offsetMinutes < 0) ? -offsetMinutes : offsetMinutes) * 60u;
if (offsetMinutes >= 0)
return (localEpochSeconds > offsetSeconds) ? (localEpochSeconds - offsetSeconds) : 0;
return localEpochSeconds + offsetSeconds;
}
static void KiRebaseUtcFromSource(void) {
if (gSourceTimeZoneKnown) {
gBaseUtcEpochSeconds = KiLocalEpochToUtc(gSourceRawEpochSeconds, gSourceTimeZoneMinutes);
} else if (gHardwareClockMode == KeHardwareClockLocal) {
bool daylight = false;
int16_t offset = KiOffsetForUtcEpoch(gSourceRawEpochSeconds, &daylight);
// The first pass treated the local clock as UTC only so we can choose
// the correct rule-year. Run one refinement against the candidate UTC
// instant to handle daylight-saving transitions cleanly.
uint64_t candidateUtc = KiLocalEpochToUtc(gSourceRawEpochSeconds, offset);
offset = KiOffsetForUtcEpoch(candidateUtc, &daylight);
gBaseUtcEpochSeconds = KiLocalEpochToUtc(gSourceRawEpochSeconds, offset);
} else {
gBaseUtcEpochSeconds = gSourceRawEpochSeconds;
}
gBaseTickMicroseconds = gSourceTickMicroseconds;
}
static int KiAsciiLower(int c) {
if (c >= 'A' && c <= 'Z') return c + ('a' - 'A');
return c;
}
static bool KiStringEqualsNoCase(const char* a, const char* b) {
if (!a || !b) return false;
while (*a && *b) {
if (KiAsciiLower((unsigned char)*a) != KiAsciiLower((unsigned char)*b))
return false;
a++;
b++;
}
return *a == '\0' && *b == '\0';
}
static bool KiParseInt32(const char* s, int32_t* out) {
if (!s || !*s || !out) return false;
int sign = 1;
if (*s == '-') {
sign = -1;
s++;
} else if (*s == '+') {
s++;
}
if (*s < '0' || *s > '9') return false;
int32_t value = 0;
while (*s >= '0' && *s <= '9') {
value = (value * 10) + (*s - '0');
s++;
}
if (*s != '\0') return false;
*out = value * sign;
return true;
}
static bool KiStartsWithNoCase(const char* s, const char* prefix) {
if (!s || !prefix) return false;
while (*prefix) {
if (KiAsciiLower((unsigned char)*s) != KiAsciiLower((unsigned char)*prefix))
return false;
s++;
prefix++;
}
return true;
}
static bool KiParseUtcOffset(const char* s, int16_t* out) {
if (!s || !out) return false;
if (KiStringEqualsNoCase(s, "utc") || KiStringEqualsNoCase(s, "gmt") ||
KiStringEqualsNoCase(s, "z") || KiStringEqualsNoCase(s, "utcz")) {
*out = 0;
return true;
}
if (KiStartsWithNoCase(s, "utc")) {
s += 3;
} else if (KiStartsWithNoCase(s, "gmt")) {
s += 3;
}
int sign = 1;
if (*s == '+') {
sign = 1;
s++;
} else if (*s == '-') {
sign = -1;
s++;
} else {
return false;
}
if (*s < '0' || *s > '9') return false;
int hours = 0;
int digits = 0;
while (*s >= '0' && *s <= '9' && digits < 2) {
hours = hours * 10 + (*s - '0');
s++;
digits++;
}
int minutes = 0;
if (*s == ':') {
s++;
if (s[0] < '0' || s[0] > '9' || s[1] < '0' || s[1] > '9') return false;
minutes = (s[0] - '0') * 10 + (s[1] - '0');
s += 2;
} else if (*s >= '0' && *s <= '9') {
// Compact form, e.g. UTC+0200. Exactly two minute digits must remain.
if (s[1] < '0' || s[1] > '9' || s[2] != '\0') return false;
minutes = (s[0] - '0') * 10 + (s[1] - '0');
s += 2;
}
if (*s != '\0') return false;
if (hours > 14 || minutes > 59) return false;
*out = (int16_t)(sign * (hours * 60 + minutes));
return true;
}
static void KiApplyDefaultTimeZonePolicy(void) {
gTimeZonePolicy.StandardOffsetMinutes = KE_CE_STANDARD_OFFSET;
gTimeZonePolicy.DstRule = KeDstRuleCentralEurope;
gTimeZonePolicy.TimeZoneKnown = true;
gHardwareClockMode = KeHardwareClockUtc;
}
void KeTimeInitialize(const BOOT_INFO* bootInfo, const HAL_API* hal) {
gTimeHal = hal;
KiApplyDefaultTimeZonePolicy();
gSourceTickMicroseconds = (hal && hal->Timer.QueryTicks) ? hal->Timer.QueryTicks() : 0;
const BOOT_TIME* bt = bootInfo ? &bootInfo->BootTime : 0;
if (bt && (bt->Flags & BOOT_TIME_FLAG_VALID) &&
KiValidCalendar(bt->Year, bt->Month, bt->Day, bt->Hour, bt->Minute,
bt->Second, bt->Nanosecond)) {
gSourceRawEpochSeconds = KiCalendarToEpochSeconds(bt->Year, bt->Month, bt->Day,
bt->Hour, bt->Minute, bt->Second);
gSourceTimeZoneKnown = (bt->Flags & BOOT_TIME_FLAG_TZ_KNOWN) &&
bt->TimeZoneMinutes != BOOT_TIME_UNSPECIFIED_TZ;
gSourceTimeZoneMinutes = gSourceTimeZoneKnown ? bt->TimeZoneMinutes : 0;
gSourceNanosecond = bt->Nanosecond;
gSourceFlags = SYS_TIME_FLAG_VALID | SYS_TIME_FLAG_UEFI;
} else {
HAL_RTC_TIME rtc;
memset(&rtc, 0, sizeof(rtc));
if (hal && hal->Rtc.QueryTime && hal->Rtc.QueryTime(&rtc) == STATUS_SUCCESS &&
(rtc.Flags & HAL_RTC_TIME_FLAG_VALID) &&
KiValidCalendar(rtc.Year, rtc.Month, rtc.Day, rtc.Hour, rtc.Minute,
rtc.Second, rtc.Nanosecond)) {
gSourceRawEpochSeconds = KiCalendarToEpochSeconds(rtc.Year, rtc.Month, rtc.Day,
rtc.Hour, rtc.Minute, rtc.Second);
gSourceTimeZoneKnown = false;
gSourceTimeZoneMinutes = 0;
gSourceNanosecond = rtc.Nanosecond;
gSourceFlags = SYS_TIME_FLAG_VALID | SYS_TIME_FLAG_RTC;
} else {
gSourceRawEpochSeconds = KiCalendarToEpochSeconds(KE_TIME_FALLBACK_YEAR,
KE_TIME_FALLBACK_MONTH,
KE_TIME_FALLBACK_DAY,
0, 0, 0);
gSourceTimeZoneKnown = false;
gSourceTimeZoneMinutes = 0;
gSourceNanosecond = 0;
gSourceFlags = SYS_TIME_FLAG_VALID | SYS_TIME_FLAG_FALLBACK;
}
}
KiRebaseUtcFromSource();
SYS_SYSTEM_TIME now;
if (KeQuerySystemTime(&now) == STATUS_SUCCESS) {
DbgPrint("time: initialized %04u-%02u-%02u %02u:%02u:%02u.%03u flags=0x%x tz=%d hw=%s epoch=%llu\n",
now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second,
now.Millisecond, now.Flags, now.TimeZoneMinutes,
gHardwareClockMode == KeHardwareClockLocal ? "local" : "utc",
now.EpochSeconds);
}
}
KSTATUS KeTimeReloadSettings(void) {
KE_TIME_ZONE_POLICY policy = gTimeZonePolicy;
char value[64];
bool fixedTimezone = false;
bool allowStandardOffsetSetting = false;
KSTATUS st = KeGetSettingString("time", "timezone", value, sizeof(value));
if (KSUCCESS(st)) {
if (KiStringEqualsNoCase(value, "central-europe") ||
KiStringEqualsNoCase(value, "europe/warsaw")) {
policy.StandardOffsetMinutes = KE_CE_STANDARD_OFFSET;
policy.DstRule = KeDstRuleCentralEurope;
policy.TimeZoneKnown = true;
} else if (KiStringEqualsNoCase(value, "cet")) {
policy.StandardOffsetMinutes = KE_CE_STANDARD_OFFSET;
policy.DstRule = KeDstRuleNone;
policy.TimeZoneKnown = true;
fixedTimezone = true;
} else if (KiStringEqualsNoCase(value, "cest")) {
policy.StandardOffsetMinutes = KE_CE_STANDARD_OFFSET + KE_DST_OFFSET_DELTA;
policy.DstRule = KeDstRuleNone;
policy.TimeZoneKnown = true;
fixedTimezone = true;
} else if (KiStringEqualsNoCase(value, "custom") ||
KiStringEqualsNoCase(value, "manual")) {
policy.DstRule = KeDstRuleNone;
policy.TimeZoneKnown = true;
fixedTimezone = true;
allowStandardOffsetSetting = true;
} else if (KiStringEqualsNoCase(value, "utc") ||
KiStringEqualsNoCase(value, "gmt") ||
KiStringEqualsNoCase(value, "z")) {
policy.StandardOffsetMinutes = 0;
policy.DstRule = KeDstRuleNone;
policy.TimeZoneKnown = true;
fixedTimezone = true;
} else {
int16_t parsedOffset = 0;
if (KiParseUtcOffset(value, &parsedOffset)) {
policy.StandardOffsetMinutes = parsedOffset;
policy.DstRule = KeDstRuleNone;
policy.TimeZoneKnown = true;
fixedTimezone = true;
}
}
}
st = KeGetSettingString("time", "standard_offset_minutes", value, sizeof(value));
if (KSUCCESS(st) && allowStandardOffsetSetting) {
int32_t minutes;
if (KiParseInt32(value, &minutes) && minutes >= -14 * 60 && minutes <= 14 * 60) {
policy.StandardOffsetMinutes = (int16_t)minutes;
policy.TimeZoneKnown = true;
fixedTimezone = true;
}
}
st = KeGetSettingString("time", "daylight_saving", value, sizeof(value));
if (KSUCCESS(st)) {
if (KiStringEqualsNoCase(value, "auto")) {
if (!fixedTimezone)
policy.DstRule = KeDstRuleCentralEurope;
} else if (KiStringEqualsNoCase(value, "central-europe")) {
policy.DstRule = KeDstRuleCentralEurope;
} else if (KiStringEqualsNoCase(value, "on") || KiStringEqualsNoCase(value, "yes") ||
KiStringEqualsNoCase(value, "true") || KiStringEqualsNoCase(value, "1")) {
policy.DstRule = KeDstRuleAlways;
} else if (KiStringEqualsNoCase(value, "off") || KiStringEqualsNoCase(value, "no") ||
KiStringEqualsNoCase(value, "false") || KiStringEqualsNoCase(value, "0")) {
policy.DstRule = KeDstRuleNone;
}
}
KE_HARDWARE_CLOCK_MODE hardwareClockMode = gHardwareClockMode;
st = KeGetSettingString("time", "hardware_clock", value, sizeof(value));
if (KSUCCESS(st)) {
if (KiStringEqualsNoCase(value, "utc") || KiStringEqualsNoCase(value, "z")) {
hardwareClockMode = KeHardwareClockUtc;
} else if (KiStringEqualsNoCase(value, "local") ||
KiStringEqualsNoCase(value, "localtime") ||
KiStringEqualsNoCase(value, "wall-clock")) {
hardwareClockMode = KeHardwareClockLocal;
}
}
gTimeZonePolicy = policy;
gHardwareClockMode = hardwareClockMode;
KiRebaseUtcFromSource();
SYS_SYSTEM_TIME now;
if (KeQuerySystemTime(&now) == STATUS_SUCCESS) {
DbgPrint("time: settings timezone=%d dst=%s hw=%s now=%04u-%02u-%02u %02u:%02u:%02u flags=0x%x epoch=%llu\n",
now.TimeZoneMinutes,
(now.Flags & SYS_TIME_FLAG_DAYLIGHT) ? "on" : "off",
gHardwareClockMode == KeHardwareClockLocal ? "local" : "utc",
now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second,
now.Flags, now.EpochSeconds);
}
return STATUS_SUCCESS;
}
__declspec(dllexport) KSTATUS KeQuerySystemTime(SYS_SYSTEM_TIME* outTime) {
if (!outTime) return STATUS_INVALID_PARAMETER;
uint64_t nowTick = (gTimeHal && gTimeHal->Timer.QueryTicks)
? gTimeHal->Timer.QueryTicks()
: gBaseTickMicroseconds;
uint64_t elapsedUs = nowTick - gBaseTickMicroseconds;
uint64_t utcEpochSeconds = gBaseUtcEpochSeconds + (elapsedUs / 1000000u);
uint64_t ns = (uint64_t)gSourceNanosecond + (elapsedUs % 1000000u) * 1000u;
if (ns >= 1000000000u) {
utcEpochSeconds += ns / 1000000000u;
ns %= 1000000000u;
}
bool daylight = false;
int16_t offset = KiOffsetForUtcEpoch(utcEpochSeconds, &daylight);
uint64_t offsetSeconds = (uint64_t)((offset < 0) ? -offset : offset) * 60u;
uint64_t localEpochSeconds;
if (offset >= 0) {
localEpochSeconds = utcEpochSeconds + offsetSeconds;
} else {
localEpochSeconds = (utcEpochSeconds > offsetSeconds) ? (utcEpochSeconds - offsetSeconds) : 0;
}
SYS_SYSTEM_TIME t;
memset(&t, 0, sizeof(t));
KiEpochSecondsToCalendar(localEpochSeconds, &t);
t.Nanosecond = (uint32_t)ns;
t.Millisecond = (uint16_t)(ns / 1000000u);
t.Flags = gSourceFlags;
if (gTimeZonePolicy.TimeZoneKnown) t.Flags |= SYS_TIME_FLAG_TZ_KNOWN;
if (daylight) t.Flags |= SYS_TIME_FLAG_DAYLIGHT;
t.TimeZoneMinutes = gTimeZonePolicy.TimeZoneKnown ? offset : KE_TZ_UNSPECIFIED;
t.EpochSeconds = utcEpochSeconds;
t.TickMicroseconds = nowTick;
*outTime = t;
return STATUS_SUCCESS;
}
__declspec(dllexport) uint64_t KeQueryUnixTimeSeconds(void) {
SYS_SYSTEM_TIME t;
if (KeQuerySystemTime(&t) != STATUS_SUCCESS)
return 0;
return t.EpochSeconds;
}
+7
View File
@@ -25,6 +25,7 @@
#include <kernel/ke_selftest.h>
#include <kernel/ke_smp.h>
#include <kernel/ke_input.h>
#include <kernel/ke_time.h>
#include <common/ini_parser.h>
typedef struct {
@@ -214,6 +215,10 @@ static void KiInitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) {
continue;
}
// Runtime modules may also export DDIs to drivers loaded later. Boot
// drivers were already registered above; keep the module model uniform.
LdrRegisterModule(runtimeKeys[i], mappedBase);
DRIVER_ENTRY_FN entry = (DRIVER_ENTRY_FN)(LdrGetEntryPoint(mappedBase));
KSTATUS ds = entry(hal);
@@ -337,6 +342,7 @@ void SystemInitThread(void* arg) {
KiRunEarlyKernelSelfTests();
KiInitializeDrivers(args->bootInfo, args->hal);
KeTimeReloadSettings();
KiResolveSystemImports(args->bootInfo);
KiReclaimBootloaderMemory(args->bootInfo);
@@ -422,6 +428,7 @@ extern void KernelMain(BOOT_INFO* bootInfo) {
gKmainHal = hal;
KeInitDebug(hal->Screen.PrintChar, bootInfo->Debug);
KeTimeInitialize(bootInfo, hal);
// CPU startup intentionally lives after HAL initialization but before IRQs
// and scheduler startup. HAL owns ACPI/MADT discovery and LAPIC INIT/SIPI;
+25 -1
View File
@@ -7,8 +7,29 @@
#define BOOT_INFO_MAGIC 0x424F4F54494E464FULL /* 'BOOTINFO' */
#define MAX_BOOT_MODULES 32
#define BOOT_TIME_FLAG_VALID 0x0001u
#define BOOT_TIME_FLAG_TZ_KNOWN 0x0002u
#define BOOT_TIME_FLAG_UEFI 0x0004u
#define BOOT_TIME_FLAG_FALLBACK 0x0008u
#define BOOT_TIME_FLAG_RTC 0x0010u
#define BOOT_TIME_UNSPECIFIED_TZ 2047
typedef struct BOOT_TIME {
uint16_t Year;
uint8_t Month;
uint8_t Day;
uint8_t Hour;
uint8_t Minute;
uint8_t Second;
uint8_t Daylight;
uint32_t Nanosecond;
int16_t TimeZoneMinutes;
uint16_t Flags;
uint32_t Reserved;
} BOOT_TIME;
typedef struct BOOT_MODULE {
char Name[32]; /* e.g. "hal.dll", "ide.sys" */
char Name[32]; /* e.g. "hal.dll", "ata.sys" */
uintptr_t VirtBase; /* Virtual address (mapped) */
uintptr_t PhysBase; /* Raw physical address (file) */
size_t ImageSize; /* File size / Image size */
@@ -44,4 +65,7 @@ typedef struct BOOT_INFO {
/* From boot.ini */
uint32_t Debug;
/* Firmware wall-clock snapshot taken before ExitBootServices. */
BOOT_TIME BootTime;
} BOOT_INFO;
+37 -16
View File
@@ -27,22 +27,42 @@ typedef struct HAL_TIMER {
uint8_t IrqNumber;
} HAL_TIMER;
typedef struct HAL_PCI {
uint32_t (*Read32)(uint8_t bus, uint8_t dev,
uint8_t fn, uint8_t reg);
void (*Write32)(uint8_t bus, uint8_t dev,
uint8_t fn, uint8_t reg, uint32_t val);
bool (*FindDevice)(uint16_t vendor, uint16_t device,
uint8_t* bus, uint8_t* dev, uint8_t* fn);
bool (*FindClass)(uint8_t classCode, uint8_t subclass,
uint8_t* bus, uint8_t* dev, uint8_t* fn);
// Returns the IRQ line from PCI config space (register 0x3C, byte 0).
// Returns 0xFF if no interrupt is wired.
uint8_t (*GetIrqLine)(uint8_t bus, uint8_t dev, uint8_t fn);
// Program a PCI MSI capability to deliver to vector (0x20 + irqSlot).
// irqSlot must correspond to a kernel IRQ stub/vector slot.
KSTATUS (*EnableMsi)(uint8_t bus, uint8_t dev, uint8_t fn, uint8_t irqSlot);
#define HAL_RTC_TIME_FLAG_VALID 0x0001u
#define HAL_RTC_TIME_FLAG_RTC 0x0002u
typedef struct HAL_RTC_TIME {
uint16_t Year;
uint8_t Month;
uint8_t Day;
uint8_t Hour;
uint8_t Minute;
uint8_t Second;
uint32_t Nanosecond;
uint16_t Flags;
uint16_t Reserved;
} HAL_RTC_TIME;
typedef struct HAL_RTC {
KSTATUS (*QueryTime)(HAL_RTC_TIME* outTime);
} HAL_RTC;
typedef struct HAL_PCI {
// Raw PCI configuration access. Policy-level operations such as
// enumeration, BAR decoding, interrupt discovery, and MSI programming
// belong to pci.sys.
uint32_t (*Read32)(uint16_t segment,
uint8_t bus,
uint8_t dev,
uint8_t fn,
uint16_t offset);
void (*Write32)(uint16_t segment,
uint8_t bus,
uint8_t dev,
uint8_t fn,
uint16_t offset,
uint32_t value);
} HAL_PCI;
typedef struct HAL_INTC {
@@ -63,6 +83,7 @@ typedef struct HAL_API {
void *(*PhysToVirt)(uint64_t physAddr);
HAL_SCREEN Screen;
HAL_TIMER Timer;
HAL_RTC Rtc;
HAL_PCI Pci;
HAL_INTC Intc;
HAL_POWER Power;
@@ -87,7 +108,7 @@ typedef struct HAL_INIT_PARAMS {
void* (*AllocatePool)(size_t size);
} HAL_INIT_PARAMS;
#define HAL_API_VERSION 3
#define HAL_API_VERSION 5
__declspec(dllexport) const HAL_API* HalGetApi(void);
__declspec(dllexport) void HalRegisterScheduler(void (*pKeSchedulerTick)(void));
+118
View File
@@ -0,0 +1,118 @@
#pragma once
// pci.h - PCI bus driver DDI exported by pci.sys
//
// Function drivers must not enumerate PCI or decode BARs themselves. They bind
// to PCI PDOs through the I/O manager and use these routines to access the PCI
// function represented by their PDO.
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <ntlite/status.h>
#include <ntlite/ddi/io_driver.h>
#ifndef PCI_API
# ifdef PCI_SYS_BUILD
# define PCI_API __declspec(dllexport)
# else
# define PCI_API __declspec(dllimport)
# endif
#endif
typedef struct PCI_ADDRESS {
uint16_t Segment;
uint8_t Bus;
uint8_t Device;
uint8_t Function;
} PCI_ADDRESS;
typedef struct PCI_DEVICE_INFO {
PCI_ADDRESS Address;
uint16_t VendorId;
uint16_t DeviceId;
uint16_t SubsystemVendorId;
uint16_t SubsystemId;
uint8_t RevisionId;
uint8_t ProgIf;
uint8_t Subclass;
uint8_t ClassCode;
uint8_t HeaderType;
uint8_t InterruptLine;
uint8_t InterruptPin;
} PCI_DEVICE_INFO;
typedef enum PCI_BAR_TYPE {
PciBarUnused = 0,
PciBarIo,
PciBarMemory32,
PciBarMemory64,
} PCI_BAR_TYPE;
typedef struct PCI_BAR {
PCI_BAR_TYPE Type;
uint8_t Index;
uint64_t Base;
uint64_t Length;
bool Prefetchable;
} PCI_BAR;
#define PCI_ENABLE_IO 0x00000001u
#define PCI_ENABLE_MEMORY 0x00000002u
#define PCI_ENABLE_BUSMASTER 0x00000004u
#define PCI_ENABLE_INTX 0x00000008u
#define PCI_DISABLE_INTX 0x00000010u
#define PCI_CONFIG_VENDOR_DEVICE 0x00u
#define PCI_CONFIG_COMMAND_STATUS 0x04u
#define PCI_CONFIG_REVISION_CLASS 0x08u
#define PCI_CONFIG_HEADER_TYPE 0x0Cu
#define PCI_CONFIG_BAR0 0x10u
#define PCI_CONFIG_INTERRUPT_LINE_PIN 0x3Cu
PCI_API uint32_t PciDriverAbiVersion(void);
PCI_API KSTATUS PciGetDeviceInfo(DEVICE_OBJECT* pdo,
PCI_DEVICE_INFO* outInfo);
PCI_API KSTATUS PciReadConfig8(DEVICE_OBJECT* pdo,
uint16_t offset,
uint8_t* outValue);
PCI_API KSTATUS PciReadConfig16(DEVICE_OBJECT* pdo,
uint16_t offset,
uint16_t* outValue);
PCI_API KSTATUS PciReadConfig32(DEVICE_OBJECT* pdo,
uint16_t offset,
uint32_t* outValue);
PCI_API KSTATUS PciWriteConfig8(DEVICE_OBJECT* pdo,
uint16_t offset,
uint8_t value);
PCI_API KSTATUS PciWriteConfig16(DEVICE_OBJECT* pdo,
uint16_t offset,
uint16_t value);
PCI_API KSTATUS PciWriteConfig32(DEVICE_OBJECT* pdo,
uint16_t offset,
uint32_t value);
PCI_API KSTATUS PciGetBar(DEVICE_OBJECT* pdo,
uint8_t index,
PCI_BAR* outBar);
PCI_API KSTATUS PciMapBar(DEVICE_OBJECT* pdo,
uint8_t index,
uint64_t pageFlags,
void** outVirtual,
uint64_t* outLength);
PCI_API KSTATUS PciEnableDevice(DEVICE_OBJECT* pdo,
uint32_t flags);
PCI_API KSTATUS PciGetInterrupt(DEVICE_OBJECT* pdo,
uint8_t* outIrq);
PCI_API KSTATUS PciEnableMsi(DEVICE_OBJECT* pdo,
uint8_t irqSlot);
+5
View File
@@ -2,6 +2,7 @@
// dirent.h - directory entry returned by SysReadDir.
#include <stdint.h>
#include <ntlite/time.h>
#define SYS_DIR_NAME_MAX 260
@@ -9,5 +10,9 @@
typedef struct SYS_DIR_ENTRY {
char Name[SYS_DIR_NAME_MAX];
uint8_t Attr;
uint8_t Reserved0[3];
uint32_t FileSize;
SYS_SYSTEM_TIME CreateTime;
SYS_SYSTEM_TIME LastAccessTime;
SYS_SYSTEM_TIME LastWriteTime;
} SYS_DIR_ENTRY;
+51 -50
View File
@@ -8,6 +8,7 @@
#include <ntlite/string_view.h>
#include <ntlite/dirent.h>
#include <ntlite/input.h>
#include <ntlite/time.h>
#define SYS_STATUS_SUCCESS 0u
#define SYS_STATUS_TIMEOUT 3u
@@ -24,7 +25,6 @@
// User process/thread environment
// ---------------------------------------------------------------------------
// GS base points at SYS_TEB. GS:[0] is the process PEB pointer.
// This is this OS' ABI, not a Windows compatibility layout.
#define SYS_PEB_MAGIC 0x30424550u /* "PEB0" */
#define SYS_TEB_MAGIC 0x30424554u /* "TEB0" */
#define SYS_ENV_VERSION 1u
@@ -104,7 +104,7 @@ typedef struct SYS_USER_APC_FRAME {
uint64_t SystemArgument2;
} SYS_USER_APC_FRAME;
#define SYS_USER_APC_FRAME_MAGIC 0x3143504152555355ULL
#define SYS_USER_APC_FRAME_MAGIC 0x3143504152455355ULL
void SysUserApcDispatcher(void);
@@ -165,9 +165,9 @@ typedef struct SYS_WRITE_CONSOLE_REQUEST {
SYS_STRING_VIEW Text;
} SYS_WRITE_CONSOLE_REQUEST;
typedef struct SYS_DEBUG_PRINT_REQUEST {
typedef struct SYS_PRINT_DEBUG_REQUEST {
SYS_STRING_VIEW Text;
} SYS_DEBUG_PRINT_REQUEST;
} SYS_PRINT_DEBUG_REQUEST;
typedef struct SYS_PUBLISH_QUEUE_REQUEST {
SYS_STRING_VIEW Name;
@@ -248,14 +248,14 @@ uint32_t SysApcReturn(const SYS_USER_APC_FRAME* frame);
// ---------------------------------------------------------------------------
// Virtual memory and handles
// ---------------------------------------------------------------------------
typedef enum SYS_VM_PROTECTION {
typedef enum SYS_PROTECT_VMION {
SYS_VM_NOACCESS = 0,
SYS_VM_READ = 1,
SYS_VM_READWRITE = 2,
SYS_VM_EXECUTE = 3,
SYS_VM_EXECUTE_READ = 4,
SYS_VM_EXECUTE_READWRITE = 5,
} SYS_VM_PROTECTION;
} SYS_PROTECT_VMION;
#define SYS_VM_FLAG_NONE 0u
#define SYS_VM_FLAG_FIXED 1u
@@ -269,40 +269,40 @@ typedef struct SYS_VM_REGION_INFO {
uint32_t OwnerPid;
} SYS_VM_REGION_INFO;
uint32_t SysVmAlloc(void* preferredBase, size_t pageCount, uint32_t protect, uint32_t flags, void** baseOut);
uint32_t SysVmFree(void* base);
uint32_t SysVmProtect(void* base, size_t pageCount, uint32_t protect, uint32_t* oldProtectOut);
uint32_t SysVmQuery(void* address, SYS_VM_REGION_INFO* out);
uint32_t SysAllocVm(void* preferredBase, size_t pageCount, uint32_t protect, uint32_t flags, void** baseOut);
uint32_t SysFreeVm(void* base);
uint32_t SysProtectVm(void* base, size_t pageCount, uint32_t protect, uint32_t* oldProtectOut);
uint32_t SysQueryVm(void* address, SYS_VM_REGION_INFO* out);
uint32_t SysCloseHandle(uint32_t handle);
// ---------------------------------------------------------------------------
// Synchronization primitives (19-31)
// ---------------------------------------------------------------------------
uint32_t SysMutexCreate(uint32_t* handleOut);
uint32_t SysMutexAcquire(uint32_t handle);
uint32_t SysMutexTryAcquire(uint32_t handle);
uint32_t SysMutexRelease(uint32_t handle);
uint32_t SysCreateMutex(uint32_t* handleOut);
uint32_t SysAcquireMutex(uint32_t handle);
uint32_t SysTryAcquireMutex(uint32_t handle);
uint32_t SysReleaseMutex(uint32_t handle);
uint32_t SysSemCreate(int32_t initial, int32_t max, uint32_t* handleOut);
uint32_t SysSemWait(uint32_t handle);
uint32_t SysSemTryWait(uint32_t handle);
uint32_t SysSemSignal(uint32_t handle);
uint32_t SysCreateSem(int32_t initial, int32_t max, uint32_t* handleOut);
uint32_t SysWaitSem(uint32_t handle);
uint32_t SysTryWaitSem(uint32_t handle);
uint32_t SysSignalSem(uint32_t handle);
uint32_t SysEventCreate(uint32_t type, uint32_t initialState, uint32_t* handleOut);
uint32_t SysEventSignal(uint32_t handle);
uint32_t SysEventClear(uint32_t handle);
uint32_t SysEventWait(uint32_t handle, uint32_t alertable);
uint32_t SysCreateEvent(uint32_t type, uint32_t initialState, uint32_t* handleOut);
uint32_t SysSignalEvent(uint32_t handle);
uint32_t SysClearEvent(uint32_t handle);
uint32_t SysWaitEvent(uint32_t handle, uint32_t alertable);
// ---------------------------------------------------------------------------
// Queues and named queues (32-38)
// ---------------------------------------------------------------------------
uint32_t SysQueueCreate(uint32_t* handleOut);
uint32_t SysQueueSend(uint32_t handle, const void* msg, bool blocking);
uint32_t SysQueueRecv(uint32_t handle, void* msg, bool blocking);
uint32_t SysCreateQueue(uint32_t* handleOut);
uint32_t SysSendQueue(uint32_t handle, const void* msg, bool blocking);
uint32_t SysRecvQueue(uint32_t handle, void* msg, bool blocking);
uint32_t SysPublishQueue(const SYS_PUBLISH_QUEUE_REQUEST* request);
uint32_t SysOpenNamedQueue(const SYS_OPEN_NAMED_QUEUE_REQUEST* request);
uint32_t SysQueueDuplicate(uint32_t handle, uint32_t targetPid, uint32_t* handleOut);
uint32_t SysNamedQueueOwnerPid(const SYS_NAMED_QUEUE_OWNER_REQUEST* request);
uint32_t SysDuplicateQueue(uint32_t handle, uint32_t targetPid, uint32_t* handleOut);
uint32_t SysGetNamedQueueOwnerPid(const SYS_NAMED_QUEUE_OWNER_REQUEST* request);
// ---------------------------------------------------------------------------
// Files, directories, and current directory (39-56)
@@ -332,23 +332,23 @@ uint32_t SysGetCwd(const SYS_GET_CWD_REQUEST* request);
// Console and graphics (57-61)
// ---------------------------------------------------------------------------
uint32_t SysWriteConsole(const SYS_WRITE_CONSOLE_REQUEST* request);
uint32_t SysScreenBlit(int x, int y, int w, int h, const uint32_t* pixels);
uint32_t SysScreenClear(uint32_t color);
uint32_t SysScreenGetSize(int* widthOut, int* heightOut);
uint32_t SysScreenPutChar(char c, int x, int y, uint32_t fg, uint32_t bg);
uint32_t SysBlitScreen(int x, int y, int w, int h, const uint32_t* pixels);
uint32_t SysClearScreen(uint32_t color);
uint32_t SysGetScreenSize(int* widthOut, int* heightOut);
uint32_t SysPutScreenChar(char c, int x, int y, uint32_t fg, uint32_t bg);
// ---------------------------------------------------------------------------
// Input (62-69)
// ---------------------------------------------------------------------------
uint64_t SysKbPoll(void);
uint64_t SysKbIsKeyDown(INPUT_KEY key);
char SysKbReadChar(void);
INPUT_KEY SysKbReadKey(void);
uint32_t SysKbGetModifiers(void);
uint64_t SysPollKeyboard(void);
uint64_t SysIsKeyDown(INPUT_KEY key);
char SysReadKeyboardChar(void);
INPUT_KEY SysReadKey(void);
uint32_t SysGetKeyModifiers(void);
uint64_t SysMousePoll(void);
uint64_t SysMouseRead(int* dx, int* dy, uint8_t* buttons);
void SysMouseGetPos(int* x, int* y);
uint64_t SysPollMouse(void);
uint64_t SysReadMouse(int* dx, int* dy, uint8_t* buttons);
void SysGetMousePos(int* x, int* y);
// ---------------------------------------------------------------------------
@@ -424,16 +424,16 @@ typedef struct SYS_POLLFD {
uint32_t ReturnedEvents;
} SYS_POLLFD;
uint32_t SysSocket(uint32_t domain, uint32_t type, uint32_t protocol, uint32_t* handleOut);
uint32_t SysBind(uint32_t socket, const SYS_SOCKET_ADDRESS_IPV4* address, size_t addressSize);
uint32_t SysListen(uint32_t socket, uint32_t backlog);
uint32_t SysAccept(uint32_t socket, SYS_SOCKET_ADDRESS_IPV4* remoteAddressOut, size_t* remoteAddressSizeInOut, uint32_t* acceptedHandleOut);
uint32_t SysConnect(uint32_t socket, const SYS_SOCKET_ADDRESS_IPV4* address, size_t addressSize);
uint32_t SysSend(uint32_t socket, const void* buffer, size_t length, uint32_t flags, size_t* sentOut);
uint32_t SysRecv(uint32_t socket, void* buffer, size_t length, uint32_t flags, size_t* receivedOut);
uint32_t SysShutdown(uint32_t socket, uint32_t how);
uint32_t SysSendTo(uint32_t socket, const SYS_SOCKET_SEND_TO_REQUEST* request);
uint32_t SysRecvFrom(uint32_t socket, const SYS_SOCKET_RECV_FROM_REQUEST* request);
uint32_t SysCreateSocket(uint32_t domain, uint32_t type, uint32_t protocol, uint32_t* handleOut);
uint32_t SysBindSocket(uint32_t socket, const SYS_SOCKET_ADDRESS_IPV4* address, size_t addressSize);
uint32_t SysListenSocket(uint32_t socket, uint32_t backlog);
uint32_t SysAcceptSocket(uint32_t socket, SYS_SOCKET_ADDRESS_IPV4* remoteAddressOut, size_t* remoteAddressSizeInOut, uint32_t* acceptedHandleOut);
uint32_t SysConnectSocket(uint32_t socket, const SYS_SOCKET_ADDRESS_IPV4* address, size_t addressSize);
uint32_t SysSendSocket(uint32_t socket, const void* buffer, size_t length, uint32_t flags, size_t* sentOut);
uint32_t SysRecvSocket(uint32_t socket, void* buffer, size_t length, uint32_t flags, size_t* receivedOut);
uint32_t SysShutdownSocket(uint32_t socket, uint32_t how);
uint32_t SysSendToSocket(uint32_t socket, const SYS_SOCKET_SEND_TO_REQUEST* request);
uint32_t SysRecvFromSocket(uint32_t socket, const SYS_SOCKET_RECV_FROM_REQUEST* request);
uint32_t SysResolveHost(const SYS_RESOLVE_HOST_REQUEST* request);
uint32_t SysSetSocketOption(uint32_t socket, const SYS_SOCKET_OPTION_REQUEST* request);
uint32_t SysGetSocketOption(uint32_t socket, const SYS_SOCKET_OPTION_REQUEST* request);
@@ -501,7 +501,8 @@ typedef struct SYS_CPU_STATS {
// Time and diagnostics
// ---------------------------------------------------------------------------
uint64_t SysGetTick(void);
uint32_t SysDebugPrint(const SYS_DEBUG_PRINT_REQUEST* request);
uint32_t SysGetSystemTime(SYS_SYSTEM_TIME* timeOut);
uint32_t SysPrintDebug(const SYS_PRINT_DEBUG_REQUEST* request);
uint32_t SysQueryTrapFrame(SYS_TRAP_FRAME_INFO* info);
uint32_t SysGetMemoryStatus(SYS_MEMORY_STATUS* statusOut);
+31
View File
@@ -0,0 +1,31 @@
#pragma once
#include <stdint.h>
#define SYS_TIME_FLAG_VALID 0x0001u
#define SYS_TIME_FLAG_TZ_KNOWN 0x0002u
#define SYS_TIME_FLAG_UEFI 0x0004u
#define SYS_TIME_FLAG_FALLBACK 0x0008u
#define SYS_TIME_FLAG_RTC 0x0010u
#define SYS_TIME_FLAG_DAYLIGHT 0x0020u
#define SYS_TIME_UNSPECIFIED_TZ 2047
// Calendar wall-clock time maintained by the kernel. DayOfWeek uses the
// Win32 convention: 0 = Sunday, 1 = Monday, ... 6 = Saturday.
// TimeZoneMinutes is minutes east of UTC for the returned local calendar.
// EpochSeconds is UTC seconds since 1970-01-01 00:00:00.
typedef struct SYS_SYSTEM_TIME {
uint16_t Year;
uint8_t Month;
uint8_t Day;
uint8_t Hour;
uint8_t Minute;
uint8_t Second;
uint8_t DayOfWeek;
uint16_t Millisecond;
uint16_t Flags;
uint32_t Nanosecond;
int16_t TimeZoneMinutes;
uint16_t Reserved0;
uint64_t EpochSeconds;
uint64_t TickMicroseconds;
} SYS_SYSTEM_TIME;
+11
View File
@@ -13,3 +13,14 @@ address=10.0.2.15
netmask=255.255.255.0
gateway=10.0.2.2
dns=10.0.2.3
[time]
; Default wall-clock policy: Central European Time with automatic EU daylight saving.
; timezone accepts: central-europe, Europe/Warsaw, cet, cest, utc, gmt, UTC+H, UTC+HH[:MM], UTC-HH[:MM].
timezone=central-europe
; daylight_saving accepts: auto, central-europe, on, off.
daylight_saving=auto
; Firmware/CMOS clock convention. QEMU/OVMF usually uses utc; use local for Windows-style RTCs.
hardware_clock=utc
; Used when timezone is a custom/fixed policy; minutes east of UTC.
standard_offset_minutes=60
+2 -2
View File
@@ -251,7 +251,7 @@ static bool g_prev_key[KEYMAP_COUNT];
static void poll_input(void)
{
for (int i = 0; i < (int)KEYMAP_COUNT; i++) {
bool cur_down = (SysKbIsKeyDown(g_keymap[i].inputKey) != 0);
bool cur_down = (SysIsKeyDown(g_keymap[i].inputKey) != 0);
bool prev_down = g_prev_key[i];
if (cur_down && !prev_down) doom_key_down(g_keymap[i].key);
@@ -295,7 +295,7 @@ static void render_frame(const uint8_t* rgba)
}
}
SysScreenBlit(0, 0, DISP_W, DISP_H, g_blit_buf);
SysBlitScreen(0, 0, DISP_W, DISP_H, g_blit_buf);
}
static int build_argv_from_command_line(const char* cmdline, char* storage, size_t storageSize,
+6 -6
View File
@@ -81,7 +81,7 @@ static void update_screen_size(void) {
int oldCols = gCols;
int oldRows = gRows;
if (SysScreenGetSize(&pxW, &pxH) == 0 && pxW > 0 && pxH > 0) {
if (SysGetScreenSize(&pxW, &pxH) == 0 && pxW > 0 && pxH > 0) {
gCols = pxW / GLYPH_W;
gRows = pxH / GLYPH_H;
@@ -111,7 +111,7 @@ static void put_cell(int col, int row, char c, uint32_t fg, uint32_t bg) {
cell->bg = bg;
}
SysScreenPutChar(c, col * GLYPH_W, row * GLYPH_H, fg, bg);
SysPutScreenChar(c, col * GLYPH_W, row * GLYPH_H, fg, bg);
}
static void clear_row(int row, uint32_t bg) {
@@ -473,8 +473,8 @@ static void editor_loop(void) {
while (true) {
render();
INPUT_KEY key = SysKbReadKey();
uint32_t mods = SysKbGetModifiers();
INPUT_KEY key = SysReadKey();
uint32_t mods = SysGetKeyModifiers();
bool ctrl = (mods & INPUT_MOD_CTRL) != 0;
if (ctrl && key == EDIT_KEY_Q) {
@@ -535,10 +535,10 @@ static void print(const char* s) {
int main(void) {
parse_filename_from_cmdline();
load_file();
SysScreenClear(COL_BG);
SysClearScreen(COL_BG);
invalidate_screen_cache();
editor_loop();
SysScreenClear(0x012456);
SysClearScreen(0x012456);
invalidate_screen_cache();
print("edit: goodbye\n");
SysExitProcess(0);
+9 -9
View File
@@ -191,9 +191,9 @@ int main(void) {
print(")\n");
uint32_t sock = 0;
st = SysSocket(SYS_AF_INET, SYS_SOCK_STREAM, SYS_IPPROTO_TCP, &sock);
st = SysCreateSocket(SYS_AF_INET, SYS_SOCK_STREAM, SYS_IPPROTO_TCP, &sock);
if (st != SYS_STATUS_SUCCESS) {
print("httpget: SysSocket failed "); print_u64(st); print("\n");
print("httpget: SysCreateSocket failed "); print_u64(st); print("\n");
SysExitProcess(1);
}
@@ -206,9 +206,9 @@ int main(void) {
addr.Address[2] = ip[2];
addr.Address[3] = ip[3];
st = SysConnect(sock, &addr, sizeof(addr));
st = SysConnectSocket(sock, &addr, sizeof(addr));
if (st != SYS_STATUS_SUCCESS) {
print("httpget: SysConnect failed "); print_u64(st); print("\n");
print("httpget: SysConnectSocket failed "); print_u64(st); print("\n");
SysCloseHandle(sock);
SysExitProcess(1);
}
@@ -225,9 +225,9 @@ int main(void) {
size_t totalSent = 0;
while (totalSent < off) {
size_t sent = 0;
st = SysSend(sock, request + totalSent, off - totalSent, 0, &sent);
st = SysSendSocket(sock, request + totalSent, off - totalSent, 0, &sent);
if (st != SYS_STATUS_SUCCESS || sent == 0) {
print("httpget: SysSend failed "); print_u64(st); print(" sent="); print_u64(sent); print("\n");
print("httpget: SysSendSocket failed "); print_u64(st); print(" sent="); print_u64(sent); print("\n");
SysCloseHandle(sock);
SysExitProcess(1);
}
@@ -238,9 +238,9 @@ int main(void) {
size_t total = 0;
for (;;) {
size_t got = 0;
st = SysRecv(sock, buf, sizeof(buf) - 1, 0, &got);
st = SysRecvSocket(sock, buf, sizeof(buf) - 1, 0, &got);
if (st != SYS_STATUS_SUCCESS) {
print("\nhttpget: SysRecv failed "); print_u64(st); print(" after "); print_u64(total); print(" bytes\n");
print("\nhttpget: SysRecvSocket failed "); print_u64(st); print(" after "); print_u64(total); print(" bytes\n");
SysCloseHandle(sock);
SysExitProcess(1);
}
@@ -251,7 +251,7 @@ int main(void) {
}
print("\nhttpget: done, "); print_u64(total); print(" bytes\n");
SysShutdown(sock, SYS_SHUTDOWN_BOTH);
SysShutdownSocket(sock, SYS_SHUTDOWN_BOTH);
SysCloseHandle(sock);
SysExitProcess(0);
return 0;
+4 -4
View File
@@ -250,9 +250,9 @@ int main(void) {
format_ipv4(ipText, sizeof(ipText), ip);
uint32_t sock = 0;
st = SysSocket(SYS_AF_INET, SYS_SOCK_RAW, SYS_IPPROTO_ICMP, &sock);
st = SysCreateSocket(SYS_AF_INET, SYS_SOCK_RAW, SYS_IPPROTO_ICMP, &sock);
if (st != SYS_STATUS_SUCCESS) {
print("ping: SysSocket(raw icmp) failed "); print_u64(st); print("\n");
print("ping: SysCreateSocket(raw icmp) failed "); print_u64(st); print("\n");
SysExitProcess(1);
}
@@ -296,7 +296,7 @@ int main(void) {
sendReq.SentOut = &sent;
uint64_t start = SysGetTick();
st = SysSendTo(sock, &sendReq);
st = SysSendToSocket(sock, &sendReq);
if (st != SYS_STATUS_SUCCESS) {
print("ping: send failed seq="); print_u64(seq); print(" status="); print_u64(st); print("\n");
if (i + 1 < count) SysSleep(1000);
@@ -319,7 +319,7 @@ int main(void) {
recvReq.RemoteAddressSizeInOut = &fromSize;
recvReq.ReceivedOut = &got;
st = SysRecvFrom(sock, &recvReq);
st = SysRecvFromSocket(sock, &recvReq);
if (st == SYS_STATUS_TIMEOUT)
break;
if (st != SYS_STATUS_SUCCESS) {
+58 -3
View File
@@ -77,12 +77,35 @@ static void printUIntWidth(uint32_t n, size_t width) {
printUInt(n);
}
static void printUIntZeroWidth(uint32_t n, size_t width) {
uint32_t digits = u64Digits(n);
while (width > digits) { print("0"); width--; }
printUInt(n);
}
static void printUInt64Width(uint64_t n, size_t width) {
uint32_t digits = u64Digits(n);
if (width > digits) printSpaces(width - digits);
printUInt64(n);
}
static void printDirTime(const SYS_SYSTEM_TIME* t) {
if (!t || !(t->Flags & SYS_TIME_FLAG_VALID)) {
print("---- -- -- --:-- ");
return;
}
printUIntZeroWidth(t->Year, 4);
print("-");
printUIntZeroWidth(t->Month, 2);
print("-");
printUIntZeroWidth(t->Day, 2);
print(" ");
printUIntZeroWidth(t->Hour, 2);
print(":");
printUIntZeroWidth(t->Minute, 2);
print(" ");
}
static void printStringWidth(const char* s, size_t width) {
size_t len = s ? strlen(s) : 0;
if (s) print(s);
@@ -95,7 +118,7 @@ static void printStringWidth(const char* s, size_t width) {
static void readLine(char* buf, int len) {
int pos = 0;
while (true) {
char c = SysKbReadChar();
char c = SysReadKeyboardChar();
if (!c) { SysYield(); continue; }
if (c == '\r' || c == '\n') { print("\n"); break; }
if ((c == '\b' || c == 127) && pos > 0) { pos--; print("\b \b"); continue; }
@@ -120,6 +143,7 @@ static void cmd_help() {
print("Available commands:\n"
" help - Show this list\n"
" mem - Show memory usage\n"
" time - Show system wall-clock time\n"
" stats - Show scheduler/CPU/PMM telemetry\n"
" ps - List processes\n"
" dir [path] - List directory contents\n"
@@ -226,6 +250,34 @@ static void cmd_stats(void) {
print(" 1024+: "); printUInt64(pmm.FreeRunHistogram[7]); print("\n");
}
static void cmd_time(void) {
SYS_SYSTEM_TIME t;
uint32_t status = SysGetSystemTime(&t);
if (status != 0) {
print("time: failed: ");
printUInt(status);
print("\n");
return;
}
printUIntZeroWidth(t.Year, 4); print("-");
printUIntZeroWidth(t.Month, 2); print("-");
printUIntZeroWidth(t.Day, 2); print(" ");
printUIntZeroWidth(t.Hour, 2); print(":");
printUIntZeroWidth(t.Minute, 2); print(":");
printUIntZeroWidth(t.Second, 2); print(".");
printUIntZeroWidth(t.Millisecond, 3);
print(" epoch="); printUInt64(t.EpochSeconds);
print(" flags=0x"); printUInt(t.Flags);
if (t.Flags & SYS_TIME_FLAG_TZ_KNOWN) {
print(" tz="); printInt(t.TimeZoneMinutes);
} else {
print(" tz=unspecified");
}
print("\n");
}
static void cmd_mem(void) {
SYS_MEMORY_STATUS st;
if (SysGetMemoryStatus(&st) != 0) {
@@ -338,6 +390,8 @@ static void cmd_dir(const char* path) {
SYS_DIR_ENTRY ke;
while (SysReadDir(hDir, &ke) == 0) {
printDirTime(&ke.LastWriteTime);
// Corrected Attribute Check: 0x10 is the Directory bit in FAT
if (ke.Attr & 0x10) {
print("<DIR> ");
@@ -397,7 +451,7 @@ static int runCommand(const char* cmd) {
if (!cmd || *cmd == '\0') return 0;
if (strcmp(cmd, "exit") == 0) return 1;
if (strcmp(cmd, "help") == 0) { cmd_help(); return 0; }
if (strcmp(cmd, "clear") == 0) { SysScreenClear(0x012456); return 0; }
if (strcmp(cmd, "clear") == 0) { SysClearScreen(0x012456); return 0; }
if (strncmp(cmd, "crash", 5) == 0) {
// Check the sub-option trailing "crash " (offset 6)
if (strcmp(cmd + 6, "void") == 0) {
@@ -437,6 +491,7 @@ static int runCommand(const char* cmd) {
}
}
if (strcmp(cmd, "mem") == 0) { cmd_mem(); return 0; }
if (strcmp(cmd, "time") == 0 || strcmp(cmd, "date") == 0) { cmd_time(); return 0; }
if (strcmp(cmd, "stats") == 0 || strcmp(cmd, "telemetry") == 0) { cmd_stats(); return 0; }
if (strcmp(cmd, "ps") == 0) { cmd_ps(); return 0; }
if (strcmp(cmd, "dir") == 0) { cmd_dir("."); return 0; }
@@ -453,7 +508,7 @@ static int runCommand(const char* cmd) {
if (create_process(program, &hProc, cmd) == 0) {
SysWaitForProcess(hProc);
SysCloseHandle(hProc);
while (SysKbPoll()) (void)SysKbReadChar();
while (SysPollKeyboard()) (void)SysReadKeyboardChar();
} else { print("shell: launch failed\n"); }
return 0;
}
+14 -14
View File
@@ -76,9 +76,9 @@ int main(void) {
}
uint32_t listener = 0;
uint32_t st = SysSocket(SYS_AF_INET, SYS_SOCK_STREAM, SYS_IPPROTO_TCP, &listener);
uint32_t st = SysCreateSocket(SYS_AF_INET, SYS_SOCK_STREAM, SYS_IPPROTO_TCP, &listener);
if (st != SYS_STATUS_SUCCESS) {
print("tcpserve: SysSocket failed "); print_u64(st); print("\n");
print("tcpserve: SysCreateSocket failed "); print_u64(st); print("\n");
SysExitProcess(1);
}
@@ -91,16 +91,16 @@ int main(void) {
bindAddr.Address[2] = 0;
bindAddr.Address[3] = 0;
st = SysBind(listener, &bindAddr, sizeof(bindAddr));
st = SysBindSocket(listener, &bindAddr, sizeof(bindAddr));
if (st != SYS_STATUS_SUCCESS) {
print("tcpserve: SysBind failed "); print_u64(st); print("\n");
print("tcpserve: SysBindSocket failed "); print_u64(st); print("\n");
SysCloseHandle(listener);
SysExitProcess(1);
}
st = SysListen(listener, 4);
st = SysListenSocket(listener, 4);
if (st != SYS_STATUS_SUCCESS) {
print("tcpserve: SysListen failed "); print_u64(st); print("\n");
print("tcpserve: SysListenSocket failed "); print_u64(st); print("\n");
SysCloseHandle(listener);
SysExitProcess(1);
}
@@ -111,9 +111,9 @@ int main(void) {
SYS_SOCKET_ADDRESS_IPV4 remote;
size_t remoteSize = sizeof(remote);
uint32_t client = 0;
st = SysAccept(listener, &remote, &remoteSize, &client);
st = SysAcceptSocket(listener, &remote, &remoteSize, &client);
if (st != SYS_STATUS_SUCCESS) {
print("tcpserve: SysAccept failed "); print_u64(st); print("\n");
print("tcpserve: SysAcceptSocket failed "); print_u64(st); print("\n");
SysCloseHandle(listener);
SysExitProcess(1);
}
@@ -129,9 +129,9 @@ int main(void) {
char request[1025];
size_t got = 0;
st = SysRecv(client, request, sizeof(request) - 1, 0, &got);
st = SysRecvSocket(client, request, sizeof(request) - 1, 0, &got);
if (st != SYS_STATUS_SUCCESS) {
print("tcpserve: SysRecv failed "); print_u64(st); print("\n");
print("tcpserve: SysRecvSocket failed "); print_u64(st); print("\n");
SysCloseHandle(client);
SysCloseHandle(listener);
SysExitProcess(1);
@@ -168,13 +168,13 @@ int main(void) {
#undef APPEND_LITERAL
size_t sent = 0;
st = SysSend(client, response, off, 0, &sent);
st = SysSendSocket(client, response, off, 0, &sent);
if (st == SYS_STATUS_SUCCESS)
st = SysSend(client, body, sizeof(body) - 1, 0, &sent);
st = SysSendSocket(client, body, sizeof(body) - 1, 0, &sent);
if (st != SYS_STATUS_SUCCESS)
print("tcpserve: SysSend failed "), print_u64(st), print("\n");
print("tcpserve: SysSendSocket failed "), print_u64(st), print("\n");
SysShutdown(client, SYS_SHUTDOWN_BOTH);
SysShutdownSocket(client, SYS_SHUTDOWN_BOTH);
SysCloseHandle(client);
SysCloseHandle(listener);
print("tcpserve: done\n");
+10 -10
View File
@@ -116,9 +116,9 @@ static int run_send(const char* cmd) {
}
uint32_t sock = 0;
uint32_t st = SysSocket(SYS_AF_INET, SYS_SOCK_DGRAM, SYS_IPPROTO_UDP, &sock);
uint32_t st = SysCreateSocket(SYS_AF_INET, SYS_SOCK_DGRAM, SYS_IPPROTO_UDP, &sock);
if (st != SYS_STATUS_SUCCESS) {
print("udp: SysSocket failed "); print_u64(st); print("\n");
print("udp: SysCreateSocket failed "); print_u64(st); print("\n");
return 1;
}
@@ -140,10 +140,10 @@ static int run_send(const char* cmd) {
req.RemoteAddressSize = sizeof(remote);
req.SentOut = &sent;
st = SysSendTo(sock, &req);
st = SysSendToSocket(sock, &req);
SysCloseHandle(sock);
if (st != SYS_STATUS_SUCCESS) {
print("udp: SysSendTo failed "); print_u64(st); print("\n");
print("udp: SysSendToSocket failed "); print_u64(st); print("\n");
return 1;
}
@@ -159,9 +159,9 @@ static int run_listen(const char* cmd) {
if (!tok[0] || !parse_port(tok, &port)) { usage(); return 1; }
uint32_t sock = 0;
uint32_t st = SysSocket(SYS_AF_INET, SYS_SOCK_DGRAM, SYS_IPPROTO_UDP, &sock);
uint32_t st = SysCreateSocket(SYS_AF_INET, SYS_SOCK_DGRAM, SYS_IPPROTO_UDP, &sock);
if (st != SYS_STATUS_SUCCESS) {
print("udp: SysSocket failed "); print_u64(st); print("\n");
print("udp: SysCreateSocket failed "); print_u64(st); print("\n");
return 1;
}
@@ -170,9 +170,9 @@ static int run_listen(const char* cmd) {
bindAddr.Family = SYS_AF_INET;
bindAddr.Port = port;
st = SysBind(sock, &bindAddr, sizeof(bindAddr));
st = SysBindSocket(sock, &bindAddr, sizeof(bindAddr));
if (st != SYS_STATUS_SUCCESS) {
print("udp: SysBind failed "); print_u64(st); print("\n");
print("udp: SysBindSocket failed "); print_u64(st); print("\n");
SysCloseHandle(sock);
return 1;
}
@@ -191,10 +191,10 @@ static int run_listen(const char* cmd) {
req.RemoteAddressSizeInOut = &remoteSize;
req.ReceivedOut = &got;
st = SysRecvFrom(sock, &req);
st = SysRecvFromSocket(sock, &req);
SysCloseHandle(sock);
if (st != SYS_STATUS_SUCCESS) {
print("udp: SysRecvFrom failed "); print_u64(st); print("\n");
print("udp: SysRecvFromSocket failed "); print_u64(st); print("\n");
return 1;
}
+1 -1
View File
@@ -6,7 +6,7 @@
typedef enum {
FD_FREE,
FD_FILE,
FD_CONSOLE_R, // fd 0 - reads from keyboard via SysKbReadChar
FD_CONSOLE_R, // fd 0 - reads from keyboard via SysReadKeyboardChar
FD_CONSOLE_W, // fd 1, 2 - writes via SysWriteConsole
FD_DEVNULL, // /dev/null
FD_DEVZERO, // /dev/zero
+5 -5
View File
@@ -7,11 +7,11 @@
#include "posix_path.h"
__declspec(dllexport) void clearscreen(void) {
SysScreenClear(0x012456);
SysClearScreen(0x012456);
}
__declspec(dllexport) void clearkeyboard(void) {
while (SysKbPoll()) (void)SysKbReadChar();
while (SysPollKeyboard()) (void)SysReadKeyboardChar();
}
__declspec(dllexport) int open(const char* path, int flags, ...) {
@@ -64,7 +64,7 @@ __declspec(dllexport) ssize_t read(int fd, void* buf, size_t count) {
// Read up to count chars from keyboard, blocking per char.
char* dst = (char*)buf;
for (size_t i = 0; i < count; i++) {
dst[i] = SysKbReadChar();
dst[i] = SysReadKeyboardChar();
if (dst[i] == '\n' || dst[i] == '\r') return (ssize_t)(i + 1);
}
return (ssize_t)count;
@@ -82,7 +82,7 @@ __declspec(dllexport) ssize_t read(int fd, void* buf, size_t count) {
}
case FD_SOCKET: {
size_t got = 0;
uint32_t s = SysRecv(e->KHandle, buf, count, 0, &got);
uint32_t s = SysRecvSocket(e->KHandle, buf, count, 0, &got);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
return (ssize_t)got;
}
@@ -115,7 +115,7 @@ __declspec(dllexport) ssize_t write(int fd, const void* buf, size_t count) {
}
case FD_SOCKET: {
size_t sent = 0;
uint32_t s = SysSend(e->KHandle, buf, count, 0, &sent);
uint32_t s = SysSendSocket(e->KHandle, buf, count, 0, &sent);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
return (ssize_t)sent;
}
+10 -10
View File
@@ -118,7 +118,7 @@ static FD_ENTRY* SocketFdGet(int fd) {
__declspec(dllexport) int socket(int domain, int type, int protocol) {
uint32_t kh = 0;
uint32_t s = SysSocket((uint32_t)domain, (uint32_t)type, (uint32_t)protocol, &kh);
uint32_t s = SysCreateSocket((uint32_t)domain, (uint32_t)type, (uint32_t)protocol, &kh);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
int fd = FdAlloc(SysGetCurrentPid(), FD_SOCKET, kh);
@@ -134,7 +134,7 @@ __declspec(dllexport) int bind(int fd, const struct sockaddr* addr, socklen_t ad
if (!e) return -1;
SYS_SOCKET_ADDRESS_IPV4 a;
if (SockAddrToSys(addr, addrlen, &a) != 0) return -1;
uint32_t s = SysBind(e->KHandle, &a, sizeof(a));
uint32_t s = SysBindSocket(e->KHandle, &a, sizeof(a));
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
return 0;
}
@@ -142,7 +142,7 @@ __declspec(dllexport) int bind(int fd, const struct sockaddr* addr, socklen_t ad
__declspec(dllexport) int listen(int fd, int backlog) {
FD_ENTRY* e = SocketFdGet(fd);
if (!e) return -1;
uint32_t s = SysListen(e->KHandle, backlog < 0 ? 0u : (uint32_t)backlog);
uint32_t s = SysListenSocket(e->KHandle, backlog < 0 ? 0u : (uint32_t)backlog);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
return 0;
}
@@ -154,7 +154,7 @@ __declspec(dllexport) int accept(int fd, struct sockaddr* addr, socklen_t* addrl
SYS_SOCKET_ADDRESS_IPV4 remote;
size_t remoteSize = sizeof(remote);
uint32_t kh = 0;
uint32_t s = SysAccept(e->KHandle, addr ? &remote : (SYS_SOCKET_ADDRESS_IPV4*)0,
uint32_t s = SysAcceptSocket(e->KHandle, addr ? &remote : (SYS_SOCKET_ADDRESS_IPV4*)0,
addr ? &remoteSize : (size_t*)0, &kh);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
@@ -172,7 +172,7 @@ __declspec(dllexport) int connect(int fd, const struct sockaddr* addr, socklen_t
if (!e) return -1;
SYS_SOCKET_ADDRESS_IPV4 a;
if (SockAddrToSys(addr, addrlen, &a) != 0) return -1;
uint32_t s = SysConnect(e->KHandle, &a, sizeof(a));
uint32_t s = SysConnectSocket(e->KHandle, &a, sizeof(a));
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
return 0;
}
@@ -181,7 +181,7 @@ __declspec(dllexport) ssize_t send(int fd, const void* buf, size_t len, int flag
FD_ENTRY* e = SocketFdGet(fd);
if (!e) return -1;
size_t sent = 0;
uint32_t s = SysSend(e->KHandle, buf, len, (uint32_t)flags, &sent);
uint32_t s = SysSendSocket(e->KHandle, buf, len, (uint32_t)flags, &sent);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
return (ssize_t)sent;
}
@@ -190,7 +190,7 @@ __declspec(dllexport) ssize_t recv(int fd, void* buf, size_t len, int flags) {
FD_ENTRY* e = SocketFdGet(fd);
if (!e) return -1;
size_t got = 0;
uint32_t s = SysRecv(e->KHandle, buf, len, (uint32_t)flags, &got);
uint32_t s = SysRecvSocket(e->KHandle, buf, len, (uint32_t)flags, &got);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
return (ssize_t)got;
}
@@ -212,7 +212,7 @@ __declspec(dllexport) ssize_t sendto(int fd, const void* buf, size_t len, int fl
req.RemoteAddressSize = sizeof(remote);
req.SentOut = &sent;
uint32_t s = SysSendTo(e->KHandle, &req);
uint32_t s = SysSendToSocket(e->KHandle, &req);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
return (ssize_t)sent;
}
@@ -234,7 +234,7 @@ __declspec(dllexport) ssize_t recvfrom(int fd, void* buf, size_t len, int flags,
req.RemoteAddressSizeInOut = src ? &remoteSize : (size_t*)0;
req.ReceivedOut = &got;
uint32_t s = SysRecvFrom(e->KHandle, &req);
uint32_t s = SysRecvFromSocket(e->KHandle, &req);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
if (src) SysToSockAddr(&remote, src, srclen);
return (ssize_t)got;
@@ -243,7 +243,7 @@ __declspec(dllexport) ssize_t recvfrom(int fd, void* buf, size_t len, int flags,
__declspec(dllexport) int shutdown(int fd, int how) {
FD_ENTRY* e = SocketFdGet(fd);
if (!e) return -1;
uint32_t s = SysShutdown(e->KHandle, (uint32_t)how);
uint32_t s = SysShutdownSocket(e->KHandle, (uint32_t)how);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
return 0;
}
+4 -4
View File
@@ -120,7 +120,7 @@ __declspec(dllexport) void pthread_exit(void* retval) {
__declspec(dllexport) int pthread_mutex_init(pthread_mutex_t* m, const pthread_mutexattr_t* attr) {
(void)attr;
uint32_t h;
uint32_t s = SysMutexCreate(&h);
uint32_t s = SysCreateMutex(&h);
if (s != 0) return ENOMEM;
m->Handle = h;
return 0;
@@ -133,16 +133,16 @@ __declspec(dllexport) int pthread_mutex_destroy(pthread_mutex_t* m) {
}
__declspec(dllexport) int pthread_mutex_lock(pthread_mutex_t* m) {
uint32_t s = SysMutexAcquire(m->Handle);
uint32_t s = SysAcquireMutex(m->Handle);
return s == 0 ? 0 : EINVAL;
}
__declspec(dllexport) int pthread_mutex_trylock(pthread_mutex_t* m) {
uint32_t s = SysMutexTryAcquire(m->Handle);
uint32_t s = SysTryAcquireMutex(m->Handle);
return s == 0 ? 0 : EAGAIN;
}
__declspec(dllexport) int pthread_mutex_unlock(pthread_mutex_t* m) {
uint32_t s = SysMutexRelease(m->Handle);
uint32_t s = SysReleaseMutex(m->Handle);
return s == 0 ? 0 : EINVAL;
}
+2 -2
View File
@@ -84,7 +84,7 @@ __declspec(dllexport) int StretchDIBits(
// Handle trivial case (1:1 copy) to bypass allocation and scaling overhead
if (DestWidth == SrcWidth && DestHeight == SrcHeight && xSrc == 0 && ySrc == 0) {
SysScreenBlit(xDest, yDest, DestWidth, DestHeight, (const uint32_t*)lpBits);
SysBlitScreen(xDest, yDest, DestWidth, DestHeight, (const uint32_t*)lpBits);
return DestHeight;
}
@@ -162,7 +162,7 @@ __declspec(dllexport) int StretchDIBits(
}
// Direct mapping to kernel screen blit using the stretched buffer
SysScreenBlit(xDest, yDest, DestWidth, DestHeight, destBuffer);
SysBlitScreen(xDest, yDest, DestWidth, DestHeight, destBuffer);
return DestHeight;
}
+143 -28
View File
@@ -80,7 +80,7 @@ static uint32_t WinProtectToSysVm(DWORD protect) {
}
}
static DWORD SysVmProtectToWin(uint32_t protect) {
static DWORD SysProtectVmToWin(uint32_t protect) {
switch (protect) {
case SYS_VM_NOACCESS: return PAGE_NOACCESS;
case SYS_VM_READ: return PAGE_READONLY;
@@ -98,6 +98,17 @@ typedef struct _FILETIME {
DWORD dwHighDateTime;
} FILETIME;
typedef struct _SYSTEMTIME {
unsigned short wYear;
unsigned short wMonth;
unsigned short wDayOfWeek;
unsigned short wDay;
unsigned short wHour;
unsigned short wMinute;
unsigned short wSecond;
unsigned short wMilliseconds;
} SYSTEMTIME;
typedef struct _WIN32_FIND_DATAA {
DWORD dwFileAttributes;
FILETIME ftCreationTime;
@@ -234,8 +245,8 @@ static void K32WriteConsoleSpan(const char* data, size_t length) {
static void K32DebugPrintA(const char* s) {
if (!s) return;
SYS_DEBUG_PRINT_REQUEST req = { SysSvFromCstr(s) };
SysDebugPrint(&req);
SYS_PRINT_DEBUG_REQUEST req = { SysSvFromCstr(s) };
SysPrintDebug(&req);
}
#define WIN32_TLS_SLOTS 64
@@ -431,7 +442,7 @@ __declspec(dllexport) void* VirtualAlloc(void* lpAddress, size_t dwSize,
size_t pages = (dwSize + 4095u) / 4096u;
void* base = NULL;
uint32_t flags = lpAddress ? SYS_VM_FLAG_FIXED : SYS_VM_FLAG_NONE;
uint32_t s = SysVmAlloc(lpAddress, pages, WinProtectToSysVm(flProtect), flags, &base);
uint32_t s = SysAllocVm(lpAddress, pages, WinProtectToSysVm(flProtect), flags, &base);
if (s != SYS_STATUS_SUCCESS) {
gLastError = (s == SYS_STATUS_NOT_FOUND || s == SYS_STATUS_INVALID_PARAMETER) ? 87 : 8;
return NULL;
@@ -442,7 +453,7 @@ __declspec(dllexport) void* VirtualAlloc(void* lpAddress, size_t dwSize,
__declspec(dllexport) BOOL VirtualFree(void* lpAddress, size_t dwSize, DWORD dwFreeType) {
(void)dwSize; (void)dwFreeType;
if (!lpAddress) return TRUE;
uint32_t s = SysVmFree(lpAddress);
uint32_t s = SysFreeVm(lpAddress);
if (s != SYS_STATUS_SUCCESS) { gLastError = 87; return FALSE; }
return TRUE;
}
@@ -452,10 +463,10 @@ __declspec(dllexport) BOOL VirtualProtect(void* lpAddress, size_t dwSize,
if (!lpAddress || !dwSize) { gLastError = 87; return FALSE; }
size_t pages = (dwSize + 4095u) / 4096u;
uint32_t oldSysProtect = 0;
uint32_t s = SysVmProtect(lpAddress, pages, WinProtectToSysVm(flNewProtect),
uint32_t s = SysProtectVm(lpAddress, pages, WinProtectToSysVm(flNewProtect),
lpflOldProtect ? &oldSysProtect : NULL);
if (s != SYS_STATUS_SUCCESS) { gLastError = 87; return FALSE; }
if (lpflOldProtect) *lpflOldProtect = SysVmProtectToWin(oldSysProtect);
if (lpflOldProtect) *lpflOldProtect = SysProtectVmToWin(oldSysProtect);
return TRUE;
}
@@ -468,13 +479,13 @@ __declspec(dllexport) size_t VirtualQuery(const void* lpAddress,
}
SYS_VM_REGION_INFO info;
uint32_t s = SysVmQuery((void*)lpAddress, &info);
uint32_t s = SysQueryVm((void*)lpAddress, &info);
if (s != SYS_STATUS_SUCCESS) {
gLastError = 87;
return 0;
}
DWORD protect = SysVmProtectToWin(info.Protect);
DWORD protect = SysProtectVmToWin(info.Protect);
lpBuffer->BaseAddress = info.Base;
lpBuffer->AllocationBase = info.Base;
lpBuffer->AllocationProtect = protect;
@@ -490,13 +501,13 @@ __declspec(dllexport) size_t VirtualQuery(const void* lpAddress,
// GetAsyncKeyState implementation over the canonical input key namespace.
__declspec(dllexport) SHORT GetAsyncKeyState(int vKey) {
if (vKey == 0x11) { // VK_CONTROL
return (SysKbIsKeyDown(INPUT_KEY_LEFT_CTRL) || SysKbIsKeyDown(INPUT_KEY_RIGHT_CTRL)) ? (SHORT)0x8000 : 0;
return (SysIsKeyDown(INPUT_KEY_LEFT_CTRL) || SysIsKeyDown(INPUT_KEY_RIGHT_CTRL)) ? (SHORT)0x8000 : 0;
}
if (vKey == 0x10) { // VK_SHIFT
return (SysKbIsKeyDown(INPUT_KEY_LEFT_SHIFT) || SysKbIsKeyDown(INPUT_KEY_RIGHT_SHIFT)) ? (SHORT)0x8000 : 0;
return (SysIsKeyDown(INPUT_KEY_LEFT_SHIFT) || SysIsKeyDown(INPUT_KEY_RIGHT_SHIFT)) ? (SHORT)0x8000 : 0;
}
if (vKey == 0x12) { // VK_MENU / ALT
return (SysKbIsKeyDown(INPUT_KEY_LEFT_ALT) || SysKbIsKeyDown(INPUT_KEY_RIGHT_ALT)) ? (SHORT)0x8000 : 0;
return (SysIsKeyDown(INPUT_KEY_LEFT_ALT) || SysIsKeyDown(INPUT_KEY_RIGHT_ALT)) ? (SHORT)0x8000 : 0;
}
static const struct { int vk; INPUT_KEY key; } vk_to_key[] = {
@@ -539,7 +550,7 @@ __declspec(dllexport) SHORT GetAsyncKeyState(int vKey) {
for (size_t i = 0; i < sizeof(vk_to_key) / sizeof(vk_to_key[0]); ++i) {
if (vk_to_key[i].vk == vKey) {
if (SysKbIsKeyDown(vk_to_key[i].key))
if (SysIsKeyDown(vk_to_key[i].key))
return (SHORT)0x8000;
break;
}
@@ -551,15 +562,15 @@ __declspec(dllexport) SHORT GetAsyncKeyState(int vKey) {
__declspec(dllexport) BOOL FlushConsoleInputBuffer(HANDLE hConsoleInput) {
(void)hConsoleInput;
// Drain the keyboard buffer by reading until empty
while (SysKbPoll()) {
(void)SysKbReadChar();
while (SysPollKeyboard()) {
(void)SysReadKeyboardChar();
}
return TRUE;
}
// !Made-up! clear console api.
__declspec(dllexport) BOOL ClearConsoleScreenBuffer(HANDLE hConsole) {
SysScreenClear(0x012456);
SysClearScreen(0x012456);
return TRUE;
}
@@ -1245,7 +1256,7 @@ __declspec(dllexport) HANDLE GetStdHandle(DWORD nStdHandle) {
}
// ReadConsoleA: blocking read of up to nNumberOfCharsToRead characters.
// Each character is read individually via SysKbReadChar so the caller can
// Each character is read individually via SysReadKeyboardChar so the caller can
// do its own line-editing (echo, backspace, etc.) one char at a time.
__declspec(dllexport) BOOL ReadConsoleA(HANDLE hConsoleInput,
void* lpBuffer,
@@ -1259,7 +1270,7 @@ __declspec(dllexport) BOOL ReadConsoleA(HANDLE hConsoleInput,
DWORD i = 0; // Notice we switched to a while loop
while (i < nNumberOfCharsToRead) {
char c = SysKbReadChar();
char c = SysReadKeyboardChar();
// Ignore unmapped keys (Shift, Ctrl, etc.)
if (c == 0) continue;
@@ -1390,6 +1401,41 @@ static void SplitFindPath(const char* searchPath,
#define FILE_ATTRIBUTE_ARCHIVE 0x00000020UL
#define FILE_ATTRIBUTE_NORMAL 0x00000080UL
static int K32DirIsLeapYear(unsigned int year) {
return ((year % 4u) == 0u && (year % 100u) != 0u) || ((year % 400u) == 0u);
}
static unsigned int K32DirDaysInMonth(unsigned int year, unsigned int month) {
static const unsigned char days[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
if (month < 1u || month > 12u) return 31u;
if (month == 2u && K32DirIsLeapYear(year)) return 29u;
return days[month - 1u];
}
static uint64_t K32DirCalendarToEpochSeconds(const SYS_SYSTEM_TIME* st) {
uint64_t days = 0;
for (unsigned int y = 1970u; y < st->Year; y++)
days += K32DirIsLeapYear(y) ? 366u : 365u;
for (unsigned int m = 1u; m < st->Month; m++)
days += K32DirDaysInMonth(st->Year, m);
days += (uint64_t)(st->Day - 1u);
return (((days * 24u) + st->Hour) * 60u + st->Minute) * 60u + st->Second;
}
static void K32DirStoreFileTime(FILETIME* ft, const SYS_SYSTEM_TIME* st) {
if (!ft || !st || !(st->Flags & SYS_TIME_FLAG_VALID) || st->Year < 1970u) {
if (ft) { ft->dwLowDateTime = 0; ft->dwHighDateTime = 0; }
return;
}
const uint64_t WINDOWS_EPOCH_BIAS_SECONDS = 11644473600ULL;
uint64_t epoch = st->EpochSeconds ? st->EpochSeconds : K32DirCalendarToEpochSeconds(st);
uint64_t value = (epoch + WINDOWS_EPOCH_BIAS_SECONDS) * 10000000ULL +
((uint64_t)st->Millisecond * 10000ULL) +
((uint64_t)st->Nanosecond / 100ULL);
ft->dwLowDateTime = (DWORD)(value & 0xFFFFFFFFULL);
ft->dwHighDateTime = (DWORD)(value >> 32);
}
static void KdirToFindData(const KDIR_ENTRY* ke, WIN32_FIND_DATAA* fd) {
// Zero the entire struct (covers all FILETIME and reserved fields)
unsigned char* p = (unsigned char*)fd;
@@ -1402,6 +1448,9 @@ static void KdirToFindData(const KDIR_ENTRY* ke, WIN32_FIND_DATAA* fd) {
fd->nFileSizeLow = ke->FileSize;
fd->nFileSizeHigh = 0;
K32DirStoreFileTime(&fd->ftCreationTime, &ke->CreateTime);
K32DirStoreFileTime(&fd->ftLastAccessTime, &ke->LastAccessTime);
K32DirStoreFileTime(&fd->ftLastWriteTime, &ke->LastWriteTime);
size_t nameLen = strlen(ke->Name);
if (nameLen >= MAX_PATH) nameLen = MAX_PATH - 1;
@@ -1687,19 +1736,85 @@ __declspec(dllexport) BOOL QueryPerformanceCounter(LARGE_INTEGER* lpPerformanceC
return TRUE;
}
static BOOL K32IsLeapYear(unsigned int year) {
return ((year % 4u) == 0u && (year % 100u) != 0u) || ((year % 400u) == 0u);
}
static unsigned int K32DaysInMonth(unsigned int year, unsigned int month) {
static const unsigned char days[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
if (month == 2u && K32IsLeapYear(year)) return 29u;
if (month < 1u || month > 12u) return 0u;
return days[month - 1u];
}
static uint64_t K32CalendarToEpochSeconds(const SYSTEMTIME* st) {
uint64_t days = 0;
for (unsigned int y = 1970u; y < st->wYear; y++)
days += K32IsLeapYear(y) ? 366u : 365u;
for (unsigned int m = 1u; m < st->wMonth; m++)
days += K32DaysInMonth(st->wYear, m);
days += (uint64_t)(st->wDay - 1u);
return (((days * 24u) + st->wHour) * 60u + st->wMinute) * 60u + st->wSecond;
}
static uint64_t K32EpochToFileTime(uint64_t epochSeconds, uint32_t nanosecond) {
const uint64_t WINDOWS_EPOCH_BIAS_SECONDS = 11644473600ULL;
return (epochSeconds + WINDOWS_EPOCH_BIAS_SECONDS) * 10000000ULL +
((uint64_t)nanosecond / 100ULL);
}
static void K32StoreFileTime(FILETIME* ft, uint64_t value) {
ft->dwLowDateTime = (DWORD)(value & 0xFFFFFFFFULL);
ft->dwHighDateTime = (DWORD)(value >> 32);
}
__declspec(dllexport) void GetSystemTime(SYSTEMTIME* lpSystemTime) {
if (!lpSystemTime) return;
SYS_SYSTEM_TIME st;
if (SysGetSystemTime(&st) != SYS_STATUS_SUCCESS) {
memset(lpSystemTime, 0, sizeof(*lpSystemTime));
return;
}
lpSystemTime->wYear = st.Year;
lpSystemTime->wMonth = st.Month;
lpSystemTime->wDayOfWeek = st.DayOfWeek;
lpSystemTime->wDay = st.Day;
lpSystemTime->wHour = st.Hour;
lpSystemTime->wMinute = st.Minute;
lpSystemTime->wSecond = st.Second;
lpSystemTime->wMilliseconds = st.Millisecond;
}
__declspec(dllexport) BOOL SystemTimeToFileTime(const SYSTEMTIME* lpSystemTime,
FILETIME* lpFileTime) {
if (!lpSystemTime || !lpFileTime) return FALSE;
if (lpSystemTime->wYear < 1970 || lpSystemTime->wMonth < 1 ||
lpSystemTime->wMonth > 12 || lpSystemTime->wDay < 1 ||
lpSystemTime->wDay > K32DaysInMonth(lpSystemTime->wYear, lpSystemTime->wMonth) ||
lpSystemTime->wHour > 23 || lpSystemTime->wMinute > 59 ||
lpSystemTime->wSecond > 59 || lpSystemTime->wMilliseconds > 999) {
return FALSE;
}
uint64_t ft = K32EpochToFileTime(K32CalendarToEpochSeconds(lpSystemTime),
(uint32_t)lpSystemTime->wMilliseconds * 1000000u);
K32StoreFileTime(lpFileTime, ft);
return TRUE;
}
__declspec(dllexport) void GetSystemTimeAsFileTime(void* lpSystemTimeAsFileTime) {
if (!lpSystemTimeAsFileTime) return;
// Baseline: 2024-01-01 00:00:00 UTC in 100-ns intervals
const unsigned long long BASELINE_FT = 133485408000000000ULL;
// SysGetTick() is in microseconds.
// 1 microsecond = 10 units of 100-nanoseconds.
unsigned long long now_us = SysGetTick();
unsigned long long ft = BASELINE_FT + (now_us * 10ULL);
// Copy the 64-bit value into the output buffer.
// We use memcpy to safely handle potential alignment issues with the void pointer.
SYS_SYSTEM_TIME st;
uint64_t ft;
if (SysGetSystemTime(&st) == SYS_STATUS_SUCCESS) {
ft = K32EpochToFileTime(st.EpochSeconds, st.Nanosecond);
} else {
const uint64_t FALLBACK_2024_01_01_FT = 133485408000000000ULL;
ft = FALLBACK_2024_01_01_FT + (SysGetTick() * 10ULL);
}
memcpy(lpSystemTimeAsFileTime, &ft, sizeof(ft));
}
+2 -2
View File
@@ -16,8 +16,8 @@ typedef struct tagPAINTSTRUCT {
static void User32DebugPrintA(const char* s) {
if (!s) return;
SYS_DEBUG_PRINT_REQUEST req = { SysSvFromCstr(s) };
SysDebugPrint(&req);
SYS_PRINT_DEBUG_REQUEST req = { SysSvFromCstr(s) };
SysPrintDebug(&req);
}
// --- Painting Functions ---
+2 -2
View File
@@ -107,7 +107,7 @@ static HEAP_SEGMENT* AddSegment(size_t payloadSize) {
if (pages < USER_HEAP_MIN_PAGES) pages = USER_HEAP_MIN_PAGES;
void* base = 0;
uint32_t s = SysVmAlloc(0, pages, SYS_VM_READWRITE, SYS_VM_FLAG_NONE, &base);
uint32_t s = SysAllocVm(0, pages, SYS_VM_READWRITE, SYS_VM_FLAG_NONE, &base);
if (s != SYS_STATUS_SUCCESS || !base)
return (HEAP_SEGMENT*)0;
@@ -138,7 +138,7 @@ static void RemoveSegmentIfEmpty(HEAP_SEGMENT* seg) {
else gSegments = seg->Next;
if (seg->Next) seg->Next->Prev = seg->Prev;
SysVmFree(seg);
SysFreeVm(seg);
}
void* _malloc(size_t size) {
+94 -93
View File
@@ -1,96 +1,97 @@
; syscall_nr.inc
SYS_EXIT_PROCESS EQU 0
SYS_EXIT_THREAD EQU 1
SYS_CREATE_PROCESS EQU 2
SYS_WAIT_FOR_PROCESS EQU 3
SYS_GET_PROCESS_EXIT_CODE EQU 4
SYS_KILL_PROCESS EQU 5
SYS_GET_PROCESS_LIST EQU 6
SYS_GET_PROCESS_PID EQU 7
SYS_CREATE_THREAD EQU 8
SYS_WAIT_THREAD EQU 9
SYS_GET_CURRENT_TID EQU 10
SYS_GET_CURRENT_PID EQU 11
SYS_SET_THREAD_PRIORITY EQU 12
SYS_YIELD EQU 13
SYS_SLEEP EQU 14
SYS_SET_USER_APC_DISPATCHER EQU 15
SYS_APC_RETURN EQU 16
SYS_VM_ALLOC EQU 17
SYS_VM_FREE EQU 18
SYS_VM_PROTECT EQU 19
SYS_VM_QUERY EQU 20
SYS_CLOSE_HANDLE EQU 21
SYS_MUTEX_CREATE EQU 22
SYS_MUTEX_ACQUIRE EQU 23
SYS_MUTEX_TRY_ACQUIRE EQU 24
SYS_MUTEX_RELEASE EQU 25
SYS_SEM_CREATE EQU 26
SYS_SEM_WAIT EQU 27
SYS_SEM_TRY_WAIT EQU 28
SYS_SEM_SIGNAL EQU 29
SYS_EVENT_CREATE EQU 30
SYS_EVENT_SIGNAL EQU 31
SYS_EVENT_CLEAR EQU 32
SYS_EVENT_WAIT EQU 33
SYS_QUEUE_CREATE EQU 34
SYS_QUEUE_SEND EQU 35
SYS_QUEUE_RECV EQU 36
SYS_PUBLISH_QUEUE EQU 37
SYS_OPEN_NAMED_QUEUE EQU 38
SYS_QUEUE_DUPLICATE EQU 39
SYS_NAMED_QUEUE_OWNER_PID EQU 40
SYS_OPEN_FILE EQU 41
SYS_CREATE_FILE EQU 42
SYS_READ_FILE EQU 43
SYS_WRITE_FILE EQU 44
SYS_READ_FILE_ASYNC EQU 45
SYS_WRITE_FILE_ASYNC EQU 46
SYS_CANCEL_IO EQU 47
SYS_SEEK_FILE EQU 48
SYS_GET_FILE_POS EQU 49
SYS_GET_FILE_SIZE EQU 50
SYS_TRUNCATE_FILE EQU 51
SYS_DELETE_FILE EQU 52
SYS_RENAME_FILE EQU 53
SYS_OPEN_DIR EQU 54
SYS_READ_DIR EQU 55
SYS_CREATE_DIR EQU 56
SYS_REMOVE_DIR EQU 57
SYS_SET_CWD EQU 58
SYS_GET_CWD EQU 59
SYS_WRITE_CONSOLE EQU 60
SYS_SCREEN_BLIT EQU 61
SYS_SCREEN_CLEAR EQU 62
SYS_SCREEN_GET_SIZE EQU 63
SYS_SCREEN_PUT_CHAR EQU 64
SYS_KB_POLL EQU 65
SYS_KB_IS_KEY_DOWN EQU 66
SYS_KB_READ_CHAR EQU 67
SYS_KB_READ_KEY EQU 68
SYS_KB_GET_MODIFIERS EQU 69
SYS_MOUSE_POLL EQU 70
SYS_MOUSE_READ EQU 71
SYS_MOUSE_GET_POS EQU 72
SYS_GET_TICK EQU 73
SYS_DEBUG_PRINT EQU 74
SYS_QUERY_TRAP_FRAME EQU 75
SYS_SOCKET EQU 76
SYS_BIND EQU 77
SYS_LISTEN EQU 78
SYS_ACCEPT EQU 79
SYS_CONNECT EQU 80
SYS_SEND EQU 81
SYS_RECV EQU 82
SYS_SHUTDOWN EQU 83
SYS_SEND_TO EQU 84
SYS_RECV_FROM EQU 85
SYS_RESOLVE_HOST EQU 86
SYS_SET_SOCKET_OPTION EQU 87
SYS_GET_SOCKET_OPTION EQU 88
SYS_POLL EQU 89
SYS_GET_MEMORY_STATUS EQU 90
SYS_QUERY_KERNEL_STATS EQU 91
SYS_EXIT_PROCESS EQU 0
SYS_EXIT_THREAD EQU 1
SYS_CREATE_PROCESS EQU 2
SYS_WAIT_FOR_PROCESS EQU 3
SYS_GET_PROCESS_EXIT_CODE EQU 4
SYS_KILL_PROCESS EQU 5
SYS_GET_PROCESS_LIST EQU 6
SYS_GET_PROCESS_PID EQU 7
SYS_CREATE_THREAD EQU 8
SYS_WAIT_THREAD EQU 9
SYS_GET_CURRENT_TID EQU 10
SYS_GET_CURRENT_PID EQU 11
SYS_SET_THREAD_PRIORITY EQU 12
SYS_YIELD EQU 13
SYS_SLEEP EQU 14
SYS_SET_USER_APC_DISPATCHER EQU 15
SYS_APC_RETURN EQU 16
SYS_ALLOC_VM EQU 17
SYS_FREE_VM EQU 18
SYS_PROTECT_VM EQU 19
SYS_QUERY_VM EQU 20
SYS_CLOSE_HANDLE EQU 21
SYS_CREATE_MUTEX EQU 22
SYS_ACQUIRE_MUTEX EQU 23
SYS_TRY_ACQUIRE_MUTEX EQU 24
SYS_RELEASE_MUTEX EQU 25
SYS_CREATE_SEM EQU 26
SYS_WAIT_SEM EQU 27
SYS_TRY_WAIT_SEM EQU 28
SYS_SIGNAL_SEM EQU 29
SYS_CREATE_EVENT EQU 30
SYS_SIGNAL_EVENT EQU 31
SYS_CLEAR_EVENT EQU 32
SYS_WAIT_EVENT EQU 33
SYS_CREATE_QUEUE EQU 34
SYS_SEND_QUEUE EQU 35
SYS_RECV_QUEUE EQU 36
SYS_PUBLISH_QUEUE EQU 37
SYS_OPEN_NAMED_QUEUE EQU 38
SYS_DUPLICATE_QUEUE EQU 39
SYS_GET_NAMED_QUEUE_OWNER_PID EQU 40
SYS_OPEN_FILE EQU 41
SYS_CREATE_FILE EQU 42
SYS_READ_FILE EQU 43
SYS_WRITE_FILE EQU 44
SYS_READ_FILE_ASYNC EQU 45
SYS_WRITE_FILE_ASYNC EQU 46
SYS_CANCEL_IO EQU 47
SYS_SEEK_FILE EQU 48
SYS_GET_FILE_POS EQU 49
SYS_GET_FILE_SIZE EQU 50
SYS_TRUNCATE_FILE EQU 51
SYS_DELETE_FILE EQU 52
SYS_RENAME_FILE EQU 53
SYS_OPEN_DIR EQU 54
SYS_READ_DIR EQU 55
SYS_CREATE_DIR EQU 56
SYS_REMOVE_DIR EQU 57
SYS_SET_CWD EQU 58
SYS_GET_CWD EQU 59
SYS_WRITE_CONSOLE EQU 60
SYS_BLIT_SCREEN EQU 61
SYS_CLEAR_SCREEN EQU 62
SYS_GET_SCREEN_SIZE EQU 63
SYS_PUT_SCREEN_CHAR EQU 64
SYS_POLL_KEYBOARD EQU 65
SYS_IS_KEY_DOWN EQU 66
SYS_READ_KEYBOARD_CHAR EQU 67
SYS_READ_KEY EQU 68
SYS_GET_KEY_MODIFIERS EQU 69
SYS_POLL_MOUSE EQU 70
SYS_READ_MOUSE EQU 71
SYS_GET_MOUSE_POS EQU 72
SYS_GET_TICK EQU 73
SYS_PRINT_DEBUG EQU 74
SYS_QUERY_TRAP_FRAME EQU 75
SYS_CREATE_SOCKET EQU 76
SYS_BIND_SOCKET EQU 77
SYS_LISTEN_SOCKET EQU 78
SYS_ACCEPT_SOCKET EQU 79
SYS_CONNECT_SOCKET EQU 80
SYS_SEND_SOCKET EQU 81
SYS_RECV_SOCKET EQU 82
SYS_SHUTDOWN_SOCKET EQU 83
SYS_SEND_TO_SOCKET EQU 84
SYS_RECV_FROM_SOCKET EQU 85
SYS_RESOLVE_HOST EQU 86
SYS_SET_SOCKET_OPTION EQU 87
SYS_GET_SOCKET_OPTION EQU 88
SYS_POLL EQU 89
SYS_GET_MEMORY_STATUS EQU 90
SYS_QUERY_KERNEL_STATS EQU 91
SYS_GET_SYSTEM_TIME EQU 92
SYS_MAX EQU 92
SYS_MAX EQU 93
+45 -44
View File
@@ -110,40 +110,40 @@ SysUserApcDispatcher ENDP
; ---------------------------------------------------------------------------
; Virtual memory and handles
; ---------------------------------------------------------------------------
SYSCALL_STUB6 VmAlloc, SYS_VM_ALLOC
SYSCALL_STUB2 VmFree, SYS_VM_FREE
SYSCALL_STUB2 VmProtect, SYS_VM_PROTECT
SYSCALL_STUB2 VmQuery, SYS_VM_QUERY
SYSCALL_STUB6 AllocVm, SYS_ALLOC_VM
SYSCALL_STUB2 FreeVm, SYS_FREE_VM
SYSCALL_STUB2 ProtectVm, SYS_PROTECT_VM
SYSCALL_STUB2 QueryVm, SYS_QUERY_VM
SYSCALL_STUB2 CloseHandle, SYS_CLOSE_HANDLE
; ---------------------------------------------------------------------------
; Synchronization objects
; ---------------------------------------------------------------------------
SYSCALL_STUB2 MutexCreate, SYS_MUTEX_CREATE
SYSCALL_STUB2 MutexAcquire, SYS_MUTEX_ACQUIRE
SYSCALL_STUB2 MutexTryAcquire, SYS_MUTEX_TRY_ACQUIRE
SYSCALL_STUB2 MutexRelease, SYS_MUTEX_RELEASE
SYSCALL_STUB2 CreateMutex, SYS_CREATE_MUTEX
SYSCALL_STUB2 AcquireMutex, SYS_ACQUIRE_MUTEX
SYSCALL_STUB2 TryAcquireMutex, SYS_TRY_ACQUIRE_MUTEX
SYSCALL_STUB2 ReleaseMutex, SYS_RELEASE_MUTEX
SYSCALL_STUB2 SemCreate, SYS_SEM_CREATE
SYSCALL_STUB2 SemWait, SYS_SEM_WAIT
SYSCALL_STUB2 SemTryWait, SYS_SEM_TRY_WAIT
SYSCALL_STUB2 SemSignal, SYS_SEM_SIGNAL
SYSCALL_STUB2 CreateSem, SYS_CREATE_SEM
SYSCALL_STUB2 WaitSem, SYS_WAIT_SEM
SYSCALL_STUB2 TryWaitSem, SYS_TRY_WAIT_SEM
SYSCALL_STUB2 SignalSem, SYS_SIGNAL_SEM
SYSCALL_STUB2 EventCreate, SYS_EVENT_CREATE
SYSCALL_STUB2 EventSignal, SYS_EVENT_SIGNAL
SYSCALL_STUB2 EventClear, SYS_EVENT_CLEAR
SYSCALL_STUB2 EventWait, SYS_EVENT_WAIT
SYSCALL_STUB2 CreateEvent, SYS_CREATE_EVENT
SYSCALL_STUB2 SignalEvent, SYS_SIGNAL_EVENT
SYSCALL_STUB2 ClearEvent, SYS_CLEAR_EVENT
SYSCALL_STUB2 WaitEvent, SYS_WAIT_EVENT
; ---------------------------------------------------------------------------
; Queues and named queues
; ---------------------------------------------------------------------------
SYSCALL_STUB2 QueueCreate, SYS_QUEUE_CREATE
SYSCALL_STUB2 QueueSend, SYS_QUEUE_SEND
SYSCALL_STUB2 QueueRecv, SYS_QUEUE_RECV
SYSCALL_STUB2 CreateQueue, SYS_CREATE_QUEUE
SYSCALL_STUB2 SendQueue, SYS_SEND_QUEUE
SYSCALL_STUB2 RecvQueue, SYS_RECV_QUEUE
SYSCALL_STUB2 PublishQueue, SYS_PUBLISH_QUEUE
SYSCALL_STUB2 OpenNamedQueue, SYS_OPEN_NAMED_QUEUE
SYSCALL_STUB2 QueueDuplicate, SYS_QUEUE_DUPLICATE
SYSCALL_STUB2 NamedQueueOwnerPid, SYS_NAMED_QUEUE_OWNER_PID
SYSCALL_STUB2 DuplicateQueue, SYS_DUPLICATE_QUEUE
SYSCALL_STUB2 GetNamedQueueOwnerPid, SYS_GET_NAMED_QUEUE_OWNER_PID
; ---------------------------------------------------------------------------
; Files, directories, and current directory
@@ -173,44 +173,45 @@ SYSCALL_STUB2 GetCwd, SYS_GET_CWD
; Console and graphics
; ---------------------------------------------------------------------------
SYSCALL_STUB2 WriteConsole, SYS_WRITE_CONSOLE
SYSCALL_STUB6 ScreenBlit, SYS_SCREEN_BLIT
SYSCALL_STUB2 ScreenClear, SYS_SCREEN_CLEAR
SYSCALL_STUB2 ScreenGetSize, SYS_SCREEN_GET_SIZE
SYSCALL_STUB6 ScreenPutChar, SYS_SCREEN_PUT_CHAR
SYSCALL_STUB6 BlitScreen, SYS_BLIT_SCREEN
SYSCALL_STUB2 ClearScreen, SYS_CLEAR_SCREEN
SYSCALL_STUB2 GetScreenSize, SYS_GET_SCREEN_SIZE
SYSCALL_STUB6 PutScreenChar, SYS_PUT_SCREEN_CHAR
; ---------------------------------------------------------------------------
; Input
; ---------------------------------------------------------------------------
SYSCALL_STUB2 KbPoll, SYS_KB_POLL
SYSCALL_STUB2 KbIsKeyDown, SYS_KB_IS_KEY_DOWN
SYSCALL_STUB2 KbReadChar, SYS_KB_READ_CHAR
SYSCALL_STUB2 KbReadKey, SYS_KB_READ_KEY
SYSCALL_STUB2 KbGetModifiers, SYS_KB_GET_MODIFIERS
SYSCALL_STUB2 PollKeyboard, SYS_POLL_KEYBOARD
SYSCALL_STUB2 IsKeyDown, SYS_IS_KEY_DOWN
SYSCALL_STUB2 ReadKeyboardChar, SYS_READ_KEYBOARD_CHAR
SYSCALL_STUB2 ReadKey, SYS_READ_KEY
SYSCALL_STUB2 GetKeyModifiers, SYS_GET_KEY_MODIFIERS
SYSCALL_STUB2 MousePoll, SYS_MOUSE_POLL
SYSCALL_STUB2 MouseRead, SYS_MOUSE_READ
SYSCALL_STUB2 MouseGetPos, SYS_MOUSE_GET_POS
SYSCALL_STUB2 PollMouse, SYS_POLL_MOUSE
SYSCALL_STUB2 ReadMouse, SYS_READ_MOUSE
SYSCALL_STUB2 GetMousePos, SYS_GET_MOUSE_POS
; ---------------------------------------------------------------------------
; Time and debug
; ---------------------------------------------------------------------------
SYSCALL_STUB2 GetTick, SYS_GET_TICK
SYSCALL_STUB2 DebugPrint, SYS_DEBUG_PRINT
SYSCALL_STUB2 GetSystemTime, SYS_GET_SYSTEM_TIME
SYSCALL_STUB2 PrintDebug, SYS_PRINT_DEBUG
SYSCALL_STUB2 QueryTrapFrame, SYS_QUERY_TRAP_FRAME
; ---------------------------------------------------------------------------
; Native sockets
; ---------------------------------------------------------------------------
SYSCALL_STUB2 Socket, SYS_SOCKET
SYSCALL_STUB2 Bind, SYS_BIND
SYSCALL_STUB2 Listen, SYS_LISTEN
SYSCALL_STUB2 Accept, SYS_ACCEPT
SYSCALL_STUB2 Connect, SYS_CONNECT
SYSCALL_STUB6 Send, SYS_SEND
SYSCALL_STUB6 Recv, SYS_RECV
SYSCALL_STUB2 Shutdown, SYS_SHUTDOWN
SYSCALL_STUB2 SendTo, SYS_SEND_TO
SYSCALL_STUB2 RecvFrom, SYS_RECV_FROM
SYSCALL_STUB2 CreateSocket, SYS_CREATE_SOCKET
SYSCALL_STUB2 BindSocket, SYS_BIND_SOCKET
SYSCALL_STUB2 ListenSocket, SYS_LISTEN_SOCKET
SYSCALL_STUB2 AcceptSocket, SYS_ACCEPT_SOCKET
SYSCALL_STUB2 ConnectSocket, SYS_CONNECT_SOCKET
SYSCALL_STUB6 SendSocket, SYS_SEND_SOCKET
SYSCALL_STUB6 RecvSocket, SYS_RECV_SOCKET
SYSCALL_STUB2 ShutdownSocket, SYS_SHUTDOWN_SOCKET
SYSCALL_STUB2 SendToSocket, SYS_SEND_TO_SOCKET
SYSCALL_STUB2 RecvFromSocket, SYS_RECV_FROM_SOCKET
SYSCALL_STUB2 ResolveHost, SYS_RESOLVE_HOST
SYSCALL_STUB2 SetSocketOption, SYS_SET_SOCKET_OPTION
SYSCALL_STUB2 GetSocketOption, SYS_GET_SOCKET_OPTION
+2 -2
View File
@@ -49,8 +49,8 @@ void itoa(int num, char* str) {
}
static void debug_print(const char* s) {
SYS_DEBUG_PRINT_REQUEST req = { SysSvFromCstr(s) };
(void)SysDebugPrint(&req);
SYS_PRINT_DEBUG_REQUEST req = { SysSvFromCstr(s) };
(void)SysPrintDebug(&req);
}
void _start(void)
+3 -3
View File
@@ -51,7 +51,7 @@ static void file_apc(void* context, SYS_IO_STATUS_BLOCK* iosb, uint64_t informat
st->Status = iosb ? iosb->Status : 0xFFFFFFFFu;
st->Information = information;
st->Delivered++;
do { SYS_DEBUG_PRINT_REQUEST req = { SYS_SV_LITERAL("async_apc: user APC callback ran\n") }; SysDebugPrint(&req); } while (0);
do { SYS_PRINT_DEBUG_REQUEST req = { SYS_SV_LITERAL("async_apc: user APC callback ran\n") }; SysPrintDebug(&req); } while (0);
}
int main(void) {
@@ -75,7 +75,7 @@ int main(void) {
}
uint32_t event = 0;
s = SysEventCreate(EVENT_AUTO_RESET, 0, &event);
s = SysCreateEvent(EVENT_AUTO_RESET, 0, &event);
if (s != SYS_STATUS_SUCCESS) {
print("async_apc: event create failed status=");
print_u64(s);
@@ -117,7 +117,7 @@ int main(void) {
}
while (!state.Delivered) {
s = SysEventWait(event, 1);
s = SysWaitEvent(event, 1);
print("async_apc: alertable wait returned ");
print_u64(s);
print("\n");
+2 -2
View File
@@ -46,7 +46,7 @@ int main(void) {
SysExitProcess(1);
}
s = SysEventCreate(EVENT_AUTO_RESET, 0, &event);
s = SysCreateEvent(EVENT_AUTO_RESET, 0, &event);
if (s != SYS_STATUS_SUCCESS) {
print("async_cancel: event create failed status="); print_u64(s); print("\n");
SysExitProcess(1);
@@ -84,7 +84,7 @@ int main(void) {
print("async_cancel: cancel returned "); print_u64(cs); print("\n");
while (iosb.Status == SYS_STATUS_PENDING) {
s = SysEventWait(event, 1);
s = SysWaitEvent(event, 1);
print("async_cancel: wait returned "); print_u64(s); print("\n");
if (s != SYS_STATUS_SUCCESS && s != SYS_STATUS_KERNEL_APC && s != SYS_STATUS_USER_APC && s != SYS_STATUS_ALERTED)
break;