"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.

    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 }