mirror of
https://github.com/djhackersdev/bemanitools.git
synced 2024-11-24 14:50:10 +01:00
124 lines
6.6 KiB
Markdown
124 lines
6.6 KiB
Markdown
# Follow-up (14th August 2019)
|
|
|
|
After publishing this post-mortem, I got messaged by a user on sows who was able to shed some more
|
|
light on this issue. The user was experiencing the same symptoms on a Win7 setup: blue screen once
|
|
the firmware was flashed to the C02 IO. This user's solutions was to use the USB2 ports on the PC
|
|
instead of the USB3 ones. This is good to know and kinda aligns with the weird things happening in
|
|
the driver (see below).
|
|
|
|
# Post-mortem: C02 IO kernel module crash on Windows 7 (29th July 2019) by icex2
|
|
|
|
## Background
|
|
|
|
The original ezusbsys.sys kernel module, which is required to run the C02 IO, was compiled for
|
|
Windows XP 32-bit, only. There is a newer driver by Cypress, cyusb3.sys, which could be used to IO2
|
|
boards on newer Windows platforms, but does not work with the C02 IO in combination with Konami's
|
|
propriatery firmware. Thus, it was not possible to run the C02 IO on anything than Windows XP
|
|
32-bit. But, with newer IIDX games running on Windows 7 64-bit, the C02 IO wasn't usable anymore.
|
|
Leaving aside, that the newer games actually require a BIO2 board and do not support C02 nor IO2
|
|
boards anymore.
|
|
|
|
## The goal
|
|
|
|
I still wanted to use my cabinet with a C02 board on newer games which is possible with BT5 adding
|
|
an emulation layer and an interface (iidxio). This IO interface can be used to implement a driver
|
|
that talks to a real IO again. Thus, implementing a ezusb iidxio driver library, we can run newer
|
|
games with an C02 IO as well.
|
|
|
|
However, there was no ezusbsys.sys driver that works on newer platforms required to run the newer
|
|
games. But, Cypress was nice and included the source code of the ezusbsys kernel module. With a few
|
|
tweaks and a very recent version of visual studio, it was quite easy to build this driver for newer
|
|
platforms, including Windows 7, 8 and 10 in both 32-bit and 64-bit variants.
|
|
|
|
## The problem
|
|
|
|
But, when using this driver on certain combinations of newer hardware (max. 1-2 years old) and
|
|
Windows 7, the kernel module might crash after the Konami C02 firmware got flashed to the ezusb
|
|
board. The result was a bluescreen and reboot.
|
|
|
|
However, the hardware was fine and the kernel module worked fine on another piece of hardware, the
|
|
stock PC that was used with iidx 20 to 24. However, this hardware is not powerful enough to run iidx
|
|
25 and newer without stuttering issues.
|
|
|
|
## The analysis/debugging
|
|
|
|
Note: The full source code can be found in the bemanitools-supplement package.
|
|
|
|
Setup:
|
|
|
|
- Native hardware with Windows 7 that was crashing
|
|
- Vmware with Windows 10 and Visual Studio 2019 to compile the kernel module. Target platform
|
|
Windows 7 64-bit
|
|
- Booting Windows 7 in test mode to allow unsigned kernel modules to run and with debug output
|
|
turned on
|
|
- dbgview on Windows 7 machine to get local kernel dbg output
|
|
|
|
Because I wanted to stick to Windows 7 in the beginning (refer to the solution section), I started
|
|
debugging the kernel module by enabling the debug message output that was already available in the
|
|
code. However, since kernel debug message printing can be very delayed, the kernel could not print
|
|
various messages before the kernel crashed.
|
|
|
|
Thus, I started stripping the kernel module step by step to narrow down the possible spots causing
|
|
the crash. After a few hours, I got the (first) issue tracked down:
|
|
|
|
After the firmware was flashed, the device had to re-enumerate. When this happens, the function
|
|
*Ezusb_PnPAddDevice* is called to create a new instance of the device. Since this kernel module is
|
|
acting as a filter driver, it has to trap this call, and add a filter device before the real device
|
|
in the device stack. Thus, each call to the ezusb device hits the filter device first and the filter
|
|
device calls the real device after doing some magic.
|
|
|
|
*Ezusb_PnPAddDevice* calls *Ezusb_CreateDeviceObject*. Afterwards, it checks the status of the call
|
|
to *Ezusb_CreateDeviceObject* and if successful, it tries attaching the device to the device stack.
|
|
However, instead of using *IoAttachDeviceToDeviceStackSafe* it uses the unsafe variant
|
|
*IoAttachDeviceToDeviceStack* which can lead to a race condition on newer Windows Systems.
|
|
Furthermore, all initialization of further variables of the *deviceObject* needs to happen BEFORE
|
|
doing that. Again, this is a race condition.
|
|
|
|
Next issue: Once the kernel calls *Ezusb_StartDevice* -> *Ezusb_ConfigureDevice* ->
|
|
*Ezusb_SelectInterfaces*, it tries to use *USBD_ParseConfigurationDescriptorEx* to get the interface
|
|
from the configuration descriptor. However, that fails for some unknown reason. I checked the data
|
|
structure and it is perfectly fine and everything is there. Thus, I wrote my own version
|
|
*Ezusb_GetInterfaceFromConfigurationDescriptor* which does all the magic required to get this part
|
|
fixed:
|
|
|
|
```
|
|
PUSB_INTERFACE_DESCRIPTOR Ezusb_GetInterfaceFromConfigurationDescriptor(
|
|
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
|
|
)
|
|
{
|
|
if (!ConfigurationDescriptor) {
|
|
Ezusb_KdPrint(("ERROR Ezusb_GetInterfaceFromConfigurationDescriptor NULL configuration desc"));
|
|
return NULL;
|
|
}
|
|
|
|
if (ConfigurationDescriptor->wTotalLength < sizeof(USB_CONFIGURATION_DESCRIPTOR) + sizeof(USB_CONFIGURATION_DESCRIPTOR)) {
|
|
Ezusb_KdPrint(("ERROR Ezusb_GetInterfaceFromConfigurationDescriptor configuration descriptor too small to have space for interface descriptor"));
|
|
return NULL;
|
|
}
|
|
|
|
// hardcoding this to a single interface because we only care about the ezusb used with IIDX (C02 IO)
|
|
if (ConfigurationDescriptor->bNumInterfaces < 1) {
|
|
Ezusb_KdPrint(("ERROR Ezusb_GetInterfaceFromConfigurationDescriptor num interfaces 0"));
|
|
return NULL;
|
|
}
|
|
|
|
// when retrieving the configuration descriptor from the usb device, the interface is located right next to it
|
|
return (PUSB_INTERFACE_DESCRIPTOR) (((unsigned char*) ConfigurationDescriptor) + sizeof(USB_CONFIGURATION_DESCRIPTOR));
|
|
}
|
|
```
|
|
|
|
And next issue is just up ahead: Following the above, we have to call
|
|
*Ezusb_USBD_CreateConfigurationRequestEx* to create a USB configuration request to set the interface
|
|
we want to use. This is executed with a *Ezusb_CallUSBD* call which sends request to the real
|
|
hardware. However, this request always fails. The call *IoCallDriver* inside *Ezusb_CallUSBD* always
|
|
returns an NTSTATUS code that is not documented anywhere (can't find the exact status code anymore,
|
|
but once you get it, try to find it in the header file).
|
|
|
|
At this point, I had to give up. I already wasted too many hours and this is clearly a dead end.
|
|
|
|
## The solution
|
|
|
|
Once I realized that I got stuck with Windows 7 and I didn't want to buy (more) new hardware, I gave
|
|
Windows 10 a try. Surprisingly, this solved all the issues and the kernel module runs fine. The C02
|
|
board is flashable without crashing and works with newer IIDX games.
|