"Fossies" - the Fresh Open Source Software Archive

Member "wine-6.0.1/dlls/ntoskrnl.exe/ntoskrnl.c" (7 Jun 2021, 136839 Bytes) of package /linux/misc/wine-6.0.1.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ntoskrnl.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 6.0_vs_6.0.1.

    1 /*
    2  * ntoskrnl.exe implementation
    3  *
    4  * Copyright (C) 2007 Alexandre Julliard
    5  * Copyright (C) 2010 Damjan Jovanovic
    6  * Copyright (C) 2016 Sebastian Lackner
    7  * Copyright (C) 2016 CodeWeavers, Aric Stewart
    8  *
    9  * This library is free software; you can redistribute it and/or
   10  * modify it under the terms of the GNU Lesser General Public
   11  * License as published by the Free Software Foundation; either
   12  * version 2.1 of the License, or (at your option) any later version.
   13  *
   14  * This library is distributed in the hope that it will be useful,
   15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   17  * Lesser General Public License for more details.
   18  *
   19  * You should have received a copy of the GNU Lesser General Public
   20  * License along with this library; if not, write to the Free Software
   21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
   22  */
   23 
   24 #include <stdarg.h>
   25 #include <assert.h>
   26 
   27 #define NONAMELESSUNION
   28 #define NONAMELESSSTRUCT
   29 
   30 #include "ntstatus.h"
   31 #define WIN32_NO_STATUS
   32 #include "windef.h"
   33 #include "winsvc.h"
   34 #include "winternl.h"
   35 #include "excpt.h"
   36 #include "winioctl.h"
   37 #include "winbase.h"
   38 #include "winreg.h"
   39 #include "ntsecapi.h"
   40 #include "ddk/csq.h"
   41 #include "ddk/ntddk.h"
   42 #include "ddk/ntifs.h"
   43 #include "ddk/wdm.h"
   44 #include "wine/server.h"
   45 #include "wine/debug.h"
   46 #include "wine/heap.h"
   47 #include "wine/rbtree.h"
   48 #include "wine/svcctl.h"
   49 
   50 #include "ntoskrnl_private.h"
   51 
   52 WINE_DEFAULT_DEBUG_CHANNEL(ntoskrnl);
   53 WINE_DECLARE_DEBUG_CHANNEL(relay);
   54 
   55 BOOLEAN KdDebuggerEnabled = FALSE;
   56 ULONG InitSafeBootMode = 0;
   57 USHORT NtBuildNumber = 0;
   58 
   59 extern LONG CALLBACK vectored_handler( EXCEPTION_POINTERS *ptrs );
   60 
   61 KSYSTEM_TIME KeTickCount = { 0, 0, 0 };
   62 
   63 typedef struct _KSERVICE_TABLE_DESCRIPTOR
   64 {
   65     PULONG_PTR Base;
   66     PULONG Count;
   67     ULONG Limit;
   68     PUCHAR Number;
   69 } KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR;
   70 
   71 KSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable[4] = { { 0 } };
   72 
   73 #define MAX_SERVICE_NAME 260
   74 
   75 static TP_POOL *dpc_call_tp;
   76 static TP_CALLBACK_ENVIRON dpc_call_tpe;
   77 DECLARE_CRITICAL_SECTION(dpc_call_cs);
   78 static DWORD dpc_call_tls_index;
   79 
   80 /* tid of the thread running client request */
   81 static DWORD request_thread;
   82 
   83 /* tid of the client thread */
   84 static DWORD client_tid;
   85 
   86 static HANDLE ntoskrnl_heap;
   87 
   88 static void *ldr_notify_cookie;
   89 
   90 static PLOAD_IMAGE_NOTIFY_ROUTINE load_image_notify_routines[8];
   91 static unsigned int load_image_notify_routine_count;
   92 
   93 struct wine_driver
   94 {
   95     DRIVER_OBJECT driver_obj;
   96     DRIVER_EXTENSION driver_extension;
   97     SERVICE_STATUS_HANDLE service_handle;
   98     struct wine_rb_entry entry;
   99 };
  100 
  101 static int wine_drivers_rb_compare( const void *key, const struct wine_rb_entry *entry )
  102 {
  103     const struct wine_driver *driver = WINE_RB_ENTRY_VALUE( entry, const struct wine_driver, entry );
  104     const UNICODE_STRING *k = key;
  105 
  106     return RtlCompareUnicodeString( k, &driver->driver_obj.DriverName, TRUE );
  107 }
  108 
  109 static struct wine_rb_tree wine_drivers = { wine_drivers_rb_compare };
  110 
  111 DECLARE_CRITICAL_SECTION(drivers_cs);
  112 
  113 static HANDLE get_device_manager(void)
  114 {
  115     static HANDLE device_manager;
  116     HANDLE handle = 0, ret = device_manager;
  117 
  118     if (!ret)
  119     {
  120         SERVER_START_REQ( create_device_manager )
  121         {
  122             req->access     = SYNCHRONIZE;
  123             req->attributes = 0;
  124             if (!wine_server_call( req )) handle = wine_server_ptr_handle( reply->handle );
  125         }
  126         SERVER_END_REQ;
  127 
  128         if (!handle)
  129         {
  130             ERR( "failed to create the device manager\n" );
  131             return 0;
  132         }
  133         if (!(ret = InterlockedCompareExchangePointer( &device_manager, handle, 0 )))
  134             ret = handle;
  135         else
  136             NtClose( handle );  /* somebody beat us to it */
  137     }
  138     return ret;
  139 }
  140 
  141 
  142 struct object_header
  143 {
  144     LONG ref;
  145     POBJECT_TYPE type;
  146 };
  147 
  148 static void free_kernel_object( void *obj )
  149 {
  150     struct object_header *header = (struct object_header *)obj - 1;
  151     HeapFree( GetProcessHeap(), 0, header );
  152 }
  153 
  154 void *alloc_kernel_object( POBJECT_TYPE type, HANDLE handle, SIZE_T size, LONG ref )
  155 {
  156     struct object_header *header;
  157 
  158     if (!(header = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*header) + size)) )
  159         return NULL;
  160 
  161     if (handle)
  162     {
  163         NTSTATUS status;
  164         SERVER_START_REQ( set_kernel_object_ptr )
  165         {
  166             req->manager  = wine_server_obj_handle( get_device_manager() );
  167             req->handle   = wine_server_obj_handle( handle );
  168             req->user_ptr = wine_server_client_ptr( header + 1 );
  169             status = wine_server_call( req );
  170         }
  171         SERVER_END_REQ;
  172         if (status) FIXME( "set_object_reference failed: %#x\n", status );
  173     }
  174 
  175     header->ref = ref;
  176     header->type = type;
  177     return header + 1;
  178 }
  179 
  180 DECLARE_CRITICAL_SECTION(obref_cs);
  181 
  182 /***********************************************************************
  183  *           ObDereferenceObject   (NTOSKRNL.EXE.@)
  184  */
  185 void WINAPI ObDereferenceObject( void *obj )
  186 {
  187     struct object_header *header = (struct object_header*)obj - 1;
  188     LONG ref;
  189 
  190     if (!obj)
  191     {
  192         FIXME("NULL obj\n");
  193         return;
  194     }
  195 
  196     EnterCriticalSection( &obref_cs );
  197 
  198     ref = --header->ref;
  199     TRACE( "(%p) ref=%u\n", obj, ref );
  200     if (!ref)
  201     {
  202         if (header->type->release)
  203         {
  204             header->type->release( obj );
  205         }
  206         else
  207         {
  208             SERVER_START_REQ( release_kernel_object )
  209             {
  210                 req->manager  = wine_server_obj_handle( get_device_manager() );
  211                 req->user_ptr = wine_server_client_ptr( obj );
  212                 if (wine_server_call( req )) FIXME( "failed to release %p\n", obj );
  213             }
  214             SERVER_END_REQ;
  215         }
  216     }
  217 
  218     LeaveCriticalSection( &obref_cs );
  219 }
  220 
  221 void ObReferenceObject( void *obj )
  222 {
  223     struct object_header *header = (struct object_header*)obj - 1;
  224     LONG ref;
  225 
  226     if (!obj)
  227     {
  228         FIXME("NULL obj\n");
  229         return;
  230     }
  231 
  232     EnterCriticalSection( &obref_cs );
  233 
  234     ref = ++header->ref;
  235     TRACE( "(%p) ref=%u\n", obj, ref );
  236     if (ref == 1)
  237     {
  238         SERVER_START_REQ( grab_kernel_object )
  239         {
  240             req->manager  = wine_server_obj_handle( get_device_manager() );
  241             req->user_ptr = wine_server_client_ptr( obj );
  242             if (wine_server_call( req )) FIXME( "failed to grab %p reference\n", obj );
  243         }
  244         SERVER_END_REQ;
  245     }
  246 
  247     LeaveCriticalSection( &obref_cs );
  248 }
  249 
  250 /***********************************************************************
  251  *           ObGetObjectType (NTOSKRNL.EXE.@)
  252  */
  253 POBJECT_TYPE WINAPI ObGetObjectType( void *object )
  254 {
  255     struct object_header *header = (struct object_header *)object - 1;
  256     return header->type;
  257 }
  258 
  259 static const POBJECT_TYPE *known_types[] =
  260 {
  261     &ExEventObjectType,
  262     &ExSemaphoreObjectType,
  263     &IoDeviceObjectType,
  264     &IoDriverObjectType,
  265     &IoFileObjectType,
  266     &PsProcessType,
  267     &PsThreadType,
  268     &SeTokenObjectType
  269 };
  270 
  271 DECLARE_CRITICAL_SECTION(handle_map_cs);
  272 
  273 NTSTATUS kernel_object_from_handle( HANDLE handle, POBJECT_TYPE type, void **ret )
  274 {
  275     void *obj;
  276     NTSTATUS status;
  277 
  278     EnterCriticalSection( &handle_map_cs );
  279 
  280     SERVER_START_REQ( get_kernel_object_ptr )
  281     {
  282         req->manager = wine_server_obj_handle( get_device_manager() );
  283         req->handle  = wine_server_obj_handle( handle );
  284         status = wine_server_call( req );
  285         obj = wine_server_get_ptr( reply->user_ptr );
  286     }
  287     SERVER_END_REQ;
  288     if (status)
  289     {
  290         LeaveCriticalSection( &handle_map_cs );
  291         return status;
  292     }
  293 
  294     if (!obj)
  295     {
  296         char buf[256];
  297         OBJECT_TYPE_INFORMATION *type_info = (OBJECT_TYPE_INFORMATION *)buf;
  298         ULONG size;
  299 
  300         status = NtQueryObject( handle, ObjectTypeInformation, buf, sizeof(buf), &size );
  301         if (status)
  302         {
  303             LeaveCriticalSection( &handle_map_cs );
  304             return status;
  305         }
  306         if (!type)
  307         {
  308             size_t i;
  309             for (i = 0; i < ARRAY_SIZE(known_types); i++)
  310             {
  311                 type = *known_types[i];
  312                 if (!RtlCompareUnicodeStrings( type->name, lstrlenW(type->name), type_info->TypeName.Buffer,
  313                                                type_info->TypeName.Length / sizeof(WCHAR), FALSE ))
  314                     break;
  315             }
  316             if (i == ARRAY_SIZE(known_types))
  317             {
  318                 FIXME("Unsupported type %s\n", debugstr_us(&type_info->TypeName));
  319                 LeaveCriticalSection( &handle_map_cs );
  320                 return STATUS_INVALID_HANDLE;
  321             }
  322         }
  323         else if (RtlCompareUnicodeStrings( type->name, lstrlenW(type->name), type_info->TypeName.Buffer,
  324                                            type_info->TypeName.Length / sizeof(WCHAR), FALSE) )
  325         {
  326             LeaveCriticalSection( &handle_map_cs );
  327             return STATUS_OBJECT_TYPE_MISMATCH;
  328         }
  329 
  330         if (type->constructor)
  331             obj = type->constructor( handle );
  332         else
  333         {
  334             FIXME( "No constructor for type %s\n", debugstr_w(type->name) );
  335             obj = alloc_kernel_object( type, handle, 0, 0 );
  336         }
  337         if (!obj) status = STATUS_NO_MEMORY;
  338     }
  339     else if (type && ObGetObjectType( obj ) != type) status = STATUS_OBJECT_TYPE_MISMATCH;
  340 
  341     LeaveCriticalSection( &handle_map_cs );
  342     if (!status) *ret = obj;
  343     return status;
  344 }
  345 
  346 /***********************************************************************
  347  *           ObReferenceObjectByHandle    (NTOSKRNL.EXE.@)
  348  */
  349 NTSTATUS WINAPI ObReferenceObjectByHandle( HANDLE handle, ACCESS_MASK access,
  350                                            POBJECT_TYPE type,
  351                                            KPROCESSOR_MODE mode, void **ptr,
  352                                            POBJECT_HANDLE_INFORMATION info )
  353 {
  354     NTSTATUS status;
  355 
  356     TRACE( "%p %x %p %d %p %p\n", handle, access, type, mode, ptr, info );
  357 
  358     if (mode != KernelMode)
  359     {
  360         FIXME("UserMode access not implemented\n");
  361         return STATUS_NOT_IMPLEMENTED;
  362     }
  363 
  364     status = kernel_object_from_handle( handle, type, ptr );
  365     if (!status) ObReferenceObject( *ptr );
  366     return status;
  367 }
  368 
  369 /***********************************************************************
  370  *           ObOpenObjectByPointer    (NTOSKRNL.EXE.@)
  371  */
  372 NTSTATUS WINAPI ObOpenObjectByPointer( void *obj, ULONG attr, ACCESS_STATE *access_state,
  373                                        ACCESS_MASK access, POBJECT_TYPE type,
  374                                        KPROCESSOR_MODE mode, HANDLE *handle )
  375 {
  376     NTSTATUS status;
  377 
  378     TRACE( "%p %x %p %x %p %d %p\n", obj, attr, access_state, access, type, mode, handle );
  379 
  380     if (mode != KernelMode)
  381     {
  382         FIXME( "UserMode access not implemented\n" );
  383         return STATUS_NOT_IMPLEMENTED;
  384     }
  385 
  386     if (attr & ~OBJ_KERNEL_HANDLE) FIXME( "attr %#x not supported\n", attr );
  387     if (access_state) FIXME( "access_state not implemented\n" );
  388 
  389     if (type && ObGetObjectType( obj ) != type) return STATUS_OBJECT_TYPE_MISMATCH;
  390 
  391     SERVER_START_REQ( get_kernel_object_handle )
  392     {
  393         req->manager  = wine_server_obj_handle( get_device_manager() );
  394         req->user_ptr = wine_server_client_ptr( obj );
  395         req->access   = access;
  396         if (!(status = wine_server_call( req )))
  397             *handle = wine_server_ptr_handle( reply->handle );
  398     }
  399     SERVER_END_REQ;
  400     return status;
  401 }
  402 
  403 
  404 static void *create_file_object( HANDLE handle );
  405 
  406 static const WCHAR file_type_name[] = {'F','i','l','e',0};
  407 
  408 static struct _OBJECT_TYPE file_type = {
  409     file_type_name,
  410     create_file_object
  411 };
  412 
  413 POBJECT_TYPE IoFileObjectType = &file_type;
  414 
  415 static void *create_file_object( HANDLE handle )
  416 {
  417     FILE_OBJECT *file;
  418     if (!(file = alloc_kernel_object( IoFileObjectType, handle, sizeof(*file), 0 ))) return NULL;
  419     file->Type = 5;  /* MSDN */
  420     file->Size = sizeof(*file);
  421     return file;
  422 }
  423 
  424 DECLARE_CRITICAL_SECTION(irp_completion_cs);
  425 
  426 static void WINAPI cancel_completed_irp( DEVICE_OBJECT *device, IRP *irp )
  427 {
  428     TRACE( "(%p %p)\n", device, irp );
  429 
  430     IoReleaseCancelSpinLock(irp->CancelIrql);
  431 
  432     irp->IoStatus.u.Status = STATUS_CANCELLED;
  433     irp->IoStatus.Information = 0;
  434     IoCompleteRequest(irp, IO_NO_INCREMENT);
  435 }
  436 
  437 /* transfer result of IRP back to wineserver */
  438 static NTSTATUS WINAPI dispatch_irp_completion( DEVICE_OBJECT *device, IRP *irp, void *context )
  439 {
  440     HANDLE irp_handle = context;
  441     void *out_buff = irp->UserBuffer;
  442     NTSTATUS status;
  443 
  444     if (irp->Flags & IRP_WRITE_OPERATION)
  445         out_buff = NULL;  /* do not transfer back input buffer */
  446 
  447     EnterCriticalSection( &irp_completion_cs );
  448 
  449     SERVER_START_REQ( set_irp_result )
  450     {
  451         req->handle   = wine_server_obj_handle( irp_handle );
  452         req->status   = irp->IoStatus.u.Status;
  453         req->size     = irp->IoStatus.Information;
  454         if (!NT_ERROR(irp->IoStatus.u.Status))
  455         {
  456             if (out_buff) wine_server_add_data( req, out_buff, irp->IoStatus.Information );
  457         }
  458         status = wine_server_call( req );
  459     }
  460     SERVER_END_REQ;
  461 
  462     if (status == STATUS_MORE_PROCESSING_REQUIRED)
  463     {
  464         /* IRP is complete, but server may have already ordered cancel call. In such case,
  465          * it will return STATUS_MORE_PROCESSING_REQUIRED, leaving the IRP alive until
  466          * cancel frees it. */
  467         if (irp->Cancel)
  468             status = STATUS_SUCCESS;
  469         else
  470             IoSetCancelRoutine( irp, cancel_completed_irp );
  471     }
  472 
  473     if (irp->UserBuffer != irp->AssociatedIrp.SystemBuffer)
  474     {
  475         HeapFree( GetProcessHeap(), 0, irp->UserBuffer );
  476         irp->UserBuffer = NULL;
  477     }
  478 
  479     LeaveCriticalSection( &irp_completion_cs );
  480     return status;
  481 }
  482 
  483 struct dispatch_context
  484 {
  485     irp_params_t params;
  486     HANDLE handle;
  487     IRP   *irp;
  488     ULONG  in_size;
  489     void  *in_buff;
  490 };
  491 
  492 static void dispatch_irp( DEVICE_OBJECT *device, IRP *irp, struct dispatch_context *context )
  493 {
  494     LARGE_INTEGER count;
  495 
  496     IoSetCompletionRoutine( irp, dispatch_irp_completion, context->handle, TRUE, TRUE, TRUE );
  497     context->handle = 0;
  498 
  499     KeQueryTickCount( &count );  /* update the global KeTickCount */
  500 
  501     context->irp = irp;
  502     device->CurrentIrp = irp;
  503     KeEnterCriticalRegion();
  504     IoCallDriver( device, irp );
  505     KeLeaveCriticalRegion();
  506     device->CurrentIrp = NULL;
  507 }
  508 
  509 /* process a create request for a given file */
  510 static NTSTATUS dispatch_create( struct dispatch_context *context )
  511 {
  512     IRP *irp;
  513     IO_STACK_LOCATION *irpsp;
  514     FILE_OBJECT *file;
  515     DEVICE_OBJECT *device = wine_server_get_ptr( context->params.create.device );
  516     HANDLE handle = wine_server_ptr_handle( context->params.create.file );
  517 
  518     if (!(file = alloc_kernel_object( IoFileObjectType, handle, sizeof(*file), 0 )))
  519         return STATUS_NO_MEMORY;
  520 
  521     TRACE( "device %p -> file %p\n", device, file );
  522 
  523     file->Type = 5;  /* MSDN */
  524     file->Size = sizeof(*file);
  525     file->DeviceObject = device;
  526 
  527     device = IoGetAttachedDevice( device );
  528 
  529     if (!(irp = IoAllocateIrp( device->StackSize, FALSE ))) return STATUS_NO_MEMORY;
  530 
  531     irpsp = IoGetNextIrpStackLocation( irp );
  532     irpsp->MajorFunction = IRP_MJ_CREATE;
  533     irpsp->FileObject = file;
  534     irpsp->Parameters.Create.SecurityContext = NULL;  /* FIXME */
  535     irpsp->Parameters.Create.Options = context->params.create.options;
  536     irpsp->Parameters.Create.ShareAccess = context->params.create.sharing;
  537     irpsp->Parameters.Create.FileAttributes = 0;
  538     irpsp->Parameters.Create.EaLength = 0;
  539 
  540     irp->Tail.Overlay.OriginalFileObject = file;
  541     irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
  542     irp->RequestorMode = UserMode;
  543     irp->AssociatedIrp.SystemBuffer = NULL;
  544     irp->UserBuffer = NULL;
  545     irp->UserIosb = NULL;
  546     irp->UserEvent = NULL;
  547 
  548     irp->Flags |= IRP_CREATE_OPERATION;
  549     dispatch_irp( device, irp, context );
  550 
  551     return STATUS_SUCCESS;
  552 }
  553 
  554 /* process a close request for a given file */
  555 static NTSTATUS dispatch_close( struct dispatch_context *context )
  556 {
  557     IRP *irp;
  558     IO_STACK_LOCATION *irpsp;
  559     DEVICE_OBJECT *device;
  560     FILE_OBJECT *file = wine_server_get_ptr( context->params.close.file );
  561 
  562     if (!file) return STATUS_INVALID_HANDLE;
  563 
  564     device = IoGetAttachedDevice( file->DeviceObject );
  565 
  566     TRACE( "device %p file %p\n", device, file );
  567 
  568     if (!(irp = IoAllocateIrp( device->StackSize, FALSE )))
  569     {
  570         ObDereferenceObject( file );
  571         return STATUS_NO_MEMORY;
  572     }
  573 
  574     irpsp = IoGetNextIrpStackLocation( irp );
  575     irpsp->MajorFunction = IRP_MJ_CLOSE;
  576     irpsp->FileObject = file;
  577 
  578     irp->Tail.Overlay.OriginalFileObject = file;
  579     irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
  580     irp->RequestorMode = UserMode;
  581     irp->AssociatedIrp.SystemBuffer = NULL;
  582     irp->UserBuffer = NULL;
  583     irp->UserIosb = NULL;
  584     irp->UserEvent = NULL;
  585 
  586     irp->Flags |= IRP_CLOSE_OPERATION;
  587     dispatch_irp( device, irp, context );
  588 
  589     return STATUS_SUCCESS;
  590 }
  591 
  592 /* process a read request for a given device */
  593 static NTSTATUS dispatch_read( struct dispatch_context *context )
  594 {
  595     IRP *irp;
  596     void *out_buff;
  597     LARGE_INTEGER offset;
  598     IO_STACK_LOCATION *irpsp;
  599     DEVICE_OBJECT *device;
  600     FILE_OBJECT *file = wine_server_get_ptr( context->params.read.file );
  601     ULONG out_size = context->params.read.out_size;
  602 
  603     if (!file) return STATUS_INVALID_HANDLE;
  604 
  605     device = IoGetAttachedDevice( file->DeviceObject );
  606 
  607     TRACE( "device %p file %p size %u\n", device, file, out_size );
  608 
  609     if (!(out_buff = HeapAlloc( GetProcessHeap(), 0, out_size ))) return STATUS_NO_MEMORY;
  610 
  611     offset.QuadPart = context->params.read.pos;
  612 
  613     if (!(irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ, device, out_buff, out_size,
  614                                               &offset, NULL, NULL )))
  615     {
  616         HeapFree( GetProcessHeap(), 0, out_buff );
  617         return STATUS_NO_MEMORY;
  618     }
  619 
  620     irp->Tail.Overlay.OriginalFileObject = file;
  621     irp->RequestorMode = UserMode;
  622 
  623     irpsp = IoGetNextIrpStackLocation( irp );
  624     irpsp->FileObject = file;
  625     irpsp->Parameters.Read.Key = context->params.read.key;
  626 
  627     irp->Flags |= IRP_READ_OPERATION;
  628     irp->Flags |= IRP_DEALLOCATE_BUFFER;  /* deallocate out_buff */
  629     dispatch_irp( device, irp, context );
  630 
  631     return STATUS_SUCCESS;
  632 }
  633 
  634 /* process a write request for a given device */
  635 static NTSTATUS dispatch_write( struct dispatch_context *context )
  636 {
  637     IRP *irp;
  638     LARGE_INTEGER offset;
  639     IO_STACK_LOCATION *irpsp;
  640     DEVICE_OBJECT *device;
  641     FILE_OBJECT *file = wine_server_get_ptr( context->params.write.file );
  642 
  643     if (!file) return STATUS_INVALID_HANDLE;
  644 
  645     device = IoGetAttachedDevice( file->DeviceObject );
  646 
  647     TRACE( "device %p file %p size %u\n", device, file, context->in_size );
  648 
  649     offset.QuadPart = context->params.write.pos;
  650 
  651     if (!(irp = IoBuildSynchronousFsdRequest( IRP_MJ_WRITE, device, context->in_buff, context->in_size,
  652                                               &offset, NULL, NULL )))
  653         return STATUS_NO_MEMORY;
  654     context->in_buff = NULL;
  655 
  656     irp->Tail.Overlay.OriginalFileObject = file;
  657     irp->RequestorMode = UserMode;
  658 
  659     irpsp = IoGetNextIrpStackLocation( irp );
  660     irpsp->FileObject = file;
  661     irpsp->Parameters.Write.Key = context->params.write.key;
  662 
  663     irp->Flags |= IRP_WRITE_OPERATION;
  664     irp->Flags |= IRP_DEALLOCATE_BUFFER;  /* deallocate in_buff */
  665     dispatch_irp( device, irp, context );
  666 
  667     return STATUS_SUCCESS;
  668 }
  669 
  670 /* process a flush request for a given device */
  671 static NTSTATUS dispatch_flush( struct dispatch_context *context )
  672 {
  673     IRP *irp;
  674     IO_STACK_LOCATION *irpsp;
  675     DEVICE_OBJECT *device;
  676     FILE_OBJECT *file = wine_server_get_ptr( context->params.flush.file );
  677 
  678     if (!file) return STATUS_INVALID_HANDLE;
  679 
  680     device = IoGetAttachedDevice( file->DeviceObject );
  681 
  682     TRACE( "device %p file %p\n", device, file );
  683 
  684     if (!(irp = IoBuildSynchronousFsdRequest( IRP_MJ_FLUSH_BUFFERS, device, NULL, 0,
  685                                               NULL, NULL, NULL )))
  686         return STATUS_NO_MEMORY;
  687 
  688     irp->Tail.Overlay.OriginalFileObject = file;
  689     irp->RequestorMode = UserMode;
  690 
  691     irpsp = IoGetNextIrpStackLocation( irp );
  692     irpsp->FileObject = file;
  693 
  694     dispatch_irp( device, irp, context );
  695 
  696     return STATUS_SUCCESS;
  697 }
  698 
  699 /* process an ioctl request for a given device */
  700 static NTSTATUS dispatch_ioctl( struct dispatch_context *context )
  701 {
  702     IO_STACK_LOCATION *irpsp;
  703     IRP *irp;
  704     void *out_buff = NULL;
  705     void *to_free = NULL;
  706     DEVICE_OBJECT *device;
  707     FILE_OBJECT *file = wine_server_get_ptr( context->params.ioctl.file );
  708     ULONG out_size = context->params.ioctl.out_size;
  709 
  710     if (!file) return STATUS_INVALID_HANDLE;
  711 
  712     device = IoGetAttachedDevice( file->DeviceObject );
  713 
  714     TRACE( "ioctl %x device %p file %p in_size %u out_size %u\n",
  715            context->params.ioctl.code, device, file, context->in_size, out_size );
  716 
  717     if (out_size)
  718     {
  719         if ((context->params.ioctl.code & 3) != METHOD_BUFFERED)
  720         {
  721             if (context->in_size < out_size) return STATUS_INVALID_DEVICE_REQUEST;
  722             context->in_size -= out_size;
  723             if (!(out_buff = HeapAlloc( GetProcessHeap(), 0, out_size ))) return STATUS_NO_MEMORY;
  724             memcpy( out_buff, (char *)context->in_buff + context->in_size, out_size );
  725         }
  726         else if (out_size > context->in_size)
  727         {
  728             if (!(out_buff = HeapAlloc( GetProcessHeap(), 0, out_size ))) return STATUS_NO_MEMORY;
  729             memcpy( out_buff, context->in_buff, context->in_size );
  730             to_free = context->in_buff;
  731             context->in_buff = out_buff;
  732         }
  733         else
  734             out_buff = context->in_buff;
  735     }
  736 
  737     irp = IoBuildDeviceIoControlRequest( context->params.ioctl.code, device, context->in_buff,
  738                                          context->in_size, out_buff, out_size, FALSE, NULL, NULL );
  739     if (!irp)
  740     {
  741         HeapFree( GetProcessHeap(), 0, out_buff );
  742         return STATUS_NO_MEMORY;
  743     }
  744 
  745     if (out_size && (context->params.ioctl.code & 3) != METHOD_BUFFERED)
  746         HeapReAlloc( GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, context->in_buff, context->in_size );
  747 
  748     irpsp = IoGetNextIrpStackLocation( irp );
  749     irpsp->FileObject = file;
  750 
  751     irp->Tail.Overlay.OriginalFileObject = file;
  752     irp->RequestorMode = UserMode;
  753     irp->AssociatedIrp.SystemBuffer = context->in_buff;
  754     context->in_buff = NULL;
  755 
  756     irp->Flags |= IRP_DEALLOCATE_BUFFER;  /* deallocate in_buff */
  757     dispatch_irp( device, irp, context );
  758 
  759     HeapFree( GetProcessHeap(), 0, to_free );
  760     return STATUS_SUCCESS;
  761 }
  762 
  763 static NTSTATUS dispatch_free( struct dispatch_context *context )
  764 {
  765     void *obj = wine_server_get_ptr( context->params.free.obj );
  766     TRACE( "freeing %p object\n", obj );
  767     free_kernel_object( obj );
  768     return STATUS_SUCCESS;
  769 }
  770 
  771 static NTSTATUS dispatch_cancel( struct dispatch_context *context )
  772 {
  773     IRP *irp = wine_server_get_ptr( context->params.cancel.irp );
  774 
  775     TRACE( "%p\n", irp );
  776 
  777     EnterCriticalSection( &irp_completion_cs );
  778     IoCancelIrp( irp );
  779     LeaveCriticalSection( &irp_completion_cs );
  780     return STATUS_SUCCESS;
  781 }
  782 
  783 typedef NTSTATUS (*dispatch_func)( struct dispatch_context *context );
  784 
  785 static const dispatch_func dispatch_funcs[] =
  786 {
  787     NULL,              /* IRP_CALL_NONE */
  788     dispatch_create,   /* IRP_CALL_CREATE */
  789     dispatch_close,    /* IRP_CALL_CLOSE */
  790     dispatch_read,     /* IRP_CALL_READ */
  791     dispatch_write,    /* IRP_CALL_WRITE */
  792     dispatch_flush,    /* IRP_CALL_FLUSH */
  793     dispatch_ioctl,    /* IRP_CALL_IOCTL */
  794     dispatch_free,     /* IRP_CALL_FREE */
  795     dispatch_cancel    /* IRP_CALL_CANCEL */
  796 };
  797 
  798 /* helper function to update service status */
  799 static void set_service_status( SERVICE_STATUS_HANDLE handle, DWORD state, DWORD accepted )
  800 {
  801     SERVICE_STATUS status;
  802     status.dwServiceType             = SERVICE_WIN32;
  803     status.dwCurrentState            = state;
  804     status.dwControlsAccepted        = accepted;
  805     status.dwWin32ExitCode           = 0;
  806     status.dwServiceSpecificExitCode = 0;
  807     status.dwCheckPoint              = 0;
  808     status.dwWaitHint                = (state == SERVICE_START_PENDING) ? 10000 : 0;
  809     SetServiceStatus( handle, &status );
  810 }
  811 
  812 static void unload_driver( struct wine_rb_entry *entry, void *context )
  813 {
  814     struct wine_driver *driver = WINE_RB_ENTRY_VALUE( entry, struct wine_driver, entry );
  815     SERVICE_STATUS_HANDLE service_handle = driver->service_handle;
  816     LDR_DATA_TABLE_ENTRY *ldr;
  817 
  818     if (!service_handle) return;    /* not a service */
  819 
  820     TRACE("%s\n", debugstr_us(&driver->driver_obj.DriverName));
  821 
  822     if (!driver->driver_obj.DriverUnload)
  823     {
  824         TRACE( "driver %s does not support unloading\n", debugstr_us(&driver->driver_obj.DriverName) );
  825         return;
  826     }
  827 
  828     ldr = driver->driver_obj.DriverSection;
  829 
  830     set_service_status( service_handle, SERVICE_STOP_PENDING, 0 );
  831 
  832     TRACE_(relay)( "\1Call driver unload %p (obj=%p)\n", driver->driver_obj.DriverUnload, &driver->driver_obj );
  833 
  834     driver->driver_obj.DriverUnload( &driver->driver_obj );
  835 
  836     TRACE_(relay)( "\1Ret  driver unload %p (obj=%p)\n", driver->driver_obj.DriverUnload, &driver->driver_obj );
  837 
  838     FreeLibrary( ldr->DllBase );
  839     IoDeleteDriver( &driver->driver_obj );
  840 
  841     set_service_status( service_handle, SERVICE_STOPPED, 0 );
  842     CloseServiceHandle( (void *)service_handle );
  843 }
  844 
  845 PEPROCESS PsInitialSystemProcess = NULL;
  846 
  847 /***********************************************************************
  848  *           wine_ntoskrnl_main_loop   (Not a Windows API)
  849  */
  850 NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event )
  851 {
  852     HANDLE manager = get_device_manager();
  853     struct dispatch_context context;
  854     NTSTATUS status = STATUS_SUCCESS;
  855     HANDLE handles[2];
  856 
  857     context.handle  = NULL;
  858     context.irp     = NULL;
  859     context.in_size = 4096;
  860     context.in_buff = NULL;
  861 
  862     /* Set the system process global before setting up the request thread trickery  */
  863     PsInitialSystemProcess = IoGetCurrentProcess();
  864     request_thread = GetCurrentThreadId();
  865 
  866     pnp_manager_start();
  867 
  868     handles[0] = stop_event;
  869     handles[1] = manager;
  870 
  871     for (;;)
  872     {
  873         NtCurrentTeb()->Reserved5[1] = NULL;
  874         if (!context.in_buff && !(context.in_buff = HeapAlloc( GetProcessHeap(), 0, context.in_size )))
  875         {
  876             ERR( "failed to allocate buffer\n" );
  877             status = STATUS_NO_MEMORY;
  878             goto done;
  879         }
  880 
  881         SERVER_START_REQ( get_next_device_request )
  882         {
  883             req->manager  = wine_server_obj_handle( manager );
  884             req->prev     = wine_server_obj_handle( context.handle );
  885             req->user_ptr = wine_server_client_ptr( context.irp );
  886             req->status   = status;
  887             wine_server_set_reply( req, context.in_buff, context.in_size );
  888             if (!(status = wine_server_call( req )))
  889             {
  890                 context.handle  = wine_server_ptr_handle( reply->next );
  891                 context.params  = reply->params;
  892                 context.in_size = reply->in_size;
  893                 client_tid = reply->client_tid;
  894                 NtCurrentTeb()->Reserved5[1] = wine_server_get_ptr( reply->client_thread );
  895             }
  896             else
  897             {
  898                 context.handle = 0; /* no previous irp */
  899                 if (status == STATUS_BUFFER_OVERFLOW)
  900                     context.in_size = reply->in_size;
  901             }
  902             context.irp = NULL;
  903         }
  904         SERVER_END_REQ;
  905 
  906         switch (status)
  907         {
  908         case STATUS_SUCCESS:
  909             assert( context.params.type != IRP_CALL_NONE && context.params.type < ARRAY_SIZE(dispatch_funcs) );
  910             status = dispatch_funcs[context.params.type]( &context );
  911             if (!context.in_buff) context.in_size = 4096;
  912             break;
  913         case STATUS_BUFFER_OVERFLOW:
  914             HeapFree( GetProcessHeap(), 0, context.in_buff );
  915             context.in_buff = NULL;
  916             /* restart with larger buffer */
  917             break;
  918         case STATUS_PENDING:
  919             for (;;)
  920             {
  921                 DWORD ret = WaitForMultipleObjectsEx( 2, handles, FALSE, INFINITE, TRUE );
  922                 if (ret == WAIT_OBJECT_0)
  923                 {
  924                     HeapFree( GetProcessHeap(), 0, context.in_buff );
  925                     status = STATUS_SUCCESS;
  926                     goto done;
  927                 }
  928                 if (ret != WAIT_IO_COMPLETION) break;
  929             }
  930             break;
  931         }
  932     }
  933 
  934 done:
  935     /* Native PnP drivers expect that all of their devices will be removed when
  936      * their unload routine is called, so we must stop the PnP manager first. */
  937     pnp_manager_stop();
  938     wine_rb_destroy( &wine_drivers, unload_driver, NULL );
  939     return status;
  940 }
  941 
  942 /***********************************************************************
  943  *           IoAllocateDriverObjectExtension  (NTOSKRNL.EXE.@)
  944  */
  945 NTSTATUS WINAPI IoAllocateDriverObjectExtension( PDRIVER_OBJECT DriverObject,
  946                                                  PVOID ClientIdentificationAddress,
  947                                                  ULONG DriverObjectExtensionSize,
  948                                                  PVOID *DriverObjectExtension )
  949 {
  950     FIXME( "stub: %p, %p, %u, %p\n", DriverObject, ClientIdentificationAddress,
  951             DriverObjectExtensionSize, DriverObjectExtension );
  952     return STATUS_NOT_IMPLEMENTED;
  953 }
  954 
  955 
  956 /***********************************************************************
  957  *           IoGetDriverObjectExtension  (NTOSKRNL.EXE.@)
  958  */
  959 PVOID WINAPI IoGetDriverObjectExtension( PDRIVER_OBJECT DriverObject,
  960                                          PVOID ClientIdentificationAddress )
  961 {
  962     FIXME( "stub: %p, %p\n", DriverObject, ClientIdentificationAddress );
  963     return NULL;
  964 }
  965 
  966 
  967 /***********************************************************************
  968  *           IoInitializeIrp  (NTOSKRNL.EXE.@)
  969  */
  970 void WINAPI IoInitializeIrp( IRP *irp, USHORT size, CCHAR stack_size )
  971 {
  972     TRACE( "%p, %u, %d\n", irp, size, stack_size );
  973 
  974     RtlZeroMemory( irp, size );
  975 
  976     irp->Type = IO_TYPE_IRP;
  977     irp->Size = size;
  978     InitializeListHead( &irp->ThreadListEntry );
  979     irp->StackCount = stack_size;
  980     irp->CurrentLocation = stack_size + 1;
  981     irp->Tail.Overlay.s.u2.CurrentStackLocation =
  982             (PIO_STACK_LOCATION)(irp + 1) + stack_size;
  983 }
  984 
  985 void WINAPI IoReuseIrp(IRP *irp, NTSTATUS iostatus)
  986 {
  987     UCHAR AllocationFlags;
  988 
  989     TRACE("irp %p, iostatus %#x.\n", irp, iostatus);
  990 
  991     AllocationFlags = irp->AllocationFlags;
  992     IoInitializeIrp(irp, irp->Size, irp->StackCount);
  993     irp->AllocationFlags = AllocationFlags;
  994     irp->IoStatus.u.Status = iostatus;
  995 }
  996 
  997 /***********************************************************************
  998  *           IoInitializeTimer   (NTOSKRNL.EXE.@)
  999  */
 1000 NTSTATUS WINAPI IoInitializeTimer(PDEVICE_OBJECT DeviceObject,
 1001                                   PIO_TIMER_ROUTINE TimerRoutine,
 1002                                   PVOID Context)
 1003 {
 1004     FIXME( "stub: %p, %p, %p\n", DeviceObject, TimerRoutine, Context );
 1005     return STATUS_NOT_IMPLEMENTED;
 1006 }
 1007 
 1008 
 1009 /***********************************************************************
 1010  *           IoStartTimer   (NTOSKRNL.EXE.@)
 1011  */
 1012 void WINAPI IoStartTimer(PDEVICE_OBJECT DeviceObject)
 1013 {
 1014     FIXME( "stub: %p\n", DeviceObject );
 1015 }
 1016 
 1017 
 1018 /***********************************************************************
 1019  *           IoStopTimer   (NTOSKRNL.EXE.@)
 1020  */
 1021 void WINAPI IoStopTimer(PDEVICE_OBJECT DeviceObject)
 1022 {
 1023     FIXME( "stub: %p\n", DeviceObject );
 1024 }
 1025 
 1026 
 1027 /***********************************************************************
 1028  *           IoAllocateIrp  (NTOSKRNL.EXE.@)
 1029  */
 1030 PIRP WINAPI IoAllocateIrp( CCHAR stack_size, BOOLEAN charge_quota )
 1031 {
 1032     SIZE_T size;
 1033     PIRP irp;
 1034     CCHAR loc_count = stack_size;
 1035 
 1036     TRACE( "%d, %d\n", stack_size, charge_quota );
 1037 
 1038     if (loc_count < 8 && loc_count != 1)
 1039         loc_count = 8;
 1040 
 1041     size = sizeof(IRP) + loc_count * sizeof(IO_STACK_LOCATION);
 1042     irp = ExAllocatePool( NonPagedPool, size );
 1043     if (irp == NULL)
 1044         return NULL;
 1045     IoInitializeIrp( irp, size, stack_size );
 1046     if (stack_size >= 1 && stack_size <= 8)
 1047         irp->AllocationFlags = IRP_ALLOCATED_FIXED_SIZE;
 1048     if (charge_quota)
 1049         irp->AllocationFlags |= IRP_LOOKASIDE_ALLOCATION;
 1050     return irp;
 1051 }
 1052 
 1053 
 1054 /***********************************************************************
 1055  *           IoFreeIrp  (NTOSKRNL.EXE.@)
 1056  */
 1057 void WINAPI IoFreeIrp( IRP *irp )
 1058 {
 1059     MDL *mdl;
 1060 
 1061     TRACE( "%p\n", irp );
 1062 
 1063     mdl = irp->MdlAddress;
 1064     while (mdl)
 1065     {
 1066         MDL *next = mdl->Next;
 1067         IoFreeMdl( mdl );
 1068         mdl = next;
 1069     }
 1070 
 1071     ExFreePool( irp );
 1072 }
 1073 
 1074 
 1075 /***********************************************************************
 1076  *           IoAllocateErrorLogEntry  (NTOSKRNL.EXE.@)
 1077  */
 1078 PVOID WINAPI IoAllocateErrorLogEntry( PVOID IoObject, UCHAR EntrySize )
 1079 {
 1080     FIXME( "stub: %p, %u\n", IoObject, EntrySize );
 1081     return NULL;
 1082 }
 1083 
 1084 
 1085 /***********************************************************************
 1086  *           IoAllocateMdl  (NTOSKRNL.EXE.@)
 1087  */
 1088 PMDL WINAPI IoAllocateMdl( PVOID va, ULONG length, BOOLEAN secondary, BOOLEAN charge_quota, IRP *irp )
 1089 {
 1090     SIZE_T mdl_size;
 1091     PMDL mdl;
 1092 
 1093     TRACE("(%p, %u, %i, %i, %p)\n", va, length, secondary, charge_quota, irp);
 1094 
 1095     if (charge_quota)
 1096         FIXME("Charge quota is not yet supported\n");
 1097 
 1098     mdl_size = sizeof(MDL) + sizeof(PFN_NUMBER) * ADDRESS_AND_SIZE_TO_SPAN_PAGES(va, length);
 1099     mdl = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, mdl_size );
 1100     if (!mdl)
 1101         return NULL;
 1102 
 1103     MmInitializeMdl( mdl, va, length );
 1104 
 1105     if (!irp) return mdl;
 1106 
 1107     if (secondary)  /* add it at the end */
 1108     {
 1109         MDL **pmdl = &irp->MdlAddress;
 1110         while (*pmdl) pmdl = &(*pmdl)->Next;
 1111         *pmdl = mdl;
 1112     }
 1113     else
 1114     {
 1115         mdl->Next = irp->MdlAddress;
 1116         irp->MdlAddress = mdl;
 1117     }
 1118     return mdl;
 1119 }
 1120 
 1121 
 1122 /***********************************************************************
 1123  *           IoFreeMdl  (NTOSKRNL.EXE.@)
 1124  */
 1125 void WINAPI IoFreeMdl(PMDL mdl)
 1126 {
 1127     TRACE("%p\n", mdl);
 1128     HeapFree(GetProcessHeap(), 0, mdl);
 1129 }
 1130 
 1131 
 1132 struct _IO_WORKITEM
 1133 {
 1134     DEVICE_OBJECT *device;
 1135     PIO_WORKITEM_ROUTINE worker;
 1136     void *context;
 1137 };
 1138 
 1139 /***********************************************************************
 1140  *           IoAllocateWorkItem  (NTOSKRNL.EXE.@)
 1141  */
 1142 PIO_WORKITEM WINAPI IoAllocateWorkItem( PDEVICE_OBJECT device )
 1143 {
 1144     PIO_WORKITEM work_item;
 1145 
 1146     TRACE( "%p\n", device );
 1147 
 1148     if (!(work_item = ExAllocatePool( PagedPool, sizeof(*work_item) ))) return NULL;
 1149     work_item->device = device;
 1150     return work_item;
 1151 }
 1152 
 1153 
 1154 /***********************************************************************
 1155  *           IoFreeWorkItem  (NTOSKRNL.EXE.@)
 1156  */
 1157 void WINAPI IoFreeWorkItem( PIO_WORKITEM work_item )
 1158 {
 1159     TRACE( "%p\n", work_item );
 1160     ExFreePool( work_item );
 1161 }
 1162 
 1163 
 1164 static void WINAPI run_work_item_worker(TP_CALLBACK_INSTANCE *instance, void *context)
 1165 {
 1166     PIO_WORKITEM work_item = context;
 1167     DEVICE_OBJECT *device = work_item->device;
 1168 
 1169     TRACE( "%p: calling %p(%p %p)\n", work_item, work_item->worker, device, work_item->context );
 1170     work_item->worker( device, work_item->context );
 1171     TRACE( "done\n" );
 1172 
 1173     ObDereferenceObject( device );
 1174 }
 1175 
 1176 /***********************************************************************
 1177  *           IoQueueWorkItem  (NTOSKRNL.EXE.@)
 1178  */
 1179 void WINAPI IoQueueWorkItem( PIO_WORKITEM work_item, PIO_WORKITEM_ROUTINE worker,
 1180                              WORK_QUEUE_TYPE type, void *context )
 1181 {
 1182     TRACE( "%p %p %u %p\n", work_item, worker, type, context );
 1183 
 1184     ObReferenceObject( work_item->device );
 1185     work_item->worker = worker;
 1186     work_item->context = context;
 1187     TrySubmitThreadpoolCallback( run_work_item_worker, work_item, NULL );
 1188 }
 1189 
 1190 /***********************************************************************
 1191  *           IoGetAttachedDevice   (NTOSKRNL.EXE.@)
 1192  */
 1193 DEVICE_OBJECT* WINAPI IoGetAttachedDevice( DEVICE_OBJECT *device )
 1194 {
 1195     DEVICE_OBJECT *result = device;
 1196 
 1197     TRACE( "(%p)\n", device );
 1198 
 1199     while (result->AttachedDevice)
 1200         result = result->AttachedDevice;
 1201 
 1202     return result;
 1203 }
 1204 
 1205 void WINAPI IoDetachDevice( DEVICE_OBJECT *device )
 1206 {
 1207     device->AttachedDevice = NULL;
 1208 }
 1209 
 1210 /***********************************************************************
 1211  *           IoAttachDeviceToDeviceStack  (NTOSKRNL.EXE.@)
 1212  */
 1213 PDEVICE_OBJECT WINAPI IoAttachDeviceToDeviceStack( DEVICE_OBJECT *source,
 1214                                                    DEVICE_OBJECT *target )
 1215 {
 1216     TRACE( "%p, %p\n", source, target );
 1217     target = IoGetAttachedDevice( target );
 1218     target->AttachedDevice = source;
 1219     source->StackSize = target->StackSize + 1;
 1220     return target;
 1221 }
 1222 
 1223 /***********************************************************************
 1224  *           IoBuildDeviceIoControlRequest  (NTOSKRNL.EXE.@)
 1225  */
 1226 PIRP WINAPI IoBuildDeviceIoControlRequest( ULONG code, PDEVICE_OBJECT device,
 1227                                            PVOID in_buff, ULONG in_len,
 1228                                            PVOID out_buff, ULONG out_len,
 1229                                            BOOLEAN internal, PKEVENT event,
 1230                                            PIO_STATUS_BLOCK iosb )
 1231 {
 1232     PIRP irp;
 1233     PIO_STACK_LOCATION irpsp;
 1234     MDL *mdl;
 1235 
 1236     TRACE( "%x, %p, %p, %u, %p, %u, %u, %p, %p\n",
 1237            code, device, in_buff, in_len, out_buff, out_len, internal, event, iosb );
 1238 
 1239     if (device == NULL)
 1240         return NULL;
 1241 
 1242     irp = IoAllocateIrp( device->StackSize, FALSE );
 1243     if (irp == NULL)
 1244         return NULL;
 1245 
 1246     irpsp = IoGetNextIrpStackLocation( irp );
 1247     irpsp->MajorFunction = internal ? IRP_MJ_INTERNAL_DEVICE_CONTROL : IRP_MJ_DEVICE_CONTROL;
 1248     irpsp->Parameters.DeviceIoControl.IoControlCode = code;
 1249     irpsp->Parameters.DeviceIoControl.InputBufferLength = in_len;
 1250     irpsp->Parameters.DeviceIoControl.OutputBufferLength = out_len;
 1251     irpsp->DeviceObject = NULL;
 1252     irpsp->CompletionRoutine = NULL;
 1253 
 1254     switch (code & 3)
 1255     {
 1256     case METHOD_BUFFERED:
 1257         irp->AssociatedIrp.SystemBuffer = in_buff;
 1258         break;
 1259     case METHOD_IN_DIRECT:
 1260     case METHOD_OUT_DIRECT:
 1261         irp->AssociatedIrp.SystemBuffer = in_buff;
 1262 
 1263         mdl = IoAllocateMdl( out_buff, out_len, FALSE, FALSE, irp );
 1264         if (!mdl)
 1265         {
 1266             IoFreeIrp( irp );
 1267             return NULL;
 1268         }
 1269 
 1270         mdl->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA;
 1271         mdl->MappedSystemVa = out_buff;
 1272         break;
 1273     case METHOD_NEITHER:
 1274         irpsp->Parameters.DeviceIoControl.Type3InputBuffer = in_buff;
 1275         break;
 1276     }
 1277 
 1278     irp->RequestorMode = KernelMode;
 1279     irp->UserBuffer = out_buff;
 1280     irp->UserIosb = iosb;
 1281     irp->UserEvent = event;
 1282     irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
 1283     return irp;
 1284 }
 1285 
 1286 /***********************************************************************
 1287  *           IoBuildAsynchronousFsdRequest  (NTOSKRNL.EXE.@)
 1288  */
 1289 PIRP WINAPI IoBuildAsynchronousFsdRequest(ULONG majorfunc, DEVICE_OBJECT *device,
 1290                                           void *buffer, ULONG length, LARGE_INTEGER *startoffset,
 1291                                           IO_STATUS_BLOCK *iosb)
 1292 {
 1293     PIRP irp;
 1294     PIO_STACK_LOCATION irpsp;
 1295 
 1296     TRACE( "(%d %p %p %d %p %p)\n", majorfunc, device, buffer, length, startoffset, iosb );
 1297 
 1298     if (!(irp = IoAllocateIrp( device->StackSize, FALSE ))) return NULL;
 1299 
 1300     irpsp = IoGetNextIrpStackLocation( irp );
 1301     irpsp->MajorFunction = majorfunc;
 1302     irpsp->DeviceObject = NULL;
 1303     irpsp->CompletionRoutine = NULL;
 1304 
 1305     irp->AssociatedIrp.SystemBuffer = buffer;
 1306 
 1307     if (device->Flags & DO_DIRECT_IO)
 1308     {
 1309         MDL *mdl = IoAllocateMdl( buffer, length, FALSE, FALSE, irp );
 1310         if (!mdl)
 1311         {
 1312             IoFreeIrp( irp );
 1313             return NULL;
 1314         }
 1315 
 1316         mdl->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA;
 1317         mdl->MappedSystemVa = buffer;
 1318     }
 1319 
 1320     switch (majorfunc)
 1321     {
 1322     case IRP_MJ_READ:
 1323         irpsp->Parameters.Read.Length = length;
 1324         irpsp->Parameters.Read.ByteOffset.QuadPart = startoffset ? startoffset->QuadPart : 0;
 1325         break;
 1326     case IRP_MJ_WRITE:
 1327         irpsp->Parameters.Write.Length = length;
 1328         irpsp->Parameters.Write.ByteOffset.QuadPart = startoffset ? startoffset->QuadPart : 0;
 1329         break;
 1330     }
 1331     irp->RequestorMode = KernelMode;
 1332     irp->UserIosb = iosb;
 1333     irp->UserEvent = NULL;
 1334     irp->UserBuffer = buffer;
 1335     irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
 1336     return irp;
 1337 }
 1338 
 1339 
 1340 
 1341 /***********************************************************************
 1342  *           IoBuildSynchronousFsdRequest  (NTOSKRNL.EXE.@)
 1343  */
 1344 PIRP WINAPI IoBuildSynchronousFsdRequest(ULONG majorfunc, PDEVICE_OBJECT device,
 1345                                          PVOID buffer, ULONG length, PLARGE_INTEGER startoffset,
 1346                                          PKEVENT event, PIO_STATUS_BLOCK iosb)
 1347 {
 1348     IRP *irp;
 1349 
 1350     TRACE("(%d %p %p %d %p %p)\n", majorfunc, device, buffer, length, startoffset, iosb);
 1351 
 1352     irp = IoBuildAsynchronousFsdRequest( majorfunc, device, buffer, length, startoffset, iosb );
 1353     if (!irp) return NULL;
 1354 
 1355     irp->UserEvent = event;
 1356     return irp;
 1357 }
 1358 
 1359 static void build_driver_keypath( const WCHAR *name, UNICODE_STRING *keypath )
 1360 {
 1361     static const WCHAR driverW[] = {'\\','D','r','i','v','e','r','\\',0};
 1362     WCHAR *str;
 1363 
 1364     /* Check what prefix is present */
 1365     if (wcsncmp( name, servicesW, lstrlenW(servicesW) ) == 0)
 1366     {
 1367         FIXME( "Driver name %s is malformed as the keypath\n", debugstr_w(name) );
 1368         RtlCreateUnicodeString( keypath, name );
 1369         return;
 1370     }
 1371     if (wcsncmp( name, driverW, lstrlenW(driverW) ) == 0)
 1372         name += lstrlenW(driverW);
 1373     else
 1374         FIXME( "Driver name %s does not properly begin with \\Driver\\\n", debugstr_w(name) );
 1375 
 1376     str = HeapAlloc( GetProcessHeap(), 0, sizeof(servicesW) + lstrlenW(name)*sizeof(WCHAR));
 1377     lstrcpyW( str, servicesW );
 1378     lstrcatW( str, name );
 1379     RtlInitUnicodeString( keypath, str );
 1380 }
 1381 
 1382 
 1383 static NTSTATUS WINAPI unhandled_irp( DEVICE_OBJECT *device, IRP *irp )
 1384 {
 1385     TRACE( "(%p, %p)\n", device, irp );
 1386     irp->IoStatus.u.Status = STATUS_INVALID_DEVICE_REQUEST;
 1387     IoCompleteRequest( irp, IO_NO_INCREMENT );
 1388     return STATUS_INVALID_DEVICE_REQUEST;
 1389 }
 1390 
 1391 
 1392 static void free_driver_object( void *obj )
 1393 {
 1394     struct wine_driver *driver = obj;
 1395     RtlFreeUnicodeString( &driver->driver_obj.DriverName );
 1396     RtlFreeUnicodeString( &driver->driver_obj.DriverExtension->ServiceKeyName );
 1397     free_kernel_object( driver );
 1398 }
 1399 
 1400 static const WCHAR driver_type_name[] = {'D','r','i','v','e','r',0};
 1401 
 1402 static struct _OBJECT_TYPE driver_type =
 1403 {
 1404     driver_type_name,
 1405     NULL,
 1406     free_driver_object
 1407 };
 1408 
 1409 POBJECT_TYPE IoDriverObjectType = &driver_type;
 1410 
 1411 
 1412 /***********************************************************************
 1413  *           IoCreateDriver   (NTOSKRNL.EXE.@)
 1414  */
 1415 NTSTATUS WINAPI IoCreateDriver( UNICODE_STRING *name, PDRIVER_INITIALIZE init )
 1416 {
 1417     struct wine_driver *driver;
 1418     NTSTATUS status;
 1419     unsigned int i;
 1420 
 1421     TRACE("(%s, %p)\n", debugstr_us(name), init);
 1422 
 1423     if (!(driver = alloc_kernel_object( IoDriverObjectType, NULL, sizeof(*driver), 1 )))
 1424         return STATUS_NO_MEMORY;
 1425 
 1426     if ((status = RtlDuplicateUnicodeString( 1, name, &driver->driver_obj.DriverName )))
 1427     {
 1428         free_kernel_object( driver );
 1429         return status;
 1430     }
 1431 
 1432     driver->driver_obj.Size            = sizeof(driver->driver_obj);
 1433     driver->driver_obj.DriverInit      = init;
 1434     driver->driver_obj.DriverExtension = &driver->driver_extension;
 1435     driver->driver_extension.DriverObject   = &driver->driver_obj;
 1436     build_driver_keypath( driver->driver_obj.DriverName.Buffer, &driver->driver_extension.ServiceKeyName );
 1437     for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
 1438         driver->driver_obj.MajorFunction[i] = unhandled_irp;
 1439 
 1440     EnterCriticalSection( &drivers_cs );
 1441     if (wine_rb_put( &wine_drivers, &driver->driver_obj.DriverName, &driver->entry ))
 1442         ERR( "failed to insert driver %s in tree\n", debugstr_us(name) );
 1443     LeaveCriticalSection( &drivers_cs );
 1444 
 1445     status = driver->driver_obj.DriverInit( &driver->driver_obj, &driver->driver_extension.ServiceKeyName );
 1446     if (status)
 1447     {
 1448         IoDeleteDriver( &driver->driver_obj );
 1449         return status;
 1450     }
 1451 
 1452     for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
 1453     {
 1454         if (driver->driver_obj.MajorFunction[i]) continue;
 1455         driver->driver_obj.MajorFunction[i] = unhandled_irp;
 1456     }
 1457 
 1458     return STATUS_SUCCESS;
 1459 }
 1460 
 1461 
 1462 /***********************************************************************
 1463  *           IoDeleteDriver   (NTOSKRNL.EXE.@)
 1464  */
 1465 void WINAPI IoDeleteDriver( DRIVER_OBJECT *driver_object )
 1466 {
 1467     TRACE( "(%p)\n", driver_object );
 1468 
 1469     EnterCriticalSection( &drivers_cs );
 1470     wine_rb_remove_key( &wine_drivers, &driver_object->DriverName );
 1471     LeaveCriticalSection( &drivers_cs );
 1472 
 1473     ObDereferenceObject( driver_object );
 1474 }
 1475 
 1476 
 1477 static const WCHAR device_type_name[] = {'D','e','v','i','c','e',0};
 1478 
 1479 static struct _OBJECT_TYPE device_type =
 1480 {
 1481     device_type_name,
 1482 };
 1483 
 1484 POBJECT_TYPE IoDeviceObjectType = &device_type;
 1485 
 1486 
 1487 /***********************************************************************
 1488  *           IoCreateDevice   (NTOSKRNL.EXE.@)
 1489  */
 1490 NTSTATUS WINAPI IoCreateDevice( DRIVER_OBJECT *driver, ULONG ext_size,
 1491                                 UNICODE_STRING *name, DEVICE_TYPE type,
 1492                                 ULONG characteristics, BOOLEAN exclusive,
 1493                                 DEVICE_OBJECT **ret_device )
 1494 {
 1495     static const WCHAR auto_format[] = {'\\','D','e','v','i','c','e','\\','%','0','8','x',0};
 1496     NTSTATUS status;
 1497     struct wine_device *wine_device;
 1498     DEVICE_OBJECT *device;
 1499     HANDLE manager = get_device_manager();
 1500     static unsigned int auto_idx = 0;
 1501     WCHAR autoW[17];
 1502 
 1503     TRACE( "(%p, %u, %s, %u, %x, %u, %p)\n",
 1504            driver, ext_size, debugstr_us(name), type, characteristics, exclusive, ret_device );
 1505 
 1506     if (!(wine_device = alloc_kernel_object( IoDeviceObjectType, NULL, sizeof(struct wine_device) + ext_size, 1 )))
 1507         return STATUS_NO_MEMORY;
 1508     device = &wine_device->device_obj;
 1509 
 1510     device->DriverObject    = driver;
 1511     device->DeviceExtension = wine_device + 1;
 1512     device->DeviceType      = type;
 1513     device->StackSize       = 1;
 1514 
 1515     if (characteristics & FILE_AUTOGENERATED_DEVICE_NAME)
 1516     {
 1517         do
 1518         {
 1519             swprintf( autoW, ARRAY_SIZE(autoW), auto_format, auto_idx++ );
 1520             SERVER_START_REQ( create_device )
 1521             {
 1522                 req->rootdir    = 0;
 1523                 req->manager    = wine_server_obj_handle( manager );
 1524                 req->user_ptr   = wine_server_client_ptr( device );
 1525                 wine_server_add_data( req, autoW, lstrlenW(autoW) * sizeof(WCHAR) );
 1526                 status = wine_server_call( req );
 1527             }
 1528             SERVER_END_REQ;
 1529         } while (status == STATUS_OBJECT_NAME_COLLISION);
 1530     }
 1531     else
 1532     {
 1533         SERVER_START_REQ( create_device )
 1534         {
 1535             req->rootdir    = 0;
 1536             req->manager    = wine_server_obj_handle( manager );
 1537             req->user_ptr   = wine_server_client_ptr( device );
 1538             if (name) wine_server_add_data( req, name->Buffer, name->Length );
 1539             status = wine_server_call( req );
 1540         }
 1541         SERVER_END_REQ;
 1542     }
 1543 
 1544     if (status)
 1545     {
 1546         free_kernel_object( device );
 1547         return status;
 1548     }
 1549 
 1550     device->NextDevice   = driver->DeviceObject;
 1551     driver->DeviceObject = device;
 1552 
 1553     *ret_device = device;
 1554     return STATUS_SUCCESS;
 1555 }
 1556 
 1557 
 1558 /***********************************************************************
 1559  *           IoDeleteDevice   (NTOSKRNL.EXE.@)
 1560  */
 1561 void WINAPI IoDeleteDevice( DEVICE_OBJECT *device )
 1562 {
 1563     NTSTATUS status;
 1564 
 1565     TRACE( "%p\n", device );
 1566 
 1567     SERVER_START_REQ( delete_device )
 1568     {
 1569         req->manager = wine_server_obj_handle( get_device_manager() );
 1570         req->device  = wine_server_client_ptr( device );
 1571         status = wine_server_call( req );
 1572     }
 1573     SERVER_END_REQ;
 1574 
 1575     if (status == STATUS_SUCCESS)
 1576     {
 1577         struct wine_device *wine_device = CONTAINING_RECORD(device, struct wine_device, device_obj);
 1578         DEVICE_OBJECT **prev = &device->DriverObject->DeviceObject;
 1579         while (*prev && *prev != device) prev = &(*prev)->NextDevice;
 1580         if (*prev) *prev = (*prev)->NextDevice;
 1581         ExFreePool( wine_device->children );
 1582         ObDereferenceObject( device );
 1583     }
 1584 }
 1585 
 1586 
 1587 /***********************************************************************
 1588  *           IoCreateSymbolicLink   (NTOSKRNL.EXE.@)
 1589  */
 1590 NTSTATUS WINAPI IoCreateSymbolicLink( UNICODE_STRING *name, UNICODE_STRING *target )
 1591 {
 1592     HANDLE handle;
 1593     OBJECT_ATTRIBUTES attr;
 1594     NTSTATUS ret;
 1595 
 1596     attr.Length                   = sizeof(attr);
 1597     attr.RootDirectory            = 0;
 1598     attr.ObjectName               = name;
 1599     attr.Attributes               = OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT;
 1600     attr.SecurityDescriptor       = NULL;
 1601     attr.SecurityQualityOfService = NULL;
 1602 
 1603     TRACE( "%s -> %s\n", debugstr_us(name), debugstr_us(target) );
 1604     if (!(ret = NtCreateSymbolicLinkObject( &handle, SYMBOLIC_LINK_ALL_ACCESS, &attr, target )))
 1605         NtClose( handle );
 1606     return ret;
 1607 }
 1608 
 1609 
 1610 /***********************************************************************
 1611  *           IoCreateUnprotectedSymbolicLink   (NTOSKRNL.EXE.@)
 1612  */
 1613 NTSTATUS WINAPI IoCreateUnprotectedSymbolicLink( UNICODE_STRING *name, UNICODE_STRING *target )
 1614 {
 1615     HANDLE handle;
 1616     OBJECT_ATTRIBUTES attr;
 1617     NTSTATUS ret;
 1618 
 1619     attr.Length                   = sizeof(attr);
 1620     attr.RootDirectory            = 0;
 1621     attr.ObjectName               = name;
 1622     attr.Attributes               = OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT;
 1623     attr.SecurityDescriptor       = NULL;
 1624     attr.SecurityQualityOfService = NULL;
 1625 
 1626     TRACE( "%s -> %s\n", debugstr_us(name), debugstr_us(target) );
 1627     if (!(ret = NtCreateSymbolicLinkObject( &handle, SYMBOLIC_LINK_ALL_ACCESS, &attr, target )))
 1628         NtClose( handle );
 1629     return ret;
 1630 }
 1631 
 1632 
 1633 /***********************************************************************
 1634  *           IoDeleteSymbolicLink   (NTOSKRNL.EXE.@)
 1635  */
 1636 NTSTATUS WINAPI IoDeleteSymbolicLink( UNICODE_STRING *name )
 1637 {
 1638     HANDLE handle;
 1639     OBJECT_ATTRIBUTES attr;
 1640     NTSTATUS status;
 1641 
 1642     attr.Length                   = sizeof(attr);
 1643     attr.RootDirectory            = 0;
 1644     attr.ObjectName               = name;
 1645     attr.Attributes               = OBJ_CASE_INSENSITIVE;
 1646     attr.SecurityDescriptor       = NULL;
 1647     attr.SecurityQualityOfService = NULL;
 1648 
 1649     if (!(status = NtOpenSymbolicLinkObject( &handle, 0, &attr )))
 1650     {
 1651         NtMakeTemporaryObject( handle );
 1652         NtClose( handle );
 1653     }
 1654     return status;
 1655 }
 1656 
 1657 /***********************************************************************
 1658  *           IoGetDeviceInterfaces   (NTOSKRNL.EXE.@)
 1659  */
 1660 NTSTATUS WINAPI IoGetDeviceInterfaces( const GUID *InterfaceClassGuid,
 1661                                        PDEVICE_OBJECT PhysicalDeviceObject,
 1662                                        ULONG Flags, PWSTR *SymbolicLinkList )
 1663 {
 1664     FIXME( "stub: %s %p %x %p\n", debugstr_guid(InterfaceClassGuid),
 1665            PhysicalDeviceObject, Flags, SymbolicLinkList );
 1666     return STATUS_NOT_IMPLEMENTED;
 1667 }
 1668 
 1669 
 1670 /***********************************************************************
 1671  *           IoGetDeviceObjectPointer   (NTOSKRNL.EXE.@)
 1672  */
 1673 NTSTATUS  WINAPI IoGetDeviceObjectPointer( UNICODE_STRING *name, ACCESS_MASK access, PFILE_OBJECT *file, PDEVICE_OBJECT *device )
 1674 {
 1675     static DEVICE_OBJECT stub_device;
 1676     static DRIVER_OBJECT stub_driver;
 1677 
 1678     FIXME( "stub: %s %x %p %p\n", debugstr_us(name), access, file, device );
 1679 
 1680     stub_device.StackSize = 0x80; /* minimum value to appease SecuROM 5.x */
 1681     stub_device.DriverObject = &stub_driver;
 1682 
 1683     *file  = NULL;
 1684     *device = &stub_device;
 1685 
 1686     return STATUS_SUCCESS;
 1687 }
 1688 
 1689 /***********************************************************************
 1690  *           IoCallDriver   (NTOSKRNL.EXE.@)
 1691  */
 1692 NTSTATUS WINAPI IoCallDriver( DEVICE_OBJECT *device, IRP *irp )
 1693 {
 1694     PDRIVER_DISPATCH dispatch;
 1695     IO_STACK_LOCATION *irpsp;
 1696     NTSTATUS status;
 1697 
 1698     --irp->CurrentLocation;
 1699     irpsp = --irp->Tail.Overlay.s.u2.CurrentStackLocation;
 1700     irpsp->DeviceObject = device;
 1701     dispatch = device->DriverObject->MajorFunction[irpsp->MajorFunction];
 1702 
 1703     TRACE_(relay)( "\1Call driver dispatch %p (device=%p,irp=%p)\n", dispatch, device, irp );
 1704 
 1705     status = dispatch( device, irp );
 1706 
 1707     TRACE_(relay)( "\1Ret  driver dispatch %p (device=%p,irp=%p) retval=%08x\n",
 1708                    dispatch, device, irp, status );
 1709 
 1710     return status;
 1711 }
 1712 
 1713 
 1714 /***********************************************************************
 1715  *           IofCallDriver   (NTOSKRNL.EXE.@)
 1716  */
 1717 DEFINE_FASTCALL_WRAPPER( IofCallDriver, 8 )
 1718 NTSTATUS FASTCALL IofCallDriver( DEVICE_OBJECT *device, IRP *irp )
 1719 {
 1720     TRACE( "%p %p\n", device, irp );
 1721     return IoCallDriver( device, irp );
 1722 }
 1723 
 1724 
 1725 /***********************************************************************
 1726  *           IoGetRelatedDeviceObject    (NTOSKRNL.EXE.@)
 1727  */
 1728 PDEVICE_OBJECT WINAPI IoGetRelatedDeviceObject( PFILE_OBJECT obj )
 1729 {
 1730     FIXME( "stub: %p\n", obj );
 1731     return NULL;
 1732 }
 1733 
 1734 static CONFIGURATION_INFORMATION configuration_information;
 1735 
 1736 /***********************************************************************
 1737  *           IoGetConfigurationInformation    (NTOSKRNL.EXE.@)
 1738  */
 1739 PCONFIGURATION_INFORMATION WINAPI IoGetConfigurationInformation(void)
 1740 {
 1741     FIXME( "partial stub\n" );
 1742     /* FIXME: return actual devices on system */
 1743     return &configuration_information;
 1744 }
 1745 
 1746 /***********************************************************************
 1747  *           IoGetStackLimits    (NTOSKRNL.EXE.@)
 1748  */
 1749 void WINAPI IoGetStackLimits(ULONG_PTR *low, ULONG_PTR *high)
 1750 {
 1751     TEB *teb = NtCurrentTeb();
 1752 
 1753     TRACE( "%p %p\n", low, high );
 1754 
 1755     *low  = (DWORD_PTR)teb->Tib.StackLimit;
 1756     *high = (DWORD_PTR)teb->Tib.StackBase;
 1757 }
 1758 
 1759 /***********************************************************************
 1760  *           IoIsWdmVersionAvailable     (NTOSKRNL.EXE.@)
 1761  */
 1762 NTSTATUS WINAPI IoIsWdmVersionAvailable(UCHAR MajorVersion, UCHAR MinorVersion)
 1763 {
 1764     DWORD version;
 1765     DWORD major;
 1766     DWORD minor;
 1767 
 1768     TRACE( "%d, 0x%X\n", MajorVersion, MinorVersion );
 1769 
 1770     version = GetVersion();
 1771     major = LOBYTE(version);
 1772     minor = HIBYTE(LOWORD(version));
 1773 
 1774     if (MajorVersion == 6 && MinorVersion == 0)
 1775     {
 1776         /* Windows Vista, Windows Server 2008, Windows 7 */
 1777     }
 1778     else if (MajorVersion == 1)
 1779     {
 1780         if (MinorVersion == 0x30)
 1781         {
 1782             /* Windows server 2003 */
 1783             MajorVersion = 6;
 1784             MinorVersion = 0;
 1785         }
 1786         else if (MinorVersion == 0x20)
 1787         {
 1788             /* Windows XP */
 1789             MajorVersion = 5;
 1790             MinorVersion = 1;
 1791         }
 1792         else if (MinorVersion == 0x10)
 1793         {
 1794             /* Windows 2000 */
 1795             MajorVersion = 5;
 1796             MinorVersion = 0;
 1797         }
 1798         else if (MinorVersion == 0x05)
 1799         {
 1800             /* Windows ME */
 1801             MajorVersion = 4;
 1802             MinorVersion = 0x5a;
 1803         }
 1804         else if (MinorVersion == 0x00)
 1805         {
 1806             /* Windows 98 */
 1807             MajorVersion = 4;
 1808             MinorVersion = 0x0a;
 1809         }
 1810         else
 1811         {
 1812             FIXME( "unknown major %d minor 0x%X\n", MajorVersion, MinorVersion );
 1813             return FALSE;
 1814         }
 1815     }
 1816     else
 1817     {
 1818         FIXME( "unknown major %d minor 0x%X\n", MajorVersion, MinorVersion );
 1819         return FALSE;
 1820     }
 1821     return major > MajorVersion || (major == MajorVersion && minor >= MinorVersion);
 1822 }
 1823 
 1824 /***********************************************************************
 1825  *           IoQueryDeviceDescription    (NTOSKRNL.EXE.@)
 1826  */
 1827 NTSTATUS WINAPI IoQueryDeviceDescription(PINTERFACE_TYPE itype, PULONG bus, PCONFIGURATION_TYPE ctype,
 1828                                      PULONG cnum, PCONFIGURATION_TYPE ptype, PULONG pnum,
 1829                                      PIO_QUERY_DEVICE_ROUTINE callout, PVOID context)
 1830 {
 1831     FIXME( "(%p %p %p %p %p %p %p %p)\n", itype, bus, ctype, cnum, ptype, pnum, callout, context);
 1832     return STATUS_NOT_IMPLEMENTED;
 1833 }
 1834 
 1835 /***********************************************************************
 1836  *           IoRegisterDriverReinitialization    (NTOSKRNL.EXE.@)
 1837  */
 1838 void WINAPI IoRegisterDriverReinitialization( PDRIVER_OBJECT obj, PDRIVER_REINITIALIZE reinit, PVOID context )
 1839 {
 1840     FIXME( "stub: %p %p %p\n", obj, reinit, context );
 1841 }
 1842 
 1843 /***********************************************************************
 1844  *           IoRegisterBootDriverReinitialization   (NTOSKRNL.EXE.@)
 1845  */
 1846 void WINAPI IoRegisterBootDriverReinitialization(DRIVER_OBJECT *driver, PDRIVER_REINITIALIZE proc, void *ctx)
 1847 {
 1848     FIXME("driver %p, proc %p, ctx %p, stub!\n", driver, proc, ctx);
 1849 }
 1850 
 1851 /***********************************************************************
 1852  *           IoRegisterShutdownNotification    (NTOSKRNL.EXE.@)
 1853  */
 1854 NTSTATUS WINAPI IoRegisterShutdownNotification( PDEVICE_OBJECT obj )
 1855 {
 1856     FIXME( "stub: %p\n", obj );
 1857     return STATUS_SUCCESS;
 1858 }
 1859 
 1860 
 1861 /***********************************************************************
 1862  *           IoUnregisterShutdownNotification    (NTOSKRNL.EXE.@)
 1863  */
 1864 VOID WINAPI IoUnregisterShutdownNotification( PDEVICE_OBJECT obj )
 1865 {
 1866     FIXME( "stub: %p\n", obj );
 1867 }
 1868 
 1869 
 1870 /***********************************************************************
 1871  *           IoReportResourceForDetection   (NTOSKRNL.EXE.@)
 1872  */
 1873 NTSTATUS WINAPI IoReportResourceForDetection( DRIVER_OBJECT *drv_obj, CM_RESOURCE_LIST *drv_list, ULONG drv_size,
 1874                                               DEVICE_OBJECT *dev_obj, CM_RESOURCE_LIST *dev_list, ULONG dev_size,
 1875                                               BOOLEAN *conflict )
 1876 {
 1877     FIXME( "(%p, %p, %u, %p, %p, %u, %p): stub\n", drv_obj, drv_list, drv_size,
 1878            dev_obj, dev_list, dev_size, conflict );
 1879 
 1880     return STATUS_NOT_IMPLEMENTED;
 1881 }
 1882 
 1883 
 1884 /***********************************************************************
 1885  *           IoReportResourceUsage    (NTOSKRNL.EXE.@)
 1886  */
 1887 NTSTATUS WINAPI IoReportResourceUsage( UNICODE_STRING *name, DRIVER_OBJECT *drv_obj, CM_RESOURCE_LIST *drv_list,
 1888                                        ULONG drv_size, DRIVER_OBJECT *dev_obj, CM_RESOURCE_LIST *dev_list,
 1889                                        ULONG dev_size, BOOLEAN overwrite, BOOLEAN *conflict )
 1890 {
 1891     FIXME( "(%s, %p, %p, %u, %p, %p, %u, %d, %p): stub\n", debugstr_us(name),
 1892            drv_obj, drv_list, drv_size, dev_obj, dev_list, dev_size, overwrite, conflict );
 1893 
 1894     return STATUS_NOT_IMPLEMENTED;
 1895 }
 1896 
 1897 
 1898 /***********************************************************************
 1899  *           IoCompleteRequest   (NTOSKRNL.EXE.@)
 1900  */
 1901 VOID WINAPI IoCompleteRequest( IRP *irp, UCHAR priority_boost )
 1902 {
 1903     IO_STACK_LOCATION *irpsp;
 1904     PIO_COMPLETION_ROUTINE routine;
 1905     NTSTATUS status, stat;
 1906     DEVICE_OBJECT *device;
 1907     int call_flag = 0;
 1908 
 1909     TRACE( "%p %u\n", irp, priority_boost );
 1910 
 1911     status = irp->IoStatus.u.Status;
 1912     while (irp->CurrentLocation <= irp->StackCount)
 1913     {
 1914         irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;
 1915         routine = irpsp->CompletionRoutine;
 1916         call_flag = 0;
 1917         if (routine)
 1918         {
 1919             if ((irpsp->Control & SL_INVOKE_ON_SUCCESS) && STATUS_SUCCESS == status)
 1920                 call_flag = 1;
 1921             if ((irpsp->Control & SL_INVOKE_ON_ERROR) && STATUS_SUCCESS != status)
 1922                 call_flag = 1;
 1923             if ((irpsp->Control & SL_INVOKE_ON_CANCEL) && irp->Cancel)
 1924                 call_flag = 1;
 1925         }
 1926         ++irp->CurrentLocation;
 1927         ++irp->Tail.Overlay.s.u2.CurrentStackLocation;
 1928         if (irp->CurrentLocation <= irp->StackCount)
 1929             device = IoGetCurrentIrpStackLocation(irp)->DeviceObject;
 1930         else
 1931             device = NULL;
 1932         if (call_flag)
 1933         {
 1934             TRACE( "calling %p( %p, %p, %p )\n", routine, device, irp, irpsp->Context );
 1935             stat = routine( device, irp, irpsp->Context );
 1936             TRACE( "CompletionRoutine returned %x\n", stat );
 1937             if (STATUS_MORE_PROCESSING_REQUIRED == stat)
 1938                 return;
 1939         }
 1940     }
 1941 
 1942     if (irp->Flags & IRP_DEALLOCATE_BUFFER)
 1943         HeapFree( GetProcessHeap(), 0, irp->AssociatedIrp.SystemBuffer );
 1944     if (irp->UserEvent) KeSetEvent( irp->UserEvent, IO_NO_INCREMENT, FALSE );
 1945 
 1946     IoFreeIrp( irp );
 1947 }
 1948 
 1949 
 1950 /***********************************************************************
 1951  *           IofCompleteRequest   (NTOSKRNL.EXE.@)
 1952  */
 1953 DEFINE_FASTCALL_WRAPPER( IofCompleteRequest, 8 )
 1954 void FASTCALL IofCompleteRequest( IRP *irp, UCHAR priority_boost )
 1955 {
 1956     TRACE( "%p %u\n", irp, priority_boost );
 1957     IoCompleteRequest( irp, priority_boost );
 1958 }
 1959 
 1960 
 1961 /***********************************************************************
 1962  *           IoCancelIrp   (NTOSKRNL.EXE.@)
 1963  */
 1964 BOOLEAN WINAPI IoCancelIrp( IRP *irp )
 1965 {
 1966     PDRIVER_CANCEL cancel_routine;
 1967     KIRQL irql;
 1968 
 1969     TRACE( "(%p)\n", irp );
 1970 
 1971     IoAcquireCancelSpinLock( &irql );
 1972     irp->Cancel = TRUE;
 1973     if (!(cancel_routine = IoSetCancelRoutine( irp, NULL )))
 1974     {
 1975         IoReleaseCancelSpinLock( irp->CancelIrql );
 1976         return FALSE;
 1977     }
 1978 
 1979     /* CancelRoutine is responsible for calling IoReleaseCancelSpinLock */
 1980     irp->CancelIrql = irql;
 1981     cancel_routine( IoGetCurrentIrpStackLocation(irp)->DeviceObject, irp );
 1982     return TRUE;
 1983 }
 1984 
 1985 
 1986 /***********************************************************************
 1987  *           InterlockedCompareExchange   (NTOSKRNL.EXE.@)
 1988  */
 1989 DEFINE_FASTCALL_WRAPPER( NTOSKRNL_InterlockedCompareExchange, 12 )
 1990 LONG FASTCALL NTOSKRNL_InterlockedCompareExchange( LONG volatile *dest, LONG xchg, LONG compare )
 1991 {
 1992     return InterlockedCompareExchange( dest, xchg, compare );
 1993 }
 1994 
 1995 
 1996 /***********************************************************************
 1997  *           InterlockedDecrement   (NTOSKRNL.EXE.@)
 1998  */
 1999 DEFINE_FASTCALL1_WRAPPER( NTOSKRNL_InterlockedDecrement )
 2000 LONG FASTCALL NTOSKRNL_InterlockedDecrement( LONG volatile *dest )
 2001 {
 2002     return InterlockedDecrement( dest );
 2003 }
 2004 
 2005 
 2006 /***********************************************************************
 2007  *           InterlockedExchange   (NTOSKRNL.EXE.@)
 2008  */
 2009 DEFINE_FASTCALL_WRAPPER( NTOSKRNL_InterlockedExchange, 8 )
 2010 LONG FASTCALL NTOSKRNL_InterlockedExchange( LONG volatile *dest, LONG val )
 2011 {
 2012     return InterlockedExchange( dest, val );
 2013 }
 2014 
 2015 
 2016 /***********************************************************************
 2017  *           InterlockedExchangeAdd   (NTOSKRNL.EXE.@)
 2018  */
 2019 DEFINE_FASTCALL_WRAPPER( NTOSKRNL_InterlockedExchangeAdd, 8 )
 2020 LONG FASTCALL NTOSKRNL_InterlockedExchangeAdd( LONG volatile *dest, LONG incr )
 2021 {
 2022     return InterlockedExchangeAdd( dest, incr );
 2023 }
 2024 
 2025 
 2026 /***********************************************************************
 2027  *           InterlockedIncrement   (NTOSKRNL.EXE.@)
 2028  */
 2029 DEFINE_FASTCALL1_WRAPPER( NTOSKRNL_InterlockedIncrement )
 2030 LONG FASTCALL NTOSKRNL_InterlockedIncrement( LONG volatile *dest )
 2031 {
 2032     return InterlockedIncrement( dest );
 2033 }
 2034 
 2035 
 2036 /***********************************************************************
 2037  *           ExAllocatePool   (NTOSKRNL.EXE.@)
 2038  */
 2039 PVOID WINAPI ExAllocatePool( POOL_TYPE type, SIZE_T size )
 2040 {
 2041     return ExAllocatePoolWithTag( type, size, 0 );
 2042 }
 2043 
 2044 
 2045 /***********************************************************************
 2046  *           ExAllocatePoolWithQuota   (NTOSKRNL.EXE.@)
 2047  */
 2048 PVOID WINAPI ExAllocatePoolWithQuota( POOL_TYPE type, SIZE_T size )
 2049 {
 2050     return ExAllocatePoolWithTag( type, size, 0 );
 2051 }
 2052 
 2053 
 2054 /***********************************************************************
 2055  *           ExAllocatePoolWithTag   (NTOSKRNL.EXE.@)
 2056  */
 2057 PVOID WINAPI ExAllocatePoolWithTag( POOL_TYPE type, SIZE_T size, ULONG tag )
 2058 {
 2059     /* FIXME: handle page alignment constraints */
 2060     void *ret = HeapAlloc( ntoskrnl_heap, 0, size );
 2061     TRACE( "%lu pool %u -> %p\n", size, type, ret );
 2062     return ret;
 2063 }
 2064 
 2065 
 2066 /***********************************************************************
 2067  *           ExAllocatePoolWithQuotaTag   (NTOSKRNL.EXE.@)
 2068  */
 2069 PVOID WINAPI ExAllocatePoolWithQuotaTag( POOL_TYPE type, SIZE_T size, ULONG tag )
 2070 {
 2071     return ExAllocatePoolWithTag( type, size, tag );
 2072 }
 2073 
 2074 
 2075 /***********************************************************************
 2076  *           ExCreateCallback   (NTOSKRNL.EXE.@)
 2077  */
 2078 NTSTATUS WINAPI ExCreateCallback(PCALLBACK_OBJECT *obj, POBJECT_ATTRIBUTES attr,
 2079                                  BOOLEAN create, BOOLEAN allow_multiple)
 2080 {
 2081     FIXME("(%p, %p, %u, %u): stub\n", obj, attr, create, allow_multiple);
 2082 
 2083     return STATUS_SUCCESS;
 2084 }
 2085 
 2086 void * WINAPI ExRegisterCallback(PCALLBACK_OBJECT callback_object,
 2087         PCALLBACK_FUNCTION callback_function, void *callback_context)
 2088 {
 2089     FIXME("callback_object %p, callback_function %p, callback_context %p stub.\n",
 2090             callback_object, callback_function, callback_context);
 2091 
 2092     return (void *)0xdeadbeef;
 2093 }
 2094 
 2095 void WINAPI ExUnregisterCallback(void *callback_registration)
 2096 {
 2097     FIXME("callback_registration %p stub.\n", callback_registration);
 2098 }
 2099 
 2100 /***********************************************************************
 2101  *           ExFreePool   (NTOSKRNL.EXE.@)
 2102  */
 2103 void WINAPI ExFreePool( void *ptr )
 2104 {
 2105     ExFreePoolWithTag( ptr, 0 );
 2106 }
 2107 
 2108 
 2109 /***********************************************************************
 2110  *           ExFreePoolWithTag   (NTOSKRNL.EXE.@)
 2111  */
 2112 void WINAPI ExFreePoolWithTag( void *ptr, ULONG tag )
 2113 {
 2114     TRACE( "%p\n", ptr );
 2115     HeapFree( ntoskrnl_heap, 0, ptr );
 2116 }
 2117 
 2118 static void initialize_lookaside_list( GENERAL_LOOKASIDE *lookaside, PALLOCATE_FUNCTION allocate, PFREE_FUNCTION free,
 2119                                        ULONG type, SIZE_T size, ULONG tag )
 2120 {
 2121 
 2122     RtlInitializeSListHead( &lookaside->u.ListHead );
 2123     lookaside->Depth                 = 4;
 2124     lookaside->MaximumDepth          = 256;
 2125     lookaside->TotalAllocates        = 0;
 2126     lookaside->u2.AllocateMisses     = 0;
 2127     lookaside->TotalFrees            = 0;
 2128     lookaside->u3.FreeMisses         = 0;
 2129     lookaside->Type                  = type;
 2130     lookaside->Tag                   = tag;
 2131     lookaside->Size                  = size;
 2132     lookaside->u4.Allocate           = allocate ? allocate : ExAllocatePoolWithTag;
 2133     lookaside->u5.Free               = free ? free : ExFreePool;
 2134     lookaside->LastTotalAllocates    = 0;
 2135     lookaside->u6.LastAllocateMisses = 0;
 2136 
 2137     /* FIXME: insert in global list of lookadside lists */
 2138 }
 2139 
 2140 /***********************************************************************
 2141  *           ExInitializeNPagedLookasideList   (NTOSKRNL.EXE.@)
 2142  */
 2143 void WINAPI ExInitializeNPagedLookasideList(PNPAGED_LOOKASIDE_LIST lookaside,
 2144                                             PALLOCATE_FUNCTION allocate,
 2145                                             PFREE_FUNCTION free,
 2146                                             ULONG flags,
 2147                                             SIZE_T size,
 2148                                             ULONG tag,
 2149                                             USHORT depth)
 2150 {
 2151     TRACE( "%p, %p, %p, %u, %lu, %u, %u\n", lookaside, allocate, free, flags, size, tag, depth );
 2152     initialize_lookaside_list( &lookaside->L, allocate, free, NonPagedPool | flags, size, tag );
 2153 }
 2154 
 2155 /***********************************************************************
 2156  *           ExInitializePagedLookasideList   (NTOSKRNL.EXE.@)
 2157  */
 2158 void WINAPI ExInitializePagedLookasideList(PPAGED_LOOKASIDE_LIST lookaside,
 2159                                            PALLOCATE_FUNCTION allocate,
 2160                                            PFREE_FUNCTION free,
 2161                                            ULONG flags,
 2162                                            SIZE_T size,
 2163                                            ULONG tag,
 2164                                            USHORT depth)
 2165 {
 2166     TRACE( "%p, %p, %p, %u, %lu, %u, %u\n", lookaside, allocate, free, flags, size, tag, depth );
 2167     initialize_lookaside_list( &lookaside->L, allocate, free, PagedPool | flags, size, tag );
 2168 }
 2169 
 2170 static void delete_lookaside_list( GENERAL_LOOKASIDE *lookaside )
 2171 {
 2172     void *entry;
 2173     while ((entry = RtlInterlockedPopEntrySList(&lookaside->u.ListHead)))
 2174         lookaside->u5.FreeEx(entry, (LOOKASIDE_LIST_EX*)lookaside);
 2175 }
 2176 
 2177 /***********************************************************************
 2178  *           ExDeleteNPagedLookasideList   (NTOSKRNL.EXE.@)
 2179  */
 2180 void WINAPI ExDeleteNPagedLookasideList( PNPAGED_LOOKASIDE_LIST lookaside )
 2181 {
 2182     TRACE( "%p\n", lookaside );
 2183     delete_lookaside_list( &lookaside->L );
 2184 }
 2185 
 2186 
 2187 /***********************************************************************
 2188  *           ExDeletePagedLookasideList  (NTOSKRNL.EXE.@)
 2189  */
 2190 void WINAPI ExDeletePagedLookasideList( PPAGED_LOOKASIDE_LIST lookaside )
 2191 {
 2192     TRACE( "%p\n", lookaside );
 2193     delete_lookaside_list( &lookaside->L );
 2194 }
 2195 
 2196 /***********************************************************************
 2197  *           ExInitializeZone   (NTOSKRNL.EXE.@)
 2198  */
 2199 NTSTATUS WINAPI ExInitializeZone(PZONE_HEADER Zone,
 2200                                  ULONG BlockSize,
 2201                                  PVOID InitialSegment,
 2202                                  ULONG InitialSegmentSize)
 2203 {
 2204     FIXME( "stub: %p, %u, %p, %u\n", Zone, BlockSize, InitialSegment, InitialSegmentSize );
 2205     return STATUS_NOT_IMPLEMENTED;
 2206 }
 2207 
 2208 /***********************************************************************
 2209 *           FsRtlIsNameInExpression   (NTOSKRNL.EXE.@)
 2210 */
 2211 BOOLEAN WINAPI FsRtlIsNameInExpression(PUNICODE_STRING expression, PUNICODE_STRING name,
 2212                                        BOOLEAN ignore, PWCH upcase)
 2213 {
 2214     FIXME("stub: %p %p %d %p\n", expression, name, ignore, upcase);
 2215     return FALSE;
 2216 }
 2217 
 2218 /***********************************************************************
 2219 *           FsRtlRegisterUncProvider   (NTOSKRNL.EXE.@)
 2220 */
 2221 NTSTATUS WINAPI FsRtlRegisterUncProvider(PHANDLE MupHandle, PUNICODE_STRING RedirDevName,
 2222                                          BOOLEAN MailslotsSupported)
 2223 {
 2224     FIXME("(%p %p %d): stub\n", MupHandle, RedirDevName, MailslotsSupported);
 2225     return STATUS_NOT_IMPLEMENTED;
 2226 }
 2227 
 2228 
 2229 static void *create_process_object( HANDLE handle )
 2230 {
 2231     PEPROCESS process;
 2232 
 2233     if (!(process = alloc_kernel_object( PsProcessType, handle, sizeof(*process), 0 ))) return NULL;
 2234 
 2235     process->header.Type = 3;
 2236     process->header.WaitListHead.Blink = INVALID_HANDLE_VALUE; /* mark as kernel object */
 2237     NtQueryInformationProcess( handle, ProcessBasicInformation, &process->info, sizeof(process->info), NULL );
 2238     IsWow64Process( handle, &process->wow64 );
 2239     return process;
 2240 }
 2241 
 2242 static const WCHAR process_type_name[] = {'P','r','o','c','e','s','s',0};
 2243 
 2244 static struct _OBJECT_TYPE process_type =
 2245 {
 2246     process_type_name,
 2247     create_process_object
 2248 };
 2249 
 2250 POBJECT_TYPE PsProcessType = &process_type;
 2251 
 2252 
 2253 /***********************************************************************
 2254  *           IoGetCurrentProcess / PsGetCurrentProcess   (NTOSKRNL.EXE.@)
 2255  */
 2256 PEPROCESS WINAPI IoGetCurrentProcess(void)
 2257 {
 2258     return KeGetCurrentThread()->process;
 2259 }
 2260 
 2261 /***********************************************************************
 2262  *           PsLookupProcessByProcessId  (NTOSKRNL.EXE.@)
 2263  */
 2264 NTSTATUS WINAPI PsLookupProcessByProcessId( HANDLE processid, PEPROCESS *process )
 2265 {
 2266     NTSTATUS status;
 2267     HANDLE handle;
 2268 
 2269     TRACE( "(%p %p)\n", processid, process );
 2270 
 2271     if (!(handle = OpenProcess( PROCESS_ALL_ACCESS, FALSE, HandleToUlong(processid) )))
 2272         return STATUS_INVALID_PARAMETER;
 2273 
 2274     status = ObReferenceObjectByHandle( handle, PROCESS_ALL_ACCESS, PsProcessType, KernelMode, (void**)process, NULL );
 2275 
 2276     NtClose( handle );
 2277     return status;
 2278 }
 2279 
 2280 /*********************************************************************
 2281  *           PsGetProcessId    (NTOSKRNL.@)
 2282  */
 2283 HANDLE WINAPI PsGetProcessId(PEPROCESS process)
 2284 {
 2285     TRACE( "%p -> %lx\n", process, process->info.UniqueProcessId );
 2286     return (HANDLE)process->info.UniqueProcessId;
 2287 }
 2288 
 2289 /*********************************************************************
 2290  *           PsGetProcessInheritedFromUniqueProcessId  (NTOSKRNL.@)
 2291  */
 2292 HANDLE WINAPI PsGetProcessInheritedFromUniqueProcessId( PEPROCESS process )
 2293 {
 2294     HANDLE id = (HANDLE)process->info.InheritedFromUniqueProcessId;
 2295     TRACE( "%p -> %p\n", process, id );
 2296     return id;
 2297 }
 2298 
 2299 static void *create_thread_object( HANDLE handle )
 2300 {
 2301     THREAD_BASIC_INFORMATION info;
 2302     struct _KTHREAD *thread;
 2303     HANDLE process;
 2304 
 2305     if (!(thread = alloc_kernel_object( PsThreadType, handle, sizeof(*thread), 0 ))) return NULL;
 2306 
 2307     thread->header.Type = 6;
 2308     thread->header.WaitListHead.Blink = INVALID_HANDLE_VALUE; /* mark as kernel object */
 2309     thread->user_affinity = 0;
 2310 
 2311     if (!NtQueryInformationThread( handle, ThreadBasicInformation, &info, sizeof(info), NULL ))
 2312     {
 2313         thread->id = info.ClientId;
 2314         if ((process = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, HandleToUlong(thread->id.UniqueProcess) )))
 2315         {
 2316             kernel_object_from_handle( process, PsProcessType, (void**)&thread->process );
 2317             NtClose( process );
 2318         }
 2319     }
 2320 
 2321 
 2322     return thread;
 2323 }
 2324 
 2325 static const WCHAR thread_type_name[] = {'T','h','r','e','a','d',0};
 2326 
 2327 static struct _OBJECT_TYPE thread_type =
 2328 {
 2329     thread_type_name,
 2330     create_thread_object
 2331 };
 2332 
 2333 POBJECT_TYPE PsThreadType = &thread_type;
 2334 
 2335 
 2336 /***********************************************************************
 2337  *           KeGetCurrentThread / PsGetCurrentThread   (NTOSKRNL.EXE.@)
 2338  */
 2339 PRKTHREAD WINAPI KeGetCurrentThread(void)
 2340 {
 2341     struct _KTHREAD *thread = NtCurrentTeb()->Reserved5[1];
 2342 
 2343     if (!thread)
 2344     {
 2345         HANDLE handle = GetCurrentThread();
 2346 
 2347         /* FIXME: we shouldn't need it, GetCurrentThread() should be client thread already */
 2348         if (GetCurrentThreadId() == request_thread)
 2349             handle = OpenThread( THREAD_QUERY_INFORMATION, FALSE, client_tid );
 2350 
 2351         kernel_object_from_handle( handle, PsThreadType, (void**)&thread );
 2352         if (handle != GetCurrentThread()) NtClose( handle );
 2353 
 2354         NtCurrentTeb()->Reserved5[1] = thread;
 2355     }
 2356 
 2357     return thread;
 2358 }
 2359 
 2360 /*****************************************************
 2361  *           PsLookupThreadByThreadId   (NTOSKRNL.EXE.@)
 2362  */
 2363 NTSTATUS WINAPI PsLookupThreadByThreadId( HANDLE threadid, PETHREAD *thread )
 2364 {
 2365     OBJECT_ATTRIBUTES attr;
 2366     CLIENT_ID cid;
 2367     NTSTATUS status;
 2368     HANDLE handle;
 2369 
 2370     TRACE( "(%p %p)\n", threadid, thread );
 2371 
 2372     cid.UniqueProcess = 0;
 2373     cid.UniqueThread = threadid;
 2374     InitializeObjectAttributes( &attr, NULL, 0, NULL, NULL );
 2375     status = NtOpenThread( &handle, THREAD_QUERY_INFORMATION, &attr, &cid );
 2376     if (status) return status;
 2377 
 2378     status = ObReferenceObjectByHandle( handle, THREAD_ALL_ACCESS, PsThreadType, KernelMode, (void**)thread, NULL );
 2379 
 2380     NtClose( handle );
 2381     return status;
 2382 }
 2383 
 2384 /*********************************************************************
 2385  *           PsGetThreadId    (NTOSKRNL.@)
 2386  */
 2387 HANDLE WINAPI PsGetThreadId(PETHREAD thread)
 2388 {
 2389     TRACE( "%p -> %p\n", thread, thread->kthread.id.UniqueThread );
 2390     return thread->kthread.id.UniqueThread;
 2391 }
 2392 
 2393 /*********************************************************************
 2394  *           PsGetThreadProcessId    (NTOSKRNL.@)
 2395  */
 2396 HANDLE WINAPI PsGetThreadProcessId( PETHREAD thread )
 2397 {
 2398     TRACE( "%p -> %p\n", thread, thread->kthread.id.UniqueProcess );
 2399     return thread->kthread.id.UniqueProcess;
 2400 }
 2401 
 2402 /***********************************************************************
 2403  *           KeInsertQueue   (NTOSKRNL.EXE.@)
 2404  */
 2405 LONG WINAPI KeInsertQueue(PRKQUEUE Queue, PLIST_ENTRY Entry)
 2406 {
 2407     FIXME( "stub: %p %p\n", Queue, Entry );
 2408     return 0;
 2409 }
 2410 
 2411 /**********************************************************************
 2412  *           KeQueryActiveProcessors   (NTOSKRNL.EXE.@)
 2413  *
 2414  * Return the active Processors as bitmask
 2415  *
 2416  * RETURNS
 2417  *   active Processors as bitmask
 2418  *
 2419  */
 2420 KAFFINITY WINAPI KeQueryActiveProcessors( void )
 2421 {
 2422     DWORD_PTR affinity_mask;
 2423 
 2424     GetProcessAffinityMask( GetCurrentProcess(), NULL, &affinity_mask);
 2425     return affinity_mask;
 2426 }
 2427 
 2428 ULONG WINAPI KeQueryActiveProcessorCountEx(USHORT group_number)
 2429 {
 2430     TRACE("group_number %u.\n", group_number);
 2431 
 2432     return GetActiveProcessorCount(group_number);
 2433 }
 2434 
 2435 /**********************************************************************
 2436  *           KeQueryInterruptTime   (NTOSKRNL.EXE.@)
 2437  *
 2438  * Return the interrupt time count
 2439  *
 2440  */
 2441 ULONGLONG WINAPI KeQueryInterruptTime( void )
 2442 {
 2443     LARGE_INTEGER totaltime;
 2444 
 2445     KeQueryTickCount(&totaltime);
 2446     return totaltime.QuadPart;
 2447 }
 2448 
 2449 
 2450 /***********************************************************************
 2451  *           KeQuerySystemTime   (NTOSKRNL.EXE.@)
 2452  */
 2453 void WINAPI KeQuerySystemTime( LARGE_INTEGER *time )
 2454 {
 2455     NtQuerySystemTime( time );
 2456 }
 2457 
 2458 
 2459 /***********************************************************************
 2460  *           KeQueryTickCount   (NTOSKRNL.EXE.@)
 2461  */
 2462 void WINAPI KeQueryTickCount( LARGE_INTEGER *count )
 2463 {
 2464     count->QuadPart = NtGetTickCount();
 2465     /* update the global variable too */
 2466     KeTickCount.LowPart   = count->u.LowPart;
 2467     KeTickCount.High1Time = count->u.HighPart;
 2468     KeTickCount.High2Time = count->u.HighPart;
 2469 }
 2470 
 2471 
 2472 /***********************************************************************
 2473  *           KeQueryTimeIncrement   (NTOSKRNL.EXE.@)
 2474  */
 2475 ULONG WINAPI KeQueryTimeIncrement(void)
 2476 {
 2477     return 10000;
 2478 }
 2479 
 2480 
 2481 /***********************************************************************
 2482  *           KeSetPriorityThread   (NTOSKRNL.EXE.@)
 2483  */
 2484 KPRIORITY WINAPI KeSetPriorityThread( PKTHREAD Thread, KPRIORITY Priority )
 2485 {
 2486     FIXME("(%p %d)\n", Thread, Priority);
 2487     return Priority;
 2488 }
 2489 
 2490 /***********************************************************************
 2491  *           KeSetSystemAffinityThread   (NTOSKRNL.EXE.@)
 2492  */
 2493 VOID WINAPI KeSetSystemAffinityThread(KAFFINITY affinity)
 2494 {
 2495     KeSetSystemAffinityThreadEx(affinity);
 2496 }
 2497 
 2498 KAFFINITY WINAPI KeSetSystemAffinityThreadEx(KAFFINITY affinity)
 2499 {
 2500     DWORD_PTR system_affinity = KeQueryActiveProcessors();
 2501     PKTHREAD thread = KeGetCurrentThread();
 2502     GROUP_AFFINITY old, new;
 2503 
 2504     TRACE("affinity %#lx.\n", affinity);
 2505 
 2506     affinity &= system_affinity;
 2507 
 2508     NtQueryInformationThread(GetCurrentThread(), ThreadGroupInformation,
 2509             &old, sizeof(old), NULL);
 2510 
 2511     if (old.Mask != system_affinity)
 2512         thread->user_affinity = old.Mask;
 2513 
 2514     memset(&new, 0, sizeof(new));
 2515     new.Mask = affinity;
 2516 
 2517     return NtSetInformationThread(GetCurrentThread(), ThreadGroupInformation, &new, sizeof(new))
 2518             ? 0 : thread->user_affinity;
 2519 }
 2520 
 2521 
 2522 /***********************************************************************
 2523  *           KeRevertToUserAffinityThread   (NTOSKRNL.EXE.@)
 2524  */
 2525 void WINAPI KeRevertToUserAffinityThread(void)
 2526 {
 2527     KeRevertToUserAffinityThreadEx(0);
 2528 }
 2529 
 2530 void WINAPI KeRevertToUserAffinityThreadEx(KAFFINITY affinity)
 2531 {
 2532     DWORD_PTR system_affinity = KeQueryActiveProcessors();
 2533     PRKTHREAD thread = KeGetCurrentThread();
 2534     GROUP_AFFINITY new;
 2535 
 2536     TRACE("affinity %#lx.\n", affinity);
 2537 
 2538     affinity &= system_affinity;
 2539 
 2540     memset(&new, 0, sizeof(new));
 2541     new.Mask = affinity ? affinity
 2542             : (thread->user_affinity ? thread->user_affinity : system_affinity);
 2543 
 2544     NtSetInformationThread(GetCurrentThread(), ThreadGroupInformation, &new, sizeof(new));
 2545     thread->user_affinity = affinity;
 2546 }
 2547 
 2548 /***********************************************************************
 2549  *           IoRegisterFileSystem   (NTOSKRNL.EXE.@)
 2550  */
 2551 VOID WINAPI IoRegisterFileSystem(PDEVICE_OBJECT DeviceObject)
 2552 {
 2553     FIXME("(%p): stub\n", DeviceObject);
 2554 }
 2555 
 2556 /***********************************************************************
 2557  *           KeExpandKernelStackAndCalloutEx   (NTOSKRNL.EXE.@)
 2558  */
 2559 NTSTATUS WINAPI KeExpandKernelStackAndCalloutEx(PEXPAND_STACK_CALLOUT callout, void *parameter, SIZE_T size,
 2560                                                 BOOLEAN wait, void *context)
 2561 {
 2562     WARN("(%p %p %lu %x %p) semi-stub: ignoring stack expand\n", callout, parameter, size, wait, context);
 2563     callout(parameter);
 2564     return STATUS_SUCCESS;
 2565 }
 2566 
 2567 /***********************************************************************
 2568  *           KeExpandKernelStackAndCallout   (NTOSKRNL.EXE.@)
 2569  */
 2570 NTSTATUS WINAPI KeExpandKernelStackAndCallout(PEXPAND_STACK_CALLOUT callout, void *parameter, SIZE_T size)
 2571 {
 2572     return KeExpandKernelStackAndCalloutEx(callout, parameter, size, TRUE, NULL);
 2573 }
 2574 
 2575 /***********************************************************************
 2576 *           IoUnregisterFileSystem   (NTOSKRNL.EXE.@)
 2577 */
 2578 VOID WINAPI IoUnregisterFileSystem(PDEVICE_OBJECT DeviceObject)
 2579 {
 2580     FIXME("(%p): stub\n", DeviceObject);
 2581 }
 2582 
 2583 /***********************************************************************
 2584  *           MmAllocateNonCachedMemory   (NTOSKRNL.EXE.@)
 2585  */
 2586 PVOID WINAPI MmAllocateNonCachedMemory( SIZE_T size )
 2587 {
 2588     TRACE( "%lu\n", size );
 2589     return VirtualAlloc( NULL, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE|PAGE_NOCACHE );
 2590 }
 2591 
 2592 /***********************************************************************
 2593  *           MmAllocateContiguousMemory   (NTOSKRNL.EXE.@)
 2594  */
 2595 PVOID WINAPI MmAllocateContiguousMemory( SIZE_T size, PHYSICAL_ADDRESS highest_valid_address )
 2596 {
 2597     FIXME( "%lu, %s stub\n", size, wine_dbgstr_longlong(highest_valid_address.QuadPart) );
 2598     return NULL;
 2599 }
 2600 
 2601 /***********************************************************************
 2602  *           MmAllocateContiguousMemorySpecifyCache   (NTOSKRNL.EXE.@)
 2603  */
 2604 PVOID WINAPI MmAllocateContiguousMemorySpecifyCache( SIZE_T size,
 2605                                                      PHYSICAL_ADDRESS lowest_valid_address,
 2606                                                      PHYSICAL_ADDRESS highest_valid_address,
 2607                                                      PHYSICAL_ADDRESS BoundaryAddressMultiple,
 2608                                                      MEMORY_CACHING_TYPE CacheType )
 2609 {
 2610     FIXME(": stub\n");
 2611     return NULL;
 2612 }
 2613 
 2614 /***********************************************************************
 2615  *           MmAllocatePagesForMdl   (NTOSKRNL.EXE.@)
 2616  */
 2617 PMDL WINAPI MmAllocatePagesForMdl(PHYSICAL_ADDRESS lowaddress, PHYSICAL_ADDRESS highaddress,
 2618                                   PHYSICAL_ADDRESS skipbytes, SIZE_T size)
 2619 {
 2620     FIXME("%s %s %s %lu: stub\n", wine_dbgstr_longlong(lowaddress.QuadPart), wine_dbgstr_longlong(highaddress.QuadPart),
 2621                                   wine_dbgstr_longlong(skipbytes.QuadPart), size);
 2622     return NULL;
 2623 }
 2624 
 2625 /***********************************************************************
 2626  *           MmBuildMdlForNonPagedPool   (NTOSKRNL.EXE.@)
 2627  */
 2628 void WINAPI MmBuildMdlForNonPagedPool(MDL *mdl)
 2629 {
 2630     FIXME("stub: %p\n", mdl);
 2631 }
 2632 
 2633 /***********************************************************************
 2634  *           MmCreateSection   (NTOSKRNL.EXE.@)
 2635  */
 2636 NTSTATUS WINAPI MmCreateSection( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
 2637                                  LARGE_INTEGER *size, ULONG protect, ULONG alloc_attr,
 2638                                  HANDLE file, FILE_OBJECT *file_obj )
 2639 {
 2640     FIXME("%p %#x %p %s %#x %#x %p %p: stub\n", handle, access, attr,
 2641         wine_dbgstr_longlong(size->QuadPart), protect, alloc_attr, file, file_obj);
 2642     return STATUS_NOT_IMPLEMENTED;
 2643 }
 2644 
 2645 /***********************************************************************
 2646  *           MmFreeNonCachedMemory   (NTOSKRNL.EXE.@)
 2647  */
 2648 void WINAPI MmFreeNonCachedMemory( void *addr, SIZE_T size )
 2649 {
 2650     TRACE( "%p %lu\n", addr, size );
 2651     VirtualFree( addr, 0, MEM_RELEASE );
 2652 }
 2653 
 2654 /***********************************************************************
 2655  *           MmIsAddressValid   (NTOSKRNL.EXE.@)
 2656  *
 2657  * Check if the process can access the virtual address without a pagefault
 2658  *
 2659  * PARAMS
 2660  *  VirtualAddress [I] Address to check
 2661  *
 2662  * RETURNS
 2663  *  Failure: FALSE
 2664  *  Success: TRUE  (Accessing the Address works without a Pagefault)
 2665  *
 2666  */
 2667 BOOLEAN WINAPI MmIsAddressValid(PVOID VirtualAddress)
 2668 {
 2669     TRACE("(%p)\n", VirtualAddress);
 2670     return !IsBadReadPtr(VirtualAddress, 1);
 2671 }
 2672 
 2673 /***********************************************************************
 2674  *           MmMapIoSpace   (NTOSKRNL.EXE.@)
 2675  */
 2676 PVOID WINAPI MmMapIoSpace( PHYSICAL_ADDRESS PhysicalAddress, DWORD NumberOfBytes, DWORD CacheType )
 2677 {
 2678     FIXME( "stub: 0x%08x%08x, %d, %d\n", PhysicalAddress.u.HighPart, PhysicalAddress.u.LowPart, NumberOfBytes, CacheType );
 2679     return NULL;
 2680 }
 2681 
 2682 
 2683 /***********************************************************************
 2684  *           MmLockPagableSectionByHandle  (NTOSKRNL.EXE.@)
 2685  */
 2686 VOID WINAPI MmLockPagableSectionByHandle(PVOID ImageSectionHandle)
 2687 {
 2688     FIXME("stub %p\n", ImageSectionHandle);
 2689 }
 2690 
 2691 /***********************************************************************
 2692  *           MmMapLockedPagesSpecifyCache  (NTOSKRNL.EXE.@)
 2693  */
 2694 PVOID WINAPI  MmMapLockedPagesSpecifyCache(PMDLX MemoryDescriptorList, KPROCESSOR_MODE AccessMode, MEMORY_CACHING_TYPE CacheType,
 2695                                            PVOID BaseAddress, ULONG BugCheckOnFailure, MM_PAGE_PRIORITY Priority)
 2696 {
 2697     FIXME("(%p, %u, %u, %p, %u, %u): stub\n", MemoryDescriptorList, AccessMode, CacheType, BaseAddress, BugCheckOnFailure, Priority);
 2698 
 2699     return NULL;
 2700 }
 2701 
 2702 /***********************************************************************
 2703  *           MmUnmapLockedPages  (NTOSKRNL.EXE.@)
 2704  */
 2705 void WINAPI MmUnmapLockedPages( void *base, MDL *mdl )
 2706 {
 2707     FIXME( "(%p %p_\n", base, mdl );
 2708 }
 2709 
 2710 /***********************************************************************
 2711  *           MmUnlockPagableImageSection  (NTOSKRNL.EXE.@)
 2712  */
 2713 VOID WINAPI MmUnlockPagableImageSection(PVOID ImageSectionHandle)
 2714 {
 2715     FIXME("stub %p\n", ImageSectionHandle);
 2716 }
 2717 
 2718 /***********************************************************************
 2719  *           MmPageEntireDriver   (NTOSKRNL.EXE.@)
 2720  */
 2721 PVOID WINAPI MmPageEntireDriver(PVOID AddrInSection)
 2722 {
 2723     TRACE("%p\n", AddrInSection);
 2724     return AddrInSection;
 2725 }
 2726 
 2727 
 2728 /***********************************************************************
 2729  *           MmProbeAndLockPages  (NTOSKRNL.EXE.@)
 2730  */
 2731 void WINAPI MmProbeAndLockPages(PMDLX MemoryDescriptorList, KPROCESSOR_MODE AccessMode, LOCK_OPERATION Operation)
 2732 {
 2733     FIXME("(%p, %u, %u): stub\n", MemoryDescriptorList, AccessMode, Operation);
 2734 }
 2735 
 2736 
 2737 /***********************************************************************
 2738  *           MmResetDriverPaging   (NTOSKRNL.EXE.@)
 2739  */
 2740 void WINAPI MmResetDriverPaging(PVOID AddrInSection)
 2741 {
 2742     TRACE("%p\n", AddrInSection);
 2743 }
 2744 
 2745 
 2746 /***********************************************************************
 2747  *           MmUnlockPages  (NTOSKRNL.EXE.@)
 2748  */
 2749 void WINAPI  MmUnlockPages(PMDLX MemoryDescriptorList)
 2750 {
 2751     FIXME("(%p): stub\n", MemoryDescriptorList);
 2752 }
 2753 
 2754 
 2755 /***********************************************************************
 2756  *           MmUnmapIoSpace   (NTOSKRNL.EXE.@)
 2757  */
 2758 VOID WINAPI MmUnmapIoSpace( PVOID BaseAddress, SIZE_T NumberOfBytes )
 2759 {
 2760     FIXME( "stub: %p, %lu\n", BaseAddress, NumberOfBytes );
 2761 }
 2762 
 2763 
 2764  /***********************************************************************
 2765  *           ObReferenceObjectByName    (NTOSKRNL.EXE.@)
 2766  */
 2767 NTSTATUS WINAPI ObReferenceObjectByName( UNICODE_STRING *ObjectName,
 2768                                          ULONG Attributes,
 2769                                          ACCESS_STATE *AccessState,
 2770                                          ACCESS_MASK DesiredAccess,
 2771                                          POBJECT_TYPE ObjectType,
 2772                                          KPROCESSOR_MODE AccessMode,
 2773                                          void *ParseContext,
 2774                                          void **Object)
 2775 {
 2776     struct wine_driver *driver;
 2777     struct wine_rb_entry *entry;
 2778 
 2779     TRACE("mostly-stub:%s %i %p %i %p %i %p %p\n", debugstr_us(ObjectName),
 2780         Attributes, AccessState, DesiredAccess, ObjectType, AccessMode,
 2781         ParseContext, Object);
 2782 
 2783     if (AccessState) FIXME("Unhandled AccessState\n");
 2784     if (DesiredAccess) FIXME("Unhandled DesiredAccess\n");
 2785     if (ParseContext) FIXME("Unhandled ParseContext\n");
 2786     if (ObjectType) FIXME("Unhandled ObjectType\n");
 2787 
 2788     if (AccessMode != KernelMode)
 2789     {
 2790         FIXME("UserMode access not implemented\n");
 2791         return STATUS_NOT_IMPLEMENTED;
 2792     }
 2793 
 2794     EnterCriticalSection(&drivers_cs);
 2795     entry = wine_rb_get(&wine_drivers, ObjectName);
 2796     LeaveCriticalSection(&drivers_cs);
 2797     if (!entry)
 2798     {
 2799         FIXME("Object (%s) not found, may not be tracked.\n", debugstr_us(ObjectName));
 2800         return STATUS_NOT_IMPLEMENTED;
 2801     }
 2802 
 2803     driver = WINE_RB_ENTRY_VALUE(entry, struct wine_driver, entry);
 2804     ObReferenceObject( *Object = &driver->driver_obj );
 2805     return STATUS_SUCCESS;
 2806 }
 2807 
 2808 
 2809 /********************************************************************
 2810  *           ObOpenObjectByName   (NTOSKRNL.EXE.@)
 2811  */
 2812 NTSTATUS WINAPI ObOpenObjectByName(POBJECT_ATTRIBUTES attr, POBJECT_TYPE type,
 2813                                    KPROCESSOR_MODE mode, ACCESS_STATE *access_state,
 2814                                    ACCESS_MASK access, PVOID ctx, HANDLE *handle)
 2815 {
 2816     NTSTATUS status;
 2817     void *object;
 2818 
 2819     TRACE( "attr(%p %s %x) %p %u %p %u %p %p\n", attr->RootDirectory, debugstr_us(attr->ObjectName),
 2820                                                  attr->Attributes, type, mode, access_state, access, ctx, handle );
 2821 
 2822     if (mode != KernelMode)
 2823     {
 2824         FIXME( "UserMode access not implemented\n" );
 2825         return STATUS_NOT_IMPLEMENTED;
 2826     }
 2827 
 2828     if (attr->RootDirectory) FIXME( "RootDirectory unhandled\n" );
 2829 
 2830     status = ObReferenceObjectByName(attr->ObjectName, attr->Attributes, access_state, access, type, mode, ctx, &object );
 2831     if (status != STATUS_SUCCESS)
 2832         return status;
 2833 
 2834     status = ObOpenObjectByPointer(object, attr->Attributes, access_state, access, type, mode, handle);
 2835 
 2836     ObDereferenceObject(object);
 2837     return status;
 2838 }
 2839 
 2840 
 2841 /***********************************************************************
 2842  *           ObReferenceObjectByPointer   (NTOSKRNL.EXE.@)
 2843  */
 2844 NTSTATUS WINAPI ObReferenceObjectByPointer(void *obj, ACCESS_MASK access,
 2845                                            POBJECT_TYPE type,
 2846                                            KPROCESSOR_MODE mode)
 2847 {
 2848     FIXME("(%p, %x, %p, %d): stub\n", obj, access, type, mode);
 2849 
 2850     return STATUS_NOT_IMPLEMENTED;
 2851 }
 2852 
 2853 
 2854 /***********************************************************************
 2855  *           ObfReferenceObject   (NTOSKRNL.EXE.@)
 2856  */
 2857 DEFINE_FASTCALL1_WRAPPER( ObfReferenceObject )
 2858 void FASTCALL ObfReferenceObject( void *obj )
 2859 {
 2860     ObReferenceObject( obj );
 2861 }
 2862 
 2863 
 2864 /***********************************************************************
 2865  *           ObfDereferenceObject   (NTOSKRNL.EXE.@)
 2866  */
 2867 DEFINE_FASTCALL1_WRAPPER( ObfDereferenceObject )
 2868 void FASTCALL ObfDereferenceObject( void *obj )
 2869 {
 2870     ObDereferenceObject( obj );
 2871 }
 2872 
 2873 /***********************************************************************
 2874  *           ObRegisterCallbacks (NTOSKRNL.EXE.@)
 2875  */
 2876 NTSTATUS WINAPI ObRegisterCallbacks(POB_CALLBACK_REGISTRATION callback, void **handle)
 2877 {
 2878     FIXME( "callback %p, handle %p.\n", callback, handle );
 2879 
 2880     if(handle)
 2881         *handle = UlongToHandle(0xdeadbeaf);
 2882 
 2883     return STATUS_SUCCESS;
 2884 }
 2885 
 2886 /***********************************************************************
 2887  *           ObUnRegisterCallbacks (NTOSKRNL.EXE.@)
 2888  */
 2889 void WINAPI ObUnRegisterCallbacks(void *handle)
 2890 {
 2891     FIXME( "stub: %p\n", handle );
 2892 }
 2893 
 2894 /***********************************************************************
 2895  *           ObGetFilterVersion (NTOSKRNL.EXE.@)
 2896  */
 2897 USHORT WINAPI ObGetFilterVersion(void)
 2898 {
 2899     FIXME( "stub:\n" );
 2900 
 2901     return OB_FLT_REGISTRATION_VERSION;
 2902 }
 2903 
 2904 /***********************************************************************
 2905  *           IoGetAttachedDeviceReference   (NTOSKRNL.EXE.@)
 2906  */
 2907 DEVICE_OBJECT* WINAPI IoGetAttachedDeviceReference( DEVICE_OBJECT *device )
 2908 {
 2909     DEVICE_OBJECT *result = IoGetAttachedDevice( device );
 2910     ObReferenceObject( result );
 2911     return result;
 2912 }
 2913 
 2914 
 2915 /***********************************************************************
 2916  *           PsCreateSystemThread   (NTOSKRNL.EXE.@)
 2917  */
 2918 NTSTATUS WINAPI PsCreateSystemThread(PHANDLE ThreadHandle, ULONG DesiredAccess,
 2919                      POBJECT_ATTRIBUTES ObjectAttributes,
 2920                          HANDLE ProcessHandle, PCLIENT_ID ClientId,
 2921                                      PKSTART_ROUTINE StartRoutine, PVOID StartContext)
 2922 {
 2923     if (!ProcessHandle) ProcessHandle = GetCurrentProcess();
 2924     return RtlCreateUserThread(ProcessHandle, 0, FALSE, 0, 0,
 2925                                0, StartRoutine, StartContext,
 2926                                ThreadHandle, ClientId);
 2927 }
 2928 
 2929 /***********************************************************************
 2930  *           PsGetCurrentProcessId   (NTOSKRNL.EXE.@)
 2931  */
 2932 HANDLE WINAPI PsGetCurrentProcessId(void)
 2933 {
 2934     return KeGetCurrentThread()->id.UniqueProcess;
 2935 }
 2936 
 2937 
 2938 /***********************************************************************
 2939  *           PsGetCurrentThreadId   (NTOSKRNL.EXE.@)
 2940  */
 2941 HANDLE WINAPI PsGetCurrentThreadId(void)
 2942 {
 2943     return KeGetCurrentThread()->id.UniqueThread;
 2944 }
 2945 
 2946 
 2947 /***********************************************************************
 2948  *           PsIsSystemThread   (NTOSKRNL.EXE.@)
 2949  */
 2950 BOOLEAN WINAPI PsIsSystemThread(PETHREAD thread)
 2951 {
 2952     return thread->kthread.process == PsInitialSystemProcess;
 2953 }
 2954 
 2955 
 2956 /***********************************************************************
 2957  *           PsGetVersion   (NTOSKRNL.EXE.@)
 2958  */
 2959 BOOLEAN WINAPI PsGetVersion(ULONG *major, ULONG *minor, ULONG *build, UNICODE_STRING *version )
 2960 {
 2961     RTL_OSVERSIONINFOEXW info;
 2962 
 2963     info.dwOSVersionInfoSize = sizeof(info);
 2964     RtlGetVersion( &info );
 2965     if (major) *major = info.dwMajorVersion;
 2966     if (minor) *minor = info.dwMinorVersion;
 2967     if (build) *build = info.dwBuildNumber;
 2968 
 2969     if (version)
 2970     {
 2971 #if 0  /* FIXME: GameGuard passes an uninitialized pointer in version->Buffer */
 2972         size_t len = min( lstrlenW(info.szCSDVersion)*sizeof(WCHAR), version->MaximumLength );
 2973         memcpy( version->Buffer, info.szCSDVersion, len );
 2974         if (len < version->MaximumLength) version->Buffer[len / sizeof(WCHAR)] = 0;
 2975         version->Length = len;
 2976 #endif
 2977     }
 2978     return TRUE;
 2979 }
 2980 
 2981 
 2982 /***********************************************************************
 2983  *           PsImpersonateClient   (NTOSKRNL.EXE.@)
 2984  */
 2985 NTSTATUS WINAPI PsImpersonateClient(PETHREAD Thread, PACCESS_TOKEN Token, BOOLEAN CopyOnOpen,
 2986                                     BOOLEAN EffectiveOnly, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
 2987 {
 2988     FIXME("(%p, %p, %u, %u, %u): stub\n", Thread, Token, CopyOnOpen, EffectiveOnly, ImpersonationLevel);
 2989 
 2990     return STATUS_NOT_IMPLEMENTED;
 2991 }
 2992 
 2993 
 2994 /***********************************************************************
 2995  *           PsRevertToSelf   (NTOSKRNL.EXE.@)
 2996  */
 2997 void WINAPI PsRevertToSelf(void)
 2998 {
 2999     FIXME("\n");
 3000 }
 3001 
 3002 
 3003 /***********************************************************************
 3004  *           PsSetCreateProcessNotifyRoutine   (NTOSKRNL.EXE.@)
 3005  */
 3006 NTSTATUS WINAPI PsSetCreateProcessNotifyRoutine( PCREATE_PROCESS_NOTIFY_ROUTINE callback, BOOLEAN remove )
 3007 {
 3008     FIXME( "stub: %p %d\n", callback, remove );
 3009     return STATUS_SUCCESS;
 3010 }
 3011 
 3012 
 3013 /***********************************************************************
 3014  *           PsSetCreateProcessNotifyRoutineEx   (NTOSKRNL.EXE.@)
 3015  */
 3016 NTSTATUS WINAPI PsSetCreateProcessNotifyRoutineEx( PCREATE_PROCESS_NOTIFY_ROUTINE_EX callback, BOOLEAN remove )
 3017 {
 3018     FIXME( "stub: %p %d\n", callback, remove );
 3019     return STATUS_SUCCESS;
 3020 }
 3021 
 3022 
 3023 /***********************************************************************
 3024  *           PsSetCreateThreadNotifyRoutine   (NTOSKRNL.EXE.@)
 3025  */
 3026 NTSTATUS WINAPI PsSetCreateThreadNotifyRoutine( PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine )
 3027 {
 3028     FIXME( "stub: %p\n", NotifyRoutine );
 3029     return STATUS_SUCCESS;
 3030 }
 3031 
 3032 
 3033 /***********************************************************************
 3034  *           PsRemoveCreateThreadNotifyRoutine  (NTOSKRNL.EXE.@)
 3035  */
 3036 NTSTATUS WINAPI PsRemoveCreateThreadNotifyRoutine( PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine )
 3037 {
 3038     FIXME( "stub: %p\n", NotifyRoutine );
 3039     return STATUS_SUCCESS;
 3040 }
 3041 
 3042 
 3043 /***********************************************************************
 3044  *           PsRemoveLoadImageNotifyRoutine  (NTOSKRNL.EXE.@)
 3045  */
 3046 NTSTATUS WINAPI PsRemoveLoadImageNotifyRoutine(PLOAD_IMAGE_NOTIFY_ROUTINE routine)
 3047  {
 3048     unsigned int i;
 3049 
 3050     TRACE("routine %p.\n", routine);
 3051 
 3052     for (i = 0; i < load_image_notify_routine_count; ++i)
 3053         if (load_image_notify_routines[i] == routine)
 3054         {
 3055             --load_image_notify_routine_count;
 3056             memmove(&load_image_notify_routines[i], &load_image_notify_routines[i + 1],
 3057                     sizeof(*load_image_notify_routines) * (load_image_notify_routine_count - i));
 3058             return STATUS_SUCCESS;
 3059         }
 3060     return STATUS_PROCEDURE_NOT_FOUND;
 3061  }
 3062 
 3063 
 3064 /***********************************************************************
 3065  *           PsReferenceProcessFilePointer  (NTOSKRNL.EXE.@)
 3066  */
 3067 NTSTATUS WINAPI PsReferenceProcessFilePointer(PEPROCESS process, FILE_OBJECT **file)
 3068 {
 3069     FIXME("%p %p\n", process, file);
 3070     return STATUS_NOT_IMPLEMENTED;
 3071 }
 3072 
 3073 
 3074 /***********************************************************************
 3075  *           PsTerminateSystemThread   (NTOSKRNL.EXE.@)
 3076  */
 3077 NTSTATUS WINAPI PsTerminateSystemThread(NTSTATUS status)
 3078 {
 3079     TRACE("status %#x.\n", status);
 3080     ExitThread( status );
 3081 }
 3082 
 3083 
 3084 /***********************************************************************
 3085  *           PsSuspendProcess   (NTOSKRNL.EXE.@)
 3086  */
 3087 NTSTATUS WINAPI PsSuspendProcess(PEPROCESS process)
 3088 {
 3089     FIXME("stub: %p\n", process);
 3090     return STATUS_NOT_IMPLEMENTED;
 3091 }
 3092 
 3093 
 3094 /***********************************************************************
 3095  *           PsResumeProcess   (NTOSKRNL.EXE.@)
 3096  */
 3097 NTSTATUS WINAPI PsResumeProcess(PEPROCESS process)
 3098 {
 3099     FIXME("stub: %p\n", process);
 3100     return STATUS_NOT_IMPLEMENTED;
 3101 }
 3102 
 3103 
 3104 /***********************************************************************
 3105  *           MmGetSystemRoutineAddress   (NTOSKRNL.EXE.@)
 3106  */
 3107 PVOID WINAPI MmGetSystemRoutineAddress(PUNICODE_STRING SystemRoutineName)
 3108 {
 3109     HMODULE hMod;
 3110     STRING routineNameA;
 3111     PVOID pFunc = NULL;
 3112 
 3113     static const WCHAR ntoskrnlW[] = {'n','t','o','s','k','r','n','l','.','e','x','e',0};
 3114     static const WCHAR halW[] = {'h','a','l','.','d','l','l',0};
 3115 
 3116     if (!SystemRoutineName) return NULL;
 3117 
 3118     if (RtlUnicodeStringToAnsiString( &routineNameA, SystemRoutineName, TRUE ) == STATUS_SUCCESS)
 3119     {
 3120         /* We only support functions exported from ntoskrnl.exe or hal.dll */
 3121         hMod = GetModuleHandleW( ntoskrnlW );
 3122         pFunc = GetProcAddress( hMod, routineNameA.Buffer );
 3123         if (!pFunc)
 3124         {
 3125            hMod = GetModuleHandleW( halW );
 3126 
 3127            if (hMod) pFunc = GetProcAddress( hMod, routineNameA.Buffer );
 3128         }
 3129         RtlFreeAnsiString( &routineNameA );
 3130     }
 3131 
 3132     if (pFunc)
 3133         TRACE( "%s -> %p\n", debugstr_us(SystemRoutineName), pFunc );
 3134     else
 3135         FIXME( "%s not found\n", debugstr_us(SystemRoutineName) );
 3136     return pFunc;
 3137 }
 3138 
 3139 /***********************************************************************
 3140  *           MmIsThisAnNtAsSystem   (NTOSKRNL.EXE.@)
 3141  */
 3142 BOOLEAN WINAPI MmIsThisAnNtAsSystem(void)
 3143 {
 3144     TRACE("\n");
 3145     return FALSE;
 3146 }
 3147 
 3148 /***********************************************************************
 3149  *           MmProtectMdlSystemAddress   (NTOSKRNL.EXE.@)
 3150  */
 3151 NTSTATUS WINAPI MmProtectMdlSystemAddress(PMDL MemoryDescriptorList, ULONG NewProtect)
 3152 {
 3153     FIXME("(%p, %u) stub\n", MemoryDescriptorList, NewProtect);
 3154     return STATUS_SUCCESS;
 3155 }
 3156 
 3157 /***********************************************************************
 3158  *           MmQuerySystemSize   (NTOSKRNL.EXE.@)
 3159  */
 3160 MM_SYSTEMSIZE WINAPI MmQuerySystemSize(void)
 3161 {
 3162     FIXME("stub\n");
 3163     return MmLargeSystem;
 3164 }
 3165 
 3166 /***********************************************************************
 3167  *           KeInitializeDpc   (NTOSKRNL.EXE.@)
 3168  */
 3169 void WINAPI KeInitializeDpc(KDPC *dpc, PKDEFERRED_ROUTINE deferred_routine, void *deferred_context)
 3170 {
 3171     FIXME("dpc %p, deferred_routine %p, deferred_context %p semi-stub.\n",
 3172             dpc, deferred_routine, deferred_context);
 3173 
 3174     dpc->DeferredRoutine = deferred_routine;
 3175     dpc->DeferredContext = deferred_context;
 3176 }
 3177 
 3178 /***********************************************************************
 3179  *          KeSetImportanceDpc   (NTOSKRNL.EXE.@)
 3180  */
 3181 VOID WINAPI KeSetImportanceDpc(PRKDPC dpc, KDPC_IMPORTANCE importance)
 3182 {
 3183     FIXME("%p, %d stub\n", dpc, importance);
 3184 }
 3185 
 3186 /***********************************************************************
 3187  *          KeSetTargetProcessorDpc   (NTOSKRNL.EXE.@)
 3188  */
 3189 VOID WINAPI KeSetTargetProcessorDpc(PRKDPC dpc, CCHAR number)
 3190 {
 3191     FIXME("%p, %d stub\n", dpc, number);
 3192 }
 3193 
 3194 /***********************************************************************
 3195  *           READ_REGISTER_BUFFER_UCHAR   (NTOSKRNL.EXE.@)
 3196  */
 3197 VOID WINAPI READ_REGISTER_BUFFER_UCHAR(PUCHAR Register, PUCHAR Buffer, ULONG Count)
 3198 {
 3199     FIXME("stub\n");
 3200 }
 3201 
 3202 /*****************************************************
 3203  *           IoWMIRegistrationControl   (NTOSKRNL.EXE.@)
 3204  */
 3205 NTSTATUS WINAPI IoWMIRegistrationControl(PDEVICE_OBJECT DeviceObject, ULONG Action)
 3206 {
 3207     FIXME("(%p %u) stub\n", DeviceObject, Action);
 3208     return STATUS_SUCCESS;
 3209 }
 3210 
 3211 /*****************************************************
 3212  *           IoWMIOpenBlock   (NTOSKRNL.EXE.@)
 3213  */
 3214 NTSTATUS WINAPI IoWMIOpenBlock(LPCGUID guid, ULONG desired_access, PVOID *data_block_obj)
 3215 {
 3216     FIXME("(%p %u %p) stub\n", guid, desired_access, data_block_obj);
 3217     return STATUS_NOT_IMPLEMENTED;
 3218 }
 3219 
 3220 /*****************************************************
 3221  *           PsSetLoadImageNotifyRoutine   (NTOSKRNL.EXE.@)
 3222  */
 3223 NTSTATUS WINAPI PsSetLoadImageNotifyRoutine(PLOAD_IMAGE_NOTIFY_ROUTINE routine)
 3224 {
 3225     FIXME("routine %p, semi-stub.\n", routine);
 3226 
 3227     if (load_image_notify_routine_count == ARRAY_SIZE(load_image_notify_routines))
 3228         return STATUS_INSUFFICIENT_RESOURCES;
 3229 
 3230     load_image_notify_routines[load_image_notify_routine_count++] = routine;
 3231 
 3232     return STATUS_SUCCESS;
 3233 }
 3234 
 3235 /*****************************************************
 3236  *           IoSetThreadHardErrorMode  (NTOSKRNL.EXE.@)
 3237  */
 3238 BOOLEAN WINAPI IoSetThreadHardErrorMode(BOOLEAN EnableHardErrors)
 3239 {
 3240     FIXME("stub\n");
 3241     return FALSE;
 3242 }
 3243 
 3244 /*****************************************************
 3245  *           Ke386IoSetAccessProcess  (NTOSKRNL.EXE.@)
 3246  */
 3247 BOOLEAN WINAPI Ke386IoSetAccessProcess(PEPROCESS *process, ULONG flag)
 3248 {
 3249     FIXME("(%p %d) stub\n", process, flag);
 3250     return FALSE;
 3251 }
 3252 
 3253 /*****************************************************
 3254  *           Ke386SetIoAccessMap  (NTOSKRNL.EXE.@)
 3255  */
 3256 BOOLEAN WINAPI Ke386SetIoAccessMap(ULONG flag, PVOID buffer)
 3257 {
 3258     FIXME("(%d %p) stub\n", flag, buffer);
 3259     return FALSE;
 3260 }
 3261 
 3262 /*****************************************************
 3263  *           IoStartNextPacket  (NTOSKRNL.EXE.@)
 3264  */
 3265 VOID WINAPI IoStartNextPacket(PDEVICE_OBJECT deviceobject, BOOLEAN cancelable)
 3266 {
 3267     FIXME("(%p %d) stub\n", deviceobject, cancelable);
 3268 }
 3269 
 3270 /*****************************************************
 3271  *           ObQueryNameString  (NTOSKRNL.EXE.@)
 3272  */
 3273 NTSTATUS WINAPI ObQueryNameString( void *object, OBJECT_NAME_INFORMATION *name, ULONG size, ULONG *ret_size )
 3274 {
 3275     HANDLE handle;
 3276     NTSTATUS ret;
 3277 
 3278     TRACE("object %p, name %p, size %u, ret_size %p.\n", object, name, size, ret_size);
 3279 
 3280     if ((ret = ObOpenObjectByPointer( object, 0, NULL, 0, NULL, KernelMode, &handle )))
 3281         return ret;
 3282     ret = NtQueryObject( handle, ObjectNameInformation, name, size, ret_size );
 3283 
 3284     NtClose( handle );
 3285     return ret;
 3286 }
 3287 
 3288 /*****************************************************
 3289  *           IoRegisterPlugPlayNotification  (NTOSKRNL.EXE.@)
 3290  */
 3291 NTSTATUS WINAPI IoRegisterPlugPlayNotification(IO_NOTIFICATION_EVENT_CATEGORY category, ULONG flags, PVOID data,
 3292                                                PDRIVER_OBJECT driver, PDRIVER_NOTIFICATION_CALLBACK_ROUTINE callback,
 3293                                                PVOID context, PVOID *notification)
 3294 {
 3295     FIXME("(%u %u %p %p %p %p %p) stub\n", category, flags, data, driver, callback, context, notification);
 3296     return STATUS_SUCCESS;
 3297 }
 3298 
 3299 /*****************************************************
 3300  *           IoUnregisterPlugPlayNotification    (NTOSKRNL.EXE.@)
 3301  */
 3302 NTSTATUS WINAPI IoUnregisterPlugPlayNotification(PVOID notification)
 3303 {
 3304     FIXME("stub: %p\n", notification);
 3305     return STATUS_SUCCESS;
 3306 }
 3307 
 3308 /*****************************************************
 3309  *           IoCsqInitialize  (NTOSKRNL.EXE.@)
 3310  */
 3311 NTSTATUS WINAPI IoCsqInitialize(PIO_CSQ csq, PIO_CSQ_INSERT_IRP insert_irp, PIO_CSQ_REMOVE_IRP remove_irp,
 3312                                 PIO_CSQ_PEEK_NEXT_IRP peek_irp, PIO_CSQ_ACQUIRE_LOCK acquire_lock,
 3313                                 PIO_CSQ_RELEASE_LOCK release_lock, PIO_CSQ_COMPLETE_CANCELED_IRP complete_irp)
 3314 {
 3315     FIXME("(%p %p %p %p %p %p %p) stub\n",
 3316           csq, insert_irp, remove_irp, peek_irp, acquire_lock, release_lock, complete_irp);
 3317     return STATUS_SUCCESS;
 3318 }
 3319 
 3320 /***********************************************************************
 3321  *           KeEnterCriticalRegion  (NTOSKRNL.EXE.@)
 3322  */
 3323 void WINAPI KeEnterCriticalRegion(void)
 3324 {
 3325     TRACE( "semi-stub\n" );
 3326     KeGetCurrentThread()->critical_region++;
 3327 }
 3328 
 3329 /***********************************************************************
 3330  *           KeLeaveCriticalRegion  (NTOSKRNL.EXE.@)
 3331  */
 3332 void WINAPI KeLeaveCriticalRegion(void)
 3333 {
 3334     TRACE( "semi-stub\n" );
 3335     KeGetCurrentThread()->critical_region--;
 3336 }
 3337 
 3338 /***********************************************************************
 3339  *           KeAreApcsDisabled    (NTOSKRNL.@)
 3340  */
 3341 BOOLEAN WINAPI KeAreApcsDisabled(void)
 3342 {
 3343     unsigned int critical_region = KeGetCurrentThread()->critical_region;
 3344     TRACE( "%u\n", critical_region );
 3345     return !!critical_region;
 3346 }
 3347 
 3348 /***********************************************************************
 3349  *           KeBugCheck    (NTOSKRNL.@)
 3350  */
 3351 void WINAPI KeBugCheck(ULONG code)
 3352 {
 3353     KeBugCheckEx(code, 0, 0, 0, 0);
 3354 }
 3355 
 3356 /***********************************************************************
 3357  *           KeBugCheckEx    (NTOSKRNL.@)
 3358  */
 3359 void WINAPI KeBugCheckEx(ULONG code, ULONG_PTR param1, ULONG_PTR param2, ULONG_PTR param3, ULONG_PTR param4)
 3360 {
 3361     ERR( "%x %lx %lx %lx %lx\n", code, param1, param2, param3, param4 );
 3362     ExitProcess( code );
 3363 }
 3364 
 3365 /***********************************************************************
 3366  *           ProbeForRead   (NTOSKRNL.EXE.@)
 3367  */
 3368 void WINAPI ProbeForRead(void *address, SIZE_T length, ULONG alignment)
 3369 {
 3370     FIXME("(%p %lu %u) stub\n", address, length, alignment);
 3371 }
 3372 
 3373 /***********************************************************************
 3374  *           ProbeForWrite   (NTOSKRNL.EXE.@)
 3375  */
 3376 void WINAPI ProbeForWrite(void *address, SIZE_T length, ULONG alignment)
 3377 {
 3378     FIXME("(%p %lu %u) stub\n", address, length, alignment);
 3379 }
 3380 
 3381 /***********************************************************************
 3382  *           CmRegisterCallback  (NTOSKRNL.EXE.@)
 3383  */
 3384 NTSTATUS WINAPI CmRegisterCallback(EX_CALLBACK_FUNCTION *function, void *context, LARGE_INTEGER *cookie)
 3385 {
 3386     FIXME("(%p %p %p): stub\n", function, context, cookie);
 3387     return STATUS_NOT_IMPLEMENTED;
 3388 }
 3389 
 3390 /***********************************************************************
 3391  *           CmUnRegisterCallback  (NTOSKRNL.EXE.@)
 3392  */
 3393 NTSTATUS WINAPI CmUnRegisterCallback(LARGE_INTEGER cookie)
 3394 {
 3395     FIXME("(%s): stub\n", wine_dbgstr_longlong(cookie.QuadPart));
 3396     return STATUS_NOT_IMPLEMENTED;
 3397 }
 3398 
 3399 /***********************************************************************
 3400  *           IoAttachDevice  (NTOSKRNL.EXE.@)
 3401  */
 3402 NTSTATUS WINAPI IoAttachDevice(DEVICE_OBJECT *source, UNICODE_STRING *target, DEVICE_OBJECT *attached)
 3403 {
 3404     FIXME("(%p, %s, %p): stub\n", source, debugstr_us(target), attached);
 3405     return STATUS_NOT_IMPLEMENTED;
 3406 }
 3407 
 3408 
 3409 static NTSTATUS open_driver( const UNICODE_STRING *service_name, SC_HANDLE *service )
 3410 {
 3411     QUERY_SERVICE_CONFIGW *service_config = NULL;
 3412     SC_HANDLE manager_handle;
 3413     DWORD config_size = 0;
 3414     WCHAR *name;
 3415 
 3416     if (!(name = RtlAllocateHeap( GetProcessHeap(), 0, service_name->Length + sizeof(WCHAR) )))
 3417         return STATUS_NO_MEMORY;
 3418 
 3419     memcpy( name, service_name->Buffer, service_name->Length );
 3420     name[ service_name->Length / sizeof(WCHAR) ] = 0;
 3421 
 3422     if (wcsncmp( name, servicesW, lstrlenW(servicesW) ))
 3423     {
 3424         FIXME( "service name %s is not a keypath\n", debugstr_us(service_name) );
 3425         RtlFreeHeap( GetProcessHeap(), 0, name );
 3426         return STATUS_NOT_IMPLEMENTED;
 3427     }
 3428 
 3429     if (!(manager_handle = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT )))
 3430     {
 3431         WARN( "failed to connect to service manager\n" );
 3432         RtlFreeHeap( GetProcessHeap(), 0, name );
 3433         return STATUS_NOT_SUPPORTED;
 3434     }
 3435 
 3436     *service = OpenServiceW( manager_handle, name + lstrlenW(servicesW),
 3437                              SERVICE_QUERY_CONFIG | SERVICE_SET_STATUS );
 3438     RtlFreeHeap( GetProcessHeap(), 0, name );
 3439     CloseServiceHandle( manager_handle );
 3440 
 3441     if (!*service)
 3442     {
 3443         WARN( "failed to open service %s\n", debugstr_us(service_name) );
 3444         return STATUS_UNSUCCESSFUL;
 3445     }
 3446 
 3447     QueryServiceConfigW( *service, NULL, 0, &config_size );
 3448     if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
 3449     {
 3450         WARN( "failed to query service config\n" );
 3451         goto error;
 3452     }
 3453 
 3454     if (!(service_config = RtlAllocateHeap( GetProcessHeap(), 0, config_size )))
 3455         goto error;
 3456 
 3457     if (!QueryServiceConfigW( *service, service_config, config_size, &config_size ))
 3458     {
 3459         WARN( "failed to query service config\n" );
 3460         goto error;
 3461     }
 3462 
 3463     if (service_config->dwServiceType != SERVICE_KERNEL_DRIVER &&
 3464         service_config->dwServiceType != SERVICE_FILE_SYSTEM_DRIVER)
 3465     {
 3466         WARN( "service %s is not a kernel driver\n", debugstr_us(service_name) );
 3467         goto error;
 3468     }
 3469 
 3470     TRACE( "opened service for driver %s\n", debugstr_us(service_name) );
 3471     RtlFreeHeap( GetProcessHeap(), 0, service_config );
 3472     return STATUS_SUCCESS;
 3473 
 3474 error:
 3475     CloseServiceHandle( *service );
 3476     RtlFreeHeap( GetProcessHeap(), 0, service_config );
 3477     return STATUS_UNSUCCESSFUL;
 3478 }
 3479 
 3480 /* find the LDR_DATA_TABLE_ENTRY corresponding to the driver module */
 3481 static LDR_DATA_TABLE_ENTRY *find_ldr_module( HMODULE module )
 3482 {
 3483     LDR_DATA_TABLE_ENTRY *ldr;
 3484     ULONG_PTR magic;
 3485 
 3486     LdrLockLoaderLock( 0, NULL, &magic );
 3487     if (LdrFindEntryForAddress( module, &ldr ))
 3488     {
 3489         WARN( "module not found for %p\n", module );
 3490         ldr = NULL;
 3491     }
 3492     LdrUnlockLoaderLock( 0, magic );
 3493 
 3494     return ldr;
 3495 }
 3496 
 3497 /* convert PE image VirtualAddress to Real Address */
 3498 static inline void *get_rva( HMODULE module, DWORD va )
 3499 {
 3500     return (void *)((char *)module + va);
 3501 }
 3502 
 3503 static void WINAPI ldr_notify_callback(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context)
 3504 {
 3505     const IMAGE_DATA_DIRECTORY *relocs;
 3506     IMAGE_BASE_RELOCATION *rel, *end;
 3507     SYSTEM_BASIC_INFORMATION info;
 3508     IMAGE_NT_HEADERS *nt;
 3509     INT_PTR delta;
 3510     char *base;
 3511     HMODULE module;
 3512 
 3513     if (reason != LDR_DLL_NOTIFICATION_REASON_LOADED) return;
 3514     TRACE( "loading %s\n", debugstr_us(data->Loaded.BaseDllName));
 3515 
 3516     module = data->Loaded.DllBase;
 3517     nt = RtlImageNtHeader( module );
 3518     base = (char *)nt->OptionalHeader.ImageBase;
 3519     if (!(delta = (char *)module - base)) return;
 3520 
 3521     /* the loader does not apply relocations to non page-aligned binaries or executables,
 3522      * we have to do it ourselves */
 3523 
 3524     NtQuerySystemInformation( SystemBasicInformation, &info, sizeof(info), NULL );
 3525     if (nt->OptionalHeader.SectionAlignment >= info.PageSize && (nt->FileHeader.Characteristics & IMAGE_FILE_DLL))
 3526         return;
 3527 
 3528     if (nt->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
 3529     {
 3530         WARN( "Need to relocate module from %p to %p, but there are no relocation records\n", base, module );
 3531         return;
 3532     }
 3533 
 3534     relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
 3535     if (!relocs->Size || !relocs->VirtualAddress) return;
 3536 
 3537     TRACE( "relocating from %p-%p to %p-%p\n", base, base + nt->OptionalHeader.SizeOfImage,
 3538            module, (char *)module + nt->OptionalHeader.SizeOfImage );
 3539 
 3540     rel = get_rva( module, relocs->VirtualAddress );
 3541     end = get_rva( module, relocs->VirtualAddress + relocs->Size );
 3542 
 3543     while (rel < end - 1 && rel->SizeOfBlock)
 3544     {
 3545         char *page = get_rva( module, rel->VirtualAddress );
 3546         DWORD old_prot1, old_prot2;
 3547 
 3548         if (rel->VirtualAddress >= nt->OptionalHeader.SizeOfImage)
 3549         {
 3550             WARN( "invalid address %p in relocation %p\n", get_rva( module, rel->VirtualAddress ), rel );
 3551             return;
 3552         }
 3553 
 3554         /* Relocation entries may hang over the end of the page, so we need to
 3555          * protect two pages. */
 3556         VirtualProtect( page, info.PageSize, PAGE_READWRITE, &old_prot1 );
 3557         VirtualProtect( page + info.PageSize, info.PageSize, PAGE_READWRITE, &old_prot2 );
 3558         rel = LdrProcessRelocationBlock( page, (rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT),
 3559                                          (USHORT *)(rel + 1), delta );
 3560         VirtualProtect( page, info.PageSize, old_prot1, &old_prot1 );
 3561         VirtualProtect( page + info.PageSize, info.PageSize, old_prot2, &old_prot2 );
 3562         if (!rel)
 3563         {
 3564             WARN( "LdrProcessRelocationBlock failed\n" );
 3565             return;
 3566         }
 3567     }
 3568 }
 3569 
 3570 /* load the .sys module for a device driver */
 3571 static HMODULE load_driver( const WCHAR *driver_name, const UNICODE_STRING *keyname )
 3572 {
 3573     static const WCHAR driversW[] = {'\\','d','r','i','v','e','r','s','\\',0};
 3574     static const WCHAR systemrootW[] = {'\\','S','y','s','t','e','m','R','o','o','t','\\',0};
 3575     static const WCHAR postfixW[] = {'.','s','y','s',0};
 3576     static const WCHAR ntprefixW[] = {'\\','?','?','\\',0};
 3577     static const WCHAR ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
 3578     HKEY driver_hkey;
 3579     HMODULE module;
 3580     LPWSTR path = NULL, str;
 3581     DWORD type, size;
 3582 
 3583     if (RegOpenKeyW( HKEY_LOCAL_MACHINE, keyname->Buffer + 18 /* skip \registry\machine */, &driver_hkey ))
 3584     {
 3585         ERR( "cannot open key %s, err=%u\n", wine_dbgstr_w(keyname->Buffer), GetLastError() );
 3586         return NULL;
 3587     }
 3588 
 3589     /* read the executable path from memory */
 3590     size = 0;
 3591     if (!RegQueryValueExW( driver_hkey, ImagePathW, NULL, &type, NULL, &size ))
 3592     {
 3593         str = HeapAlloc( GetProcessHeap(), 0, size );
 3594         if (!RegQueryValueExW( driver_hkey, ImagePathW, NULL, &type, (LPBYTE)str, &size ))
 3595         {
 3596             size = ExpandEnvironmentStringsW(str,NULL,0);
 3597             path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
 3598             ExpandEnvironmentStringsW(str,path,size);
 3599         }
 3600         HeapFree( GetProcessHeap(), 0, str );
 3601         if (!path)
 3602         {
 3603             RegCloseKey( driver_hkey );
 3604             return NULL;
 3605         }
 3606 
 3607         if (!wcsnicmp( path, systemrootW, 12 ))
 3608         {
 3609             WCHAR buffer[MAX_PATH];
 3610 
 3611             GetWindowsDirectoryW(buffer, MAX_PATH);
 3612 
 3613             str = HeapAlloc(GetProcessHeap(), 0, (size -11 + lstrlenW(buffer))
 3614                                                         * sizeof(WCHAR));
 3615             lstrcpyW(str, buffer);
 3616             lstrcatW(str, path + 11);
 3617             HeapFree( GetProcessHeap(), 0, path );
 3618             path = str;
 3619         }
 3620         else if (!wcsncmp( path, ntprefixW, 4 ))
 3621             str = path + 4;
 3622         else
 3623             str = path;
 3624     }
 3625     else
 3626     {
 3627         /* default is to use the driver name + ".sys" */
 3628         WCHAR buffer[MAX_PATH];
 3629         GetSystemDirectoryW(buffer, MAX_PATH);
 3630         path = HeapAlloc(GetProcessHeap(),0,
 3631           (lstrlenW(buffer) + lstrlenW(driversW) + lstrlenW(driver_name) + lstrlenW(postfixW) + 1)
 3632           *sizeof(WCHAR));
 3633         lstrcpyW(path, buffer);
 3634         lstrcatW(path, driversW);
 3635         lstrcatW(path, driver_name);
 3636         lstrcatW(path, postfixW);
 3637         str = path;
 3638     }
 3639     RegCloseKey( driver_hkey );
 3640 
 3641     TRACE( "loading driver %s\n", wine_dbgstr_w(str) );
 3642 
 3643     module = LoadLibraryW( str );
 3644 
 3645     if (module && load_image_notify_routine_count)
 3646     {
 3647         UNICODE_STRING module_name;
 3648         IMAGE_NT_HEADERS *nt;
 3649         IMAGE_INFO info;
 3650         unsigned int i;
 3651 
 3652         RtlInitUnicodeString(&module_name, str);
 3653         nt = RtlImageNtHeader(module);
 3654         memset(&info, 0, sizeof(info));
 3655         info.u.s.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT;
 3656         info.u.s.SystemModeImage = TRUE;
 3657         info.ImageSize = nt->OptionalHeader.SizeOfImage;
 3658         info.ImageBase = module;
 3659 
 3660         for (i = 0; i < load_image_notify_routine_count; ++i)
 3661         {
 3662             TRACE("Calling image load notify %p.\n", load_image_notify_routines[i]);
 3663             load_image_notify_routines[i](&module_name, NULL, &info);
 3664             TRACE("Called image load notify %p.\n", load_image_notify_routines[i]);
 3665         }
 3666     }
 3667 
 3668     HeapFree( GetProcessHeap(), 0, path );
 3669     return module;
 3670 }
 3671 
 3672 /* call the driver init entry point */
 3673 static NTSTATUS WINAPI init_driver( DRIVER_OBJECT *driver_object, UNICODE_STRING *keyname )
 3674 {
 3675     unsigned int i;
 3676     NTSTATUS status;
 3677     const IMAGE_NT_HEADERS *nt;
 3678     const WCHAR *driver_name;
 3679     HMODULE module;
 3680 
 3681     /* Retrieve driver name from the keyname */
 3682     driver_name = wcsrchr( keyname->Buffer, '\\' );
 3683     driver_name++;
 3684 
 3685     module = load_driver( driver_name, keyname );
 3686     if (!module)
 3687         return STATUS_DLL_INIT_FAILED;
 3688 
 3689     driver_object->DriverSection = find_ldr_module( module );
 3690     driver_object->DriverStart = ((LDR_DATA_TABLE_ENTRY *)driver_object->DriverSection)->DllBase;
 3691     driver_object->DriverSize = ((LDR_DATA_TABLE_ENTRY *)driver_object->DriverSection)->SizeOfImage;
 3692 
 3693     nt = RtlImageNtHeader( module );
 3694     if (!nt->OptionalHeader.AddressOfEntryPoint) return STATUS_SUCCESS;
 3695     driver_object->DriverInit = (PDRIVER_INITIALIZE)((char *)module + nt->OptionalHeader.AddressOfEntryPoint);
 3696 
 3697     TRACE_(relay)( "\1Call driver init %p (obj=%p,str=%s)\n",
 3698                    driver_object->DriverInit, driver_object, wine_dbgstr_w(keyname->Buffer) );
 3699 
 3700     status = driver_object->DriverInit( driver_object, keyname );
 3701 
 3702     TRACE_(relay)( "\1Ret  driver init %p (obj=%p,str=%s) retval=%08x\n",
 3703                    driver_object->DriverInit, driver_object, wine_dbgstr_w(keyname->Buffer), status );
 3704 
 3705     TRACE( "init done for %s obj %p\n", wine_dbgstr_w(driver_name), driver_object );
 3706     TRACE( "- DriverInit = %p\n", driver_object->DriverInit );
 3707     TRACE( "- DriverStartIo = %p\n", driver_object->DriverStartIo );
 3708     TRACE( "- DriverUnload = %p\n", driver_object->DriverUnload );
 3709     for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
 3710         TRACE( "- MajorFunction[%d] = %p\n", i, driver_object->MajorFunction[i] );
 3711 
 3712     return status;
 3713 }
 3714 
 3715 static BOOLEAN get_drv_name( UNICODE_STRING *drv_name, const UNICODE_STRING *service_name )
 3716 {
 3717     static const WCHAR driverW[] = {'\\','D','r','i','v','e','r','\\',0};
 3718     WCHAR *str;
 3719 
 3720     if (!(str = heap_alloc( sizeof(driverW) + service_name->Length - lstrlenW(servicesW)*sizeof(WCHAR) )))
 3721         return FALSE;
 3722 
 3723     lstrcpyW( str, driverW );
 3724     lstrcpynW( str + lstrlenW(driverW), service_name->Buffer + lstrlenW(servicesW),
 3725             service_name->Length/sizeof(WCHAR) - lstrlenW(servicesW) + 1 );
 3726     RtlInitUnicodeString( drv_name, str );
 3727     return TRUE;
 3728 }
 3729 
 3730 /***********************************************************************
 3731  *           ZwLoadDriver (NTOSKRNL.EXE.@)
 3732  */
 3733 NTSTATUS WINAPI ZwLoadDriver( const UNICODE_STRING *service_name )
 3734 {
 3735     SERVICE_STATUS_HANDLE service_handle;
 3736     struct wine_rb_entry *entry;
 3737     struct wine_driver *driver;
 3738     UNICODE_STRING drv_name;
 3739     NTSTATUS status;
 3740 
 3741     TRACE( "(%s)\n", debugstr_us(service_name) );
 3742 
 3743     if ((status = open_driver( service_name, (SC_HANDLE *)&service_handle )) != STATUS_SUCCESS)
 3744         return status;
 3745 
 3746     if (!get_drv_name( &drv_name, service_name ))
 3747     {
 3748         CloseServiceHandle( (void *)service_handle );
 3749         return STATUS_NO_MEMORY;
 3750     }
 3751 
 3752     if (wine_rb_get( &wine_drivers, &drv_name ))
 3753     {
 3754         TRACE( "driver %s already loaded\n", debugstr_us(&drv_name) );
 3755         RtlFreeUnicodeString( &drv_name );
 3756         CloseServiceHandle( (void *)service_handle );
 3757         return STATUS_IMAGE_ALREADY_LOADED;
 3758     }
 3759 
 3760     set_service_status( service_handle, SERVICE_START_PENDING, 0 );
 3761 
 3762     status = IoCreateDriver( &drv_name, init_driver );
 3763     entry = wine_rb_get( &wine_drivers, &drv_name );
 3764     RtlFreeUnicodeString( &drv_name );
 3765     if (status != STATUS_SUCCESS)
 3766     {
 3767         ERR( "failed to create driver %s: %08x\n", debugstr_us(service_name), status );
 3768         goto error;
 3769     }
 3770 
 3771     driver = WINE_RB_ENTRY_VALUE( entry, struct wine_driver, entry );
 3772     driver->service_handle = service_handle;
 3773 
 3774     pnp_manager_enumerate_root_devices( service_name->Buffer + wcslen( servicesW ) );
 3775 
 3776     set_service_status( service_handle, SERVICE_RUNNING,
 3777                         SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN );
 3778     return STATUS_SUCCESS;
 3779 
 3780 error:
 3781     set_service_status( service_handle, SERVICE_STOPPED, 0 );
 3782     CloseServiceHandle( (void *)service_handle );
 3783     return status;
 3784 }
 3785 
 3786 /***********************************************************************
 3787  *           ZwUnloadDriver (NTOSKRNL.EXE.@)
 3788  */
 3789 NTSTATUS WINAPI ZwUnloadDriver( const UNICODE_STRING *service_name )
 3790 {
 3791     struct wine_rb_entry *entry;
 3792     UNICODE_STRING drv_name;
 3793 
 3794     TRACE( "(%s)\n", debugstr_us(service_name) );
 3795 
 3796     if (!get_drv_name( &drv_name, service_name ))
 3797         return STATUS_NO_MEMORY;
 3798 
 3799     entry = wine_rb_get( &wine_drivers, &drv_name );
 3800     RtlFreeUnicodeString( &drv_name );
 3801     if (!entry)
 3802     {
 3803         ERR( "failed to locate driver %s\n", debugstr_us(service_name) );
 3804         return STATUS_OBJECT_NAME_NOT_FOUND;
 3805     }
 3806 
 3807     unload_driver( entry, NULL );
 3808 
 3809     return STATUS_SUCCESS;
 3810 }
 3811 
 3812 /***********************************************************************
 3813  *           IoCreateFile (NTOSKRNL.EXE.@)
 3814  */
 3815 NTSTATUS WINAPI IoCreateFile(HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
 3816                               IO_STATUS_BLOCK *io, LARGE_INTEGER *alloc_size, ULONG attributes, ULONG sharing,
 3817                               ULONG disposition, ULONG create_options, VOID *ea_buffer, ULONG ea_length,
 3818                               CREATE_FILE_TYPE file_type, VOID *parameters, ULONG options )
 3819 {
 3820     FIXME(": stub\n");
 3821     return STATUS_NOT_IMPLEMENTED;
 3822 }
 3823 
 3824 /***********************************************************************
 3825  *           IoCreateNotificationEvent (NTOSKRNL.EXE.@)
 3826  */
 3827 PKEVENT WINAPI IoCreateNotificationEvent(UNICODE_STRING *name, HANDLE *handle)
 3828 {
 3829     FIXME( "stub: %s %p\n", debugstr_us(name), handle );
 3830     return NULL;
 3831 }
 3832 
 3833 
 3834 /**************************************************************************
 3835  *      __chkstk (NTOSKRNL.@)
 3836  */
 3837 #ifdef __x86_64__
 3838 /* Supposed to touch all the stack pages, but we shouldn't need that. */
 3839 __ASM_GLOBAL_FUNC( __chkstk, "ret" );
 3840 #elif defined(__i386__)
 3841 __ASM_GLOBAL_FUNC( _chkstk,
 3842                    "negl %eax\n\t"
 3843                    "addl %esp,%eax\n\t"
 3844                    "xchgl %esp,%eax\n\t"
 3845                    "movl 0(%eax),%eax\n\t"  /* copy return address from old location */
 3846                    "movl %eax,0(%esp)\n\t"
 3847                    "ret" )
 3848 #elif defined(__arm__)
 3849 /* Incoming r4 contains words to allocate, converting to bytes then return */
 3850 __ASM_GLOBAL_FUNC( __chkstk, "lsl r4, r4, #2\n\t"
 3851                              "bx lr" )
 3852 #elif defined(__aarch64__)
 3853 /* Supposed to touch all the stack pages, but we shouldn't need that. */
 3854 __ASM_GLOBAL_FUNC( __chkstk, "ret" );
 3855 #endif
 3856 
 3857 /*********************************************************************
 3858  *           PsAcquireProcessExitSynchronization    (NTOSKRNL.@)
 3859 */
 3860 NTSTATUS WINAPI PsAcquireProcessExitSynchronization(PEPROCESS process)
 3861 {
 3862     FIXME("stub: %p\n", process);
 3863 
 3864     return STATUS_NOT_IMPLEMENTED;
 3865 }
 3866 
 3867 /*********************************************************************
 3868  *           PsReleaseProcessExitSynchronization    (NTOSKRNL.@)
 3869  */
 3870 void WINAPI PsReleaseProcessExitSynchronization(PEPROCESS process)
 3871 {
 3872     FIXME("stub: %p\n", process);
 3873 }
 3874 
 3875 typedef struct _EX_PUSH_LOCK_WAIT_BLOCK *PEX_PUSH_LOCK_WAIT_BLOCK;
 3876 /*********************************************************************
 3877  *           ExfUnblockPushLock    (NTOSKRNL.@)
 3878  */
 3879 DEFINE_FASTCALL_WRAPPER( ExfUnblockPushLock, 8 )
 3880 void FASTCALL ExfUnblockPushLock( EX_PUSH_LOCK *lock, PEX_PUSH_LOCK_WAIT_BLOCK block )
 3881 {
 3882     FIXME( "stub: %p, %p\n", lock, block );
 3883 }
 3884 
 3885 /*********************************************************************
 3886  *           FsRtlRegisterFileSystemFilterCallbacks    (NTOSKRNL.@)
 3887  */
 3888 NTSTATUS WINAPI FsRtlRegisterFileSystemFilterCallbacks( DRIVER_OBJECT *object, PFS_FILTER_CALLBACKS callbacks)
 3889 {
 3890     FIXME("stub: %p %p\n", object, callbacks);
 3891     return STATUS_NOT_IMPLEMENTED;
 3892 }
 3893 
 3894 /*********************************************************************
 3895  *           SeSinglePrivilegeCheck    (NTOSKRNL.@)
 3896  */
 3897 BOOLEAN WINAPI SeSinglePrivilegeCheck(LUID privilege, KPROCESSOR_MODE mode)
 3898 {
 3899     static int once;
 3900     if (!once++) FIXME("stub: %08x%08x %u\n", privilege.HighPart, privilege.LowPart, mode);
 3901     return TRUE;
 3902 }
 3903 
 3904 /*********************************************************************
 3905  *           SePrivilegeCheck    (NTOSKRNL.@)
 3906  */
 3907 BOOLEAN WINAPI SePrivilegeCheck(PRIVILEGE_SET *privileges, SECURITY_SUBJECT_CONTEXT *context, KPROCESSOR_MODE mode)
 3908 {
 3909     FIXME("stub: %p %p %u\n", privileges, context, mode);
 3910     return TRUE;
 3911 }
 3912 
 3913 /*********************************************************************
 3914  *           SeLocateProcessImageName    (NTOSKRNL.@)
 3915  */
 3916 NTSTATUS WINAPI SeLocateProcessImageName(PEPROCESS process, UNICODE_STRING **image_name)
 3917 {
 3918     FIXME("stub: %p %p\n", process, image_name);
 3919     if (image_name) *image_name = NULL;
 3920     return STATUS_NOT_IMPLEMENTED;
 3921 }
 3922 
 3923 /*********************************************************************
 3924  *           KeFlushQueuedDpcs    (NTOSKRNL.@)
 3925  */
 3926 void WINAPI KeFlushQueuedDpcs(void)
 3927 {
 3928     FIXME("stub!\n");
 3929 }
 3930 
 3931 /*********************************************************************
 3932  *           DbgQueryDebugFilterState    (NTOSKRNL.@)
 3933  */
 3934 NTSTATUS WINAPI DbgQueryDebugFilterState(ULONG component, ULONG level)
 3935 {
 3936     FIXME("stub: %d %d\n", component, level);
 3937     return STATUS_NOT_IMPLEMENTED;
 3938 }
 3939 
 3940 /*********************************************************************
 3941  *           PsGetProcessWow64Process    (NTOSKRNL.@)
 3942  */
 3943 PVOID WINAPI PsGetProcessWow64Process(PEPROCESS process)
 3944 {
 3945     FIXME("stub: %p\n", process);
 3946     return NULL;
 3947 }
 3948 
 3949 /*********************************************************************
 3950  *           MmCopyVirtualMemory    (NTOSKRNL.@)
 3951  */
 3952 NTSTATUS WINAPI MmCopyVirtualMemory(PEPROCESS fromprocess, void *fromaddress, PEPROCESS toprocess,
 3953                                     void *toaddress, SIZE_T bufsize, KPROCESSOR_MODE mode,
 3954                                     SIZE_T *copied)
 3955 {
 3956     FIXME("fromprocess %p, fromaddress %p, toprocess %p, toaddress %p, bufsize %lu, mode %d, copied %p stub.\n",
 3957             fromprocess, fromaddress, toprocess, toaddress, bufsize, mode, copied);
 3958 
 3959     *copied = 0;
 3960     return STATUS_NOT_IMPLEMENTED;
 3961 }
 3962 
 3963 /*********************************************************************
 3964  *           KeEnterGuardedRegion    (NTOSKRNL.@)
 3965  */
 3966 void WINAPI KeEnterGuardedRegion(void)
 3967 {
 3968     FIXME("\n");
 3969 }
 3970 
 3971 /*********************************************************************
 3972  *           KeLeaveGuardedRegion    (NTOSKRNL.@)
 3973  */
 3974 void WINAPI KeLeaveGuardedRegion(void)
 3975 {
 3976     FIXME("\n");
 3977 }
 3978 
 3979 static const WCHAR token_type_name[] = {'T','o','k','e','n',0};
 3980 
 3981 static struct _OBJECT_TYPE token_type =
 3982 {
 3983     token_type_name
 3984 };
 3985 
 3986 POBJECT_TYPE SeTokenObjectType = &token_type;
 3987 
 3988 /*************************************************************************
 3989  *           ExUuidCreate            (NTOSKRNL.@)
 3990  *
 3991  * Creates a 128bit UUID.
 3992  *
 3993  * RETURNS
 3994  *
 3995  *  STATUS_SUCCESS if successful.
 3996  *  RPC_NT_UUID_LOCAL_ONLY if UUID is only locally unique.
 3997  *
 3998  * NOTES
 3999  *
 4000  *  Follows RFC 4122, section 4.4 (Algorithms for Creating a UUID from
 4001  *  Truly Random or Pseudo-Random Numbers)
 4002  */
 4003 NTSTATUS WINAPI ExUuidCreate(UUID *uuid)
 4004 {
 4005     RtlGenRandom(uuid, sizeof(*uuid));
 4006     /* Clear the version bits and set the version (4) */
 4007     uuid->Data3 &= 0x0fff;
 4008     uuid->Data3 |= (4 << 12);
 4009     /* Set the topmost bits of Data4 (clock_seq_hi_and_reserved) as
 4010      * specified in RFC 4122, section 4.4.
 4011      */
 4012     uuid->Data4[0] &= 0x3f;
 4013     uuid->Data4[0] |= 0x80;
 4014 
 4015     TRACE("%s\n", debugstr_guid(uuid));
 4016 
 4017     return STATUS_SUCCESS;
 4018 }
 4019 
 4020 /***********************************************************************
 4021  *           ExSetTimerResolution   (NTOSKRNL.EXE.@)
 4022  */
 4023 ULONG WINAPI ExSetTimerResolution(ULONG time, BOOLEAN set_resolution)
 4024 {
 4025     FIXME("stub: %u %d\n", time, set_resolution);
 4026     return KeQueryTimeIncrement();
 4027 }
 4028 
 4029 /***********************************************************************
 4030  *           IoGetRequestorProcess   (NTOSKRNL.EXE.@)
 4031  */
 4032 PEPROCESS WINAPI IoGetRequestorProcess(IRP *irp)
 4033 {
 4034     TRACE("irp %p.\n", irp);
 4035     return irp->Tail.Overlay.Thread->kthread.process;
 4036 }
 4037 
 4038 #ifdef _WIN64
 4039 /***********************************************************************
 4040  *           IoIs32bitProcess   (NTOSKRNL.EXE.@)
 4041  */
 4042 BOOLEAN WINAPI IoIs32bitProcess(IRP *irp)
 4043 {
 4044     TRACE("irp %p.\n", irp);
 4045     return irp->Tail.Overlay.Thread->kthread.process->wow64;
 4046 }
 4047 #endif
 4048 
 4049 /***********************************************************************
 4050  *           RtlIsNtDdiVersionAvailable   (NTOSKRNL.EXE.@)
 4051  */
 4052 BOOLEAN WINAPI RtlIsNtDdiVersionAvailable(ULONG version)
 4053 {
 4054     FIXME("stub: %d\n", version);
 4055     return FALSE;
 4056 }
 4057 
 4058 BOOLEAN WINAPI KdRefreshDebuggerNotPresent(void)
 4059 {
 4060     TRACE(".\n");
 4061 
 4062     return !KdDebuggerEnabled;
 4063 }
 4064 
 4065 struct generic_call_dpc_context
 4066 {
 4067     DEFERRED_REVERSE_BARRIER *reverse_barrier;
 4068     PKDEFERRED_ROUTINE routine;
 4069     ULONG *cpu_count_barrier;
 4070     void *context;
 4071     ULONG cpu_index;
 4072     ULONG current_barrier_flag;
 4073     LONG *barrier_passed_count;
 4074 };
 4075 
 4076 static void WINAPI generic_call_dpc_callback(TP_CALLBACK_INSTANCE *instance, void *context)
 4077 {
 4078     struct generic_call_dpc_context *c = context;
 4079     GROUP_AFFINITY old, new;
 4080 
 4081     TRACE("instance %p, context %p.\n", instance, context);
 4082 
 4083     NtQueryInformationThread(GetCurrentThread(), ThreadGroupInformation,
 4084             &old, sizeof(old), NULL);
 4085 
 4086     memset(&new, 0, sizeof(new));
 4087 
 4088     new.Mask = 1 << c->cpu_index;
 4089     NtSetInformationThread(GetCurrentThread(), ThreadGroupInformation, &new, sizeof(new));
 4090 
 4091     TlsSetValue(dpc_call_tls_index, context);
 4092     c->routine((PKDPC)0xdeadbeef, c->context, c->cpu_count_barrier, c->reverse_barrier);
 4093     TlsSetValue(dpc_call_tls_index, NULL);
 4094     NtSetInformationThread(GetCurrentThread(), ThreadGroupInformation, &old, sizeof(old));
 4095 }
 4096 
 4097 void WINAPI KeGenericCallDpc(PKDEFERRED_ROUTINE routine, void *context)
 4098 {
 4099     ULONG cpu_count = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
 4100     static struct generic_call_dpc_context *contexts;
 4101     DEFERRED_REVERSE_BARRIER reverse_barrier;
 4102     static ULONG last_cpu_count;
 4103     LONG barrier_passed_count;
 4104     ULONG cpu_count_barrier;
 4105     ULONG i;
 4106 
 4107     TRACE("routine %p, context %p.\n", routine, context);
 4108 
 4109     EnterCriticalSection(&dpc_call_cs);
 4110 
 4111     if (!dpc_call_tp)
 4112     {
 4113         if (!(dpc_call_tp = CreateThreadpool(NULL)))
 4114         {
 4115             ERR("Could not create thread pool.\n");
 4116             LeaveCriticalSection(&dpc_call_cs);
 4117             return;
 4118         }
 4119 
 4120         SetThreadpoolThreadMinimum(dpc_call_tp, cpu_count);
 4121         SetThreadpoolThreadMaximum(dpc_call_tp, cpu_count);
 4122 
 4123         memset(&dpc_call_tpe, 0, sizeof(dpc_call_tpe));
 4124         dpc_call_tpe.Version = 1;
 4125         dpc_call_tpe.Pool = dpc_call_tp;
 4126     }
 4127 
 4128     reverse_barrier.Barrier = cpu_count;
 4129     reverse_barrier.TotalProcessors = cpu_count;
 4130     cpu_count_barrier = cpu_count;
 4131 
 4132     if (contexts)
 4133     {
 4134         if (last_cpu_count < cpu_count)
 4135         {
 4136             static struct generic_call_dpc_context *new_contexts;
 4137             if (!(new_contexts = heap_realloc(contexts, sizeof(*contexts) * cpu_count)))
 4138             {
 4139                 ERR("No memory.\n");
 4140                 LeaveCriticalSection(&dpc_call_cs);
 4141                 return;
 4142             }
 4143             contexts = new_contexts;
 4144             SetThreadpoolThreadMinimum(dpc_call_tp, cpu_count);
 4145             SetThreadpoolThreadMaximum(dpc_call_tp, cpu_count);
 4146         }
 4147     }
 4148     else if (!(contexts = heap_alloc(sizeof(*contexts) * cpu_count)))
 4149     {
 4150         ERR("No memory.\n");
 4151         LeaveCriticalSection(&dpc_call_cs);
 4152         return;
 4153     }
 4154 
 4155     memset(contexts, 0, sizeof(*contexts) * cpu_count);
 4156     last_cpu_count = cpu_count;
 4157     barrier_passed_count = 0;
 4158 
 4159     for (i = 0; i < cpu_count; ++i)
 4160     {
 4161         contexts[i].reverse_barrier = &reverse_barrier;
 4162         contexts[i].cpu_count_barrier = &cpu_count_barrier;
 4163         contexts[i].routine = routine;
 4164         contexts[i].context = context;
 4165         contexts[i].cpu_index = i;
 4166         contexts[i].barrier_passed_count = &barrier_passed_count;
 4167 
 4168         TrySubmitThreadpoolCallback(generic_call_dpc_callback, &contexts[i], &dpc_call_tpe);
 4169     }
 4170 
 4171     while (InterlockedCompareExchange((LONG *)&cpu_count_barrier, 0, 0))
 4172         SwitchToThread();
 4173 
 4174     LeaveCriticalSection(&dpc_call_cs);
 4175 }
 4176 
 4177 
 4178 BOOLEAN WINAPI KeSignalCallDpcSynchronize(void *barrier)
 4179 {
 4180     struct generic_call_dpc_context *context = TlsGetValue(dpc_call_tls_index);
 4181     DEFERRED_REVERSE_BARRIER *b = barrier;
 4182     LONG curr_flag, comp, done_value;
 4183     BOOL first;
 4184 
 4185     TRACE("barrier %p, context %p.\n", barrier, context);
 4186 
 4187     if (!context)
 4188     {
 4189         WARN("Called outside of DPC context.\n");
 4190         return FALSE;
 4191     }
 4192 
 4193     context->current_barrier_flag ^= 0x80000000;
 4194     curr_flag = context->current_barrier_flag;
 4195 
 4196     first = !context->cpu_index;
 4197     comp = curr_flag + context->cpu_index;
 4198     done_value = curr_flag + b->TotalProcessors;
 4199 
 4200     if (first)
 4201         InterlockedExchange((LONG *)&b->Barrier, comp);
 4202 
 4203     while (InterlockedCompareExchange((LONG *)&b->Barrier, comp + 1, comp) != done_value)
 4204         ;
 4205 
 4206     InterlockedIncrement(context->barrier_passed_count);
 4207 
 4208     while (first && InterlockedCompareExchange(context->barrier_passed_count, 0, b->TotalProcessors))
 4209         ;
 4210 
 4211     return first;
 4212 }
 4213 
 4214 void WINAPI KeSignalCallDpcDone(void *barrier)
 4215 {
 4216     InterlockedDecrement((LONG *)barrier);
 4217 }
 4218 
 4219 void * WINAPI PsGetProcessSectionBaseAddress(PEPROCESS process)
 4220 {
 4221     void *image_base;
 4222     NTSTATUS status;
 4223     SIZE_T size;
 4224     HANDLE h;
 4225 
 4226     TRACE("process %p.\n", process);
 4227 
 4228     if ((status = ObOpenObjectByPointer(process, 0, NULL, PROCESS_ALL_ACCESS, NULL, KernelMode, &h)))
 4229     {
 4230         WARN("Error opening process object, status %#x.\n", status);
 4231         return NULL;
 4232     }
 4233 
 4234     status = NtReadVirtualMemory(h, &process->info.PebBaseAddress->ImageBaseAddress,
 4235             &image_base, sizeof(image_base), &size);
 4236 
 4237     NtClose(h);
 4238 
 4239     if (status || size != sizeof(image_base))
 4240     {
 4241         WARN("Error reading process memory, status %#x, size %lu.\n", status, size);
 4242         return NULL;
 4243     }
 4244 
 4245     TRACE("returning %p.\n", image_base);
 4246     return image_base;
 4247 }
 4248 
 4249 void WINAPI KeStackAttachProcess(KPROCESS *process, KAPC_STATE *apc_state)
 4250 {
 4251     FIXME("process %p, apc_state %p stub.\n", process, apc_state);
 4252 }
 4253 
 4254 void WINAPI KeUnstackDetachProcess(KAPC_STATE *apc_state)
 4255 {
 4256     FIXME("apc_state %p stub.\n", apc_state);
 4257 }
 4258 
 4259 NTSTATUS WINAPI KdDisableDebugger(void)
 4260 {
 4261     FIXME(": stub.\n");
 4262     return STATUS_DEBUGGER_INACTIVE;
 4263 }
 4264 
 4265 NTSTATUS WINAPI KdEnableDebugger(void)
 4266 {
 4267     FIXME(": stub.\n");
 4268     return STATUS_DEBUGGER_INACTIVE;
 4269 }
 4270 
 4271 /*****************************************************
 4272  *           DllMain
 4273  */
 4274 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
 4275 {
 4276     static void *handler;
 4277     LARGE_INTEGER count;
 4278 
 4279     switch(reason)
 4280     {
 4281     case DLL_PROCESS_ATTACH:
 4282         DisableThreadLibraryCalls( inst );
 4283 #if defined(__i386__) || defined(__x86_64__)
 4284         handler = RtlAddVectoredExceptionHandler( TRUE, vectored_handler );
 4285 #endif
 4286         KeQueryTickCount( &count );  /* initialize the global KeTickCount */
 4287         NtBuildNumber = NtCurrentTeb()->Peb->OSBuildNumber;
 4288         ntoskrnl_heap = HeapCreate( HEAP_CREATE_ENABLE_EXECUTE, 0, 0 );
 4289         dpc_call_tls_index = TlsAlloc();
 4290         LdrRegisterDllNotification( 0, ldr_notify_callback, NULL, &ldr_notify_cookie );
 4291         break;
 4292     case DLL_PROCESS_DETACH:
 4293         LdrUnregisterDllNotification( ldr_notify_cookie );
 4294 
 4295         if (reserved) break;
 4296 
 4297         if (dpc_call_tp)
 4298             CloseThreadpool(dpc_call_tp);
 4299 
 4300         HeapDestroy( ntoskrnl_heap );
 4301         RtlRemoveVectoredExceptionHandler( handler );
 4302         break;
 4303     }
 4304     return TRUE;
 4305 }