Details
-
Bug
-
Resolution: Unresolved
-
Major
-
None
-
None
Description
I connected the adapter to my ReactOS laptop, installed the drivers, then connected the serial cable to a Linux PC with cutecom. Then I tried testing it with echo hello > COM3. It didn't work. <0xff> is all that showed up in cutecom no matter what I typed. I tried figuring out the problem with Claude and Gemini but it kept finding bug after bug, but couldn't get the adapter to work. This took me like a month, so I decided to just put we found here. I'm giving up on making this work for now.
Here's a summary with the bugs and code Claude and Gemini found.
Compatibility Report: Official FTDI CDM Driver Stack on ReactOS
|
|
|
Target Driver: Official FTDI CDM v2.08.24 WHQL driver package (ftdibus.sys,
|
ftser2k.sys, ftcserco.dll, serenum.sys)
|
Target Hardware: FTDI FT232R USB-to-UART (VID: 0x0403, PID: 0x6001)
|
Tested Build: ReactOS 0.4.17-x86-dev (Build 20260826-5483dc0 / NT 5.2 Build 3790
|
SP2 target)
|
Testing Platforms: Bare-metal Intel ICH7/ICH8 chipset (Toshiba Satellite) & QEMU
|
x86
|
|
|
Clean-Room & Provenance Notice:
|
All analysis and suggested patches below are derived strictly from black-box
|
behavioral testing, live serial/KDB logging, public Microsoft MSDN/WDK
|
documentation, and the official Intel UHCI Design Guide [3].
|
|
|
1. NT Kernel I/O Manager (ntoskrnl/iomgr)
|
|
|
Issue: Buffer Corruption & Invalid VA Handling in IoBuildPartialMdl
|
|
|
- File: ntoskrnl/io/iomgr/iomdl.c
|
- Applicable Specification: Microsoft WDK documentation for IoBuildPartialMdl
|
and MmGetSystemAddressForMdlSafe.
|
- Problem Description:
|
1. For Direct/Buffered I/O user requests, SourceMdl->MappedSystemVa is
|
initially NULL. ReactOS previously evaluated:
|
\text\{TargetMdl->MappedSystemVa} = (\text\{PCHAR})\text\{SourceMdl->MappedSystemVa} + \text\{Offset};
|
This produced an invalid low address pointer ((PVOID)Offset). When
|
drivers subsequently called MmUnmapLockedPages, dereferencing this
|
address caused a Bug Check 0x0A or 0x7E.
|
2. In IoBuildPartialMdl, ReactOS omitted MDL_PAGES_LOCKED from the
|
inherited FlagsMask.
|
3. ReactOS unconditionally copied MDL_MAPPED_TO_SYSTEM_VA into
|
TargetMdl->MdlFlags even when MappedSystemVa was NULL. When subsequent
|
drivers (e.g., usbport.sys) invoked
|
MmGetSystemAddressForMdlSafe(TargetMdl), the macro saw
|
MDL_MAPPED_TO_SYSTEM_VA asserted, skipped mapping the locked pages, and
|
returned NULL, causing silent data drops.
|
- Suggested Fix: Ensure TargetMdl inherits MDL_PAGES_LOCKED, and only apply
|
MDL_MAPPED_TO_SYSTEM_VA if a non-NULL system address exists:
|
|
|
// In ntoskrnl/io/iomgr/iomdl.c -> IoBuildPartialMdl
|
|
|
ULONG FlagsMask = (MDL_IO_PAGE_READ |
|
MDL_SOURCE_IS_NONPAGED_POOL |
|
MDL_PAGES_LOCKED |
|
MDL_IO_SPACE);
|
|
|
TargetMdl->MdlFlags &= (MDL_ALLOCATED_FIXED_SIZE | MDL_ALLOCATED_MUST_SUCCEED);
|
TargetMdl->MdlFlags |= SourceMdl->MdlFlags & FlagsMask;
|
TargetMdl->MdlFlags |= MDL_PARTIAL;
|
|
|
/* Only propagate mapped VA if source was mapped */
|
if (SourceMdl->MappedSystemVa != NULL)
|
{
|
TargetMdl->MappedSystemVa = (PCHAR)SourceMdl->MappedSystemVa + Offset;
|
TargetMdl->MdlFlags |= (SourceMdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA);
|
}
|
else
|
{
|
TargetMdl->MappedSystemVa = NULL;
|
}
|
|
|
2. Run-Time Library / Configuration Manager (sdk/lib/rtl)
|
|
|
Issue: RTL_REGISTRY_DEVICEMAP Rejection Under Volatile \HARDWARE Hive
|
|
|
- File: sdk/lib/rtl/registry.c
|
- Applicable Specification: Windows NT Configuration Manager hive semantics;
|
MSDN RtlWriteRegistryValue.
|
- Problem Description:
|
ftser2k.sys registers its serial mapping via
|
RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP, L"SERIALCOMM", ...).
|
RtlpGetRegistryHandle invoked ZwCreateKey with CreateOptions =
|
REG_OPTION_NON_VOLATILE. Because \Registry\Machine\HARDWARE is strictly an
|
in-memory volatile tree, cmparse.c correctly enforces that non-volatile
|
child keys cannot reside under a volatile parent hive, returning
|
STATUS_CHILD_MUST_BE_VOLATILE (0xC0000181).
|
ftser2k.sys treats this as a fatal initialization error: it immediately
|
calls IoDeleteSymbolicLink, destroys \DosDevices\COMx, and unregisters the
|
port.
|
- Suggested Fix:
|
Ensure RtlpGetRegistryHandle marks keys created relative to
|
RTL_REGISTRY_DEVICEMAP (and RTL_REGISTRY_HARDWARE) as REG_OPTION_VOLATILE:
|
|
|
--- a/sdk/lib/rtl/registry.c
|
+++ b/sdk/lib/rtl/registry.c
|
@@ -113,11 +113,16 @@ RtlpGetRegistryHandle(IN ULONG RelativeTo,
|
if (Create)
|
{
|
+ ULONG CreateOptions = REG_OPTION_NON_VOLATILE;
|
+
|
+ if (RelativeTo == RTL_REGISTRY_DEVICEMAP || RelativeTo == RTL_REGISTRY_HARDWARE)
|
+ CreateOptions = REG_OPTION_VOLATILE;
|
+
|
Status = ZwCreateKey(KeyHandle,
|
GENERIC_WRITE,
|
&ObjectAttributes,
|
0,
|
NULL,
|
- 0,
|
+ CreateOptions,
|
NULL);
|
}
|
|
|
3. Serial Class Driver / Upper Filter (drivers/serial/serenum)
|
|
|
Issue: Unbounded Synchronous Read Deadlocks Central PnP Worker
|
|
|
- File: drivers/serial/serenum/detect.c
|
- Applicable Specification: WDK Synchronous IRP handling in UpperFilter
|
drivers.
|
- Problem Description:
|
During device enumeration (IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations),
|
serenum.sys probes the serial port for legacy mice using
|
IoBuildSynchronousFsdRequest(IRP_MJ_READ). ReadBytes waits on a KEVENT using
|
KeWaitForSingleObject with Timeout = NULL (infinite).
|
When non-mouse serial devices (such as USB UART adapters) are attached,
|
ftser2k.sys pends the read request indefinitely. Because this call executes
|
synchronously inside the central executive work item
|
(PipDeviceActionWorker), the entire PnP subsystem deadlocks permanently,
|
freezing device enumeration and system startup.
|
- Suggested Fix:
|
Add a relative timeout (e.g., 2 seconds) and an IoCancelIrp fallback to
|
allow legacy probing to abort gracefully when no device responds:
|
|
|
// In drivers/serial/serenum/detect.c -> ReadBytes
|
|
|
Status = IoCallDriver(LowerDevice, Irp);
|
if (Status == STATUS_PENDING)
|
{
|
/* 2-second relative safety timeout (-20,000,000 in 100ns units) */
|
LARGE_INTEGER timeout;
|
timeout.QuadPart = -20000000LL;
|
|
|
Status = KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, &timeout);
|
if (Status == STATUS_TIMEOUT)
|
{
|
IoCancelIrp(Irp);
|
KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
|
Status = STATUS_IO_TIMEOUT;
|
}
|
else
|
{
|
Status = ioStatus.Status;
|
}
|
}
|
|
|
4. Setup API (dll/win32/setupapi)
|
|
|
Issue: Omission of Default Parameters Subkey on Driver Service Creation
|
|
|
- File: dll/win32/setupapi/install.c
|
- Applicable Specification: Windows Driver Installation Model / SCM Service
|
Parameters.
|
- Problem Description:
|
When installing kernel driver services from an .inf file via
|
SetupInstallServicesFromInfSectionExW, ReactOS creates
|
HKLM\SYSTEM\CurrentControlSet\Services\<ServiceName>, but does not create
|
the standard Parameters subkey unless explicitly instructed by a dedicated
|
INF directive. Standard Windows co-installers (such as ftcserco.dll) attempt
|
to open Services\<ServiceName>\Parameters to store hardware arbitration
|
data; when this key is absent, the co-installer fails.
|
- Suggested Fix:
|
Automatically create the Parameters subkey when registering any
|
SERVICE_KERNEL_DRIVER or SERVICE_FILE_SYSTEM_DRIVER:
|
|
|
// In dll/win32/setupapi/install.c -> create_service
|
|
|
if (ServiceType & (SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER))
|
{
|
HKEY hParametersKey;
|
if (RegCreateKeyExW(hServiceKey, L"Parameters", 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hParametersKey, NULL) == ERROR_SUCCESS)
|
{
|
RegCloseKey(hParametersKey);
|
}
|
}
|
|
|
5. USB 1.1 UHCI Miniport Driver (drivers/usb/usbuhci)
|
|
|
Issue A: Division-by-Zero on Uninitialized Endpoint Packet Sizes
|
|
|
- File: drivers/usb/usbuhci/usbuhci.c
|
- Problem Description:
|
In UhciQueryEndpointRequirements, TdCount was computed using direct division
|
by EndpointProperties->TotalMaxPacketSize. If queried when descriptors are
|
uninitialized or packet sizes report zero, the kernel triggers an immediate
|
divide-by-zero Bug Check (0x7E).
|
- Suggested Fix:
|
Guard the calculations for both Control and Bulk transfer queries:
|
if (EndpointProperties->TotalMaxPacketSize == 0)
|
TdCount = 0;
|
else
|
TdCount = EndpointProperties->MaxTransferSize / EndpointProperties->TotalMaxPacketSize;
|
|
|
Issue B: Missing Endpoint Data Toggle Implementation
|
|
|
- File: drivers/usb/usbuhci/usbuhci.c
|
- Problem Description:
|
UhciSetEndpointDataToggle was left as an unimplemented stub
|
(DPRINT_IMPL("UNIMPLEMENTED. FIXME\n")). Without tracking the toggle state,
|
bulk endpoints fail to maintain DATA0/DATA1 PID synchronization, causing
|
devices to discard subsequent transactions.
|
- Suggested Fix:
|
VOID NTAPI UhciSetEndpointDataToggle(IN PVOID uhciExtension, IN PVOID uhciEndpoint, IN ULONG DataToggle)
|
{
|
PUHCI_ENDPOINT UhciEndpoint = uhciEndpoint;
|
UhciEndpoint->DataToggle = (BOOL)DataToggle;
|
}
|
|
|
Issue C: Invalid Short Packet Detect (SPD) on OUT Tokens Halts Hardware Queue
|
|
|
- File: drivers/usb/usbuhci/usbuhci.c
|
- Applicable Specification: Intel Universal Host Controller Interface (UHCI)
|
Design Guide, Section 3.2.2 [3].
|
- Problem Description:
|
In UhciMapAsyncTransferToTDs, TD->HwTD.ControlStatus.ShortPacketDetect = 1;
|
was set unconditionally. Per Section 3.2.2 of the Intel UHCI Specification,
|
Bit 29 (SPD) is only valid for IN transactions [3]; setting SPD on OUT
|
transactions is undefined behavior that causes physical Intel ICH host
|
controllers to halt processing the transfer queue [3].
|
- Suggested Fix:
|
Restrict the SPD bit strictly to IN transactions:
|
TD->HwTD.ControlStatus.ShortPacketDetect = (PIDCode == UHCI_TD_PID_IN);
|
|
|
6. Ports Class Installer (dll/win32/msports)
|
|
|
Issue: Non-Standard Third-Party Serial Adapters Bypassed in Device Manager
|
|
|
- File: dll/win32/msports/classinst.c
|
- Problem Description:
|
In classinst.c, GetPortType exclusively checked for the proprietary binary
|
registry value PortSubClass (which Microsoft defines in its inbox serial
|
INF). Third-party USB-to-serial manufacturers (FTDI, Prolific, Silicon Labs,
|
WCH) do not provide this value.
|
As a result, GetPortType returned UnknownPort, causing InstallPort to fall
|
through to default: return ERROR_DI_DO_DEFAULT; and bypass InstallSerialPort
|
entirely. This prevented FriendlyName (USB Serial Port (COMx)) from being
|
set and left the device named generically as USB Serial Port.
|
- Suggested Fix:
|
If PortSubClass is absent, check DIREG_DEV for PortName: if it does not
|
begin with LPT, classify any device in the Ports setup class as a
|
SerialPort:
|
|
|
// In dll/win32/msports/classinst.c -> GetPortType
|
|
|
if (PortType == UnknownPort)
|
{
|
HKEY hDevKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
|
if (hDevKey != INVALID_HANDLE_VALUE)
|
{
|
WCHAR szName[16];
|
dwSize = sizeof(szName);
|
if (RegQueryValueExW(hDevKey, L"PortName", NULL, NULL, (PBYTE)szName, &dwSize) == ERROR_SUCCESS)
|
{
|
if (_wcsnicmp(szName, L"LPT", 3) == 0)
|
PortType = ParallelPort;
|
else
|
PortType = SerialPort;
|
}
|
RegCloseKey(hDevKey);
|
}
|
|
|
/* Fallback: any non-parallel port in GUID_DEVCLASS_PORTS is a serial port */
|
if (PortType == UnknownPort)
|
PortType = SerialPort;
|
}
|
|
|
7. Command Shell Output Redirection (base/shell/cmd)
|
|
|
Issue: CreateFile Disposition Failure on Hardware Communications Resources
|
|
|
- File: base/shell/cmd/redir.c
|
- Applicable Specification: Win32 CreateFile specification for communications
|
resources (COM1–COM9).
|
- Problem Description:
|
When shell redirection is targeted at a COM port (e.g., echo text > COM3),
|
redir.c calls GetFileAttributesW(s). Because serial drivers manage character
|
stream devices, they return STATUS_INVALID_DEVICE_REQUEST to file attribute
|
queries, causing GetFileAttributesW to return INVALID_FILE_ATTRIBUTES.
|
redir.c then falls back to dwCreationDisposition = CREATE_ALWAYS and
|
dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE. Per Win32 specification,
|
opening communications resources with CREATE_ALWAYS or non-zero share modes
|
fails with ERROR_INVALID_PARAMETER (87). cmd.exe fails silently and never
|
writes to the port.
|
- Suggested Fix:
|
Identify reserved device names (COMx, LPTx, CON, NUL) and enforce
|
dwCreationDisposition = OPEN_EXISTING and dwShareMode = 0:
|
|
|
// In base/shell/cmd/redir.c -> PerformRedirection
|
|
|
if (IsDeviceName(s) || ((dwAttributes != INVALID_FILE_ATTRIBUTES) && (dwAttributes & FILE_ATTRIBUTE_DEVICE)))
|
{
|
dwCreationDisposition = OPEN_EXISTING;
|
dwShareMode = 0;
|
}
|
else
|
{
|
dwCreationDisposition = (Append ? OPEN_ALWAYS : CREATE_ALWAYS);
|
}
|
Attachments
Issue Links
- relates to
-
CORE-20241 [DRIVERS] FTDI drivers - CDM 2.08.24 WHQL Certified doesn't end the setup.
-
- Untriaged
-