IoControlCode always 0 in 64 bit Driver

2009-04-02
2013-06-06
  • Brian Hawley

    Brian Hawley - 2009-04-02

    Has anyone experienced a problem where the IoControlCode of the Parameters structure is always 0, instead of the value passed via the DeviceIoControl call from 32 bit application space?  The other fields, such as InputBufferLength all look correct.  And with a 32 bit driver, the IoControlCode is correct.

    Here's the code snippet...

            if((pIrpSp = IoGetCurrentIrpStackLocation(pIrp)) == NULL) {
                    ERROR("ERROR: lmmdrv::stack location is NULL\n");
                    pIrp->IoStatus.Status = STATUS_ACCESS_DENIED;
                    pIrp->IoStatus.Information = nBytes;
                    IoCompleteRequest(pIrp, IO_NO_INCREMENT);
                    return STATUS_ACCESS_DENIED;
            }

            functionCode = pIrpSp->Parameters.DeviceIoControl.IoControlCode;
            nBytes = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
            buffer = pIrp->AssociatedIrp.SystemBuffer;

    -------------

    In a driver compiled with mingw32 functionCode has the correct value.  But in a driver compiled with mingw64 the value is always 0.  I dumped the DeviceIoControl structure...

    struct {
                ULONG OutputBufferLength;
                ULONG POINTER_ALIGNMENT InputBufferLength;
                ULONG POINTER_ALIGNMENT IoControlCode;
                PVOID Type3InputBuffer;
            } DeviceIoControl;

    byte 0 = 0
    byte 1 = 0
    byte 2 = 0
    byte 3 = 0
    byte 4 = 79
    byte 5 = f5
    byte 6 = 8
    byte 7 = 0
    byte 8 = 0
    byte 9 = 0
    byte 10 = 0
    byte 11 = 0
    byte 12 = 79
    byte 13 = f5
    byte 14 = 8
    byte 15 = 0

    We use METHOD_BUFFERED, so the Type3InputBuffer section isn't used....although I find it interesting that it contains the same value as the InputBufferLength.  

    Another odd thing is that the OutputBufferLength should have the same value as the InputBufferLength, but instead it is 0.  It makes me wonder if both aren't getting stepped on. 

    The sizeof() the IoControlCode reports as 4 bytes, so I am assuming ULONG is 4 bytes as far as mingw is concerned.  But I'm wondering if perhaps the native compiler (or 64 bit kernel) is somethow thinking differently and is actually stepping on the OutputBufferLength when updating InputBufferLength and stepping on IoControlCode when updating Type3InputBuffer.

    Any thoughts or suggestions would be appreciated.

    Thanks.

     
    • Brian Hawley

      Brian Hawley - 2009-04-07

      I wanted to post how I got it to work in case anyone is following the same path some day.

      I attempted to define the POINTER_ALIGNMENT as the native DDK does do something different for WIN64. 

      i.e. 

      #if defined(_WIN64)
      #define POINTER_ALIGNMENT DECLSPEC_ALIGN(8)
      #else
      #define POINTER_ALIGNMENT
      #endif

      where DECLSPEC_ALIGN is:

      #define DECLSPEC_ALIGN(x) __attribute__((aligned(x)))

      However that had absolutely no impact in the structure size or field offsets.  So, I went a different route...the following modification to the DeviceIoControl structure in the w32api winddk.h works.

      #ifdef _WIN64

      struct {

      uint32_t dummy3;
      ULONG POINTER_ALIGNMENT  OutputBufferLength;

      uint32_t dummy1;
      ULONG POINTER_ALIGNMENT  InputBufferLength;

      uint32_t dummy2;
           ULONG POINTER_ALIGNMENT  IoControlCode;

      #else
          ULONG  OutputBufferLength;
           ULONG POINTER_ALIGNMENT  InputBufferLength;
           ULONG POINTER_ALIGNMENT  IoControlCode;
      #endif

            PVOID  Type3InputBuffer;
          } DeviceIoControl;

       
    • Kai Tietz

      Kai Tietz - 2009-04-19

      Hello,

      just to inform you. We provide now the DDK as optional package. It should works for 32-bit x86 and to 64-bit x64 Windows. If you find some issues about it, please don't hesitate to tell me.

      Cheers,
      Kai

       
    • Brian Hawley

      Brian Hawley - 2009-04-20

      Thanks Kai.  I will check it out today.

       
    • Brian Hawley

      Brian Hawley - 2009-04-20

      The structure isn't defined any differently for 32 and 64 bit architectures, so unless there is a different library to link to, as well, simply using the header files mentioned do not solve the above alignment related issue.

       
    • Kai Tietz

      Kai Tietz - 2009-04-21

      Well, alignments for gcc are still an issue. It is possible to align by the attribute align(<value>), but it isn't usable in some conditions. Also an unaligned attribute isn't present for gcc, too.
      But possibly I can try to push this on gcc. I'll try.

      Cheers,
      Kai

       
    • Brian Hawley

      Brian Hawley - 2009-04-29

      I am downloading the 4/20 toolchain today and will test.

      I ran into another issue with the PartialResource structure.  They added some stuff for the 64 bit version which isn't in the 32 bit version, so the size changed.  I did note that this new ddk does have that definition in it.

      Perhaps the new libraries have something different for the original problem I reported.

      I will let you know the results.

       
    • Brian Hawley

      Brian Hawley - 2009-04-29

      I noticed the snapshot has both 32 and 64 bit lib defs.

      Is this toolchain intended to build both 32 and 64 bit targets?

       
      • Kai Tietz

        Kai Tietz - 2009-04-29

        Hello,

        yes this toolchain is intended to worl on 32-bit and 64-bit Windows OSes (XP and newer).

        Cheers,
        Kai

         
    • Brian Hawley

      Brian Hawley - 2009-04-29

      Just to clarify, by 32 and 64 bit targets, I meant the generated code, not where the toolchain would run.

      If this toolchain can generate code for both 32 bit and 64 bit systems, is the default 32, or 64 bit?  i.e. do i have to use -m32 to get 32 bit, or is 32 bit the default and -m64 generates 64 bit code?

       
    • Kai Tietz

      Kai Tietz - 2009-04-29

      Well for gcc's 4.4.x series we support toolchains for targeting 64-bit (bytarget x86_64-pc-mingw32) or targeting 32-bit (by target i686-pc-mingw32). For the upcoming 4.5 we support also multilib configuration (-m32 and -m64) by target (i686|x86_64)-w64-mingw32. The major thing here is the vendor key, because it enables this new feature for 4.5.

      We have at the moment some issues about the installation of shared libraries in multilib configurationon 4.5. But we will fix that until 4.5 gets official released.

      Cheers,
      Kai

       
      • Brian Hawley

        Brian Hawley - 2009-04-29

        So for now, do you recommend using the mingw32 supplied compiler rather than the compiler from this project for doing 32 bit target generation?

         
        • Kai Tietz

          Kai Tietz - 2009-04-29

          We are still on to verify our 32-bit compiler with mingw.org's official version. Our compiler works in most cases, but of course is still a "beta" version. So for productive code on 32-bit the mingw.org's version is at the moment to be prefered. But of course we are very interested in test on our new 32-bit toolchain, so that we can improve things for it.

          The missing header I will clarify and add it, if we got it.

          Thanks,
          Kai

           
    • Brian Hawley

      Brian Hawley - 2009-04-29

      Compiles fail with

      v:/tools/generic-i386-winxp64/mingw/include/ddk/ntdef.h:10: fatal error: sdkddkver.h: No such file or directory
      compilation terminated.

      I could not find sdkddkver.h in the snapshot tree at all.

      Here is what I did to setup /tools/generic/i386-winxp64. 

      I took the automated build from 0420 and extracted it.  The ddk include files were not in there, so I copied

      trunk/mingw-w64-headers/include/ddk/include/* to tools/generic-i386-winxp64/mingw/include/ddk

      The mingw/include directory does not appear to be part of the default includes, so I added it to the -I flag to gcc.  It seems a little strange to me that the default include directory wouldn't be specified.  But the 32 bit does the same thing (not specifying the mingw/include directory).

      If someone can point me to the sdkddkver.h file, I can continue testing this toolchain.

       
    • Brian Hawley

      Brian Hawley - 2009-04-29

      I would be happy to test it.

      I need a little clarification though.

      Am I to use the mingw-w64-bin_i686-mingw_20090420.zip and simply specify -m32 as a flag to the bin/x86_64-pc-mingw32-gcc.exe?

      Or am I to use a different toolchain?

      by the way, having gcc.exe in bin, mingw/bin, and x86_64-pc-mingw32/bin is a little confusing to me.  I'm not really sure which one I'm supposed to be invoking.  but clearly the include and libs are coming from mingw/include and mingw/lib.

       
    • Brian Hawley

      Brian Hawley - 2009-04-29

      I found the sdkddkver.h at http://www.koders.com/c/fidED7B5C9278170873F90805C8AC0A07224A1A33B0.aspx

      I put it into the mingw/include directory.

      When I compile now, I get

      v:/tools/generic-i386-winxp64/mingw/include/ddk/wdm.h:373: error: #error Unknown architecture

      which comes from:

      ^M
      #if defined(_M_IX86)^M
      #define YieldProcessor _mm_pause^M
      #elif defined (_M_AMD64)^M
      #define YieldProcessor _mm_pause^M
      #elif defined(_M_PPC)^M
      #define YieldProcessor() __asm__ __volatile__("nop");^M
      #elif defined(_M_MIPS)^M
      #define YieldProcessor() __asm__ __volatile__("nop");^M
      #elif defined(_M_ARM)^M
      #define YieldProcessor()^M
      #else^M
      #error Unknown architecture^M
      #endif^M

      I would have expected the compiler to define one of these based on the target code generation selected (i.e. -m64)

       
      • Kai Tietz

        Kai Tietz - 2009-04-29

        Thank you for noticing that. We don't define the _M_... macros at the moment, so on build you need to add it manually. I'll update our header-set to define those macros.

        Possibly you could add a bug report for this in our tracker.

        Thanks,
        Kai

         
    • Kai Tietz

      Kai Tietz - 2009-04-29

      Thank you! Any help to stabilze and improve our toolchain is very welcome.
      For the moment you need to use different toolchains for this. We have to improve multilib build (on 4.5 base). There are some small nits left, before it can be used out of the box. Also the 4.5 is under construction and new bugs and regressions are pretty likely. So I would recomment to use the 4.4.x based toolchains.

      The only binaries to be used are in /bin. The folders /mingw/bin and x86_64-pc-mingw32/bin are for internal use of toolchain only. The duplication of x86_64-pc-mingw32/ and mingw/ are just for native toolchains present. Normally mingw/ is a link to x86_64-pc-mingw32/, but zip doesn't handle this, so it is getting duplicated. If you have a tool to create junction points, you can remove the mingw/ folder and create a junction point with name "mingw" to the x86_64-pc-mingw32/ folder.

      We plan to provide for this in some future a packaging tool, which is able to handle and setup it more efficient.

      Cheers,
      Kai

       
      • Brian Hawley

        Brian Hawley - 2009-04-29

        I don't see a prebuilt toolchain in the 'Toolchains targeting win32' for mingw.  Only linux.

        Is the toolchain somewhere else?

         
    • Brian Hawley

      Brian Hawley - 2009-04-29

      I defined the _M_AMD64, and proceeded with building.  I also had to manually define __x86_64__.

      Next I get a compile error:

      v:/tools/generic-i386-winxp64/mingw/include/ddk/wdm.h:1717: error: expected ')' before 'Descriptor'

      and a couple others just like it.

      This is in a section of code of an ifdef

      #if (NTDDI_VERSION >= NTDDI_VISTA)

      I'm not building for vista (nor am i building on vista) so I thought if I could find the value for NTDDI_VISTA I could set NTDDI_VERSION to something lower than that, but I can not find the definition anywhere in the headers.  So this code is getting compiled in regardless.   I surrounded it by #if 0 #endif to keep it from being compiled in.  I suspect the issue is the PIO_RESOURCE_DESCRIPTOR is somehow not getting defined.  If I include winddk.h (where it is defined) I get all sorts of errors.  So, something needs to be done differently here, I just don't know what it is.

      Next, I get ddk/winnt4.h does not exist.  I just comment out where I include this file for now.  Perhaps ReactOS has the definitions in this file elsewhere now.

      Compilation continues until

      v:/tools/generic-i386-winxp64/mingw/include/winbase.h:139: error: expected specifier-qualifier-list before 'DWORD'
      , which is referring to the DWORD Offset in the below snippet...

      typedef struct _OVERLAPPED {
         ULONG_PTR Internal;
         ULONG_PTR InternalHigh;
         __extension__ union {
           __extension__ struct {
         DWORD Offset;
         DWORD OffsetHigh;
           };
           PVOID Pointer;
         };
         HANDLE hEvent;
      } OVERLAPPED,*LPOVERLAPPED;

      But, if I don't include winbase.h, then I don't get WAIT_OBJECT_0, which I need.  For now, I have just defined WAIT_OBJECT_0 in my own files.  But this doesn't seem to be a good long term solution.  DWORD typedef'd in ddk/ntstrsafe.h to an unsigned long.  Perhaps the ReactOS expects DWORD to be defined outside of the header files?  This doesn't seem like the obvious place for a global definition of DWORD.  w32api defines DWORD in windef.h, and windef.h is included by ntddk.h.  However, while ReactOS defines them in windef.h, it also defines some basic types in ntdef.h, and ntddk includes ntdef.h.  So, these symbols don't appear to be getting defined. 

      Finally, after these hacks, I get through .c compilation, but at link time:

      c:/tmp/bhawley/generic-i386-winxp/Libraries/2.2.0.1/lib/libbase_K64.a(pal__windows.o_K64):pal__windows.c:(.text+0x192): undefined reference to `KeQuerySystemTime'
      c:/tmp/bhawley/generic-i386-winxp/Libraries/2.2.0.1/lib/libbase_K64.a(pal__windows.o_K64):pal__windows.c:(.text+0x1cf): undefined reference to `KeQuerySystemTime'
      c:/tmp/bhawley/generic-i386-winxp/Libraries/2.2.0.1/lib/libbase_K64.a(pal__windows.o_K64):pal__windows.c:(.text+0x263): undefined reference to `_imp__KfAcquireSpinLock'
      c:/tmp/bhawley/generic-i386-winxp/Libraries/2.2.0.1/lib/libbase_K64.a(pal__windows.o_K64):pal__windows.c:(.text+0x2ab): undefined reference to `_imp__KfReleaseSpinLock'
      c:/tmp/bhawley/generic-i386-winxp/Libraries/2.2.0.1/lib/libbase_K64.a(pal__windows.o_K64):pal__windows.c:(.text+0x300): undefined reference to `_imp__KfReleaseSpinLock'
      c:/tmp/bhawley/generic-i386-winxp/Libraries/2.2.0.1/lib/libbase_K64.a(pal__windows.o_K64):pal__windows.c:(.text+0x388): undefined reference to `_imp__KeInitializeSpinLock'
      c:/tmp/bhawley/generic-i386-winxp/Libraries/2.2.0.1/lib/libbase_K64.a(pal__windows.o_K64):pal__windows.c:(.text+0x5be): undefined reference to `_imp__KfAcquireSpinLock'

      I see in winddk.h for __x86_64__ they have a macro for these.  However, the section thats getting used in a build is the section with #ifdef _X86_.  I am not defining _X86_ with -D, so its getting defined by something outside of my makefiles.  Could this be getting defined by gcc in the 64 bit toolchain?  If I undef _X86_ then the build completes without the linker errors.

      And, while it does generate driver code that runs, the orignal problem with alignment of the structure that contains IoControlCode not addressed. 

      -- Brian

       
    • Brian Hawley

      Brian Hawley - 2009-04-29

      On the bright side, with those changes mentioned above, and the change made to address the lack of pointer alignment in structures, things work pretty well.

      the headers even have a fix for the CmResource structure that I was going to have to make manually to the w32api headers.

      The IoControlCode not being correctly aligned is when thunking from 32 bit applications.  I have not been able to test 64 bit applications.  They may not exhibit the same issues.

       

Log in to post a comment.

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:

JavaScript is required for this form.





No, thanks