From e41bf6e2c0cb0714fee4bc4da9917291ee164563 Mon Sep 17 00:00:00 2001 From: Maksymilian Wilczynski Date: Thu, 11 Jun 2026 18:11:59 +0200 Subject: [PATCH] add system time, clean up pci into pci.sys, clean up syscall names, fix USERAPC1 typo --- OVMF/OVMF_VARS_4M.fd | Bin 540672 -> 540672 bytes OVMF/OVMF_VARS_4M_d.fd | Bin 540672 -> 540672 bytes code/boot/uefi/main.c | 20 + code/build/build.c | 41 +- code/drivers/bus/pci/pci.c | 603 ++++++++++++++++ code/drivers/bus/pci/pci.h | 45 ++ code/drivers/bus/usb/usb.c | 88 +-- code/drivers/bus/usb/usb.h | 45 +- code/drivers/bus/usb/usb_bus.c | 46 +- code/drivers/bus/usb/usb_core.c | 2 +- code/drivers/bus/usb/usb_xhci.c | 319 +++++---- code/drivers/drivers.ini | 4 +- code/drivers/fs/fat32/fat32.c | 302 +++++++- code/drivers/fs/fat32/fat32.h | 1 + code/drivers/net/rtl8139/rtl8139.c | 326 +++++++-- code/drivers/net/rtl8139/rtl8139.h | 49 +- code/drivers/net/rtl8139/rtl8139_pci.c | 114 +-- code/drivers/net/rtl816x/rtl816x.c | 347 ++++++++-- code/drivers/net/rtl816x/rtl816x.h | 53 +- code/drivers/net/rtl816x/rtl816x_pci.c | 126 ---- code/drivers/storage/ahci/ahci.c | 350 +++++++--- code/drivers/storage/ahci/ahci.h | 43 +- code/drivers/storage/ahci/ahci_port.c | 12 +- code/drivers/storage/ata/ata.c | 686 +++++++++++++++++++ code/drivers/storage/ata/ata.h | 130 ++++ code/drivers/storage/ide/ide.c | 531 -------------- code/drivers/storage/ide/ide.h | 102 --- code/drivers/storage/ide/ide_bus.c | 87 --- code/kernel/hal/hal_main.c | 13 +- code/kernel/hal/hal_pci.c | 178 +---- code/kernel/hal/hal_rtc.c | 163 +++++ code/kernel/include/kernel/ke_apc.h | 2 +- code/kernel/include/kernel/ke_time.h | 11 + code/kernel/include/kernel/syscall_nr.h | 187 ++--- code/kernel/ke_syscall.c | 192 +++--- code/kernel/ke_time.c | 500 ++++++++++++++ code/kernel/kmain.c | 7 + code/public/ntlite/boot_info.h | 26 +- code/public/ntlite/ddi/hal_api.h | 53 +- code/public/ntlite/ddi/pci.h | 118 ++++ code/public/ntlite/dirent.h | 5 + code/public/ntlite/syscall.h | 101 +-- code/public/ntlite/time.h | 31 + code/settings.ini | 11 + code/user/apps/doom/doom.c | 4 +- code/user/apps/edit/edit.c | 12 +- code/user/apps/httpget/httpget.c | 18 +- code/user/apps/ping/ping.c | 8 +- code/user/apps/shell_native/shell_native.c | 61 +- code/user/apps/tcpserve/tcpserve.c | 28 +- code/user/apps/udp/udp.c | 20 +- code/user/personalities/posix/posix_fd.h | 2 +- code/user/personalities/posix/posix_io.c | 10 +- code/user/personalities/posix/posix_socket.c | 20 +- code/user/personalities/posix/posix_thread.c | 8 +- code/user/personalities/win32/gdi32.c | 4 +- code/user/personalities/win32/kernel32.c | 171 ++++- code/user/personalities/win32/user32.c | 4 +- code/user/runtime/heap.c | 4 +- code/user/syscall/syscall_nr.inc | 187 ++--- code/user/syscall/syscall_stubs.asm | 89 +-- code/user/system/init/init.c | 4 +- code/user/tests/async_apc/async_apc.c | 6 +- code/user/tests/async_cancel/async_cancel.c | 4 +- 64 files changed, 4514 insertions(+), 2220 deletions(-) create mode 100644 code/drivers/bus/pci/pci.c create mode 100644 code/drivers/bus/pci/pci.h delete mode 100644 code/drivers/net/rtl816x/rtl816x_pci.c create mode 100644 code/drivers/storage/ata/ata.c create mode 100644 code/drivers/storage/ata/ata.h delete mode 100644 code/drivers/storage/ide/ide.c delete mode 100644 code/drivers/storage/ide/ide.h delete mode 100644 code/drivers/storage/ide/ide_bus.c create mode 100644 code/kernel/hal/hal_rtc.c create mode 100644 code/kernel/include/kernel/ke_time.h create mode 100644 code/kernel/ke_time.c create mode 100644 code/public/ntlite/ddi/pci.h create mode 100644 code/public/ntlite/time.h diff --git a/OVMF/OVMF_VARS_4M.fd b/OVMF/OVMF_VARS_4M.fd index 9ddd15448bd41534a095f15b5d45bf832af6caa4..d868e5ae18d71dad9a218c04f5829c03a4d42aef 100644 GIT binary patch delta 68 zcmZo@P;3CA7RD`1a_N)(f}FM|q%&RO+Wane7b~O3=7~X`0@LNvnVc9s+Y{57wkM`D Xx3{+mu(S!Vwh6Gc39v5{;4lCHPGc58 delta 56 zcmZo@P;3CA7RD`1a_Q5}I+&ccC!{l7;%fJr%(UHWGV`{Y?H6V+Nhr1nu(S!Vwh6Gc L39v5{;4lCHJ;oAU diff --git a/OVMF/OVMF_VARS_4M_d.fd b/OVMF/OVMF_VARS_4M_d.fd index e155cd812a598322e33d7f10c06cc9618cb204da..0341b418f8a879a8310dc55641b61f86c5605017 100644 GIT binary patch delta 160 zcmZo@P;6*W+`zYNvYe6A=743FxF%a!sBMn0ox#eewmH$LUw}~^LTNxKO$en0p|l~C z4usN$PKzGY5~Ce4A%+5?v{ZVz0>WM9}Oz|tnb+9tr( LCcwT-fWrU)PpvVP delta 55 zcmZo@P;6*W+`zYNdfhxmr_BM&E^)O_TFD5+Oxq`|WX?<5uCSi5;76MPOPc^|n*dvz K0Q)il4g&y)OBB5T diff --git a/code/boot/uefi/main.c b/code/boot/uefi/main.c index 9389ccf..de961a2 100644 --- a/code/boot/uefi/main.c +++ b/code/boot/uefi/main.c @@ -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); diff --git a/code/build/build.c b/code/build/build.c index 51e745e..319d413 100644 --- a/code/build/build.c +++ b/code/build/build.c @@ -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"}, diff --git a/code/drivers/bus/pci/pci.c b/code/drivers/bus/pci/pci.c new file mode 100644 index 0000000..e188d03 --- /dev/null +++ b/code/drivers/bus/pci/pci.c @@ -0,0 +1,603 @@ +// pci.c - PCI bus driver, PDO enumerator, and exported PCI DDI +#include "pci.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +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; +} diff --git a/code/drivers/bus/pci/pci.h b/code/drivers/bus/pci/pci.h new file mode 100644 index 0000000..187cfee --- /dev/null +++ b/code/drivers/bus/pci/pci.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include +#include + +#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; diff --git a/code/drivers/bus/usb/usb.c b/code/drivers/bus/usb/usb.c index 433da83..65f9811 100644 --- a/code/drivers/bus/usb/usb.c +++ b/code/drivers/bus/usb/usb.c @@ -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; } diff --git a/code/drivers/bus/usb/usb.h b/code/drivers/bus/usb/usb.h index ec20b35..cbf62b3 100644 --- a/code/drivers/bus/usb/usb.h +++ b/code/drivers/bus/usb/usb.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -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); diff --git a/code/drivers/bus/usb/usb_bus.c b/code/drivers/bus/usb/usb_bus.c index c044e1b..bbe6f23 100644 --- a/code/drivers/bus/usb/usb_bus.c +++ b/code/drivers/bus/usb/usb_bus.c @@ -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), diff --git a/code/drivers/bus/usb/usb_core.c b/code/drivers/bus/usb/usb_core.c index 252d882..899f540 100644 --- a/code/drivers/bus/usb/usb_core.c +++ b/code/drivers/bus/usb/usb_core.c @@ -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; diff --git a/code/drivers/bus/usb/usb_xhci.c b/code/drivers/bus/usb/usb_xhci.c index c615665..edb03a5 100644 --- a/code/drivers/bus/usb/usb_xhci.c +++ b/code/drivers/bus/usb/usb_xhci.c @@ -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; +} diff --git a/code/drivers/drivers.ini b/code/drivers/drivers.ini index d1b3560..0ad70e4 100644 --- a/code/drivers/drivers.ini +++ b/code/drivers/drivers.ini @@ -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 diff --git a/code/drivers/fs/fat32/fat32.c b/code/drivers/fs/fat32/fat32.c index 8d13913..2cb5d6a 100644 --- a/code/drivers/fs/fat32/fat32.c +++ b/code/drivers/fs/fat32/fat32.c @@ -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; diff --git a/code/drivers/fs/fat32/fat32.h b/code/drivers/fs/fat32/fat32.h index be93f55..804ccec 100644 --- a/code/drivers/fs/fat32/fat32.h +++ b/code/drivers/fs/fat32/fat32.h @@ -14,6 +14,7 @@ #include #include #include +#include typedef struct FAT32_VOL_S FAT32_VOL; diff --git a/code/drivers/net/rtl8139/rtl8139.c b/code/drivers/net/rtl8139/rtl8139.c index 47da4e2..f4008ce 100644 --- a/code/drivers/net/rtl8139/rtl8139.c +++ b/code/drivers/net/rtl8139/rtl8139.c @@ -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; } diff --git a/code/drivers/net/rtl8139/rtl8139.h b/code/drivers/net/rtl8139/rtl8139.h index 6192405..5645c28 100644 --- a/code/drivers/net/rtl8139/rtl8139.h +++ b/code/drivers/net/rtl8139/rtl8139.h @@ -8,6 +8,8 @@ #include #include +#include +#include #include #include #include @@ -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); diff --git a/code/drivers/net/rtl8139/rtl8139_pci.c b/code/drivers/net/rtl8139/rtl8139_pci.c index 32cc6f3..5f408fd 100644 --- a/code/drivers/net/rtl8139/rtl8139_pci.c +++ b/code/drivers/net/rtl8139/rtl8139_pci.c @@ -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. diff --git a/code/drivers/net/rtl816x/rtl816x.c b/code/drivers/net/rtl816x/rtl816x.c index 98eb07f..6dc51f3 100644 --- a/code/drivers/net/rtl816x/rtl816x.c +++ b/code/drivers/net/rtl816x/rtl816x.c @@ -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; } diff --git a/code/drivers/net/rtl816x/rtl816x.h b/code/drivers/net/rtl816x/rtl816x.h index 780ff1c..4e72d91 100644 --- a/code/drivers/net/rtl816x/rtl816x.h +++ b/code/drivers/net/rtl816x/rtl816x.h @@ -1,4 +1,4 @@ -// rtl816x.h - shared rtl816x driver internals. +// rtl816x.h - shared rtl8168/rtl8169 driver internals. #pragma once #include @@ -8,6 +8,8 @@ #include #include +#include +#include #include #include #include @@ -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); diff --git a/code/drivers/net/rtl816x/rtl816x_pci.c b/code/drivers/net/rtl816x/rtl816x_pci.c deleted file mode 100644 index 5446aa0..0000000 --- a/code/drivers/net/rtl816x/rtl816x_pci.c +++ /dev/null @@ -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); -} diff --git a/code/drivers/storage/ahci/ahci.c b/code/drivers/storage/ahci/ahci.c index 8917a8e..73e3a06 100644 --- a/code/drivers/storage/ahci/ahci.c +++ b/code/drivers/storage/ahci/ahci.c @@ -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; } diff --git a/code/drivers/storage/ahci/ahci.h b/code/drivers/storage/ahci/ahci.h index 4bc33f5..adc9dea 100644 --- a/code/drivers/storage/ahci/ahci.h +++ b/code/drivers/storage/ahci/ahci.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -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); diff --git a/code/drivers/storage/ahci/ahci_port.c b/code/drivers/storage/ahci/ahci_port.c index c71a44e..ad4fab3 100644 --- a/code/drivers/storage/ahci/ahci_port.c +++ b/code/drivers/storage/ahci/ahci_port.c @@ -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; } } diff --git a/code/drivers/storage/ata/ata.c b/code/drivers/storage/ata/ata.c new file mode 100644 index 0000000..9ca5605 --- /dev/null +++ b/code/drivers/storage/ata/ata.c @@ -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; +} diff --git a/code/drivers/storage/ata/ata.h b/code/drivers/storage/ata/ata.h new file mode 100644 index 0000000..c762dde --- /dev/null +++ b/code/drivers/storage/ata/ata.h @@ -0,0 +1,130 @@ +// ata.h - PCI IDE / ATA driver internals. +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); diff --git a/code/drivers/storage/ide/ide.c b/code/drivers/storage/ide/ide.c deleted file mode 100644 index 8def9b2..0000000 --- a/code/drivers/storage/ide/ide.c +++ /dev/null @@ -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); -} diff --git a/code/drivers/storage/ide/ide.h b/code/drivers/storage/ide/ide.h deleted file mode 100644 index dd46269..0000000 --- a/code/drivers/storage/ide/ide.h +++ /dev/null @@ -1,102 +0,0 @@ -// ide.h - shared IDE/ATA driver internals. -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// --------------------------------------------------------------------------- -// 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); diff --git a/code/drivers/storage/ide/ide_bus.c b/code/drivers/storage/ide/ide_bus.c deleted file mode 100644 index add0410..0000000 --- a/code/drivers/storage/ide/ide_bus.c +++ /dev/null @@ -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; -} diff --git a/code/kernel/hal/hal_main.c b/code/kernel/hal/hal_main.c index 54ec30e..afbb95f 100644 --- a/code/kernel/hal/hal_main.c +++ b/code/kernel/hal/hal_main.c @@ -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; diff --git a/code/kernel/hal/hal_pci.c b/code/kernel/hal/hal_pci.c index c6d3198..fc5e34d 100644 --- a/code/kernel/hal/hal_pci.c +++ b/code/kernel/hal/hal_pci.c @@ -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 #include -#include -#include #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; } diff --git a/code/kernel/hal/hal_rtc.c b/code/kernel/hal/hal_rtc.c new file mode 100644 index 0000000..ec7bbef --- /dev/null +++ b/code/kernel/hal/hal_rtc.c @@ -0,0 +1,163 @@ +// hal_rtc.c - legacy CMOS RTC fallback clock +#include +#include +#include +#include +#include +#include +#include + +#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"); + } +} diff --git a/code/kernel/include/kernel/ke_apc.h b/code/kernel/include/kernel/ke_apc.h index 5c7c626..5fc5552 100644 --- a/code/kernel/include/kernel/ke_apc.h +++ b/code/kernel/include/kernel/ke_apc.h @@ -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; diff --git a/code/kernel/include/kernel/ke_time.h b/code/kernel/include/kernel/ke_time.h new file mode 100644 index 0000000..7bc8db9 --- /dev/null +++ b/code/kernel/include/kernel/ke_time.h @@ -0,0 +1,11 @@ +#pragma once +#include +#include + +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); diff --git a/code/kernel/include/kernel/syscall_nr.h b/code/kernel/include/kernel/syscall_nr.h index 0263304..7c191a1 100644 --- a/code/kernel/include/kernel/syscall_nr.h +++ b/code/kernel/include/kernel/syscall_nr.h @@ -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 diff --git a/code/kernel/ke_syscall.c b/code/kernel/ke_syscall.c index 5460ac4..6e9ba4a 100644 --- a/code/kernel/ke_syscall.c +++ b/code/kernel/ke_syscall.c @@ -61,6 +61,7 @@ #include #include #include +#include #include // --------------------------------------------------------------------------- @@ -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 }; // --------------------------------------------------------------------------- diff --git a/code/kernel/ke_time.c b/code/kernel/ke_time.c new file mode 100644 index 0000000..abe996b --- /dev/null +++ b/code/kernel/ke_time.c @@ -0,0 +1,500 @@ +// ke_time.c - kernel wall-clock time service +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/code/kernel/kmain.c b/code/kernel/kmain.c index 1719835..da9d232 100644 --- a/code/kernel/kmain.c +++ b/code/kernel/kmain.c @@ -25,6 +25,7 @@ #include #include #include +#include #include 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; diff --git a/code/public/ntlite/boot_info.h b/code/public/ntlite/boot_info.h index 7f390cb..e25a31e 100644 --- a/code/public/ntlite/boot_info.h +++ b/code/public/ntlite/boot_info.h @@ -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; diff --git a/code/public/ntlite/ddi/hal_api.h b/code/public/ntlite/ddi/hal_api.h index 073c49f..c9c7ab4 100644 --- a/code/public/ntlite/ddi/hal_api.h +++ b/code/public/ntlite/ddi/hal_api.h @@ -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)); diff --git a/code/public/ntlite/ddi/pci.h b/code/public/ntlite/ddi/pci.h new file mode 100644 index 0000000..50fb21e --- /dev/null +++ b/code/public/ntlite/ddi/pci.h @@ -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 +#include +#include +#include +#include + +#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); diff --git a/code/public/ntlite/dirent.h b/code/public/ntlite/dirent.h index 94d25cc..dc1bc38 100644 --- a/code/public/ntlite/dirent.h +++ b/code/public/ntlite/dirent.h @@ -2,6 +2,7 @@ // dirent.h - directory entry returned by SysReadDir. #include +#include #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; diff --git a/code/public/ntlite/syscall.h b/code/public/ntlite/syscall.h index a1dbb79..08cae45 100644 --- a/code/public/ntlite/syscall.h +++ b/code/public/ntlite/syscall.h @@ -8,6 +8,7 @@ #include #include #include +#include #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); diff --git a/code/public/ntlite/time.h b/code/public/ntlite/time.h new file mode 100644 index 0000000..4ed1703 --- /dev/null +++ b/code/public/ntlite/time.h @@ -0,0 +1,31 @@ +#pragma once +#include + +#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; diff --git a/code/settings.ini b/code/settings.ini index 2bf8fc5..8d64eff 100644 --- a/code/settings.ini +++ b/code/settings.ini @@ -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 diff --git a/code/user/apps/doom/doom.c b/code/user/apps/doom/doom.c index f5effe1..cc41b7c 100644 --- a/code/user/apps/doom/doom.c +++ b/code/user/apps/doom/doom.c @@ -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, diff --git a/code/user/apps/edit/edit.c b/code/user/apps/edit/edit.c index c33f977..5402480 100644 --- a/code/user/apps/edit/edit.c +++ b/code/user/apps/edit/edit.c @@ -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); diff --git a/code/user/apps/httpget/httpget.c b/code/user/apps/httpget/httpget.c index fb6fb1e..757a70d 100644 --- a/code/user/apps/httpget/httpget.c +++ b/code/user/apps/httpget/httpget.c @@ -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; diff --git a/code/user/apps/ping/ping.c b/code/user/apps/ping/ping.c index 2e74aa8..3792b03 100644 --- a/code/user/apps/ping/ping.c +++ b/code/user/apps/ping/ping.c @@ -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) { diff --git a/code/user/apps/shell_native/shell_native.c b/code/user/apps/shell_native/shell_native.c index a34ab55..812d1ce 100644 --- a/code/user/apps/shell_native/shell_native.c +++ b/code/user/apps/shell_native/shell_native.c @@ -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(" "); @@ -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; } diff --git a/code/user/apps/tcpserve/tcpserve.c b/code/user/apps/tcpserve/tcpserve.c index c313c9c..45e0936 100644 --- a/code/user/apps/tcpserve/tcpserve.c +++ b/code/user/apps/tcpserve/tcpserve.c @@ -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"); diff --git a/code/user/apps/udp/udp.c b/code/user/apps/udp/udp.c index 26c33c9..5bb4eb8 100644 --- a/code/user/apps/udp/udp.c +++ b/code/user/apps/udp/udp.c @@ -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; } diff --git a/code/user/personalities/posix/posix_fd.h b/code/user/personalities/posix/posix_fd.h index f151e8e..53fe94a 100644 --- a/code/user/personalities/posix/posix_fd.h +++ b/code/user/personalities/posix/posix_fd.h @@ -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 diff --git a/code/user/personalities/posix/posix_io.c b/code/user/personalities/posix/posix_io.c index 087ef2d..5481883 100644 --- a/code/user/personalities/posix/posix_io.c +++ b/code/user/personalities/posix/posix_io.c @@ -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; } diff --git a/code/user/personalities/posix/posix_socket.c b/code/user/personalities/posix/posix_socket.c index fee7caa..b8fd82c 100644 --- a/code/user/personalities/posix/posix_socket.c +++ b/code/user/personalities/posix/posix_socket.c @@ -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; } diff --git a/code/user/personalities/posix/posix_thread.c b/code/user/personalities/posix/posix_thread.c index d1a265e..5bdb156 100644 --- a/code/user/personalities/posix/posix_thread.c +++ b/code/user/personalities/posix/posix_thread.c @@ -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; } diff --git a/code/user/personalities/win32/gdi32.c b/code/user/personalities/win32/gdi32.c index c99f209..e251c5c 100644 --- a/code/user/personalities/win32/gdi32.c +++ b/code/user/personalities/win32/gdi32.c @@ -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; } diff --git a/code/user/personalities/win32/kernel32.c b/code/user/personalities/win32/kernel32.c index 2725163..7df8d74 100644 --- a/code/user/personalities/win32/kernel32.c +++ b/code/user/personalities/win32/kernel32.c @@ -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)); } diff --git a/code/user/personalities/win32/user32.c b/code/user/personalities/win32/user32.c index beaf9a6..5fbb43f 100644 --- a/code/user/personalities/win32/user32.c +++ b/code/user/personalities/win32/user32.c @@ -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 --- diff --git a/code/user/runtime/heap.c b/code/user/runtime/heap.c index 1d30bfd..9320430 100644 --- a/code/user/runtime/heap.c +++ b/code/user/runtime/heap.c @@ -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) { diff --git a/code/user/syscall/syscall_nr.inc b/code/user/syscall/syscall_nr.inc index 586ffed..bbc0d07 100644 --- a/code/user/syscall/syscall_nr.inc +++ b/code/user/syscall/syscall_nr.inc @@ -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 diff --git a/code/user/syscall/syscall_stubs.asm b/code/user/syscall/syscall_stubs.asm index 3a342a3..9a20ec9 100644 --- a/code/user/syscall/syscall_stubs.asm +++ b/code/user/syscall/syscall_stubs.asm @@ -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 diff --git a/code/user/system/init/init.c b/code/user/system/init/init.c index d8e4d85..344c666 100644 --- a/code/user/system/init/init.c +++ b/code/user/system/init/init.c @@ -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) diff --git a/code/user/tests/async_apc/async_apc.c b/code/user/tests/async_apc/async_apc.c index 39ac210..f72ff47 100644 --- a/code/user/tests/async_apc/async_apc.c +++ b/code/user/tests/async_apc/async_apc.c @@ -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"); diff --git a/code/user/tests/async_cancel/async_cancel.c b/code/user/tests/async_cancel/async_cancel.c index 45adca6..845468a 100644 --- a/code/user/tests/async_cancel/async_cancel.c +++ b/code/user/tests/async_cancel/async_cancel.c @@ -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;