add system time, clean up pci into pci.sys, clean up syscall names, fix USERAPC1 typo
This commit is contained in:
1 parent
c1a291c4c9
commit
e41bf6e2c0
64 files changed
+4514
-2220
No files matched your search
@@ -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
@@ -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"},
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
@@ -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),
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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.
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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, §ors, &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, §ors, &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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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, §ors, &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, §ors, &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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
@@ -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
@@ -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
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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 ---
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user