http://bugs.winehq.org/show_bug.cgi?id=7876
------- Additional Comments From focht@gmx.net 2007-25-05 09:43 ------- Hello,
due to some stall (read: hit-the-wall) in other kmode projects, I gave this one a shot with my current ntoskrnl impl. After adding MmMapIoSpace() and MmUnmapIoSpace() impl to ntoskrnl the usermode part issues a lot of device ioctls. This consists of direct i/o port reads, gathering peripherals (ACPI ..), chipset info, timing/calibration loops and the like.
There is a showstopper for now and probably forever due to the way wine is currently designed. In short: user mode pointers hidden in ioctl input buffers are passed from user mode to kernel mode.
Now lets go into details...
--- snip relevant trace --- ... 003c:Call ntdll.RtlAllocateHeap(00610000,00000000,0000000c) ret=00460fa4 003c:Ret ntdll.RtlAllocateHeap() retval=00b6b768 ret=00460fa4 003c:Call ntdll.RtlAllocateHeap(00610000,00000000,00000014) ret=00460fa4 003c:Ret ntdll.RtlAllocateHeap() retval=00b6b780 ret=00460fa4 003c:Call ntdll.RtlAllocateHeap(00610000,00000000,00000404) ret=00460fa4 003c:Ret ntdll.RtlAllocateHeap() retval=00b6b7a0 ret=00460fa4 003c:Call KERNEL32.DeviceIoControl(00000074,9c402420,0034f494,0000000c,0034f4a0,00000008,0034f4cc,00000000) ret=0047548e 0043:Ret KERNEL32.WaitForMultipleObjects() retval=00000001 ret=603194a9 0043:Call ntdll.RtlFreeHeap(00110000,00000000,00188d68) ret=603190c2 0043:Ret ntdll.RtlFreeHeap() retval=00000001 ret=603190c2 0043:Call ntdll.RtlAllocateHeap(00110000,00000000,0000000c) ret=603190e8 0043:Ret ntdll.RtlAllocateHeap() retval=00188d68 ret=603190e8 0043:Call ntdll.RtlFreeHeap(00110000,00000000,00188d80) ret=60319149 0043:Ret ntdll.RtlFreeHeap() retval=00000001 ret=60319149 0043:Call ntdll.RtlAllocateHeap(00110000,00000000,00000008) ret=60319183 0043:Ret ntdll.RtlAllocateHeap() retval=00188d80 ret=60319183 0043:trace:ntoskrnl:process_ioctl ioctl 9c402420 device 0x188ca0 in_size 12 out_size 8 0043:trace:ntoskrnl:process_ioctl 0x188d68 0x188d80 0043:Call ntdll.NtGetTickCount() ret=60318920 0043:Ret ntdll.NtGetTickCount() retval=005e6933 ret=60318920 0043:Call driver dispatch 0x350480 (device=0x188ca0,irp=0x6095c7a4) 0043:Call KERNEL32.GetEnvironmentVariableW(6032276e L"DebugBreak",6095c434,00000104) ret=60318afd 0043:Ret KERNEL32.GetEnvironmentVariableW() retval=00000000 ret=60318afd 0043:Call ntoskrnl.exe.MmMapIoSpace(00000000,00000000,00000400,00000000) ret=00350716 0043:fixme:ntoskrnl:MmMapIoSpace stub: 0x0 1024 0 0043:Call ntdll.RtlAllocateHeap(00110000,00000000,00000400) ret=60318f13 0043:Ret ntdll.RtlAllocateHeap() retval=0018ca68 ret=60318f13 0043:Ret ntoskrnl.exe.MmMapIoSpace() retval=0018ca68 ret=00350716 0043:trace:seh:raise_exception code=c0000005 flags=0 addr=0x350733 0043:trace:seh:raise_exception info[0]=00000001 0043:trace:seh:raise_exception info[1]=00b6b7a0 0043:trace:seh:raise_exception eax=00b6b740 ebx=00000400 ecx=00b6b7a0 edx=ff6212c8 esi=00188d68 edi=6095c7a4 0043:trace:seh:raise_exception ebp=6095c748 esp=6095c6c4 cs=0073 ds=007b es=007b fs=0033 gs=003b flags=00010283 --- snip relevant trace ---
So whats going on...
ioctl code 9c402420 decodes as follows:
device: 0xc40 (cpu-z ring0 driver) function: 0x908 access: FILE_ANY_ACCESS method: METHOD_BUFFERED
The client (usermode) allocates 2 buffers (RtlAllocateHeap preceeding the ioctl), with input buffer size = 0xc and output buffer size = 0x8. It passes data in input buffer, specific to function code, which is used in kernel driver for further operations.
- ioctl in/out buffers get copied in wineserver (see RtlAllocateHeap() after ioctl). - IRP gets constructed and passed to the drivers ioctl handler.
The temporary buffers are assigned to IRP:
(1) irp.AssociatedIrp.SystemBuffer = in_buff; irp.UserBuffer = out_buff; ... irpsp.Parameters.DeviceIoControl.Type3InputBuffer = in_buff;
---
The kernel driver accesses the input buffer to extract data. In this case the buffer contains parameters which are used for driver functions.
FIRST error: the Type3InputBuffer is accessed to extract parameters. This is not allowed in kernel mode drivers when the METHOD_BUFFERED flag is passed using ioctl. With METHOD_BUFFERED, the input buffer is in Irp->AssociatedIrp.SystemBuffer. This is a general rule for kernel driver developers ... but well :-)
Though wine "corrects" this error, by associating the input buffer pointer to both locations, see (1)
Now it gets interesting. The following is memory dump of input buffer (Type3InputBuffer, 3x4 DWORDs -> size 0xC):
offset+0: 00000000 offset+4: 00000400 offset+8 00b6b7a0
The first DWORD is the physical address and the second one is length in bytes used for MmMapIoSpace(). The driver maps physical memory into nonpaged area to access it. This direct access is used to dump data from peripherals, like the memory controller hub (MCHBAR) and others.
The real problem is the third parameter. This is actually a user mode pointer, allocated before the ioctl call (look for 0x00b6b7a0 address in trace). This buffer is used as target buffer to hold the data copied from physical space.
Wine doesnt know about this data, because it only sees the device ioctl input and output buffers as "whole" data block. So it cannot translate any contained pointers automatically to a valid user space address. Remember: the kernel driver runs in winedevice process, while the user mode client runs in another address space.
Dang. Lost. The driver would have to run in same address space as the usermode client which breaks the whole design...
Hope you enjoyed this little analysis ... and sorry, this problem can't be possibly fixed. :-(
Regards