msi/tests: Delete the temp .msi file in all failure cases.
[wine.git] / dlls / ntoskrnl.exe / ntoskrnl.c
blob7aaf66dd6db03db70e4dd962cdb76391542de9ca
1 /*
2 * ntoskrnl.exe implementation
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
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.
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.
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
24 #include <assert.h>
26 #include "ntoskrnl_private.h"
27 #include "excpt.h"
28 #include "winreg.h"
29 #include "ntsecapi.h"
30 #include "evntprov.h"
31 #include "ddk/csq.h"
32 #include "wine/server.h"
33 #include "wine/heap.h"
34 #include "wine/svcctl.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(ntoskrnl);
37 WINE_DECLARE_DEBUG_CHANNEL(relay);
39 BOOLEAN KdDebuggerEnabled = FALSE;
40 ULONG InitSafeBootMode = 0;
41 USHORT NtBuildNumber = 0;
43 extern LONG CALLBACK vectored_handler( EXCEPTION_POINTERS *ptrs );
45 KSYSTEM_TIME KeTickCount = { 0, 0, 0 };
47 typedef struct _KSERVICE_TABLE_DESCRIPTOR
49 PULONG_PTR Base;
50 PULONG Count;
51 ULONG Limit;
52 PUCHAR Number;
53 } KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR;
55 KSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable[4] = { { 0 } };
57 #define MAX_SERVICE_NAME 260
59 static TP_POOL *dpc_call_tp;
60 static TP_CALLBACK_ENVIRON dpc_call_tpe;
61 DECLARE_CRITICAL_SECTION(dpc_call_cs);
62 static DWORD dpc_call_tls_index;
64 /* tid of the thread running client request */
65 static DWORD request_thread;
67 /* tid of the client thread */
68 static DWORD client_tid;
70 static HANDLE ntoskrnl_heap;
72 static void *ldr_notify_cookie;
74 static PLOAD_IMAGE_NOTIFY_ROUTINE load_image_notify_routines[8];
75 static unsigned int load_image_notify_routine_count;
77 struct irp_data
79 HANDLE handle;
80 IRP *irp;
81 BOOL async;
82 BOOL complete;
85 static int wine_drivers_rb_compare( const void *key, const struct wine_rb_entry *entry )
87 const struct wine_driver *driver = WINE_RB_ENTRY_VALUE( entry, const struct wine_driver, entry );
88 const UNICODE_STRING *k = key;
90 return RtlCompareUnicodeString( k, &driver->driver_obj.DriverName, TRUE );
93 static struct wine_rb_tree wine_drivers = { wine_drivers_rb_compare };
95 DECLARE_CRITICAL_SECTION(drivers_cs);
97 struct wine_driver *get_driver( const WCHAR *name )
99 static const WCHAR driverW[] = L"\\Driver\\";
100 struct wine_rb_entry *entry;
101 UNICODE_STRING drv_name;
103 drv_name.Length = (wcslen( driverW ) + wcslen( name )) * sizeof(WCHAR);
104 if (!(drv_name.Buffer = malloc( drv_name.Length + sizeof(WCHAR) )))
105 return NULL;
106 wcscpy( drv_name.Buffer, driverW );
107 wcscat( drv_name.Buffer, name );
108 entry = wine_rb_get( &wine_drivers, &drv_name );
109 free( drv_name.Buffer );
111 if (entry) return WINE_RB_ENTRY_VALUE( entry, struct wine_driver, entry );
112 return NULL;
115 static HANDLE get_device_manager(void)
117 static HANDLE device_manager;
118 HANDLE handle = 0, ret = device_manager;
120 if (!ret)
122 SERVER_START_REQ( create_device_manager )
124 req->access = SYNCHRONIZE;
125 req->attributes = 0;
126 if (!wine_server_call( req )) handle = wine_server_ptr_handle( reply->handle );
128 SERVER_END_REQ;
130 if (!handle)
132 ERR( "failed to create the device manager\n" );
133 return 0;
135 if (!(ret = InterlockedCompareExchangePointer( &device_manager, handle, 0 )))
136 ret = handle;
137 else
138 NtClose( handle ); /* somebody beat us to it */
140 return ret;
144 struct object_header
146 LONG ref;
147 POBJECT_TYPE type;
150 static void free_kernel_object( void *obj )
152 struct object_header *header = (struct object_header *)obj - 1;
153 HeapFree( GetProcessHeap(), 0, header );
156 void *alloc_kernel_object( POBJECT_TYPE type, HANDLE handle, SIZE_T size, LONG ref )
158 struct object_header *header;
160 if (!(header = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*header) + size)) )
161 return NULL;
163 if (handle)
165 NTSTATUS status;
166 SERVER_START_REQ( set_kernel_object_ptr )
168 req->manager = wine_server_obj_handle( get_device_manager() );
169 req->handle = wine_server_obj_handle( handle );
170 req->user_ptr = wine_server_client_ptr( header + 1 );
171 status = wine_server_call( req );
173 SERVER_END_REQ;
174 if (status) FIXME( "set_object_reference failed: %#lx\n", status );
177 header->ref = ref;
178 header->type = type;
179 return header + 1;
182 DECLARE_CRITICAL_SECTION(obref_cs);
184 /***********************************************************************
185 * ObDereferenceObject (NTOSKRNL.EXE.@)
187 void WINAPI ObDereferenceObject( void *obj )
189 struct object_header *header = (struct object_header*)obj - 1;
190 LONG ref;
192 if (!obj)
194 FIXME("NULL obj\n");
195 return;
198 EnterCriticalSection( &obref_cs );
200 ref = --header->ref;
201 TRACE( "(%p) ref=%lu\n", obj, ref );
202 if (!ref)
204 if (header->type->release)
206 header->type->release( obj );
208 else
210 SERVER_START_REQ( release_kernel_object )
212 req->manager = wine_server_obj_handle( get_device_manager() );
213 req->user_ptr = wine_server_client_ptr( obj );
214 if (wine_server_call( req )) FIXME( "failed to release %p\n", obj );
216 SERVER_END_REQ;
220 LeaveCriticalSection( &obref_cs );
223 void ObReferenceObject( void *obj )
225 struct object_header *header = (struct object_header*)obj - 1;
226 LONG ref;
228 if (!obj)
230 FIXME("NULL obj\n");
231 return;
234 EnterCriticalSection( &obref_cs );
236 ref = ++header->ref;
237 TRACE( "(%p) ref=%lu\n", obj, ref );
238 if (ref == 1)
240 SERVER_START_REQ( grab_kernel_object )
242 req->manager = wine_server_obj_handle( get_device_manager() );
243 req->user_ptr = wine_server_client_ptr( obj );
244 if (wine_server_call( req )) FIXME( "failed to grab %p reference\n", obj );
246 SERVER_END_REQ;
249 LeaveCriticalSection( &obref_cs );
252 /***********************************************************************
253 * ObGetObjectType (NTOSKRNL.EXE.@)
255 POBJECT_TYPE WINAPI ObGetObjectType( void *object )
257 struct object_header *header = (struct object_header *)object - 1;
258 return header->type;
261 static const POBJECT_TYPE *known_types[] =
263 &ExEventObjectType,
264 &ExSemaphoreObjectType,
265 &IoDeviceObjectType,
266 &IoDriverObjectType,
267 &IoFileObjectType,
268 &PsProcessType,
269 &PsThreadType,
270 &SeTokenObjectType
273 DECLARE_CRITICAL_SECTION(handle_map_cs);
275 NTSTATUS kernel_object_from_handle( HANDLE handle, POBJECT_TYPE type, void **ret )
277 void *obj;
278 NTSTATUS status;
280 EnterCriticalSection( &handle_map_cs );
282 SERVER_START_REQ( get_kernel_object_ptr )
284 req->manager = wine_server_obj_handle( get_device_manager() );
285 req->handle = wine_server_obj_handle( handle );
286 status = wine_server_call( req );
287 obj = wine_server_get_ptr( reply->user_ptr );
289 SERVER_END_REQ;
290 if (status)
292 LeaveCriticalSection( &handle_map_cs );
293 return status;
296 if (!obj)
298 char buf[256];
299 OBJECT_TYPE_INFORMATION *type_info = (OBJECT_TYPE_INFORMATION *)buf;
300 ULONG size;
302 status = NtQueryObject( handle, ObjectTypeInformation, buf, sizeof(buf), &size );
303 if (status)
305 LeaveCriticalSection( &handle_map_cs );
306 return status;
308 if (!type)
310 size_t i;
311 for (i = 0; i < ARRAY_SIZE(known_types); i++)
313 type = *known_types[i];
314 if (!RtlCompareUnicodeStrings( type->name, lstrlenW(type->name), type_info->TypeName.Buffer,
315 type_info->TypeName.Length / sizeof(WCHAR), FALSE ))
316 break;
318 if (i == ARRAY_SIZE(known_types))
320 FIXME("Unsupported type %s\n", debugstr_us(&type_info->TypeName));
321 LeaveCriticalSection( &handle_map_cs );
322 return STATUS_INVALID_HANDLE;
325 else if (RtlCompareUnicodeStrings( type->name, lstrlenW(type->name), type_info->TypeName.Buffer,
326 type_info->TypeName.Length / sizeof(WCHAR), FALSE) )
328 LeaveCriticalSection( &handle_map_cs );
329 return STATUS_OBJECT_TYPE_MISMATCH;
332 if (type->constructor)
333 obj = type->constructor( handle );
334 else
336 FIXME( "No constructor for type %s\n", debugstr_w(type->name) );
337 obj = alloc_kernel_object( type, handle, 0, 0 );
339 if (!obj) status = STATUS_NO_MEMORY;
341 else if (type && ObGetObjectType( obj ) != type) status = STATUS_OBJECT_TYPE_MISMATCH;
343 LeaveCriticalSection( &handle_map_cs );
344 if (!status) *ret = obj;
345 return status;
348 /***********************************************************************
349 * ObReferenceObjectByHandle (NTOSKRNL.EXE.@)
351 NTSTATUS WINAPI ObReferenceObjectByHandle( HANDLE handle, ACCESS_MASK access,
352 POBJECT_TYPE type,
353 KPROCESSOR_MODE mode, void **ptr,
354 POBJECT_HANDLE_INFORMATION info )
356 NTSTATUS status;
358 TRACE( "%p %lx %p %d %p %p\n", handle, access, type, mode, ptr, info );
360 if (mode != KernelMode)
362 FIXME("UserMode access not implemented\n");
363 return STATUS_NOT_IMPLEMENTED;
366 status = kernel_object_from_handle( handle, type, ptr );
367 if (!status) ObReferenceObject( *ptr );
368 return status;
371 /***********************************************************************
372 * ObOpenObjectByPointer (NTOSKRNL.EXE.@)
374 NTSTATUS WINAPI ObOpenObjectByPointer( void *obj, ULONG attr, ACCESS_STATE *access_state,
375 ACCESS_MASK access, POBJECT_TYPE type,
376 KPROCESSOR_MODE mode, HANDLE *handle )
378 NTSTATUS status;
380 TRACE( "%p %lx %p %lx %p %d %p\n", obj, attr, access_state, access, type, mode, handle );
382 if (mode != KernelMode)
384 FIXME( "UserMode access not implemented\n" );
385 return STATUS_NOT_IMPLEMENTED;
388 if (attr & ~OBJ_KERNEL_HANDLE) FIXME( "attr %#lx not supported\n", attr );
389 if (access_state) FIXME( "access_state not implemented\n" );
391 if (type && ObGetObjectType( obj ) != type) return STATUS_OBJECT_TYPE_MISMATCH;
393 SERVER_START_REQ( get_kernel_object_handle )
395 req->manager = wine_server_obj_handle( get_device_manager() );
396 req->user_ptr = wine_server_client_ptr( obj );
397 req->access = access;
398 if (!(status = wine_server_call( req )))
399 *handle = wine_server_ptr_handle( reply->handle );
401 SERVER_END_REQ;
402 return status;
406 static void *create_file_object( HANDLE handle );
408 static const WCHAR file_type_name[] = {'F','i','l','e',0};
410 static struct _OBJECT_TYPE file_type = {
411 file_type_name,
412 create_file_object
415 POBJECT_TYPE IoFileObjectType = &file_type;
417 static void *create_file_object( HANDLE handle )
419 FILE_OBJECT *file;
420 if (!(file = alloc_kernel_object( IoFileObjectType, handle, sizeof(*file), 0 ))) return NULL;
421 file->Type = 5; /* MSDN */
422 file->Size = sizeof(*file);
423 return file;
426 DECLARE_CRITICAL_SECTION(irp_completion_cs);
428 static void free_dispatch_irp( struct irp_data *irp_data )
430 IRP *irp = irp_data->irp;
432 if (irp->UserBuffer != irp->AssociatedIrp.SystemBuffer)
434 HeapFree( GetProcessHeap(), 0, irp->UserBuffer );
435 irp->UserBuffer = NULL;
438 free( irp_data );
441 static ULONG get_irp_output_size( IRP *irp )
443 IO_STACK_LOCATION *stack = IoGetNextIrpStackLocation( irp );
445 if (!irp->UserBuffer || (irp->Flags & IRP_WRITE_OPERATION))
446 return 0;
448 /* For IRPs not using buffered I/O, the driver is supposed to have direct
449 * access to the user's output buffer, either via an MDL (direct I/O) or
450 * with the raw user VA (neither). We can't fully support this, but we
451 * should at least copy the entire buffer back to the caller. */
452 switch (stack->MajorFunction)
454 case IRP_MJ_FILE_SYSTEM_CONTROL:
455 case IRP_MJ_DEVICE_CONTROL:
456 case IRP_MJ_INTERNAL_DEVICE_CONTROL:
457 if ((stack->Parameters.DeviceIoControl.IoControlCode & 3) != METHOD_BUFFERED)
458 return stack->Parameters.DeviceIoControl.OutputBufferLength;
459 break;
461 case IRP_MJ_READ:
462 /* FIXME: Handle non-buffered reads. */
463 default:
464 break;
467 if (NT_ERROR(irp->IoStatus.Status))
468 return 0;
469 return irp->IoStatus.Information;
472 /* transfer result of IRP back to wineserver */
473 static NTSTATUS WINAPI dispatch_irp_completion( DEVICE_OBJECT *device, IRP *irp, void *context )
475 struct irp_data *irp_data = context;
476 NTSTATUS status;
477 ULONG out_size;
479 EnterCriticalSection( &irp_completion_cs );
481 irp_data->complete = TRUE;
482 if (!irp_data->async)
484 /* main loop will report completion via get_next_device_request */
485 LeaveCriticalSection( &irp_completion_cs );
486 return STATUS_MORE_PROCESSING_REQUIRED;
489 out_size = get_irp_output_size( irp );
491 SERVER_START_REQ( set_irp_result )
493 req->handle = wine_server_obj_handle( irp_data->handle );
494 req->status = irp->IoStatus.Status;
495 req->size = irp->IoStatus.Information;
496 if (out_size) wine_server_add_data( req, irp->UserBuffer, out_size );
497 status = wine_server_call( req );
499 SERVER_END_REQ;
501 free_dispatch_irp( irp_data );
503 LeaveCriticalSection( &irp_completion_cs );
504 return status;
507 struct dispatch_context
509 irp_params_t params;
510 HANDLE handle;
511 struct irp_data *irp_data;
512 ULONG in_size;
513 void *in_buff;
516 static NTSTATUS dispatch_irp( DEVICE_OBJECT *device, IRP *irp, struct dispatch_context *context )
518 struct irp_data *irp_data;
519 LARGE_INTEGER count;
520 NTSTATUS status;
522 if (!(irp_data = malloc( sizeof(*irp_data) )))
523 return STATUS_NO_MEMORY;
524 irp_data->handle = context->handle;
525 irp_data->irp = irp;
526 irp_data->async = FALSE;
527 irp_data->complete = FALSE;
529 IoSetCompletionRoutine( irp, dispatch_irp_completion, irp_data, TRUE, TRUE, TRUE );
530 context->irp_data = irp_data;
531 context->handle = 0;
533 KeQueryTickCount( &count ); /* update the global KeTickCount */
535 device->CurrentIrp = irp;
536 KeEnterCriticalRegion();
537 status = IoCallDriver( device, irp );
538 KeLeaveCriticalRegion();
539 device->CurrentIrp = NULL;
541 if (status != STATUS_PENDING && !irp_data->complete)
542 ERR( "dispatch routine returned %#lx but didn't complete the IRP\n", status );
544 return status;
547 /* process a create request for a given file */
548 static NTSTATUS dispatch_create( struct dispatch_context *context )
550 IRP *irp;
551 IO_STACK_LOCATION *irpsp;
552 FILE_OBJECT *file;
553 DEVICE_OBJECT *device = wine_server_get_ptr( context->params.create.device );
554 HANDLE handle = wine_server_ptr_handle( context->params.create.file );
556 if (!(file = alloc_kernel_object( IoFileObjectType, handle, sizeof(*file), 0 )))
557 return STATUS_NO_MEMORY;
559 TRACE( "device %p -> file %p\n", device, file );
561 file->Type = 5; /* MSDN */
562 file->Size = sizeof(*file);
563 file->DeviceObject = device;
565 device = IoGetAttachedDevice( device );
567 if (!(irp = IoAllocateIrp( device->StackSize, FALSE ))) return STATUS_NO_MEMORY;
569 irpsp = IoGetNextIrpStackLocation( irp );
570 irpsp->MajorFunction = IRP_MJ_CREATE;
571 irpsp->FileObject = file;
572 irpsp->Parameters.Create.SecurityContext = NULL; /* FIXME */
573 irpsp->Parameters.Create.Options = context->params.create.options;
574 irpsp->Parameters.Create.ShareAccess = context->params.create.sharing;
575 irpsp->Parameters.Create.FileAttributes = 0;
576 irpsp->Parameters.Create.EaLength = 0;
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;
586 irp->Flags |= IRP_CREATE_OPERATION;
587 return dispatch_irp( device, irp, context );
590 /* process a close request for a given file */
591 static NTSTATUS dispatch_close( struct dispatch_context *context )
593 IRP *irp;
594 IO_STACK_LOCATION *irpsp;
595 DEVICE_OBJECT *device;
596 FILE_OBJECT *file = wine_server_get_ptr( context->params.close.file );
598 if (!file) return STATUS_INVALID_HANDLE;
600 device = IoGetAttachedDevice( file->DeviceObject );
602 TRACE( "device %p file %p\n", device, file );
604 if (!(irp = IoAllocateIrp( device->StackSize, FALSE )))
606 ObDereferenceObject( file );
607 return STATUS_NO_MEMORY;
610 irpsp = IoGetNextIrpStackLocation( irp );
611 irpsp->MajorFunction = IRP_MJ_CLOSE;
612 irpsp->FileObject = file;
614 irp->Tail.Overlay.OriginalFileObject = file;
615 irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
616 irp->RequestorMode = UserMode;
617 irp->AssociatedIrp.SystemBuffer = NULL;
618 irp->UserBuffer = NULL;
619 irp->UserIosb = NULL;
620 irp->UserEvent = NULL;
622 irp->Flags |= IRP_CLOSE_OPERATION;
623 return dispatch_irp( device, irp, context );
626 /* process a read request for a given device */
627 static NTSTATUS dispatch_read( struct dispatch_context *context )
629 IRP *irp;
630 void *out_buff;
631 LARGE_INTEGER offset;
632 IO_STACK_LOCATION *irpsp;
633 DEVICE_OBJECT *device;
634 FILE_OBJECT *file = wine_server_get_ptr( context->params.read.file );
635 ULONG out_size = context->params.read.out_size;
637 if (!file) return STATUS_INVALID_HANDLE;
639 device = IoGetAttachedDevice( file->DeviceObject );
641 TRACE( "device %p file %p size %lu\n", device, file, out_size );
643 if (!(out_buff = HeapAlloc( GetProcessHeap(), 0, out_size ))) return STATUS_NO_MEMORY;
645 offset.QuadPart = context->params.read.pos;
647 if (!(irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ, device, out_buff, out_size,
648 &offset, NULL, NULL )))
650 HeapFree( GetProcessHeap(), 0, out_buff );
651 return STATUS_NO_MEMORY;
654 irp->Tail.Overlay.OriginalFileObject = file;
655 irp->RequestorMode = UserMode;
657 irpsp = IoGetNextIrpStackLocation( irp );
658 irpsp->FileObject = file;
659 irpsp->Parameters.Read.Key = context->params.read.key;
661 irp->Flags |= IRP_READ_OPERATION;
662 irp->Flags |= IRP_DEALLOCATE_BUFFER; /* deallocate out_buff */
663 return dispatch_irp( device, irp, context );
666 /* process a write request for a given device */
667 static NTSTATUS dispatch_write( struct dispatch_context *context )
669 IRP *irp;
670 LARGE_INTEGER offset;
671 IO_STACK_LOCATION *irpsp;
672 DEVICE_OBJECT *device;
673 FILE_OBJECT *file = wine_server_get_ptr( context->params.write.file );
675 if (!file) return STATUS_INVALID_HANDLE;
677 device = IoGetAttachedDevice( file->DeviceObject );
679 TRACE( "device %p file %p size %lu\n", device, file, context->in_size );
681 offset.QuadPart = context->params.write.pos;
683 if (!(irp = IoBuildSynchronousFsdRequest( IRP_MJ_WRITE, device, context->in_buff, context->in_size,
684 &offset, NULL, NULL )))
685 return STATUS_NO_MEMORY;
686 context->in_buff = NULL;
688 irp->Tail.Overlay.OriginalFileObject = file;
689 irp->RequestorMode = UserMode;
691 irpsp = IoGetNextIrpStackLocation( irp );
692 irpsp->FileObject = file;
693 irpsp->Parameters.Write.Key = context->params.write.key;
695 irp->Flags |= IRP_WRITE_OPERATION;
696 irp->Flags |= IRP_DEALLOCATE_BUFFER; /* deallocate in_buff */
697 return dispatch_irp( device, irp, context );
700 /* process a flush request for a given device */
701 static NTSTATUS dispatch_flush( struct dispatch_context *context )
703 IRP *irp;
704 IO_STACK_LOCATION *irpsp;
705 DEVICE_OBJECT *device;
706 FILE_OBJECT *file = wine_server_get_ptr( context->params.flush.file );
708 if (!file) return STATUS_INVALID_HANDLE;
710 device = IoGetAttachedDevice( file->DeviceObject );
712 TRACE( "device %p file %p\n", device, file );
714 if (!(irp = IoBuildSynchronousFsdRequest( IRP_MJ_FLUSH_BUFFERS, device, NULL, 0,
715 NULL, NULL, NULL )))
716 return STATUS_NO_MEMORY;
718 irp->Tail.Overlay.OriginalFileObject = file;
719 irp->RequestorMode = UserMode;
721 irpsp = IoGetNextIrpStackLocation( irp );
722 irpsp->FileObject = file;
724 return dispatch_irp( device, irp, context );
727 /* process an ioctl request for a given device */
728 static NTSTATUS dispatch_ioctl( struct dispatch_context *context )
730 IO_STACK_LOCATION *irpsp;
731 IRP *irp;
732 void *out_buff = NULL;
733 void *to_free = NULL;
734 DEVICE_OBJECT *device;
735 FILE_OBJECT *file = wine_server_get_ptr( context->params.ioctl.file );
736 ULONG out_size = context->params.ioctl.out_size;
737 NTSTATUS status;
739 if (!file) return STATUS_INVALID_HANDLE;
741 device = IoGetAttachedDevice( file->DeviceObject );
743 TRACE( "ioctl %x device %p file %p in_size %lu out_size %lu\n",
744 context->params.ioctl.code, device, file, context->in_size, out_size );
746 if (out_size)
748 if ((context->params.ioctl.code & 3) != METHOD_BUFFERED)
750 if (context->in_size < out_size) return STATUS_INVALID_DEVICE_REQUEST;
751 context->in_size -= out_size;
752 if (!(out_buff = HeapAlloc( GetProcessHeap(), 0, out_size ))) return STATUS_NO_MEMORY;
753 memcpy( out_buff, (char *)context->in_buff + context->in_size, out_size );
755 else if (out_size > context->in_size)
757 if (!(out_buff = HeapAlloc( GetProcessHeap(), 0, out_size ))) return STATUS_NO_MEMORY;
758 memcpy( out_buff, context->in_buff, context->in_size );
759 to_free = context->in_buff;
760 context->in_buff = out_buff;
762 else
763 out_buff = context->in_buff;
766 irp = IoBuildDeviceIoControlRequest( context->params.ioctl.code, device, context->in_buff,
767 context->in_size, out_buff, out_size, FALSE, NULL, NULL );
768 if (!irp)
770 HeapFree( GetProcessHeap(), 0, out_buff );
771 return STATUS_NO_MEMORY;
774 if (out_size && (context->params.ioctl.code & 3) != METHOD_BUFFERED)
775 HeapReAlloc( GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, context->in_buff, context->in_size );
777 irpsp = IoGetNextIrpStackLocation( irp );
778 irpsp->FileObject = file;
780 irp->Tail.Overlay.OriginalFileObject = file;
781 irp->RequestorMode = UserMode;
782 irp->AssociatedIrp.SystemBuffer = context->in_buff;
783 context->in_buff = NULL;
785 irp->Flags |= IRP_DEALLOCATE_BUFFER; /* deallocate in_buff */
786 status = dispatch_irp( device, irp, context );
788 HeapFree( GetProcessHeap(), 0, to_free );
789 return status;
792 /* process a volume information request for a given device */
793 static NTSTATUS dispatch_volume( struct dispatch_context *context )
795 IO_STACK_LOCATION *irpsp;
796 IRP *irp;
797 void *out_buff = NULL;
798 DEVICE_OBJECT *device;
799 FILE_OBJECT *file = wine_server_get_ptr( context->params.volume.file );
800 ULONG out_size = context->params.volume.out_size;
802 if (!file) return STATUS_INVALID_HANDLE;
804 device = IoGetAttachedDevice( file->DeviceObject );
806 TRACE( "class 0x%x device %p file %p in_size %lu out_size %lu\n",
807 context->params.volume.info_class, device, file, context->in_size, out_size );
809 if (!(out_buff = HeapAlloc( GetProcessHeap(), 0, out_size ))) return STATUS_NO_MEMORY;
811 irp = IoAllocateIrp( device->StackSize, FALSE );
812 if (!irp)
814 HeapFree( GetProcessHeap(), 0, out_buff );
815 return STATUS_NO_MEMORY;
818 irpsp = IoGetNextIrpStackLocation( irp );
819 irpsp->MajorFunction = IRP_MJ_QUERY_VOLUME_INFORMATION;
820 irpsp->Parameters.QueryVolume.FsInformationClass = context->params.volume.info_class;
821 irpsp->Parameters.QueryVolume.Length = out_size;
822 irpsp->DeviceObject = NULL;
823 irpsp->CompletionRoutine = NULL;
824 irpsp->FileObject = file;
825 irp->AssociatedIrp.SystemBuffer = out_buff;
826 irp->RequestorMode = KernelMode;
827 irp->UserBuffer = out_buff;
828 irp->UserIosb = NULL;
829 irp->UserEvent = NULL;
830 irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
831 irp->Tail.Overlay.OriginalFileObject = file;
832 irp->RequestorMode = UserMode;
834 irp->Flags |= IRP_DEALLOCATE_BUFFER; /* deallocate out_buff */
835 return dispatch_irp( device, irp, context );
838 static NTSTATUS dispatch_free( struct dispatch_context *context )
840 void *obj = wine_server_get_ptr( context->params.free.obj );
841 TRACE( "freeing %p object\n", obj );
842 free_kernel_object( obj );
843 return STATUS_SUCCESS;
846 static NTSTATUS dispatch_cancel( struct dispatch_context *context )
848 IRP *irp = wine_server_get_ptr( context->params.cancel.irp );
850 TRACE( "%p\n", irp );
852 EnterCriticalSection( &irp_completion_cs );
853 IoCancelIrp( irp );
854 LeaveCriticalSection( &irp_completion_cs );
855 return STATUS_SUCCESS;
858 typedef NTSTATUS (*dispatch_func)( struct dispatch_context *context );
860 static const dispatch_func dispatch_funcs[] =
862 NULL, /* IRP_CALL_NONE */
863 dispatch_create, /* IRP_CALL_CREATE */
864 dispatch_close, /* IRP_CALL_CLOSE */
865 dispatch_read, /* IRP_CALL_READ */
866 dispatch_write, /* IRP_CALL_WRITE */
867 dispatch_flush, /* IRP_CALL_FLUSH */
868 dispatch_ioctl, /* IRP_CALL_IOCTL */
869 dispatch_volume, /* IRP_CALL_VOLUME */
870 dispatch_free, /* IRP_CALL_FREE */
871 dispatch_cancel /* IRP_CALL_CANCEL */
874 /* helper function to update service status */
875 static void set_service_status( SERVICE_STATUS_HANDLE handle, DWORD state, DWORD accepted )
877 SERVICE_STATUS status;
878 status.dwServiceType = SERVICE_WIN32;
879 status.dwCurrentState = state;
880 status.dwControlsAccepted = accepted;
881 status.dwWin32ExitCode = 0;
882 status.dwServiceSpecificExitCode = 0;
883 status.dwCheckPoint = 0;
884 status.dwWaitHint = (state == SERVICE_START_PENDING) ? 10000 : 0;
885 SetServiceStatus( handle, &status );
888 static void unload_driver( struct wine_rb_entry *entry, void *context )
890 struct wine_driver *driver = WINE_RB_ENTRY_VALUE( entry, struct wine_driver, entry );
891 SERVICE_STATUS_HANDLE service_handle = driver->service_handle;
892 LDR_DATA_TABLE_ENTRY *ldr;
894 if (!service_handle) return; /* not a service */
896 TRACE("%s\n", debugstr_us(&driver->driver_obj.DriverName));
898 if (!driver->driver_obj.DriverUnload)
900 TRACE( "driver %s does not support unloading\n", debugstr_us(&driver->driver_obj.DriverName) );
901 return;
904 ldr = driver->driver_obj.DriverSection;
906 set_service_status( service_handle, SERVICE_STOP_PENDING, 0 );
908 TRACE_(relay)( "\1Call driver unload %p (obj=%p)\n", driver->driver_obj.DriverUnload, &driver->driver_obj );
910 driver->driver_obj.DriverUnload( &driver->driver_obj );
912 TRACE_(relay)( "\1Ret driver unload %p (obj=%p)\n", driver->driver_obj.DriverUnload, &driver->driver_obj );
914 FreeLibrary( ldr->DllBase );
915 IoDeleteDriver( &driver->driver_obj );
917 set_service_status( service_handle, SERVICE_STOPPED, 0 );
918 CloseServiceHandle( (void *)service_handle );
921 PEPROCESS PsInitialSystemProcess = NULL;
923 /***********************************************************************
924 * wine_ntoskrnl_main_loop (Not a Windows API)
926 NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event )
928 HANDLE manager = get_device_manager();
929 struct dispatch_context context = {.in_size = 4096};
930 NTSTATUS status = STATUS_SUCCESS;
931 struct wine_driver *driver;
932 HANDLE handles[2];
934 /* Set the system process global before setting up the request thread trickery */
935 PsInitialSystemProcess = IoGetCurrentProcess();
936 request_thread = GetCurrentThreadId();
938 pnp_manager_start();
940 handles[0] = stop_event;
941 handles[1] = manager;
943 for (;;)
945 NtCurrentTeb()->Instrumentation[1] = NULL;
946 if (!context.in_buff && !(context.in_buff = HeapAlloc( GetProcessHeap(), 0, context.in_size )))
948 ERR( "failed to allocate buffer\n" );
949 status = STATUS_NO_MEMORY;
950 goto done;
953 EnterCriticalSection( &irp_completion_cs );
955 SERVER_START_REQ( get_next_device_request )
957 req->manager = wine_server_obj_handle( manager );
958 req->prev = wine_server_obj_handle( context.handle );
960 if (context.irp_data)
962 IRP *irp = context.irp_data->irp;
964 req->user_ptr = wine_server_client_ptr( irp );
965 req->status = status;
967 if (context.irp_data->complete)
969 /* IRP completed even before we got here; we can report completion now */
970 unsigned int out_size = get_irp_output_size( irp );
972 req->prev = wine_server_obj_handle( context.irp_data->handle );
973 req->pending = irp->PendingReturned;
974 req->iosb_status = irp->IoStatus.Status;
975 req->result = irp->IoStatus.Information;
976 if (out_size) wine_server_add_data( req, irp->UserBuffer, out_size );
978 else
980 req->pending = 1;
983 else
985 req->user_ptr = 0;
986 req->status = status;
989 wine_server_set_reply( req, context.in_buff, context.in_size );
990 if (!(status = wine_server_call( req )))
992 context.handle = wine_server_ptr_handle( reply->next );
993 context.params = reply->params;
994 context.in_size = reply->in_size;
995 client_tid = reply->client_tid;
996 NtCurrentTeb()->Instrumentation[1] = wine_server_get_ptr( reply->client_thread );
998 else
1000 context.handle = 0; /* no previous irp */
1001 if (status == STATUS_BUFFER_OVERFLOW)
1002 context.in_size = reply->in_size;
1005 SERVER_END_REQ;
1007 if (context.irp_data)
1009 if (context.irp_data->complete)
1011 IRP *irp = context.irp_data->irp;
1012 free_dispatch_irp( context.irp_data );
1013 IoCompleteRequest( irp, IO_NO_INCREMENT );
1015 else
1017 context.irp_data->async = TRUE;
1021 LeaveCriticalSection( &irp_completion_cs );
1023 context.irp_data = NULL;
1025 switch (status)
1027 case STATUS_SUCCESS:
1028 assert( context.params.type != IRP_CALL_NONE && context.params.type < ARRAY_SIZE(dispatch_funcs) );
1029 status = dispatch_funcs[context.params.type]( &context );
1030 if (!context.in_buff) context.in_size = 4096;
1031 break;
1032 case STATUS_BUFFER_OVERFLOW:
1033 HeapFree( GetProcessHeap(), 0, context.in_buff );
1034 context.in_buff = NULL;
1035 /* restart with larger buffer */
1036 break;
1037 case STATUS_PENDING:
1038 for (;;)
1040 DWORD ret = WaitForMultipleObjectsEx( 2, handles, FALSE, INFINITE, TRUE );
1041 if (ret == WAIT_OBJECT_0)
1043 HeapFree( GetProcessHeap(), 0, context.in_buff );
1044 status = STATUS_SUCCESS;
1045 goto done;
1047 if (ret != WAIT_IO_COMPLETION) break;
1049 break;
1053 done:
1054 /* Native PnP drivers expect that all of their devices will be removed when
1055 * their unload routine is called. Moreover, we cannot unload a module
1056 * until we have removed devices for all lower drivers, so we have to stop
1057 * all devices first, and then unload all drivers. */
1058 WINE_RB_FOR_EACH_ENTRY( driver, &wine_drivers, struct wine_driver, entry )
1059 pnp_manager_stop_driver( driver );
1060 wine_rb_destroy( &wine_drivers, unload_driver, NULL );
1061 pnp_manager_stop();
1062 return status;
1065 /***********************************************************************
1066 * IoAllocateDriverObjectExtension (NTOSKRNL.EXE.@)
1068 NTSTATUS WINAPI IoAllocateDriverObjectExtension( PDRIVER_OBJECT DriverObject,
1069 PVOID ClientIdentificationAddress,
1070 ULONG DriverObjectExtensionSize,
1071 PVOID *DriverObjectExtension )
1073 FIXME( "stub: %p, %p, %lu, %p\n", DriverObject, ClientIdentificationAddress,
1074 DriverObjectExtensionSize, DriverObjectExtension );
1075 return STATUS_NOT_IMPLEMENTED;
1079 /***********************************************************************
1080 * IoGetDriverObjectExtension (NTOSKRNL.EXE.@)
1082 PVOID WINAPI IoGetDriverObjectExtension( PDRIVER_OBJECT DriverObject,
1083 PVOID ClientIdentificationAddress )
1085 FIXME( "stub: %p, %p\n", DriverObject, ClientIdentificationAddress );
1086 return NULL;
1090 /***********************************************************************
1091 * IoInitializeIrp (NTOSKRNL.EXE.@)
1093 void WINAPI IoInitializeIrp( IRP *irp, USHORT size, CCHAR stack_size )
1095 TRACE( "%p, %u, %d\n", irp, size, stack_size );
1097 RtlZeroMemory( irp, size );
1099 irp->Type = IO_TYPE_IRP;
1100 irp->Size = size;
1101 InitializeListHead( &irp->ThreadListEntry );
1102 irp->StackCount = stack_size;
1103 irp->CurrentLocation = stack_size + 1;
1104 irp->Tail.Overlay.CurrentStackLocation =
1105 (PIO_STACK_LOCATION)(irp + 1) + stack_size;
1108 void WINAPI IoReuseIrp(IRP *irp, NTSTATUS iostatus)
1110 UCHAR AllocationFlags;
1112 TRACE("irp %p, iostatus %#lx.\n", irp, iostatus);
1114 AllocationFlags = irp->AllocationFlags;
1115 IoInitializeIrp(irp, irp->Size, irp->StackCount);
1116 irp->AllocationFlags = AllocationFlags;
1117 irp->IoStatus.Status = iostatus;
1120 /***********************************************************************
1121 * IoInitializeTimer (NTOSKRNL.EXE.@)
1123 NTSTATUS WINAPI IoInitializeTimer(PDEVICE_OBJECT DeviceObject,
1124 PIO_TIMER_ROUTINE TimerRoutine,
1125 PVOID Context)
1127 FIXME( "stub: %p, %p, %p\n", DeviceObject, TimerRoutine, Context );
1128 return STATUS_NOT_IMPLEMENTED;
1132 /***********************************************************************
1133 * IoStartTimer (NTOSKRNL.EXE.@)
1135 void WINAPI IoStartTimer(PDEVICE_OBJECT DeviceObject)
1137 FIXME( "stub: %p\n", DeviceObject );
1141 /***********************************************************************
1142 * IoStopTimer (NTOSKRNL.EXE.@)
1144 void WINAPI IoStopTimer(PDEVICE_OBJECT DeviceObject)
1146 FIXME( "stub: %p\n", DeviceObject );
1150 /***********************************************************************
1151 * IoAllocateIrp (NTOSKRNL.EXE.@)
1153 PIRP WINAPI IoAllocateIrp( CCHAR stack_size, BOOLEAN charge_quota )
1155 SIZE_T size;
1156 PIRP irp;
1157 CCHAR loc_count = stack_size;
1159 TRACE( "%d, %d\n", stack_size, charge_quota );
1161 if (loc_count < 8 && loc_count != 1)
1162 loc_count = 8;
1164 size = sizeof(IRP) + loc_count * sizeof(IO_STACK_LOCATION);
1165 irp = ExAllocatePool( NonPagedPool, size );
1166 if (irp == NULL)
1167 return NULL;
1168 IoInitializeIrp( irp, size, stack_size );
1169 if (stack_size >= 1 && stack_size <= 8)
1170 irp->AllocationFlags = IRP_ALLOCATED_FIXED_SIZE;
1171 if (charge_quota)
1172 irp->AllocationFlags |= IRP_LOOKASIDE_ALLOCATION;
1173 return irp;
1177 /***********************************************************************
1178 * IoFreeIrp (NTOSKRNL.EXE.@)
1180 void WINAPI IoFreeIrp( IRP *irp )
1182 MDL *mdl;
1184 TRACE( "%p\n", irp );
1186 mdl = irp->MdlAddress;
1187 while (mdl)
1189 MDL *next = mdl->Next;
1190 IoFreeMdl( mdl );
1191 mdl = next;
1194 ExFreePool( irp );
1198 /***********************************************************************
1199 * IoAllocateErrorLogEntry (NTOSKRNL.EXE.@)
1201 PVOID WINAPI IoAllocateErrorLogEntry( PVOID IoObject, UCHAR EntrySize )
1203 FIXME( "stub: %p, %u\n", IoObject, EntrySize );
1204 return NULL;
1208 /***********************************************************************
1209 * IoAllocateMdl (NTOSKRNL.EXE.@)
1211 PMDL WINAPI IoAllocateMdl( PVOID va, ULONG length, BOOLEAN secondary, BOOLEAN charge_quota, IRP *irp )
1213 SIZE_T mdl_size;
1214 PMDL mdl;
1216 TRACE("(%p, %lu, %i, %i, %p)\n", va, length, secondary, charge_quota, irp);
1218 if (charge_quota)
1219 FIXME("Charge quota is not yet supported\n");
1221 mdl_size = sizeof(MDL) + sizeof(PFN_NUMBER) * ADDRESS_AND_SIZE_TO_SPAN_PAGES(va, length);
1222 mdl = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, mdl_size );
1223 if (!mdl)
1224 return NULL;
1226 MmInitializeMdl( mdl, va, length );
1228 if (!irp) return mdl;
1230 if (secondary) /* add it at the end */
1232 MDL **pmdl = &irp->MdlAddress;
1233 while (*pmdl) pmdl = &(*pmdl)->Next;
1234 *pmdl = mdl;
1236 else
1238 mdl->Next = irp->MdlAddress;
1239 irp->MdlAddress = mdl;
1241 return mdl;
1245 /***********************************************************************
1246 * IoFreeMdl (NTOSKRNL.EXE.@)
1248 void WINAPI IoFreeMdl(PMDL mdl)
1250 TRACE("%p\n", mdl);
1251 HeapFree(GetProcessHeap(), 0, mdl);
1255 struct _IO_WORKITEM
1257 DEVICE_OBJECT *device;
1258 PIO_WORKITEM_ROUTINE worker;
1259 void *context;
1262 /***********************************************************************
1263 * IoAllocateWorkItem (NTOSKRNL.EXE.@)
1265 PIO_WORKITEM WINAPI IoAllocateWorkItem( PDEVICE_OBJECT device )
1267 PIO_WORKITEM work_item;
1269 TRACE( "%p\n", device );
1271 if (!(work_item = ExAllocatePool( PagedPool, sizeof(*work_item) ))) return NULL;
1272 work_item->device = device;
1273 return work_item;
1277 /***********************************************************************
1278 * IoFreeWorkItem (NTOSKRNL.EXE.@)
1280 void WINAPI IoFreeWorkItem( PIO_WORKITEM work_item )
1282 TRACE( "%p\n", work_item );
1283 ExFreePool( work_item );
1287 static void WINAPI run_work_item_worker(TP_CALLBACK_INSTANCE *instance, void *context)
1289 PIO_WORKITEM work_item = context;
1290 DEVICE_OBJECT *device = work_item->device;
1292 TRACE( "%p: calling %p(%p %p)\n", work_item, work_item->worker, device, work_item->context );
1293 work_item->worker( device, work_item->context );
1294 TRACE( "done\n" );
1296 ObDereferenceObject( device );
1299 /***********************************************************************
1300 * IoQueueWorkItem (NTOSKRNL.EXE.@)
1302 void WINAPI IoQueueWorkItem( PIO_WORKITEM work_item, PIO_WORKITEM_ROUTINE worker,
1303 WORK_QUEUE_TYPE type, void *context )
1305 TRACE( "%p %p %u %p\n", work_item, worker, type, context );
1307 ObReferenceObject( work_item->device );
1308 work_item->worker = worker;
1309 work_item->context = context;
1310 TrySubmitThreadpoolCallback( run_work_item_worker, work_item, NULL );
1313 /***********************************************************************
1314 * IoGetAttachedDevice (NTOSKRNL.EXE.@)
1316 DEVICE_OBJECT* WINAPI IoGetAttachedDevice( DEVICE_OBJECT *device )
1318 DEVICE_OBJECT *result = device;
1320 TRACE( "(%p)\n", device );
1322 while (result->AttachedDevice)
1323 result = result->AttachedDevice;
1325 return result;
1328 void WINAPI IoDetachDevice( DEVICE_OBJECT *device )
1330 device->AttachedDevice = NULL;
1333 /***********************************************************************
1334 * IoAttachDeviceToDeviceStack (NTOSKRNL.EXE.@)
1336 PDEVICE_OBJECT WINAPI IoAttachDeviceToDeviceStack( DEVICE_OBJECT *source,
1337 DEVICE_OBJECT *target )
1339 TRACE( "%p, %p\n", source, target );
1340 target = IoGetAttachedDevice( target );
1341 target->AttachedDevice = source;
1342 source->StackSize = target->StackSize + 1;
1343 return target;
1346 /***********************************************************************
1347 * IoBuildDeviceIoControlRequest (NTOSKRNL.EXE.@)
1349 PIRP WINAPI IoBuildDeviceIoControlRequest( ULONG code, PDEVICE_OBJECT device,
1350 PVOID in_buff, ULONG in_len,
1351 PVOID out_buff, ULONG out_len,
1352 BOOLEAN internal, PKEVENT event,
1353 PIO_STATUS_BLOCK iosb )
1355 PIRP irp;
1356 PIO_STACK_LOCATION irpsp;
1357 MDL *mdl;
1359 TRACE( "%lx, %p, %p, %lu, %p, %lu, %u, %p, %p\n",
1360 code, device, in_buff, in_len, out_buff, out_len, internal, event, iosb );
1362 if (device == NULL)
1363 return NULL;
1365 irp = IoAllocateIrp( device->StackSize, FALSE );
1366 if (irp == NULL)
1367 return NULL;
1369 irpsp = IoGetNextIrpStackLocation( irp );
1370 irpsp->MajorFunction = internal ? IRP_MJ_INTERNAL_DEVICE_CONTROL : IRP_MJ_DEVICE_CONTROL;
1371 irpsp->Parameters.DeviceIoControl.IoControlCode = code;
1372 irpsp->Parameters.DeviceIoControl.InputBufferLength = in_len;
1373 irpsp->Parameters.DeviceIoControl.OutputBufferLength = out_len;
1374 irpsp->DeviceObject = NULL;
1375 irpsp->CompletionRoutine = NULL;
1377 switch (code & 3)
1379 case METHOD_BUFFERED:
1380 irp->AssociatedIrp.SystemBuffer = in_buff;
1381 break;
1382 case METHOD_IN_DIRECT:
1383 case METHOD_OUT_DIRECT:
1384 irp->AssociatedIrp.SystemBuffer = in_buff;
1386 mdl = IoAllocateMdl( out_buff, out_len, FALSE, FALSE, irp );
1387 if (!mdl)
1389 IoFreeIrp( irp );
1390 return NULL;
1393 mdl->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA;
1394 mdl->MappedSystemVa = out_buff;
1395 break;
1396 case METHOD_NEITHER:
1397 irpsp->Parameters.DeviceIoControl.Type3InputBuffer = in_buff;
1398 break;
1401 irp->RequestorMode = KernelMode;
1402 irp->UserBuffer = out_buff;
1403 irp->UserIosb = iosb;
1404 irp->UserEvent = event;
1405 irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
1406 return irp;
1409 /***********************************************************************
1410 * IoBuildAsynchronousFsdRequest (NTOSKRNL.EXE.@)
1412 PIRP WINAPI IoBuildAsynchronousFsdRequest(ULONG majorfunc, DEVICE_OBJECT *device,
1413 void *buffer, ULONG length, LARGE_INTEGER *startoffset,
1414 IO_STATUS_BLOCK *iosb)
1416 PIRP irp;
1417 PIO_STACK_LOCATION irpsp;
1419 TRACE( "(%ld %p %p %ld %p %p)\n", majorfunc, device, buffer, length, startoffset, iosb );
1421 if (!(irp = IoAllocateIrp( device->StackSize, FALSE ))) return NULL;
1423 irpsp = IoGetNextIrpStackLocation( irp );
1424 irpsp->MajorFunction = majorfunc;
1425 irpsp->DeviceObject = NULL;
1426 irpsp->CompletionRoutine = NULL;
1428 irp->AssociatedIrp.SystemBuffer = buffer;
1430 if (device->Flags & DO_DIRECT_IO)
1432 MDL *mdl = IoAllocateMdl( buffer, length, FALSE, FALSE, irp );
1433 if (!mdl)
1435 IoFreeIrp( irp );
1436 return NULL;
1439 mdl->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA;
1440 mdl->MappedSystemVa = buffer;
1443 switch (majorfunc)
1445 case IRP_MJ_READ:
1446 irpsp->Parameters.Read.Length = length;
1447 irpsp->Parameters.Read.ByteOffset.QuadPart = startoffset ? startoffset->QuadPart : 0;
1448 break;
1449 case IRP_MJ_WRITE:
1450 irpsp->Parameters.Write.Length = length;
1451 irpsp->Parameters.Write.ByteOffset.QuadPart = startoffset ? startoffset->QuadPart : 0;
1452 break;
1454 irp->RequestorMode = KernelMode;
1455 irp->UserIosb = iosb;
1456 irp->UserEvent = NULL;
1457 irp->UserBuffer = buffer;
1458 irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
1459 return irp;
1464 /***********************************************************************
1465 * IoBuildSynchronousFsdRequest (NTOSKRNL.EXE.@)
1467 PIRP WINAPI IoBuildSynchronousFsdRequest(ULONG majorfunc, PDEVICE_OBJECT device,
1468 PVOID buffer, ULONG length, PLARGE_INTEGER startoffset,
1469 PKEVENT event, PIO_STATUS_BLOCK iosb)
1471 IRP *irp;
1473 TRACE("(%ld %p %p %ld %p %p)\n", majorfunc, device, buffer, length, startoffset, iosb);
1475 irp = IoBuildAsynchronousFsdRequest( majorfunc, device, buffer, length, startoffset, iosb );
1476 if (!irp) return NULL;
1478 irp->UserEvent = event;
1479 return irp;
1482 static void build_driver_keypath( const WCHAR *name, UNICODE_STRING *keypath )
1484 static const WCHAR driverW[] = {'\\','D','r','i','v','e','r','\\',0};
1485 WCHAR *str;
1487 /* Check what prefix is present */
1488 if (wcsncmp( name, servicesW, lstrlenW(servicesW) ) == 0)
1490 FIXME( "Driver name %s is malformed as the keypath\n", debugstr_w(name) );
1491 RtlCreateUnicodeString( keypath, name );
1492 return;
1494 if (wcsncmp( name, driverW, lstrlenW(driverW) ) == 0)
1495 name += lstrlenW(driverW);
1496 else
1497 FIXME( "Driver name %s does not properly begin with \\Driver\\\n", debugstr_w(name) );
1499 str = HeapAlloc( GetProcessHeap(), 0, sizeof(servicesW) + lstrlenW(name)*sizeof(WCHAR));
1500 lstrcpyW( str, servicesW );
1501 lstrcatW( str, name );
1502 RtlInitUnicodeString( keypath, str );
1506 static NTSTATUS WINAPI unhandled_irp( DEVICE_OBJECT *device, IRP *irp )
1508 TRACE( "(%p, %p)\n", device, irp );
1509 irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
1510 IoCompleteRequest( irp, IO_NO_INCREMENT );
1511 return STATUS_INVALID_DEVICE_REQUEST;
1515 static void free_driver_object( void *obj )
1517 struct wine_driver *driver = obj;
1518 RtlFreeUnicodeString( &driver->driver_obj.DriverName );
1519 RtlFreeUnicodeString( &driver->driver_obj.DriverExtension->ServiceKeyName );
1520 free_kernel_object( driver );
1523 static const WCHAR driver_type_name[] = {'D','r','i','v','e','r',0};
1525 static struct _OBJECT_TYPE driver_type =
1527 driver_type_name,
1528 NULL,
1529 free_driver_object
1532 POBJECT_TYPE IoDriverObjectType = &driver_type;
1535 /***********************************************************************
1536 * IoCreateDriver (NTOSKRNL.EXE.@)
1538 NTSTATUS WINAPI IoCreateDriver( UNICODE_STRING *name, PDRIVER_INITIALIZE init )
1540 struct wine_driver *driver;
1541 NTSTATUS status;
1542 unsigned int i;
1544 TRACE("(%s, %p)\n", debugstr_us(name), init);
1546 if (!(driver = alloc_kernel_object( IoDriverObjectType, NULL, sizeof(*driver), 1 )))
1547 return STATUS_NO_MEMORY;
1549 if ((status = RtlDuplicateUnicodeString( 1, name, &driver->driver_obj.DriverName )))
1551 free_kernel_object( driver );
1552 return status;
1555 driver->driver_obj.Size = sizeof(driver->driver_obj);
1556 driver->driver_obj.DriverInit = init;
1557 driver->driver_obj.DriverExtension = &driver->driver_extension;
1558 driver->driver_extension.DriverObject = &driver->driver_obj;
1559 build_driver_keypath( driver->driver_obj.DriverName.Buffer, &driver->driver_extension.ServiceKeyName );
1560 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1561 driver->driver_obj.MajorFunction[i] = unhandled_irp;
1562 list_init( &driver->root_pnp_devices );
1564 EnterCriticalSection( &drivers_cs );
1565 if (wine_rb_put( &wine_drivers, &driver->driver_obj.DriverName, &driver->entry ))
1566 ERR( "failed to insert driver %s in tree\n", debugstr_us(name) );
1567 LeaveCriticalSection( &drivers_cs );
1569 status = driver->driver_obj.DriverInit( &driver->driver_obj, &driver->driver_extension.ServiceKeyName );
1570 if (status)
1572 IoDeleteDriver( &driver->driver_obj );
1573 return status;
1576 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1578 if (driver->driver_obj.MajorFunction[i]) continue;
1579 driver->driver_obj.MajorFunction[i] = unhandled_irp;
1582 return STATUS_SUCCESS;
1586 /***********************************************************************
1587 * IoDeleteDriver (NTOSKRNL.EXE.@)
1589 void WINAPI IoDeleteDriver( DRIVER_OBJECT *driver_object )
1591 TRACE( "(%p)\n", driver_object );
1593 EnterCriticalSection( &drivers_cs );
1594 wine_rb_remove_key( &wine_drivers, &driver_object->DriverName );
1595 LeaveCriticalSection( &drivers_cs );
1597 ObDereferenceObject( driver_object );
1601 static const WCHAR device_type_name[] = {'D','e','v','i','c','e',0};
1603 static struct _OBJECT_TYPE device_type =
1605 device_type_name,
1608 POBJECT_TYPE IoDeviceObjectType = &device_type;
1610 /***********************************************************************
1611 * IoCreateDeviceSecure (NTOSKRNL.EXE.@)
1613 NTSTATUS WINAPI IoCreateDeviceSecure( DRIVER_OBJECT *driver, ULONG ext_size,
1614 UNICODE_STRING *name, DEVICE_TYPE type,
1615 ULONG characteristics, BOOLEAN exclusive,
1616 PCUNICODE_STRING sddl, LPCGUID guid,
1617 DEVICE_OBJECT **ret_device )
1619 FIXME( "(%p, %lu, %s, %lu, %lx, %u, %s, %s, %p): semi-stub\n",
1620 driver, ext_size, debugstr_us(name), type, characteristics, exclusive,
1621 debugstr_us(sddl), wine_dbgstr_guid(guid), ret_device );
1623 return IoCreateDevice( driver, ext_size, name, type, characteristics, exclusive, ret_device );
1626 /***********************************************************************
1627 * IoCreateDevice (NTOSKRNL.EXE.@)
1629 NTSTATUS WINAPI IoCreateDevice( DRIVER_OBJECT *driver, ULONG ext_size,
1630 UNICODE_STRING *name, DEVICE_TYPE type,
1631 ULONG characteristics, BOOLEAN exclusive,
1632 DEVICE_OBJECT **ret_device )
1634 static const WCHAR auto_format[] = {'\\','D','e','v','i','c','e','\\','%','0','8','x',0};
1635 NTSTATUS status;
1636 struct wine_device *wine_device;
1637 DEVICE_OBJECT *device;
1638 HANDLE manager = get_device_manager();
1639 static unsigned int auto_idx = 0;
1640 WCHAR autoW[17];
1642 TRACE( "(%p, %lu, %s, %lu, %lx, %u, %p)\n",
1643 driver, ext_size, debugstr_us(name), type, characteristics, exclusive, ret_device );
1645 if (!(wine_device = alloc_kernel_object( IoDeviceObjectType, NULL, sizeof(struct wine_device) + ext_size, 1 )))
1646 return STATUS_NO_MEMORY;
1647 device = &wine_device->device_obj;
1649 device->DriverObject = driver;
1650 device->DeviceExtension = wine_device + 1;
1651 device->DeviceType = type;
1652 device->StackSize = 1;
1654 if (characteristics & FILE_AUTOGENERATED_DEVICE_NAME)
1658 swprintf( autoW, ARRAY_SIZE(autoW), auto_format, auto_idx++ );
1659 SERVER_START_REQ( create_device )
1661 req->rootdir = 0;
1662 req->manager = wine_server_obj_handle( manager );
1663 req->user_ptr = wine_server_client_ptr( device );
1664 wine_server_add_data( req, autoW, lstrlenW(autoW) * sizeof(WCHAR) );
1665 status = wine_server_call( req );
1667 SERVER_END_REQ;
1668 } while (status == STATUS_OBJECT_NAME_COLLISION);
1670 else
1672 SERVER_START_REQ( create_device )
1674 req->rootdir = 0;
1675 req->manager = wine_server_obj_handle( manager );
1676 req->user_ptr = wine_server_client_ptr( device );
1677 if (name) wine_server_add_data( req, name->Buffer, name->Length );
1678 status = wine_server_call( req );
1680 SERVER_END_REQ;
1683 if (status)
1685 free_kernel_object( device );
1686 return status;
1689 device->NextDevice = driver->DeviceObject;
1690 driver->DeviceObject = device;
1692 *ret_device = device;
1693 return STATUS_SUCCESS;
1697 /***********************************************************************
1698 * IoDeleteDevice (NTOSKRNL.EXE.@)
1700 void WINAPI IoDeleteDevice( DEVICE_OBJECT *device )
1702 NTSTATUS status;
1704 TRACE( "%p\n", device );
1706 SERVER_START_REQ( delete_device )
1708 req->manager = wine_server_obj_handle( get_device_manager() );
1709 req->device = wine_server_client_ptr( device );
1710 status = wine_server_call( req );
1712 SERVER_END_REQ;
1714 if (status == STATUS_SUCCESS)
1716 struct wine_device *wine_device = CONTAINING_RECORD(device, struct wine_device, device_obj);
1717 DEVICE_OBJECT **prev = &device->DriverObject->DeviceObject;
1718 DEVICE_RELATIONS *children;
1719 unsigned int i;
1721 while (*prev && *prev != device) prev = &(*prev)->NextDevice;
1722 if (*prev) *prev = (*prev)->NextDevice;
1723 if ((children = wine_device->children))
1725 for (i = 0; i < children->Count; ++i)
1726 ObDereferenceObject( children->Objects[i] );
1727 ExFreePool( children );
1729 ObDereferenceObject( device );
1734 /***********************************************************************
1735 * IoCreateSymbolicLink (NTOSKRNL.EXE.@)
1737 NTSTATUS WINAPI IoCreateSymbolicLink( UNICODE_STRING *name, UNICODE_STRING *target )
1739 HANDLE handle;
1740 OBJECT_ATTRIBUTES attr;
1741 NTSTATUS ret;
1743 attr.Length = sizeof(attr);
1744 attr.RootDirectory = 0;
1745 attr.ObjectName = name;
1746 attr.Attributes = OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT;
1747 attr.SecurityDescriptor = NULL;
1748 attr.SecurityQualityOfService = NULL;
1750 TRACE( "%s -> %s\n", debugstr_us(name), debugstr_us(target) );
1751 if (!(ret = NtCreateSymbolicLinkObject( &handle, SYMBOLIC_LINK_ALL_ACCESS, &attr, target )))
1752 NtClose( handle );
1753 return ret;
1757 /***********************************************************************
1758 * IoCreateUnprotectedSymbolicLink (NTOSKRNL.EXE.@)
1760 NTSTATUS WINAPI IoCreateUnprotectedSymbolicLink( UNICODE_STRING *name, UNICODE_STRING *target )
1762 HANDLE handle;
1763 OBJECT_ATTRIBUTES attr;
1764 NTSTATUS ret;
1766 attr.Length = sizeof(attr);
1767 attr.RootDirectory = 0;
1768 attr.ObjectName = name;
1769 attr.Attributes = OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT;
1770 attr.SecurityDescriptor = NULL;
1771 attr.SecurityQualityOfService = NULL;
1773 TRACE( "%s -> %s\n", debugstr_us(name), debugstr_us(target) );
1774 if (!(ret = NtCreateSymbolicLinkObject( &handle, SYMBOLIC_LINK_ALL_ACCESS, &attr, target )))
1775 NtClose( handle );
1776 return ret;
1780 /***********************************************************************
1781 * IoDeleteSymbolicLink (NTOSKRNL.EXE.@)
1783 NTSTATUS WINAPI IoDeleteSymbolicLink( UNICODE_STRING *name )
1785 HANDLE handle;
1786 OBJECT_ATTRIBUTES attr;
1787 NTSTATUS status;
1789 attr.Length = sizeof(attr);
1790 attr.RootDirectory = 0;
1791 attr.ObjectName = name;
1792 attr.Attributes = OBJ_CASE_INSENSITIVE;
1793 attr.SecurityDescriptor = NULL;
1794 attr.SecurityQualityOfService = NULL;
1796 if (!(status = NtOpenSymbolicLinkObject( &handle, DELETE, &attr )))
1798 NtMakeTemporaryObject( handle );
1799 NtClose( handle );
1801 return status;
1804 /***********************************************************************
1805 * IoGetDeviceInterfaces (NTOSKRNL.EXE.@)
1807 NTSTATUS WINAPI IoGetDeviceInterfaces( const GUID *InterfaceClassGuid,
1808 PDEVICE_OBJECT PhysicalDeviceObject,
1809 ULONG Flags, PWSTR *SymbolicLinkList )
1811 FIXME( "stub: %s %p %lx %p\n", debugstr_guid(InterfaceClassGuid),
1812 PhysicalDeviceObject, Flags, SymbolicLinkList );
1813 return STATUS_NOT_IMPLEMENTED;
1817 /***********************************************************************
1818 * IoGetDeviceObjectPointer (NTOSKRNL.EXE.@)
1820 NTSTATUS WINAPI IoGetDeviceObjectPointer( UNICODE_STRING *name, ACCESS_MASK access, PFILE_OBJECT *file, PDEVICE_OBJECT *device )
1822 static DEVICE_OBJECT stub_device;
1823 static DRIVER_OBJECT stub_driver;
1825 FIXME( "stub: %s %lx %p %p\n", debugstr_us(name), access, file, device );
1827 stub_device.StackSize = 0x80; /* minimum value to appease SecuROM 5.x */
1828 stub_device.DriverObject = &stub_driver;
1830 *file = NULL;
1831 *device = &stub_device;
1833 return STATUS_SUCCESS;
1836 /***********************************************************************
1837 * IoCallDriver (NTOSKRNL.EXE.@)
1839 NTSTATUS WINAPI IoCallDriver( DEVICE_OBJECT *device, IRP *irp )
1841 PDRIVER_DISPATCH dispatch;
1842 IO_STACK_LOCATION *irpsp;
1843 NTSTATUS status;
1845 --irp->CurrentLocation;
1846 irpsp = --irp->Tail.Overlay.CurrentStackLocation;
1847 irpsp->DeviceObject = device;
1848 dispatch = device->DriverObject->MajorFunction[irpsp->MajorFunction];
1850 TRACE_(relay)( "\1Call driver dispatch %p (device=%p,irp=%p)\n", dispatch, device, irp );
1852 status = dispatch( device, irp );
1854 TRACE_(relay)( "\1Ret driver dispatch %p (device=%p,irp=%p) retval=%08lx\n",
1855 dispatch, device, irp, status );
1857 return status;
1861 /***********************************************************************
1862 * IofCallDriver (NTOSKRNL.EXE.@)
1864 DEFINE_FASTCALL_WRAPPER( IofCallDriver, 8 )
1865 NTSTATUS FASTCALL IofCallDriver( DEVICE_OBJECT *device, IRP *irp )
1867 TRACE( "%p %p\n", device, irp );
1868 return IoCallDriver( device, irp );
1872 /***********************************************************************
1873 * IoGetRelatedDeviceObject (NTOSKRNL.EXE.@)
1875 PDEVICE_OBJECT WINAPI IoGetRelatedDeviceObject( PFILE_OBJECT obj )
1877 FIXME( "stub: %p\n", obj );
1878 return NULL;
1881 static CONFIGURATION_INFORMATION configuration_information;
1883 /***********************************************************************
1884 * IoGetConfigurationInformation (NTOSKRNL.EXE.@)
1886 PCONFIGURATION_INFORMATION WINAPI IoGetConfigurationInformation(void)
1888 FIXME( "partial stub\n" );
1889 /* FIXME: return actual devices on system */
1890 return &configuration_information;
1893 /***********************************************************************
1894 * IoGetStackLimits (NTOSKRNL.EXE.@)
1896 void WINAPI IoGetStackLimits(ULONG_PTR *low, ULONG_PTR *high)
1898 TEB *teb = NtCurrentTeb();
1900 TRACE( "%p %p\n", low, high );
1902 *low = (DWORD_PTR)teb->Tib.StackLimit;
1903 *high = (DWORD_PTR)teb->Tib.StackBase;
1906 /***********************************************************************
1907 * IoIsWdmVersionAvailable (NTOSKRNL.EXE.@)
1909 NTSTATUS WINAPI IoIsWdmVersionAvailable(UCHAR MajorVersion, UCHAR MinorVersion)
1911 DWORD version;
1912 DWORD major;
1913 DWORD minor;
1915 TRACE( "%d, 0x%X\n", MajorVersion, MinorVersion );
1917 version = GetVersion();
1918 major = LOBYTE(version);
1919 minor = HIBYTE(LOWORD(version));
1921 if (MajorVersion == 6 && MinorVersion == 0)
1923 /* Windows Vista, Windows Server 2008, Windows 7 */
1925 else if (MajorVersion == 1)
1927 if (MinorVersion == 0x30)
1929 /* Windows server 2003 */
1930 MajorVersion = 6;
1931 MinorVersion = 0;
1933 else if (MinorVersion == 0x20)
1935 /* Windows XP */
1936 MajorVersion = 5;
1937 MinorVersion = 1;
1939 else if (MinorVersion == 0x10)
1941 /* Windows 2000 */
1942 MajorVersion = 5;
1943 MinorVersion = 0;
1945 else if (MinorVersion == 0x05)
1947 /* Windows ME */
1948 MajorVersion = 4;
1949 MinorVersion = 0x5a;
1951 else if (MinorVersion == 0x00)
1953 /* Windows 98 */
1954 MajorVersion = 4;
1955 MinorVersion = 0x0a;
1957 else
1959 FIXME( "unknown major %d minor 0x%X\n", MajorVersion, MinorVersion );
1960 return FALSE;
1963 else
1965 FIXME( "unknown major %d minor 0x%X\n", MajorVersion, MinorVersion );
1966 return FALSE;
1968 return major > MajorVersion || (major == MajorVersion && minor >= MinorVersion);
1971 /***********************************************************************
1972 * IoQueryDeviceDescription (NTOSKRNL.EXE.@)
1974 NTSTATUS WINAPI IoQueryDeviceDescription(PINTERFACE_TYPE itype, PULONG bus, PCONFIGURATION_TYPE ctype,
1975 PULONG cnum, PCONFIGURATION_TYPE ptype, PULONG pnum,
1976 PIO_QUERY_DEVICE_ROUTINE callout, PVOID context)
1978 FIXME( "(%p %p %p %p %p %p %p %p)\n", itype, bus, ctype, cnum, ptype, pnum, callout, context);
1979 return STATUS_NOT_IMPLEMENTED;
1982 /***********************************************************************
1983 * IoRegisterDriverReinitialization (NTOSKRNL.EXE.@)
1985 void WINAPI IoRegisterDriverReinitialization( PDRIVER_OBJECT obj, PDRIVER_REINITIALIZE reinit, PVOID context )
1987 FIXME( "stub: %p %p %p\n", obj, reinit, context );
1990 /***********************************************************************
1991 * IoRegisterBootDriverReinitialization (NTOSKRNL.EXE.@)
1993 void WINAPI IoRegisterBootDriverReinitialization(DRIVER_OBJECT *driver, PDRIVER_REINITIALIZE proc, void *ctx)
1995 FIXME("driver %p, proc %p, ctx %p, stub!\n", driver, proc, ctx);
1998 /***********************************************************************
1999 * IoRegisterShutdownNotification (NTOSKRNL.EXE.@)
2001 NTSTATUS WINAPI IoRegisterShutdownNotification( PDEVICE_OBJECT obj )
2003 FIXME( "stub: %p\n", obj );
2004 return STATUS_SUCCESS;
2008 /***********************************************************************
2009 * IoUnregisterShutdownNotification (NTOSKRNL.EXE.@)
2011 VOID WINAPI IoUnregisterShutdownNotification( PDEVICE_OBJECT obj )
2013 FIXME( "stub: %p\n", obj );
2017 /***********************************************************************
2018 * IoReportResourceForDetection (NTOSKRNL.EXE.@)
2020 NTSTATUS WINAPI IoReportResourceForDetection( DRIVER_OBJECT *drv_obj, CM_RESOURCE_LIST *drv_list, ULONG drv_size,
2021 DEVICE_OBJECT *dev_obj, CM_RESOURCE_LIST *dev_list, ULONG dev_size,
2022 BOOLEAN *conflict )
2024 FIXME( "(%p, %p, %lu, %p, %p, %lu, %p): stub\n", drv_obj, drv_list, drv_size,
2025 dev_obj, dev_list, dev_size, conflict );
2027 return STATUS_NOT_IMPLEMENTED;
2031 /***********************************************************************
2032 * IoReportResourceUsage (NTOSKRNL.EXE.@)
2034 NTSTATUS WINAPI IoReportResourceUsage( UNICODE_STRING *name, DRIVER_OBJECT *drv_obj, CM_RESOURCE_LIST *drv_list,
2035 ULONG drv_size, DRIVER_OBJECT *dev_obj, CM_RESOURCE_LIST *dev_list,
2036 ULONG dev_size, BOOLEAN overwrite, BOOLEAN *conflict )
2038 FIXME( "(%s, %p, %p, %lu, %p, %p, %lu, %d, %p): stub\n", debugstr_us(name),
2039 drv_obj, drv_list, drv_size, dev_obj, dev_list, dev_size, overwrite, conflict );
2041 return STATUS_NOT_IMPLEMENTED;
2045 /***********************************************************************
2046 * IoCompleteRequest (NTOSKRNL.EXE.@)
2048 VOID WINAPI IoCompleteRequest( IRP *irp, UCHAR priority_boost )
2050 IO_STACK_LOCATION *irpsp;
2051 PIO_COMPLETION_ROUTINE routine;
2052 NTSTATUS status, stat;
2053 DEVICE_OBJECT *device;
2054 int call_flag = 0;
2056 TRACE( "%p %u\n", irp, priority_boost );
2058 status = irp->IoStatus.Status;
2059 while (irp->CurrentLocation <= irp->StackCount)
2061 irpsp = irp->Tail.Overlay.CurrentStackLocation;
2062 routine = irpsp->CompletionRoutine;
2063 call_flag = 0;
2064 if (routine)
2066 if ((irpsp->Control & SL_INVOKE_ON_SUCCESS) && STATUS_SUCCESS == status)
2067 call_flag = 1;
2068 if ((irpsp->Control & SL_INVOKE_ON_ERROR) && STATUS_SUCCESS != status)
2069 call_flag = 1;
2070 if ((irpsp->Control & SL_INVOKE_ON_CANCEL) && irp->Cancel)
2071 call_flag = 1;
2073 ++irp->CurrentLocation;
2074 ++irp->Tail.Overlay.CurrentStackLocation;
2075 if (irp->CurrentLocation <= irp->StackCount)
2076 device = IoGetCurrentIrpStackLocation(irp)->DeviceObject;
2077 else
2078 device = NULL;
2079 irp->PendingReturned = !!(irpsp->Control & SL_PENDING_RETURNED);
2080 irpsp->Control = 0;
2081 if (call_flag)
2083 TRACE( "calling %p( %p, %p, %p )\n", routine, device, irp, irpsp->Context );
2084 stat = routine( device, irp, irpsp->Context );
2085 TRACE( "CompletionRoutine returned %lx\n", stat );
2086 if (STATUS_MORE_PROCESSING_REQUIRED == stat)
2087 return;
2091 if (irp->Flags & IRP_DEALLOCATE_BUFFER)
2092 HeapFree( GetProcessHeap(), 0, irp->AssociatedIrp.SystemBuffer );
2093 if (irp->UserIosb) *irp->UserIosb = irp->IoStatus;
2094 if (irp->UserEvent) KeSetEvent( irp->UserEvent, IO_NO_INCREMENT, FALSE );
2096 IoFreeIrp( irp );
2100 /***********************************************************************
2101 * IofCompleteRequest (NTOSKRNL.EXE.@)
2103 DEFINE_FASTCALL_WRAPPER( IofCompleteRequest, 8 )
2104 void FASTCALL IofCompleteRequest( IRP *irp, UCHAR priority_boost )
2106 TRACE( "%p %u\n", irp, priority_boost );
2107 IoCompleteRequest( irp, priority_boost );
2111 /***********************************************************************
2112 * IoCancelIrp (NTOSKRNL.EXE.@)
2114 BOOLEAN WINAPI IoCancelIrp( IRP *irp )
2116 PDRIVER_CANCEL cancel_routine;
2117 KIRQL irql;
2119 TRACE( "(%p)\n", irp );
2121 IoAcquireCancelSpinLock( &irql );
2122 irp->Cancel = TRUE;
2123 if (!(cancel_routine = IoSetCancelRoutine( irp, NULL )))
2125 IoReleaseCancelSpinLock( irp->CancelIrql );
2126 return FALSE;
2129 /* CancelRoutine is responsible for calling IoReleaseCancelSpinLock */
2130 irp->CancelIrql = irql;
2131 cancel_routine( IoGetCurrentIrpStackLocation(irp)->DeviceObject, irp );
2132 return TRUE;
2136 /***********************************************************************
2137 * InterlockedCompareExchange (NTOSKRNL.EXE.@)
2139 DEFINE_FASTCALL_WRAPPER( NTOSKRNL_InterlockedCompareExchange, 12 )
2140 LONG FASTCALL NTOSKRNL_InterlockedCompareExchange( LONG volatile *dest, LONG xchg, LONG compare )
2142 return InterlockedCompareExchange( dest, xchg, compare );
2146 /***********************************************************************
2147 * InterlockedDecrement (NTOSKRNL.EXE.@)
2149 DEFINE_FASTCALL1_WRAPPER( NTOSKRNL_InterlockedDecrement )
2150 LONG FASTCALL NTOSKRNL_InterlockedDecrement( LONG volatile *dest )
2152 return InterlockedDecrement( dest );
2156 /***********************************************************************
2157 * InterlockedExchange (NTOSKRNL.EXE.@)
2159 DEFINE_FASTCALL_WRAPPER( NTOSKRNL_InterlockedExchange, 8 )
2160 LONG FASTCALL NTOSKRNL_InterlockedExchange( LONG volatile *dest, LONG val )
2162 return InterlockedExchange( dest, val );
2166 /***********************************************************************
2167 * InterlockedExchangeAdd (NTOSKRNL.EXE.@)
2169 DEFINE_FASTCALL_WRAPPER( NTOSKRNL_InterlockedExchangeAdd, 8 )
2170 LONG FASTCALL NTOSKRNL_InterlockedExchangeAdd( LONG volatile *dest, LONG incr )
2172 return InterlockedExchangeAdd( dest, incr );
2176 /***********************************************************************
2177 * InterlockedIncrement (NTOSKRNL.EXE.@)
2179 DEFINE_FASTCALL1_WRAPPER( NTOSKRNL_InterlockedIncrement )
2180 LONG FASTCALL NTOSKRNL_InterlockedIncrement( LONG volatile *dest )
2182 return InterlockedIncrement( dest );
2185 #ifdef __i386__
2187 /*************************************************************************
2188 * RtlUshortByteSwap (NTOSKRNL.EXE.@)
2190 __ASM_FASTCALL_FUNC(RtlUshortByteSwap, 4,
2191 "movb %ch,%al\n\t"
2192 "movb %cl,%ah\n\t"
2193 "ret")
2195 /*************************************************************************
2196 * RtlUlongByteSwap (NTOSKRNL.EXE.@)
2198 __ASM_FASTCALL_FUNC(RtlUlongByteSwap, 4,
2199 "movl %ecx,%eax\n\t"
2200 "bswap %eax\n\t"
2201 "ret")
2203 /*************************************************************************
2204 * RtlUlonglongByteSwap (NTOSKRNL.EXE.@)
2206 __ASM_FASTCALL_FUNC(RtlUlonglongByteSwap, 8,
2207 "movl 4(%esp),%edx\n\t"
2208 "bswap %edx\n\t"
2209 "movl 8(%esp),%eax\n\t"
2210 "bswap %eax\n\t"
2211 "ret $8")
2213 #endif /* __i386__ */
2215 /***********************************************************************
2216 * ExAllocatePool2 (NTOSKRNL.EXE.@)
2218 void * WINAPI ExAllocatePool2( POOL_FLAGS flags, SIZE_T size, ULONG tag )
2220 /* FIXME: handle page alignment constraints */
2221 void *ret = HeapAlloc( ntoskrnl_heap, 0, size );
2222 TRACE( "(0x%I64x, %Iu, %s) -> %p\n", flags, size, debugstr_fourcc(tag), ret );
2223 return ret;
2226 static POOL_FLAGS pool_type_to_flags( POOL_TYPE type )
2228 switch (type & 7)
2230 case NonPagedPool:
2231 case NonPagedPoolMustSucceed:
2232 return POOL_FLAG_NON_PAGED;
2233 case PagedPool:
2234 return POOL_FLAG_PAGED;
2235 case NonPagedPoolCacheAligned:
2236 case NonPagedPoolCacheAlignedMustS:
2237 return POOL_FLAG_NON_PAGED|POOL_FLAG_CACHE_ALIGNED;
2238 case PagedPoolCacheAligned:
2239 return POOL_FLAG_PAGED|POOL_FLAG_CACHE_ALIGNED;
2240 default:
2241 return 0;
2245 /***********************************************************************
2246 * ExAllocatePool (NTOSKRNL.EXE.@)
2248 PVOID WINAPI ExAllocatePool( POOL_TYPE type, SIZE_T size )
2250 POOL_FLAGS flags = pool_type_to_flags( type );
2251 if (type & POOL_RAISE_IF_ALLOCATION_FAILURE)
2252 flags |= POOL_FLAG_RAISE_ON_FAILURE;
2254 return ExAllocatePool2( flags, size, 0 );
2257 /***********************************************************************
2258 * ExAllocatePoolWithQuota (NTOSKRNL.EXE.@)
2260 PVOID WINAPI ExAllocatePoolWithQuota( POOL_TYPE type, SIZE_T size )
2262 POOL_FLAGS flags = pool_type_to_flags( type ) | POOL_FLAG_USE_QUOTA;
2263 if (!(type & POOL_QUOTA_FAIL_INSTEAD_OF_RAISE))
2264 flags |= POOL_FLAG_RAISE_ON_FAILURE;
2266 return ExAllocatePool2( flags, size, 0 );
2269 /***********************************************************************
2270 * ExAllocatePoolWithTag (NTOSKRNL.EXE.@)
2272 PVOID WINAPI ExAllocatePoolWithTag( POOL_TYPE type, SIZE_T size, ULONG tag )
2274 POOL_FLAGS flags = pool_type_to_flags( type );
2275 if (type & POOL_RAISE_IF_ALLOCATION_FAILURE)
2276 flags |= POOL_FLAG_RAISE_ON_FAILURE;
2278 return ExAllocatePool2( flags, size, tag );
2281 /***********************************************************************
2282 * ExAllocatePoolWithQuotaTag (NTOSKRNL.EXE.@)
2284 PVOID WINAPI ExAllocatePoolWithQuotaTag( POOL_TYPE type, SIZE_T size, ULONG tag )
2286 POOL_FLAGS flags = pool_type_to_flags( type ) | POOL_FLAG_USE_QUOTA;
2287 if (!(type & POOL_QUOTA_FAIL_INSTEAD_OF_RAISE))
2288 flags |= POOL_FLAG_RAISE_ON_FAILURE;
2290 return ExAllocatePool2( flags, size, tag );
2293 /***********************************************************************
2294 * ExCreateCallback (NTOSKRNL.EXE.@)
2296 NTSTATUS WINAPI ExCreateCallback(PCALLBACK_OBJECT *obj, POBJECT_ATTRIBUTES attr,
2297 BOOLEAN create, BOOLEAN allow_multiple)
2299 FIXME("(%p, %p, %u, %u): stub\n", obj, attr, create, allow_multiple);
2301 return STATUS_SUCCESS;
2304 void * WINAPI ExRegisterCallback(PCALLBACK_OBJECT callback_object,
2305 PCALLBACK_FUNCTION callback_function, void *callback_context)
2307 FIXME("callback_object %p, callback_function %p, callback_context %p stub.\n",
2308 callback_object, callback_function, callback_context);
2310 return (void *)0xdeadbeef;
2313 void WINAPI ExUnregisterCallback(void *callback_registration)
2315 FIXME("callback_registration %p stub.\n", callback_registration);
2318 /***********************************************************************
2319 * ExNotifyCallback (NTOSKRNL.EXE.@)
2321 void WINAPI ExNotifyCallback(void *obj, void *arg1, void *arg2)
2323 FIXME("(%p, %p, %p): stub\n", obj, arg1, arg2);
2326 /***********************************************************************
2327 * ExFreePool (NTOSKRNL.EXE.@)
2329 void WINAPI ExFreePool( void *ptr )
2331 ExFreePoolWithTag( ptr, 0 );
2335 /***********************************************************************
2336 * ExFreePoolWithTag (NTOSKRNL.EXE.@)
2338 void WINAPI ExFreePoolWithTag( void *ptr, ULONG tag )
2340 TRACE( "%p\n", ptr );
2341 HeapFree( ntoskrnl_heap, 0, ptr );
2344 static void initialize_lookaside_list( GENERAL_LOOKASIDE *lookaside, PALLOCATE_FUNCTION allocate, PFREE_FUNCTION free,
2345 ULONG type, SIZE_T size, ULONG tag )
2348 RtlInitializeSListHead( &lookaside->ListHead );
2349 lookaside->Depth = 4;
2350 lookaside->MaximumDepth = 256;
2351 lookaside->TotalAllocates = 0;
2352 lookaside->AllocateMisses = 0;
2353 lookaside->TotalFrees = 0;
2354 lookaside->FreeMisses = 0;
2355 lookaside->Type = type;
2356 lookaside->Tag = tag;
2357 lookaside->Size = size;
2358 lookaside->Allocate = allocate ? allocate : ExAllocatePoolWithTag;
2359 lookaside->Free = free ? free : ExFreePool;
2360 lookaside->LastTotalAllocates = 0;
2361 lookaside->LastAllocateMisses = 0;
2363 /* FIXME: insert in global list of lookadside lists */
2366 /***********************************************************************
2367 * ExInitializeNPagedLookasideList (NTOSKRNL.EXE.@)
2369 void WINAPI ExInitializeNPagedLookasideList(PNPAGED_LOOKASIDE_LIST lookaside,
2370 PALLOCATE_FUNCTION allocate,
2371 PFREE_FUNCTION free,
2372 ULONG flags,
2373 SIZE_T size,
2374 ULONG tag,
2375 USHORT depth)
2377 TRACE( "%p, %p, %p, %lu, %Iu, %lu, %u\n", lookaside, allocate, free, flags, size, tag, depth );
2378 initialize_lookaside_list( &lookaside->L, allocate, free, NonPagedPool | flags, size, tag );
2381 /***********************************************************************
2382 * ExInitializePagedLookasideList (NTOSKRNL.EXE.@)
2384 void WINAPI ExInitializePagedLookasideList(PPAGED_LOOKASIDE_LIST lookaside,
2385 PALLOCATE_FUNCTION allocate,
2386 PFREE_FUNCTION free,
2387 ULONG flags,
2388 SIZE_T size,
2389 ULONG tag,
2390 USHORT depth)
2392 TRACE( "%p, %p, %p, %lu, %Iu, %lu, %u\n", lookaside, allocate, free, flags, size, tag, depth );
2393 initialize_lookaside_list( &lookaside->L, allocate, free, PagedPool | flags, size, tag );
2396 static void delete_lookaside_list( GENERAL_LOOKASIDE *lookaside )
2398 void *entry;
2399 while ((entry = RtlInterlockedPopEntrySList(&lookaside->ListHead)))
2400 lookaside->FreeEx(entry, (LOOKASIDE_LIST_EX*)lookaside);
2403 /***********************************************************************
2404 * ExDeleteNPagedLookasideList (NTOSKRNL.EXE.@)
2406 void WINAPI ExDeleteNPagedLookasideList( PNPAGED_LOOKASIDE_LIST lookaside )
2408 TRACE( "%p\n", lookaside );
2409 delete_lookaside_list( &lookaside->L );
2413 /***********************************************************************
2414 * ExDeletePagedLookasideList (NTOSKRNL.EXE.@)
2416 void WINAPI ExDeletePagedLookasideList( PPAGED_LOOKASIDE_LIST lookaside )
2418 TRACE( "%p\n", lookaside );
2419 delete_lookaside_list( &lookaside->L );
2422 /***********************************************************************
2423 * ExInitializeZone (NTOSKRNL.EXE.@)
2425 NTSTATUS WINAPI ExInitializeZone(PZONE_HEADER Zone,
2426 ULONG BlockSize,
2427 PVOID InitialSegment,
2428 ULONG InitialSegmentSize)
2430 FIXME( "stub: %p, %lu, %p, %lu\n", Zone, BlockSize, InitialSegment, InitialSegmentSize );
2431 return STATUS_NOT_IMPLEMENTED;
2434 /***********************************************************************
2435 * FsRtlIsNameInExpression (NTOSKRNL.EXE.@)
2437 BOOLEAN WINAPI FsRtlIsNameInExpression(PUNICODE_STRING expression, PUNICODE_STRING name,
2438 BOOLEAN ignore, PWCH upcase)
2440 FIXME("stub: %p %p %d %p\n", expression, name, ignore, upcase);
2441 return FALSE;
2444 /***********************************************************************
2445 * FsRtlRegisterUncProvider (NTOSKRNL.EXE.@)
2447 NTSTATUS WINAPI FsRtlRegisterUncProvider(PHANDLE MupHandle, PUNICODE_STRING RedirDevName,
2448 BOOLEAN MailslotsSupported)
2450 FIXME("(%p %p %d): stub\n", MupHandle, RedirDevName, MailslotsSupported);
2451 return STATUS_NOT_IMPLEMENTED;
2455 static void *create_process_object( HANDLE handle )
2457 PEPROCESS process;
2459 if (!(process = alloc_kernel_object( PsProcessType, handle, sizeof(*process), 0 ))) return NULL;
2461 process->header.Type = 3;
2462 process->header.WaitListHead.Blink = INVALID_HANDLE_VALUE; /* mark as kernel object */
2463 NtQueryInformationProcess( handle, ProcessBasicInformation, &process->info, sizeof(process->info), NULL );
2464 IsWow64Process( handle, &process->wow64 );
2465 return process;
2468 static const WCHAR process_type_name[] = {'P','r','o','c','e','s','s',0};
2470 static struct _OBJECT_TYPE process_type =
2472 process_type_name,
2473 create_process_object
2476 POBJECT_TYPE PsProcessType = &process_type;
2479 /***********************************************************************
2480 * IoGetCurrentProcess / PsGetCurrentProcess (NTOSKRNL.EXE.@)
2482 PEPROCESS WINAPI IoGetCurrentProcess(void)
2484 return KeGetCurrentThread()->process;
2487 /***********************************************************************
2488 * PsLookupProcessByProcessId (NTOSKRNL.EXE.@)
2490 NTSTATUS WINAPI PsLookupProcessByProcessId( HANDLE processid, PEPROCESS *process )
2492 NTSTATUS status;
2493 HANDLE handle;
2495 TRACE( "(%p %p)\n", processid, process );
2497 if (!(handle = OpenProcess( PROCESS_ALL_ACCESS, FALSE, HandleToUlong(processid) )))
2498 return STATUS_INVALID_PARAMETER;
2500 status = ObReferenceObjectByHandle( handle, PROCESS_ALL_ACCESS, PsProcessType, KernelMode, (void**)process, NULL );
2502 NtClose( handle );
2503 return status;
2506 /*********************************************************************
2507 * PsGetProcessId (NTOSKRNL.@)
2509 HANDLE WINAPI PsGetProcessId(PEPROCESS process)
2511 TRACE( "%p -> %Ix\n", process, process->info.UniqueProcessId );
2512 return (HANDLE)process->info.UniqueProcessId;
2515 /*********************************************************************
2516 * PsGetProcessInheritedFromUniqueProcessId (NTOSKRNL.@)
2518 HANDLE WINAPI PsGetProcessInheritedFromUniqueProcessId( PEPROCESS process )
2520 HANDLE id = (HANDLE)process->info.InheritedFromUniqueProcessId;
2521 TRACE( "%p -> %p\n", process, id );
2522 return id;
2525 static void *create_thread_object( HANDLE handle )
2527 THREAD_BASIC_INFORMATION info;
2528 struct _KTHREAD *thread;
2529 HANDLE process;
2531 if (!(thread = alloc_kernel_object( PsThreadType, handle, sizeof(*thread), 0 ))) return NULL;
2533 thread->header.Type = 6;
2534 thread->header.WaitListHead.Blink = INVALID_HANDLE_VALUE; /* mark as kernel object */
2535 thread->user_affinity = 0;
2537 if (!NtQueryInformationThread( handle, ThreadBasicInformation, &info, sizeof(info), NULL ))
2539 thread->id = info.ClientId;
2540 if ((process = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, HandleToUlong(thread->id.UniqueProcess) )))
2542 kernel_object_from_handle( process, PsProcessType, (void**)&thread->process );
2543 NtClose( process );
2548 return thread;
2551 static const WCHAR thread_type_name[] = {'T','h','r','e','a','d',0};
2553 static struct _OBJECT_TYPE thread_type =
2555 thread_type_name,
2556 create_thread_object
2559 POBJECT_TYPE PsThreadType = &thread_type;
2562 /***********************************************************************
2563 * KeGetCurrentThread / PsGetCurrentThread (NTOSKRNL.EXE.@)
2565 PRKTHREAD WINAPI KeGetCurrentThread(void)
2567 struct _KTHREAD *thread = NtCurrentTeb()->Instrumentation[1];
2569 if (!thread)
2571 HANDLE handle = GetCurrentThread();
2573 /* FIXME: we shouldn't need it, GetCurrentThread() should be client thread already */
2574 if (GetCurrentThreadId() == request_thread)
2575 handle = OpenThread( THREAD_QUERY_INFORMATION, FALSE, client_tid );
2577 kernel_object_from_handle( handle, PsThreadType, (void**)&thread );
2578 if (handle != GetCurrentThread()) NtClose( handle );
2580 NtCurrentTeb()->Instrumentation[1] = thread;
2583 return thread;
2586 /*****************************************************
2587 * PsLookupThreadByThreadId (NTOSKRNL.EXE.@)
2589 NTSTATUS WINAPI PsLookupThreadByThreadId( HANDLE threadid, PETHREAD *thread )
2591 OBJECT_ATTRIBUTES attr;
2592 CLIENT_ID cid;
2593 NTSTATUS status;
2594 HANDLE handle;
2596 TRACE( "(%p %p)\n", threadid, thread );
2598 cid.UniqueProcess = 0;
2599 cid.UniqueThread = threadid;
2600 InitializeObjectAttributes( &attr, NULL, 0, NULL, NULL );
2601 status = NtOpenThread( &handle, THREAD_QUERY_INFORMATION, &attr, &cid );
2602 if (status) return status;
2604 status = ObReferenceObjectByHandle( handle, THREAD_ALL_ACCESS, PsThreadType, KernelMode, (void**)thread, NULL );
2606 NtClose( handle );
2607 return status;
2610 /*********************************************************************
2611 * PsGetThreadId (NTOSKRNL.@)
2613 HANDLE WINAPI PsGetThreadId(PETHREAD thread)
2615 TRACE( "%p -> %p\n", thread, thread->kthread.id.UniqueThread );
2616 return thread->kthread.id.UniqueThread;
2619 /*********************************************************************
2620 * PsGetThreadProcessId (NTOSKRNL.@)
2622 HANDLE WINAPI PsGetThreadProcessId( PETHREAD thread )
2624 TRACE( "%p -> %p\n", thread, thread->kthread.id.UniqueProcess );
2625 return thread->kthread.id.UniqueProcess;
2628 /***********************************************************************
2629 * KeInsertQueue (NTOSKRNL.EXE.@)
2631 LONG WINAPI KeInsertQueue(PRKQUEUE Queue, PLIST_ENTRY Entry)
2633 FIXME( "stub: %p %p\n", Queue, Entry );
2634 return 0;
2637 /***********************************************************************
2638 * KeInsertQueueDpc (NTOSKRNL.EXE.@)
2640 BOOLEAN WINAPI KeInsertQueueDpc(PRKDPC Dpc, PVOID SystemArgument1, PVOID SystemArgument2)
2642 FIXME( "stub: (%p %p %p)\n", Dpc, SystemArgument1, SystemArgument2 );
2643 return TRUE;
2646 /**********************************************************************
2647 * KeQueryActiveProcessors (NTOSKRNL.EXE.@)
2649 * Return the active Processors as bitmask
2651 * RETURNS
2652 * active Processors as bitmask
2655 KAFFINITY WINAPI KeQueryActiveProcessors( void )
2657 DWORD_PTR affinity_mask;
2659 GetProcessAffinityMask( GetCurrentProcess(), NULL, &affinity_mask);
2660 return affinity_mask;
2663 ULONG WINAPI KeQueryActiveProcessorCountEx(USHORT group_number)
2665 TRACE("group_number %u.\n", group_number);
2667 return GetActiveProcessorCount(group_number);
2670 ULONG WINAPI KeQueryActiveProcessorCount(PKAFFINITY active_processors)
2672 TRACE("active_processors %p.\n", active_processors);
2674 if(active_processors)
2675 *active_processors = KeQueryActiveProcessors();
2677 return KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
2680 /**********************************************************************
2681 * KeQueryInterruptTime (NTOSKRNL.EXE.@)
2683 * Return the interrupt time count
2686 ULONGLONG WINAPI KeQueryInterruptTime( void )
2688 LARGE_INTEGER totaltime;
2690 KeQueryTickCount(&totaltime);
2691 return totaltime.QuadPart;
2694 /***********************************************************************
2695 * KeQueryPriorityThread (NTOSKRNL.EXE.@)
2697 KPRIORITY WINAPI KeQueryPriorityThread( PKTHREAD Thread )
2699 FIXME("(%p): stub.\n", Thread);
2700 /* priority must be a value between 0 and 31 */
2701 return 15;
2704 /***********************************************************************
2705 * KeQuerySystemTime (NTOSKRNL.EXE.@)
2707 void WINAPI KeQuerySystemTime( LARGE_INTEGER *time )
2709 NtQuerySystemTime( time );
2713 /***********************************************************************
2714 * KeQueryTickCount (NTOSKRNL.EXE.@)
2716 void WINAPI KeQueryTickCount( LARGE_INTEGER *count )
2718 count->QuadPart = NtGetTickCount();
2719 /* update the global variable too */
2720 KeTickCount.LowPart = count->u.LowPart;
2721 KeTickCount.High1Time = count->u.HighPart;
2722 KeTickCount.High2Time = count->u.HighPart;
2726 /***********************************************************************
2727 * KeQueryTimeIncrement (NTOSKRNL.EXE.@)
2729 ULONG WINAPI KeQueryTimeIncrement(void)
2731 return 10000;
2735 /***********************************************************************
2736 * KeSetPriorityThread (NTOSKRNL.EXE.@)
2738 KPRIORITY WINAPI KeSetPriorityThread( PKTHREAD Thread, KPRIORITY Priority )
2740 FIXME("(%p %ld)\n", Thread, Priority);
2741 return Priority;
2744 /***********************************************************************
2745 * KeSetSystemAffinityThread (NTOSKRNL.EXE.@)
2747 VOID WINAPI KeSetSystemAffinityThread(KAFFINITY affinity)
2749 KeSetSystemAffinityThreadEx(affinity);
2752 KAFFINITY WINAPI KeSetSystemAffinityThreadEx(KAFFINITY affinity)
2754 DWORD_PTR system_affinity = KeQueryActiveProcessors();
2755 PKTHREAD thread = KeGetCurrentThread();
2756 GROUP_AFFINITY old, new;
2758 TRACE("affinity %#Ix.\n", affinity);
2760 affinity &= system_affinity;
2762 NtQueryInformationThread(GetCurrentThread(), ThreadGroupInformation,
2763 &old, sizeof(old), NULL);
2765 if (old.Mask != system_affinity)
2766 thread->user_affinity = old.Mask;
2768 memset(&new, 0, sizeof(new));
2769 new.Mask = affinity;
2771 return NtSetInformationThread(GetCurrentThread(), ThreadGroupInformation, &new, sizeof(new))
2772 ? 0 : thread->user_affinity;
2776 /***********************************************************************
2777 * KeRevertToUserAffinityThread (NTOSKRNL.EXE.@)
2779 void WINAPI KeRevertToUserAffinityThread(void)
2781 KeRevertToUserAffinityThreadEx(0);
2784 void WINAPI KeRevertToUserAffinityThreadEx(KAFFINITY affinity)
2786 DWORD_PTR system_affinity = KeQueryActiveProcessors();
2787 PRKTHREAD thread = KeGetCurrentThread();
2788 GROUP_AFFINITY new;
2790 TRACE("affinity %#Ix.\n", affinity);
2792 affinity &= system_affinity;
2794 memset(&new, 0, sizeof(new));
2795 new.Mask = affinity ? affinity
2796 : (thread->user_affinity ? thread->user_affinity : system_affinity);
2798 NtSetInformationThread(GetCurrentThread(), ThreadGroupInformation, &new, sizeof(new));
2799 thread->user_affinity = affinity;
2802 /***********************************************************************
2803 * IoRegisterFileSystem (NTOSKRNL.EXE.@)
2805 VOID WINAPI IoRegisterFileSystem(PDEVICE_OBJECT DeviceObject)
2807 FIXME("(%p): stub\n", DeviceObject);
2810 /***********************************************************************
2811 * KeExpandKernelStackAndCalloutEx (NTOSKRNL.EXE.@)
2813 NTSTATUS WINAPI KeExpandKernelStackAndCalloutEx(PEXPAND_STACK_CALLOUT callout, void *parameter, SIZE_T size,
2814 BOOLEAN wait, void *context)
2816 WARN("(%p %p %Iu %x %p) semi-stub: ignoring stack expand\n", callout, parameter, size, wait, context);
2817 callout(parameter);
2818 return STATUS_SUCCESS;
2821 /***********************************************************************
2822 * KeExpandKernelStackAndCallout (NTOSKRNL.EXE.@)
2824 NTSTATUS WINAPI KeExpandKernelStackAndCallout(PEXPAND_STACK_CALLOUT callout, void *parameter, SIZE_T size)
2826 return KeExpandKernelStackAndCalloutEx(callout, parameter, size, TRUE, NULL);
2829 /***********************************************************************
2830 * IoUnregisterFileSystem (NTOSKRNL.EXE.@)
2832 VOID WINAPI IoUnregisterFileSystem(PDEVICE_OBJECT DeviceObject)
2834 FIXME("(%p): stub\n", DeviceObject);
2837 /***********************************************************************
2838 * MmAllocateNonCachedMemory (NTOSKRNL.EXE.@)
2840 PVOID WINAPI MmAllocateNonCachedMemory( SIZE_T size )
2842 TRACE( "%Iu\n", size );
2843 return VirtualAlloc( NULL, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE|PAGE_NOCACHE );
2846 /***********************************************************************
2847 * MmAllocateContiguousMemory (NTOSKRNL.EXE.@)
2849 PVOID WINAPI MmAllocateContiguousMemory( SIZE_T size, PHYSICAL_ADDRESS highest_valid_address )
2851 FIXME( "%Iu, %s stub\n", size, wine_dbgstr_longlong(highest_valid_address.QuadPart) );
2852 return NULL;
2855 /***********************************************************************
2856 * MmAllocateContiguousMemorySpecifyCache (NTOSKRNL.EXE.@)
2858 PVOID WINAPI MmAllocateContiguousMemorySpecifyCache( SIZE_T size,
2859 PHYSICAL_ADDRESS lowest_valid_address,
2860 PHYSICAL_ADDRESS highest_valid_address,
2861 PHYSICAL_ADDRESS BoundaryAddressMultiple,
2862 MEMORY_CACHING_TYPE CacheType )
2864 FIXME(": stub\n");
2865 return NULL;
2868 /***********************************************************************
2869 * MmAllocatePagesForMdl (NTOSKRNL.EXE.@)
2871 PMDL WINAPI MmAllocatePagesForMdl(PHYSICAL_ADDRESS lowaddress, PHYSICAL_ADDRESS highaddress,
2872 PHYSICAL_ADDRESS skipbytes, SIZE_T size)
2874 FIXME("%s %s %s %Iu: stub\n", wine_dbgstr_longlong(lowaddress.QuadPart), wine_dbgstr_longlong(highaddress.QuadPart),
2875 wine_dbgstr_longlong(skipbytes.QuadPart), size);
2876 return NULL;
2879 /***********************************************************************
2880 * MmBuildMdlForNonPagedPool (NTOSKRNL.EXE.@)
2882 void WINAPI MmBuildMdlForNonPagedPool(MDL *mdl)
2884 FIXME("stub: %p\n", mdl);
2887 /***********************************************************************
2888 * MmCreateSection (NTOSKRNL.EXE.@)
2890 NTSTATUS WINAPI MmCreateSection( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
2891 LARGE_INTEGER *size, ULONG protect, ULONG alloc_attr,
2892 HANDLE file, FILE_OBJECT *file_obj )
2894 FIXME("%p %#lx %p %s %#lx %#lx %p %p: stub\n", handle, access, attr,
2895 wine_dbgstr_longlong(size->QuadPart), protect, alloc_attr, file, file_obj);
2896 return STATUS_NOT_IMPLEMENTED;
2899 /***********************************************************************
2900 * MmFreeNonCachedMemory (NTOSKRNL.EXE.@)
2902 void WINAPI MmFreeNonCachedMemory( void *addr, SIZE_T size )
2904 TRACE( "%p %Iu\n", addr, size );
2905 VirtualFree( addr, 0, MEM_RELEASE );
2908 /***********************************************************************
2909 * MmIsAddressValid (NTOSKRNL.EXE.@)
2911 * Check if the process can access the virtual address without a pagefault
2913 * PARAMS
2914 * VirtualAddress [I] Address to check
2916 * RETURNS
2917 * Failure: FALSE
2918 * Success: TRUE (Accessing the Address works without a Pagefault)
2921 BOOLEAN WINAPI MmIsAddressValid(PVOID VirtualAddress)
2923 TRACE("(%p)\n", VirtualAddress);
2924 return !IsBadReadPtr(VirtualAddress, 1);
2927 /***********************************************************************
2928 * MmGetPhysicalAddress (NTOSKRNL.EXE.@)
2930 PHYSICAL_ADDRESS WINAPI MmGetPhysicalAddress(void *virtual_address)
2932 PHYSICAL_ADDRESS ret;
2933 FIXME("(%p): semi-stub\n", virtual_address);
2934 ret.QuadPart = (ULONG_PTR)virtual_address;
2935 return ret;
2938 /***********************************************************************
2939 * MmMapIoSpace (NTOSKRNL.EXE.@)
2941 PVOID WINAPI MmMapIoSpace( PHYSICAL_ADDRESS PhysicalAddress, DWORD NumberOfBytes, DWORD CacheType )
2943 FIXME( "stub: 0x%08lx%08lx, %ld, %ld\n", PhysicalAddress.HighPart, PhysicalAddress.LowPart, NumberOfBytes, CacheType );
2944 return NULL;
2948 /***********************************************************************
2949 * MmLockPagableSectionByHandle (NTOSKRNL.EXE.@)
2951 VOID WINAPI MmLockPagableSectionByHandle(PVOID ImageSectionHandle)
2953 FIXME("stub %p\n", ImageSectionHandle);
2956 /***********************************************************************
2957 * MmMapLockedPagesSpecifyCache (NTOSKRNL.EXE.@)
2959 PVOID WINAPI MmMapLockedPagesSpecifyCache(PMDLX MemoryDescriptorList, KPROCESSOR_MODE AccessMode, MEMORY_CACHING_TYPE CacheType,
2960 PVOID BaseAddress, ULONG BugCheckOnFailure, MM_PAGE_PRIORITY Priority)
2962 FIXME("(%p, %u, %u, %p, %lu, %u): stub\n", MemoryDescriptorList, AccessMode, CacheType, BaseAddress, BugCheckOnFailure, Priority);
2964 return NULL;
2967 /***********************************************************************
2968 * MmUnmapLockedPages (NTOSKRNL.EXE.@)
2970 void WINAPI MmUnmapLockedPages( void *base, MDL *mdl )
2972 FIXME( "(%p %p_\n", base, mdl );
2975 /***********************************************************************
2976 * MmUnlockPagableImageSection (NTOSKRNL.EXE.@)
2978 VOID WINAPI MmUnlockPagableImageSection(PVOID ImageSectionHandle)
2980 FIXME("stub %p\n", ImageSectionHandle);
2983 /***********************************************************************
2984 * MmPageEntireDriver (NTOSKRNL.EXE.@)
2986 PVOID WINAPI MmPageEntireDriver(PVOID AddrInSection)
2988 TRACE("%p\n", AddrInSection);
2989 return AddrInSection;
2993 /***********************************************************************
2994 * MmProbeAndLockPages (NTOSKRNL.EXE.@)
2996 void WINAPI MmProbeAndLockPages(PMDLX MemoryDescriptorList, KPROCESSOR_MODE AccessMode, LOCK_OPERATION Operation)
2998 FIXME("(%p, %u, %u): stub\n", MemoryDescriptorList, AccessMode, Operation);
3002 /***********************************************************************
3003 * MmResetDriverPaging (NTOSKRNL.EXE.@)
3005 void WINAPI MmResetDriverPaging(PVOID AddrInSection)
3007 TRACE("%p\n", AddrInSection);
3011 /***********************************************************************
3012 * MmUnlockPages (NTOSKRNL.EXE.@)
3014 void WINAPI MmUnlockPages(PMDLX MemoryDescriptorList)
3016 FIXME("(%p): stub\n", MemoryDescriptorList);
3020 /***********************************************************************
3021 * MmUnmapIoSpace (NTOSKRNL.EXE.@)
3023 VOID WINAPI MmUnmapIoSpace( PVOID BaseAddress, SIZE_T NumberOfBytes )
3025 FIXME( "stub: %p, %Iu\n", BaseAddress, NumberOfBytes );
3029 /***********************************************************************
3030 * ObReferenceObjectByName (NTOSKRNL.EXE.@)
3032 NTSTATUS WINAPI ObReferenceObjectByName( UNICODE_STRING *ObjectName,
3033 ULONG Attributes,
3034 ACCESS_STATE *AccessState,
3035 ACCESS_MASK DesiredAccess,
3036 POBJECT_TYPE ObjectType,
3037 KPROCESSOR_MODE AccessMode,
3038 void *ParseContext,
3039 void **Object)
3041 struct wine_driver *driver;
3042 struct wine_rb_entry *entry;
3044 TRACE("mostly-stub:%s %li %p %li %p %i %p %p\n", debugstr_us(ObjectName),
3045 Attributes, AccessState, DesiredAccess, ObjectType, AccessMode,
3046 ParseContext, Object);
3048 if (AccessState) FIXME("Unhandled AccessState\n");
3049 if (DesiredAccess) FIXME("Unhandled DesiredAccess\n");
3050 if (ParseContext) FIXME("Unhandled ParseContext\n");
3051 if (ObjectType) FIXME("Unhandled ObjectType\n");
3053 if (AccessMode != KernelMode)
3055 FIXME("UserMode access not implemented\n");
3056 return STATUS_NOT_IMPLEMENTED;
3059 EnterCriticalSection(&drivers_cs);
3060 entry = wine_rb_get(&wine_drivers, ObjectName);
3061 LeaveCriticalSection(&drivers_cs);
3062 if (!entry)
3064 FIXME("Object (%s) not found, may not be tracked.\n", debugstr_us(ObjectName));
3065 return STATUS_NOT_IMPLEMENTED;
3068 driver = WINE_RB_ENTRY_VALUE(entry, struct wine_driver, entry);
3069 ObReferenceObject( *Object = &driver->driver_obj );
3070 return STATUS_SUCCESS;
3074 /********************************************************************
3075 * ObOpenObjectByName (NTOSKRNL.EXE.@)
3077 NTSTATUS WINAPI ObOpenObjectByName(POBJECT_ATTRIBUTES attr, POBJECT_TYPE type,
3078 KPROCESSOR_MODE mode, ACCESS_STATE *access_state,
3079 ACCESS_MASK access, PVOID ctx, HANDLE *handle)
3081 NTSTATUS status;
3082 void *object;
3084 TRACE( "attr(%p %s %lx) %p %u %p %lu %p %p\n", attr->RootDirectory, debugstr_us(attr->ObjectName),
3085 attr->Attributes, type, mode, access_state, access, ctx, handle );
3087 if (mode != KernelMode)
3089 FIXME( "UserMode access not implemented\n" );
3090 return STATUS_NOT_IMPLEMENTED;
3093 if (attr->RootDirectory) FIXME( "RootDirectory unhandled\n" );
3095 status = ObReferenceObjectByName(attr->ObjectName, attr->Attributes, access_state, access, type, mode, ctx, &object );
3096 if (status != STATUS_SUCCESS)
3097 return status;
3099 status = ObOpenObjectByPointer(object, attr->Attributes, access_state, access, type, mode, handle);
3101 ObDereferenceObject(object);
3102 return status;
3106 /***********************************************************************
3107 * ObReferenceObjectByPointer (NTOSKRNL.EXE.@)
3109 NTSTATUS WINAPI ObReferenceObjectByPointer(void *obj, ACCESS_MASK access,
3110 POBJECT_TYPE type,
3111 KPROCESSOR_MODE mode)
3113 FIXME("(%p, %lx, %p, %d): stub\n", obj, access, type, mode);
3115 return STATUS_NOT_IMPLEMENTED;
3119 /***********************************************************************
3120 * ObfReferenceObject (NTOSKRNL.EXE.@)
3122 DEFINE_FASTCALL1_WRAPPER( ObfReferenceObject )
3123 void FASTCALL ObfReferenceObject( void *obj )
3125 ObReferenceObject( obj );
3129 /***********************************************************************
3130 * ObfDereferenceObject (NTOSKRNL.EXE.@)
3132 DEFINE_FASTCALL1_WRAPPER( ObfDereferenceObject )
3133 void FASTCALL ObfDereferenceObject( void *obj )
3135 ObDereferenceObject( obj );
3138 /***********************************************************************
3139 * ObRegisterCallbacks (NTOSKRNL.EXE.@)
3141 NTSTATUS WINAPI ObRegisterCallbacks(POB_CALLBACK_REGISTRATION callback, void **handle)
3143 FIXME( "callback %p, handle %p.\n", callback, handle );
3145 if(handle)
3146 *handle = UlongToHandle(0xdeadbeaf);
3148 return STATUS_SUCCESS;
3151 /***********************************************************************
3152 * ObUnRegisterCallbacks (NTOSKRNL.EXE.@)
3154 void WINAPI ObUnRegisterCallbacks(void *handle)
3156 FIXME( "stub: %p\n", handle );
3159 /***********************************************************************
3160 * ObGetFilterVersion (NTOSKRNL.EXE.@)
3162 USHORT WINAPI ObGetFilterVersion(void)
3164 FIXME( "stub:\n" );
3166 return OB_FLT_REGISTRATION_VERSION;
3169 /***********************************************************************
3170 * IoGetAttachedDeviceReference (NTOSKRNL.EXE.@)
3172 DEVICE_OBJECT* WINAPI IoGetAttachedDeviceReference( DEVICE_OBJECT *device )
3174 DEVICE_OBJECT *result = IoGetAttachedDevice( device );
3175 ObReferenceObject( result );
3176 return result;
3180 /***********************************************************************
3181 * PsCreateSystemThread (NTOSKRNL.EXE.@)
3183 NTSTATUS WINAPI PsCreateSystemThread(PHANDLE ThreadHandle, ULONG DesiredAccess,
3184 POBJECT_ATTRIBUTES ObjectAttributes,
3185 HANDLE ProcessHandle, PCLIENT_ID ClientId,
3186 PKSTART_ROUTINE StartRoutine, PVOID StartContext)
3188 if (!ProcessHandle) ProcessHandle = GetCurrentProcess();
3189 return RtlCreateUserThread(ProcessHandle, 0, FALSE, 0, 0,
3190 0, StartRoutine, StartContext,
3191 ThreadHandle, ClientId);
3194 /***********************************************************************
3195 * PsGetCurrentProcessId (NTOSKRNL.EXE.@)
3197 HANDLE WINAPI PsGetCurrentProcessId(void)
3199 return KeGetCurrentThread()->id.UniqueProcess;
3202 /***********************************************************************
3203 * PsGetCurrentProcessSessionId (NTOSKRNL.EXE.@)
3205 ULONG WINAPI PsGetCurrentProcessSessionId(void)
3207 return PsGetCurrentProcess()->info.PebBaseAddress->SessionId;
3210 /***********************************************************************
3211 * PsGetCurrentThreadId (NTOSKRNL.EXE.@)
3213 HANDLE WINAPI PsGetCurrentThreadId(void)
3215 return KeGetCurrentThread()->id.UniqueThread;
3219 /***********************************************************************
3220 * PsIsSystemThread (NTOSKRNL.EXE.@)
3222 BOOLEAN WINAPI PsIsSystemThread(PETHREAD thread)
3224 return thread->kthread.process == PsInitialSystemProcess;
3228 /***********************************************************************
3229 * PsGetVersion (NTOSKRNL.EXE.@)
3231 BOOLEAN WINAPI PsGetVersion(ULONG *major, ULONG *minor, ULONG *build, UNICODE_STRING *version )
3233 RTL_OSVERSIONINFOEXW info;
3235 info.dwOSVersionInfoSize = sizeof(info);
3236 RtlGetVersion( &info );
3237 if (major) *major = info.dwMajorVersion;
3238 if (minor) *minor = info.dwMinorVersion;
3239 if (build) *build = info.dwBuildNumber;
3241 if (version)
3243 #if 0 /* FIXME: GameGuard passes an uninitialized pointer in version->Buffer */
3244 size_t len = min( lstrlenW(info.szCSDVersion)*sizeof(WCHAR), version->MaximumLength );
3245 memcpy( version->Buffer, info.szCSDVersion, len );
3246 if (len < version->MaximumLength) version->Buffer[len / sizeof(WCHAR)] = 0;
3247 version->Length = len;
3248 #endif
3250 return TRUE;
3254 /***********************************************************************
3255 * PsImpersonateClient (NTOSKRNL.EXE.@)
3257 NTSTATUS WINAPI PsImpersonateClient(PETHREAD Thread, PACCESS_TOKEN Token, BOOLEAN CopyOnOpen,
3258 BOOLEAN EffectiveOnly, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
3260 FIXME("(%p, %p, %u, %u, %u): stub\n", Thread, Token, CopyOnOpen, EffectiveOnly, ImpersonationLevel);
3262 return STATUS_NOT_IMPLEMENTED;
3266 /***********************************************************************
3267 * PsRevertToSelf (NTOSKRNL.EXE.@)
3269 void WINAPI PsRevertToSelf(void)
3271 FIXME("\n");
3275 /***********************************************************************
3276 * PsSetCreateProcessNotifyRoutine (NTOSKRNL.EXE.@)
3278 NTSTATUS WINAPI PsSetCreateProcessNotifyRoutine( PCREATE_PROCESS_NOTIFY_ROUTINE callback, BOOLEAN remove )
3280 FIXME( "stub: %p %d\n", callback, remove );
3281 return STATUS_SUCCESS;
3285 /***********************************************************************
3286 * PsSetCreateProcessNotifyRoutineEx (NTOSKRNL.EXE.@)
3288 NTSTATUS WINAPI PsSetCreateProcessNotifyRoutineEx( PCREATE_PROCESS_NOTIFY_ROUTINE_EX callback, BOOLEAN remove )
3290 FIXME( "stub: %p %d\n", callback, remove );
3291 return STATUS_SUCCESS;
3295 /***********************************************************************
3296 * PsSetCreateThreadNotifyRoutine (NTOSKRNL.EXE.@)
3298 NTSTATUS WINAPI PsSetCreateThreadNotifyRoutine( PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine )
3300 FIXME( "stub: %p\n", NotifyRoutine );
3301 return STATUS_SUCCESS;
3305 /***********************************************************************
3306 * PsRemoveCreateThreadNotifyRoutine (NTOSKRNL.EXE.@)
3308 NTSTATUS WINAPI PsRemoveCreateThreadNotifyRoutine( PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine )
3310 FIXME( "stub: %p\n", NotifyRoutine );
3311 return STATUS_SUCCESS;
3315 /***********************************************************************
3316 * PsRemoveLoadImageNotifyRoutine (NTOSKRNL.EXE.@)
3318 NTSTATUS WINAPI PsRemoveLoadImageNotifyRoutine(PLOAD_IMAGE_NOTIFY_ROUTINE routine)
3320 unsigned int i;
3322 TRACE("routine %p.\n", routine);
3324 for (i = 0; i < load_image_notify_routine_count; ++i)
3325 if (load_image_notify_routines[i] == routine)
3327 --load_image_notify_routine_count;
3328 memmove(&load_image_notify_routines[i], &load_image_notify_routines[i + 1],
3329 sizeof(*load_image_notify_routines) * (load_image_notify_routine_count - i));
3330 return STATUS_SUCCESS;
3332 return STATUS_PROCEDURE_NOT_FOUND;
3336 /***********************************************************************
3337 * PsReferenceProcessFilePointer (NTOSKRNL.EXE.@)
3339 NTSTATUS WINAPI PsReferenceProcessFilePointer(PEPROCESS process, FILE_OBJECT **file)
3341 FIXME("%p %p\n", process, file);
3342 return STATUS_NOT_IMPLEMENTED;
3346 /***********************************************************************
3347 * PsTerminateSystemThread (NTOSKRNL.EXE.@)
3349 NTSTATUS WINAPI PsTerminateSystemThread(NTSTATUS status)
3351 TRACE("status %#lx.\n", status);
3352 ExitThread( status );
3356 /***********************************************************************
3357 * PsSuspendProcess (NTOSKRNL.EXE.@)
3359 NTSTATUS WINAPI PsSuspendProcess(PEPROCESS process)
3361 FIXME("stub: %p\n", process);
3362 return STATUS_NOT_IMPLEMENTED;
3366 /***********************************************************************
3367 * PsResumeProcess (NTOSKRNL.EXE.@)
3369 NTSTATUS WINAPI PsResumeProcess(PEPROCESS process)
3371 FIXME("stub: %p\n", process);
3372 return STATUS_NOT_IMPLEMENTED;
3376 /***********************************************************************
3377 * MmGetSystemRoutineAddress (NTOSKRNL.EXE.@)
3379 PVOID WINAPI MmGetSystemRoutineAddress(PUNICODE_STRING SystemRoutineName)
3381 HMODULE hMod;
3382 STRING routineNameA;
3383 PVOID pFunc = NULL;
3385 static const WCHAR ntoskrnlW[] = {'n','t','o','s','k','r','n','l','.','e','x','e',0};
3386 static const WCHAR halW[] = {'h','a','l','.','d','l','l',0};
3388 if (!SystemRoutineName) return NULL;
3390 if (RtlUnicodeStringToAnsiString( &routineNameA, SystemRoutineName, TRUE ) == STATUS_SUCCESS)
3392 /* We only support functions exported from ntoskrnl.exe or hal.dll */
3393 hMod = GetModuleHandleW( ntoskrnlW );
3394 pFunc = GetProcAddress( hMod, routineNameA.Buffer );
3395 if (!pFunc)
3397 hMod = LoadLibraryW( halW );
3398 if (hMod) pFunc = GetProcAddress( hMod, routineNameA.Buffer );
3400 RtlFreeAnsiString( &routineNameA );
3403 if (pFunc)
3404 TRACE( "%s -> %p\n", debugstr_us(SystemRoutineName), pFunc );
3405 else
3406 FIXME( "%s not found\n", debugstr_us(SystemRoutineName) );
3407 return pFunc;
3410 /***********************************************************************
3411 * MmIsThisAnNtAsSystem (NTOSKRNL.EXE.@)
3413 BOOLEAN WINAPI MmIsThisAnNtAsSystem(void)
3415 TRACE("\n");
3416 return FALSE;
3419 /***********************************************************************
3420 * MmProtectMdlSystemAddress (NTOSKRNL.EXE.@)
3422 NTSTATUS WINAPI MmProtectMdlSystemAddress(PMDL MemoryDescriptorList, ULONG NewProtect)
3424 FIXME("(%p, %lu) stub\n", MemoryDescriptorList, NewProtect);
3425 return STATUS_SUCCESS;
3428 /***********************************************************************
3429 * MmQuerySystemSize (NTOSKRNL.EXE.@)
3431 MM_SYSTEMSIZE WINAPI MmQuerySystemSize(void)
3433 FIXME("stub\n");
3434 return MmLargeSystem;
3437 /***********************************************************************
3438 * KeInitializeDpc (NTOSKRNL.EXE.@)
3440 void WINAPI KeInitializeDpc(KDPC *dpc, PKDEFERRED_ROUTINE deferred_routine, void *deferred_context)
3442 FIXME("dpc %p, deferred_routine %p, deferred_context %p semi-stub.\n",
3443 dpc, deferred_routine, deferred_context);
3445 dpc->DeferredRoutine = deferred_routine;
3446 dpc->DeferredContext = deferred_context;
3449 /***********************************************************************
3450 * KeSetImportanceDpc (NTOSKRNL.EXE.@)
3452 VOID WINAPI KeSetImportanceDpc(PRKDPC dpc, KDPC_IMPORTANCE importance)
3454 FIXME("%p, %d stub\n", dpc, importance);
3457 /***********************************************************************
3458 * KeSetTargetProcessorDpcEx (NTOSKRNL.EXE.@)
3460 VOID WINAPI KeSetTargetProcessorDpcEx(PRKDPC dpc, PPROCESSOR_NUMBER process_number)
3462 FIXME("%p, %p stub\n", dpc, process_number);
3465 /***********************************************************************
3466 * KeSetTargetProcessorDpc (NTOSKRNL.EXE.@)
3468 VOID WINAPI KeSetTargetProcessorDpc(PRKDPC dpc, CCHAR number)
3470 FIXME("%p, %d stub\n", dpc, number);
3473 /***********************************************************************
3474 * KeGetCurrentProcessorNumberEx (NTOSKRNL.EXE.@)
3476 ULONG WINAPI KeGetCurrentProcessorNumberEx(PPROCESSOR_NUMBER process_number)
3478 ULONG cur_number = NtGetCurrentProcessorNumber();
3480 FIXME("%p semi-stub\n", process_number);
3482 if (process_number)
3484 process_number->Group = 0;
3485 process_number->Reserved = 0;
3486 process_number->Number = cur_number;
3489 return cur_number;
3492 /***********************************************************************
3493 * KeQueryMaximumProcessorCountEx (NTOSKRNL.EXE.@)
3495 ULONG WINAPI KeQueryMaximumProcessorCountEx(USHORT group_number)
3497 return GetMaximumProcessorCount(group_number);
3500 /***********************************************************************
3501 * KeQueryMaximumProcessorCount (NTOSKRNL.EXE.@)
3503 ULONG WINAPI KeQueryMaximumProcessorCount(void)
3505 return KeQueryMaximumProcessorCountEx(0);
3508 /***********************************************************************
3509 * READ_REGISTER_BUFFER_UCHAR (NTOSKRNL.EXE.@)
3511 VOID WINAPI READ_REGISTER_BUFFER_UCHAR(PUCHAR Register, PUCHAR Buffer, ULONG Count)
3513 FIXME("stub\n");
3516 /*****************************************************
3517 * IoWMIRegistrationControl (NTOSKRNL.EXE.@)
3519 NTSTATUS WINAPI IoWMIRegistrationControl(PDEVICE_OBJECT DeviceObject, ULONG Action)
3521 FIXME("(%p %lu) stub\n", DeviceObject, Action);
3522 return STATUS_SUCCESS;
3525 /*****************************************************
3526 * IoWMIOpenBlock (NTOSKRNL.EXE.@)
3528 NTSTATUS WINAPI IoWMIOpenBlock(LPCGUID guid, ULONG desired_access, PVOID *data_block_obj)
3530 FIXME("(%p %lu %p) stub\n", guid, desired_access, data_block_obj);
3531 return STATUS_NOT_IMPLEMENTED;
3534 /*****************************************************
3535 * PsSetLoadImageNotifyRoutine (NTOSKRNL.EXE.@)
3537 NTSTATUS WINAPI PsSetLoadImageNotifyRoutine(PLOAD_IMAGE_NOTIFY_ROUTINE routine)
3539 return PsSetLoadImageNotifyRoutineEx(routine, 0);
3542 /*****************************************************
3543 * PsSetLoadImageNotifyRoutineEx (NTOSKRNL.EXE.@)
3545 NTSTATUS WINAPI PsSetLoadImageNotifyRoutineEx(PLOAD_IMAGE_NOTIFY_ROUTINE routine, ULONG_PTR flags)
3547 FIXME("routine %p, flags %Ix semi-stub.\n", routine, flags);
3549 if (load_image_notify_routine_count == ARRAY_SIZE(load_image_notify_routines))
3550 return STATUS_INSUFFICIENT_RESOURCES;
3552 load_image_notify_routines[load_image_notify_routine_count++] = routine;
3554 return STATUS_SUCCESS;
3557 /*****************************************************
3558 * IoSetThreadHardErrorMode (NTOSKRNL.EXE.@)
3560 BOOLEAN WINAPI IoSetThreadHardErrorMode(BOOLEAN EnableHardErrors)
3562 FIXME("stub\n");
3563 return FALSE;
3566 /*****************************************************
3567 * Ke386IoSetAccessProcess (NTOSKRNL.EXE.@)
3569 BOOLEAN WINAPI Ke386IoSetAccessProcess(PEPROCESS *process, ULONG flag)
3571 FIXME("(%p %ld) stub\n", process, flag);
3572 return FALSE;
3575 /*****************************************************
3576 * Ke386QueryIoAccessMap (NTOSKRNL.EXE.@)
3578 BOOLEAN WINAPI Ke386QueryIoAccessMap(ULONG flag, PVOID buffer)
3580 FIXME("(%ld %p) stub\n", flag, buffer);
3581 return FALSE;
3584 /*****************************************************
3585 * Ke386SetIoAccessMap (NTOSKRNL.EXE.@)
3587 BOOLEAN WINAPI Ke386SetIoAccessMap(ULONG flag, PVOID buffer)
3589 FIXME("(%ld %p) stub\n", flag, buffer);
3590 return FALSE;
3593 /*****************************************************
3594 * IoStartNextPacket (NTOSKRNL.EXE.@)
3596 VOID WINAPI IoStartNextPacket(PDEVICE_OBJECT deviceobject, BOOLEAN cancelable)
3598 FIXME("(%p %d) stub\n", deviceobject, cancelable);
3601 /*****************************************************
3602 * ObQueryNameString (NTOSKRNL.EXE.@)
3604 NTSTATUS WINAPI ObQueryNameString( void *object, OBJECT_NAME_INFORMATION *name, ULONG size, ULONG *ret_size )
3606 HANDLE handle;
3607 NTSTATUS ret;
3609 TRACE("object %p, name %p, size %lu, ret_size %p.\n", object, name, size, ret_size);
3611 if ((ret = ObOpenObjectByPointer( object, 0, NULL, 0, NULL, KernelMode, &handle )))
3612 return ret;
3613 ret = NtQueryObject( handle, ObjectNameInformation, name, size, ret_size );
3615 NtClose( handle );
3616 return ret;
3619 /*****************************************************
3620 * IoRegisterPlugPlayNotification (NTOSKRNL.EXE.@)
3622 NTSTATUS WINAPI IoRegisterPlugPlayNotification(IO_NOTIFICATION_EVENT_CATEGORY category, ULONG flags, PVOID data,
3623 PDRIVER_OBJECT driver, PDRIVER_NOTIFICATION_CALLBACK_ROUTINE callback,
3624 PVOID context, PVOID *notification)
3626 FIXME("(%u %lu %p %p %p %p %p) stub\n", category, flags, data, driver, callback, context, notification);
3627 return STATUS_SUCCESS;
3630 /*****************************************************
3631 * IoUnregisterPlugPlayNotification (NTOSKRNL.EXE.@)
3633 NTSTATUS WINAPI IoUnregisterPlugPlayNotification(PVOID notification)
3635 FIXME("stub: %p\n", notification);
3636 return STATUS_SUCCESS;
3639 /*****************************************************
3640 * IoCsqInitialize (NTOSKRNL.EXE.@)
3642 NTSTATUS WINAPI IoCsqInitialize(PIO_CSQ csq, PIO_CSQ_INSERT_IRP insert_irp, PIO_CSQ_REMOVE_IRP remove_irp,
3643 PIO_CSQ_PEEK_NEXT_IRP peek_irp, PIO_CSQ_ACQUIRE_LOCK acquire_lock,
3644 PIO_CSQ_RELEASE_LOCK release_lock, PIO_CSQ_COMPLETE_CANCELED_IRP complete_irp)
3646 FIXME("(%p %p %p %p %p %p %p) stub\n",
3647 csq, insert_irp, remove_irp, peek_irp, acquire_lock, release_lock, complete_irp);
3648 return STATUS_SUCCESS;
3651 /***********************************************************************
3652 * KeEnterCriticalRegion (NTOSKRNL.EXE.@)
3654 void WINAPI KeEnterCriticalRegion(void)
3656 TRACE( "semi-stub\n" );
3657 KeGetCurrentThread()->critical_region++;
3660 /***********************************************************************
3661 * KeLeaveCriticalRegion (NTOSKRNL.EXE.@)
3663 void WINAPI KeLeaveCriticalRegion(void)
3665 TRACE( "semi-stub\n" );
3666 KeGetCurrentThread()->critical_region--;
3669 /***********************************************************************
3670 * KeAreApcsDisabled (NTOSKRNL.@)
3672 BOOLEAN WINAPI KeAreApcsDisabled(void)
3674 unsigned int critical_region = KeGetCurrentThread()->critical_region;
3675 TRACE( "%u\n", critical_region );
3676 return !!critical_region;
3679 /***********************************************************************
3680 * KeAreAllApcsDisabled (NTOSKRNL.@)
3682 BOOLEAN WINAPI KeAreAllApcsDisabled(void)
3684 return KeAreApcsDisabled();
3687 /***********************************************************************
3688 * KeBugCheck (NTOSKRNL.@)
3690 void WINAPI KeBugCheck(ULONG code)
3692 KeBugCheckEx(code, 0, 0, 0, 0);
3695 /***********************************************************************
3696 * KeBugCheckEx (NTOSKRNL.@)
3698 void WINAPI KeBugCheckEx(ULONG code, ULONG_PTR param1, ULONG_PTR param2, ULONG_PTR param3, ULONG_PTR param4)
3700 ERR( "%lx %Ix %Ix %Ix %Ix\n", code, param1, param2, param3, param4 );
3701 ExitProcess( code );
3704 /***********************************************************************
3705 * ProbeForRead (NTOSKRNL.EXE.@)
3707 void WINAPI ProbeForRead(void *address, SIZE_T length, ULONG alignment)
3709 FIXME("(%p %Iu %lu) stub\n", address, length, alignment);
3712 /***********************************************************************
3713 * ProbeForWrite (NTOSKRNL.EXE.@)
3715 void WINAPI ProbeForWrite(void *address, SIZE_T length, ULONG alignment)
3717 FIXME("(%p %Iu %lu) stub\n", address, length, alignment);
3720 /***********************************************************************
3721 * CmRegisterCallback (NTOSKRNL.EXE.@)
3723 NTSTATUS WINAPI CmRegisterCallback(EX_CALLBACK_FUNCTION *function, void *context, LARGE_INTEGER *cookie)
3725 FIXME("(%p %p %p): stub\n", function, context, cookie);
3726 return STATUS_NOT_IMPLEMENTED;
3729 /***********************************************************************
3730 * CmUnRegisterCallback (NTOSKRNL.EXE.@)
3732 NTSTATUS WINAPI CmUnRegisterCallback(LARGE_INTEGER cookie)
3734 FIXME("(%s): stub\n", wine_dbgstr_longlong(cookie.QuadPart));
3735 return STATUS_NOT_IMPLEMENTED;
3738 /***********************************************************************
3739 * IoAttachDevice (NTOSKRNL.EXE.@)
3741 NTSTATUS WINAPI IoAttachDevice(DEVICE_OBJECT *source, UNICODE_STRING *target, DEVICE_OBJECT *attached)
3743 FIXME("(%p, %s, %p): stub\n", source, debugstr_us(target), attached);
3744 return STATUS_NOT_IMPLEMENTED;
3748 static NTSTATUS open_driver( const UNICODE_STRING *service_name, SC_HANDLE *service )
3750 QUERY_SERVICE_CONFIGW *service_config = NULL;
3751 SC_HANDLE manager_handle;
3752 DWORD config_size = 0;
3753 WCHAR *name;
3755 if (!(name = RtlAllocateHeap( GetProcessHeap(), 0, service_name->Length + sizeof(WCHAR) )))
3756 return STATUS_NO_MEMORY;
3758 memcpy( name, service_name->Buffer, service_name->Length );
3759 name[ service_name->Length / sizeof(WCHAR) ] = 0;
3761 if (wcsncmp( name, servicesW, lstrlenW(servicesW) ))
3763 FIXME( "service name %s is not a keypath\n", debugstr_us(service_name) );
3764 RtlFreeHeap( GetProcessHeap(), 0, name );
3765 return STATUS_NOT_IMPLEMENTED;
3768 if (!(manager_handle = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT )))
3770 WARN( "failed to connect to service manager\n" );
3771 RtlFreeHeap( GetProcessHeap(), 0, name );
3772 return STATUS_NOT_SUPPORTED;
3775 *service = OpenServiceW( manager_handle, name + lstrlenW(servicesW),
3776 SERVICE_QUERY_CONFIG | SERVICE_SET_STATUS );
3777 RtlFreeHeap( GetProcessHeap(), 0, name );
3778 CloseServiceHandle( manager_handle );
3780 if (!*service)
3782 WARN( "failed to open service %s\n", debugstr_us(service_name) );
3783 return STATUS_UNSUCCESSFUL;
3786 QueryServiceConfigW( *service, NULL, 0, &config_size );
3787 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3789 WARN( "failed to query service config\n" );
3790 goto error;
3793 if (!(service_config = RtlAllocateHeap( GetProcessHeap(), 0, config_size )))
3794 goto error;
3796 if (!QueryServiceConfigW( *service, service_config, config_size, &config_size ))
3798 WARN( "failed to query service config\n" );
3799 goto error;
3802 if (service_config->dwServiceType != SERVICE_KERNEL_DRIVER &&
3803 service_config->dwServiceType != SERVICE_FILE_SYSTEM_DRIVER)
3805 WARN( "service %s is not a kernel driver\n", debugstr_us(service_name) );
3806 goto error;
3809 TRACE( "opened service for driver %s\n", debugstr_us(service_name) );
3810 RtlFreeHeap( GetProcessHeap(), 0, service_config );
3811 return STATUS_SUCCESS;
3813 error:
3814 CloseServiceHandle( *service );
3815 RtlFreeHeap( GetProcessHeap(), 0, service_config );
3816 return STATUS_UNSUCCESSFUL;
3819 /* find the LDR_DATA_TABLE_ENTRY corresponding to the driver module */
3820 static LDR_DATA_TABLE_ENTRY *find_ldr_module( HMODULE module )
3822 LDR_DATA_TABLE_ENTRY *ldr;
3823 ULONG_PTR magic;
3825 LdrLockLoaderLock( 0, NULL, &magic );
3826 if (LdrFindEntryForAddress( module, &ldr ))
3828 WARN( "module not found for %p\n", module );
3829 ldr = NULL;
3831 LdrUnlockLoaderLock( 0, magic );
3833 return ldr;
3836 /* convert PE image VirtualAddress to Real Address */
3837 static inline void *get_rva( HMODULE module, DWORD va )
3839 return (void *)((char *)module + va);
3842 static void WINAPI ldr_notify_callback(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context)
3844 const IMAGE_DATA_DIRECTORY *relocs;
3845 IMAGE_BASE_RELOCATION *rel, *end;
3846 SYSTEM_BASIC_INFORMATION info;
3847 IMAGE_NT_HEADERS *nt;
3848 INT_PTR delta;
3849 char *base;
3850 HMODULE module;
3852 if (reason != LDR_DLL_NOTIFICATION_REASON_LOADED) return;
3853 TRACE( "loading %s\n", debugstr_us(data->Loaded.BaseDllName));
3855 module = data->Loaded.DllBase;
3856 nt = RtlImageNtHeader( module );
3857 base = (char *)nt->OptionalHeader.ImageBase;
3858 if (!(delta = (char *)module - base)) return;
3860 /* the loader does not apply relocations to non page-aligned binaries or executables,
3861 * we have to do it ourselves */
3863 NtQuerySystemInformation( SystemBasicInformation, &info, sizeof(info), NULL );
3864 if (nt->OptionalHeader.SectionAlignment >= info.PageSize && (nt->FileHeader.Characteristics & IMAGE_FILE_DLL))
3865 return;
3867 if (nt->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
3869 WARN( "Need to relocate module from %p to %p, but there are no relocation records\n", base, module );
3870 return;
3873 relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
3874 if (!relocs->Size || !relocs->VirtualAddress) return;
3876 TRACE( "relocating from %p-%p to %p-%p\n", base, base + nt->OptionalHeader.SizeOfImage,
3877 module, (char *)module + nt->OptionalHeader.SizeOfImage );
3879 rel = get_rva( module, relocs->VirtualAddress );
3880 end = get_rva( module, relocs->VirtualAddress + relocs->Size );
3882 while (rel < end - 1 && rel->SizeOfBlock)
3884 char *page = get_rva( module, rel->VirtualAddress );
3885 DWORD old_prot1, old_prot2;
3887 if (rel->VirtualAddress >= nt->OptionalHeader.SizeOfImage)
3889 WARN( "invalid address %p in relocation %p\n", get_rva( module, rel->VirtualAddress ), rel );
3890 return;
3893 /* Relocation entries may hang over the end of the page, so we need to
3894 * protect two pages. */
3895 VirtualProtect( page, info.PageSize, PAGE_READWRITE, &old_prot1 );
3896 VirtualProtect( page + info.PageSize, info.PageSize, PAGE_READWRITE, &old_prot2 );
3897 rel = LdrProcessRelocationBlock( page, (rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT),
3898 (USHORT *)(rel + 1), delta );
3899 VirtualProtect( page, info.PageSize, old_prot1, &old_prot1 );
3900 VirtualProtect( page + info.PageSize, info.PageSize, old_prot2, &old_prot2 );
3901 if (!rel)
3903 WARN( "LdrProcessRelocationBlock failed\n" );
3904 return;
3909 /* load the .sys module for a device driver */
3910 static HMODULE load_driver( const WCHAR *driver_name, const UNICODE_STRING *keyname )
3912 static const WCHAR driversW[] = {'\\','d','r','i','v','e','r','s','\\',0};
3913 static const WCHAR systemrootW[] = {'\\','S','y','s','t','e','m','R','o','o','t','\\',0};
3914 static const WCHAR postfixW[] = {'.','s','y','s',0};
3915 static const WCHAR ntprefixW[] = {'\\','?','?','\\',0};
3916 static const WCHAR ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
3917 HKEY driver_hkey;
3918 HMODULE module;
3919 LPWSTR path = NULL, str;
3920 DWORD type, size;
3922 if (RegOpenKeyW( HKEY_LOCAL_MACHINE, keyname->Buffer + 18 /* skip \registry\machine */, &driver_hkey ))
3924 ERR( "cannot open key %s, err=%lu\n", wine_dbgstr_w(keyname->Buffer), GetLastError() );
3925 return NULL;
3928 /* read the executable path from memory */
3929 size = 0;
3930 if (!RegQueryValueExW( driver_hkey, ImagePathW, NULL, &type, NULL, &size ))
3932 str = HeapAlloc( GetProcessHeap(), 0, size );
3933 if (!RegQueryValueExW( driver_hkey, ImagePathW, NULL, &type, (LPBYTE)str, &size ))
3935 size = ExpandEnvironmentStringsW(str,NULL,0);
3936 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
3937 ExpandEnvironmentStringsW(str,path,size);
3939 HeapFree( GetProcessHeap(), 0, str );
3940 if (!path)
3942 RegCloseKey( driver_hkey );
3943 return NULL;
3946 if (!wcsnicmp( path, systemrootW, 12 ))
3948 WCHAR buffer[MAX_PATH];
3950 GetWindowsDirectoryW(buffer, MAX_PATH);
3952 str = HeapAlloc(GetProcessHeap(), 0, (size -11 + lstrlenW(buffer))
3953 * sizeof(WCHAR));
3954 lstrcpyW(str, buffer);
3955 lstrcatW(str, path + 11);
3956 HeapFree( GetProcessHeap(), 0, path );
3957 path = str;
3959 else if (!wcsncmp( path, ntprefixW, 4 ))
3960 str = path + 4;
3961 else
3962 str = path;
3964 else
3966 /* default is to use the driver name + ".sys" */
3967 WCHAR buffer[MAX_PATH];
3968 GetSystemDirectoryW(buffer, MAX_PATH);
3969 path = HeapAlloc(GetProcessHeap(),0,
3970 (lstrlenW(buffer) + lstrlenW(driversW) + lstrlenW(driver_name) + lstrlenW(postfixW) + 1)
3971 *sizeof(WCHAR));
3972 lstrcpyW(path, buffer);
3973 lstrcatW(path, driversW);
3974 lstrcatW(path, driver_name);
3975 lstrcatW(path, postfixW);
3976 str = path;
3978 RegCloseKey( driver_hkey );
3980 TRACE( "loading driver %s\n", wine_dbgstr_w(str) );
3982 module = LoadLibraryExW( str, 0, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS );
3984 if (module && load_image_notify_routine_count)
3986 UNICODE_STRING module_name;
3987 IMAGE_NT_HEADERS *nt;
3988 IMAGE_INFO info;
3989 unsigned int i;
3991 RtlInitUnicodeString(&module_name, str);
3992 nt = RtlImageNtHeader(module);
3993 memset(&info, 0, sizeof(info));
3994 info.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT;
3995 info.SystemModeImage = TRUE;
3996 info.ImageSize = nt->OptionalHeader.SizeOfImage;
3997 info.ImageBase = module;
3999 for (i = 0; i < load_image_notify_routine_count; ++i)
4001 TRACE("Calling image load notify %p.\n", load_image_notify_routines[i]);
4002 load_image_notify_routines[i](&module_name, NULL, &info);
4003 TRACE("Called image load notify %p.\n", load_image_notify_routines[i]);
4007 HeapFree( GetProcessHeap(), 0, path );
4008 return module;
4011 /* call the driver init entry point */
4012 static NTSTATUS WINAPI init_driver( DRIVER_OBJECT *driver_object, UNICODE_STRING *keyname )
4014 unsigned int i;
4015 NTSTATUS status;
4016 const IMAGE_NT_HEADERS *nt;
4017 const WCHAR *driver_name;
4018 HMODULE module;
4020 /* Retrieve driver name from the keyname */
4021 driver_name = wcsrchr( keyname->Buffer, '\\' );
4022 driver_name++;
4024 module = load_driver( driver_name, keyname );
4025 if (!module)
4026 return STATUS_DLL_INIT_FAILED;
4028 driver_object->DriverSection = find_ldr_module( module );
4029 driver_object->DriverStart = ((LDR_DATA_TABLE_ENTRY *)driver_object->DriverSection)->DllBase;
4030 driver_object->DriverSize = ((LDR_DATA_TABLE_ENTRY *)driver_object->DriverSection)->SizeOfImage;
4032 nt = RtlImageNtHeader( module );
4033 if (!nt->OptionalHeader.AddressOfEntryPoint) return STATUS_SUCCESS;
4034 driver_object->DriverInit = (PDRIVER_INITIALIZE)((char *)module + nt->OptionalHeader.AddressOfEntryPoint);
4036 TRACE_(relay)( "\1Call driver init %p (obj=%p,str=%s)\n",
4037 driver_object->DriverInit, driver_object, wine_dbgstr_w(keyname->Buffer) );
4039 status = driver_object->DriverInit( driver_object, keyname );
4041 TRACE_(relay)( "\1Ret driver init %p (obj=%p,str=%s) retval=%08lx\n",
4042 driver_object->DriverInit, driver_object, wine_dbgstr_w(keyname->Buffer), status );
4044 TRACE( "init done for %s obj %p\n", wine_dbgstr_w(driver_name), driver_object );
4045 TRACE( "- DriverInit = %p\n", driver_object->DriverInit );
4046 TRACE( "- DriverStartIo = %p\n", driver_object->DriverStartIo );
4047 TRACE( "- DriverUnload = %p\n", driver_object->DriverUnload );
4048 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
4049 TRACE( "- MajorFunction[%d] = %p\n", i, driver_object->MajorFunction[i] );
4051 return status;
4054 static BOOLEAN get_drv_name( UNICODE_STRING *drv_name, const UNICODE_STRING *service_name )
4056 static const WCHAR driverW[] = {'\\','D','r','i','v','e','r','\\',0};
4057 WCHAR *str;
4059 if (!(str = heap_alloc( sizeof(driverW) + service_name->Length - lstrlenW(servicesW)*sizeof(WCHAR) )))
4060 return FALSE;
4062 lstrcpyW( str, driverW );
4063 lstrcpynW( str + lstrlenW(driverW), service_name->Buffer + lstrlenW(servicesW),
4064 service_name->Length/sizeof(WCHAR) - lstrlenW(servicesW) + 1 );
4065 RtlInitUnicodeString( drv_name, str );
4066 return TRUE;
4069 /***********************************************************************
4070 * ZwLoadDriver (NTOSKRNL.EXE.@)
4072 NTSTATUS WINAPI ZwLoadDriver( const UNICODE_STRING *service_name )
4074 SERVICE_STATUS_HANDLE service_handle;
4075 struct wine_rb_entry *entry;
4076 struct wine_driver *driver;
4077 UNICODE_STRING drv_name;
4078 NTSTATUS status;
4080 TRACE( "(%s)\n", debugstr_us(service_name) );
4082 if ((status = open_driver( service_name, (SC_HANDLE *)&service_handle )) != STATUS_SUCCESS)
4083 return status;
4085 if (!get_drv_name( &drv_name, service_name ))
4087 CloseServiceHandle( (void *)service_handle );
4088 return STATUS_NO_MEMORY;
4091 if (wine_rb_get( &wine_drivers, &drv_name ))
4093 TRACE( "driver %s already loaded\n", debugstr_us(&drv_name) );
4094 RtlFreeUnicodeString( &drv_name );
4095 CloseServiceHandle( (void *)service_handle );
4096 return STATUS_IMAGE_ALREADY_LOADED;
4099 set_service_status( service_handle, SERVICE_START_PENDING, 0 );
4101 status = IoCreateDriver( &drv_name, init_driver );
4102 entry = wine_rb_get( &wine_drivers, &drv_name );
4103 RtlFreeUnicodeString( &drv_name );
4104 if (status != STATUS_SUCCESS)
4106 ERR( "failed to create driver %s: %08lx\n", debugstr_us(service_name), status );
4107 goto error;
4110 driver = WINE_RB_ENTRY_VALUE( entry, struct wine_driver, entry );
4111 driver->service_handle = service_handle;
4113 wine_enumerate_root_devices( service_name->Buffer + wcslen( servicesW ) );
4115 set_service_status( service_handle, SERVICE_RUNNING,
4116 SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN );
4117 return STATUS_SUCCESS;
4119 error:
4120 set_service_status( service_handle, SERVICE_STOPPED, 0 );
4121 CloseServiceHandle( (void *)service_handle );
4122 return status;
4125 /***********************************************************************
4126 * ZwUnloadDriver (NTOSKRNL.EXE.@)
4128 NTSTATUS WINAPI ZwUnloadDriver( const UNICODE_STRING *service_name )
4130 struct wine_rb_entry *entry;
4131 struct wine_driver *driver;
4132 UNICODE_STRING drv_name;
4134 TRACE( "(%s)\n", debugstr_us(service_name) );
4136 if (!get_drv_name( &drv_name, service_name ))
4137 return STATUS_NO_MEMORY;
4139 entry = wine_rb_get( &wine_drivers, &drv_name );
4140 RtlFreeUnicodeString( &drv_name );
4141 if (!entry)
4143 ERR( "failed to locate driver %s\n", debugstr_us(service_name) );
4144 return STATUS_OBJECT_NAME_NOT_FOUND;
4146 driver = WINE_RB_ENTRY_VALUE( entry, struct wine_driver, entry );
4148 if (!list_empty( &driver->root_pnp_devices ))
4150 ERR( "cannot unload driver %s which still has running PnP devices\n", debugstr_us(service_name) );
4151 return STATUS_UNSUCCESSFUL;
4154 unload_driver( entry, NULL );
4156 return STATUS_SUCCESS;
4159 /***********************************************************************
4160 * IoCreateFileEx (NTOSKRNL.EXE.@)
4162 NTSTATUS WINAPI IoCreateFileEx(HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
4163 IO_STATUS_BLOCK *io, LARGE_INTEGER *alloc_size, ULONG attributes, ULONG sharing,
4164 ULONG disposition, ULONG create_options, VOID *ea_buffer, ULONG ea_length,
4165 CREATE_FILE_TYPE file_type, VOID *parameters, ULONG options, void *driverctx)
4167 FIXME(": semi-stub\n");
4168 return NtCreateFile(handle, access, attr, io, alloc_size, attributes, sharing, disposition,
4169 create_options, ea_buffer, ea_length);
4172 /***********************************************************************
4173 * IoCreateFile (NTOSKRNL.EXE.@)
4175 NTSTATUS WINAPI IoCreateFile(HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
4176 IO_STATUS_BLOCK *io, LARGE_INTEGER *alloc_size, ULONG attributes, ULONG sharing,
4177 ULONG disposition, ULONG create_options, VOID *ea_buffer, ULONG ea_length,
4178 CREATE_FILE_TYPE file_type, VOID *parameters, ULONG options )
4180 FIXME(": semi-stub\n");
4181 return IoCreateFileEx(handle, access, attr, io, alloc_size, attributes, sharing, disposition,
4182 create_options, ea_buffer, ea_length, file_type, parameters, options, NULL);
4185 /**************************************************************************
4186 * __chkstk (NTOSKRNL.@)
4188 #ifdef __x86_64__
4189 /* Supposed to touch all the stack pages, but we shouldn't need that. */
4190 __ASM_GLOBAL_FUNC( __chkstk, "ret" );
4191 #elif defined(__i386__)
4192 __ASM_GLOBAL_FUNC( _chkstk,
4193 "negl %eax\n\t"
4194 "addl %esp,%eax\n\t"
4195 "xchgl %esp,%eax\n\t"
4196 "movl 0(%eax),%eax\n\t" /* copy return address from old location */
4197 "movl %eax,0(%esp)\n\t"
4198 "ret" )
4199 #elif defined(__arm__)
4200 /* Incoming r4 contains words to allocate, converting to bytes then return */
4201 __ASM_GLOBAL_FUNC( __chkstk, "lsl r4, r4, #2\n\t"
4202 "bx lr" )
4203 #elif defined(__aarch64__)
4204 /* Supposed to touch all the stack pages, but we shouldn't need that. */
4205 __ASM_GLOBAL_FUNC( __chkstk, "ret" );
4206 #endif
4208 /*********************************************************************
4209 * PsAcquireProcessExitSynchronization (NTOSKRNL.@)
4211 NTSTATUS WINAPI PsAcquireProcessExitSynchronization(PEPROCESS process)
4213 FIXME("stub: %p\n", process);
4215 return STATUS_NOT_IMPLEMENTED;
4218 /*********************************************************************
4219 * PsReleaseProcessExitSynchronization (NTOSKRNL.@)
4221 void WINAPI PsReleaseProcessExitSynchronization(PEPROCESS process)
4223 FIXME("stub: %p\n", process);
4226 typedef struct _EX_PUSH_LOCK_WAIT_BLOCK *PEX_PUSH_LOCK_WAIT_BLOCK;
4227 /*********************************************************************
4228 * ExfUnblockPushLock (NTOSKRNL.@)
4230 DEFINE_FASTCALL_WRAPPER( ExfUnblockPushLock, 8 )
4231 void FASTCALL ExfUnblockPushLock( EX_PUSH_LOCK *lock, PEX_PUSH_LOCK_WAIT_BLOCK block )
4233 FIXME( "stub: %p, %p\n", lock, block );
4236 /*********************************************************************
4237 * FsRtlRegisterFileSystemFilterCallbacks (NTOSKRNL.@)
4239 NTSTATUS WINAPI FsRtlRegisterFileSystemFilterCallbacks( DRIVER_OBJECT *object, PFS_FILTER_CALLBACKS callbacks)
4241 FIXME("stub: %p %p\n", object, callbacks);
4242 return STATUS_NOT_IMPLEMENTED;
4245 /*********************************************************************
4246 * SeSinglePrivilegeCheck (NTOSKRNL.@)
4248 BOOLEAN WINAPI SeSinglePrivilegeCheck(LUID privilege, KPROCESSOR_MODE mode)
4250 static int once;
4251 if (!once++) FIXME("stub: %08lx%08lx %u\n", privilege.HighPart, privilege.LowPart, mode);
4252 return TRUE;
4255 /*********************************************************************
4256 * SePrivilegeCheck (NTOSKRNL.@)
4258 BOOLEAN WINAPI SePrivilegeCheck(PRIVILEGE_SET *privileges, SECURITY_SUBJECT_CONTEXT *context, KPROCESSOR_MODE mode)
4260 FIXME("stub: %p %p %u\n", privileges, context, mode);
4261 return TRUE;
4264 /*********************************************************************
4265 * SeLocateProcessImageName (NTOSKRNL.@)
4267 NTSTATUS WINAPI SeLocateProcessImageName(PEPROCESS process, UNICODE_STRING **image_name)
4269 FIXME("stub: %p %p\n", process, image_name);
4270 if (image_name) *image_name = NULL;
4271 return STATUS_NOT_IMPLEMENTED;
4274 /*********************************************************************
4275 * KeFlushQueuedDpcs (NTOSKRNL.@)
4277 void WINAPI KeFlushQueuedDpcs(void)
4279 FIXME("stub!\n");
4282 /*********************************************************************
4283 * DbgQueryDebugFilterState (NTOSKRNL.@)
4285 NTSTATUS WINAPI DbgQueryDebugFilterState(ULONG component, ULONG level)
4287 FIXME("stub: %ld %ld\n", component, level);
4288 return STATUS_NOT_IMPLEMENTED;
4291 /*********************************************************************
4292 * PsGetProcessWow64Process (NTOSKRNL.@)
4294 PVOID WINAPI PsGetProcessWow64Process(PEPROCESS process)
4296 FIXME("stub: %p\n", process);
4297 return NULL;
4300 /*********************************************************************
4301 * MmCopyVirtualMemory (NTOSKRNL.@)
4303 NTSTATUS WINAPI MmCopyVirtualMemory(PEPROCESS fromprocess, void *fromaddress, PEPROCESS toprocess,
4304 void *toaddress, SIZE_T bufsize, KPROCESSOR_MODE mode,
4305 SIZE_T *copied)
4307 FIXME("fromprocess %p, fromaddress %p, toprocess %p, toaddress %p, bufsize %Iu, mode %d, copied %p stub.\n",
4308 fromprocess, fromaddress, toprocess, toaddress, bufsize, mode, copied);
4310 *copied = 0;
4311 return STATUS_NOT_IMPLEMENTED;
4314 /*********************************************************************
4315 * KeEnterGuardedRegion (NTOSKRNL.@)
4317 void WINAPI KeEnterGuardedRegion(void)
4319 FIXME("\n");
4322 /*********************************************************************
4323 * KeLeaveGuardedRegion (NTOSKRNL.@)
4325 void WINAPI KeLeaveGuardedRegion(void)
4327 FIXME("\n");
4330 static const WCHAR token_type_name[] = {'T','o','k','e','n',0};
4332 static struct _OBJECT_TYPE token_type =
4334 token_type_name
4337 POBJECT_TYPE SeTokenObjectType = &token_type;
4339 /*************************************************************************
4340 * ExUuidCreate (NTOSKRNL.@)
4342 * Creates a 128bit UUID.
4344 * RETURNS
4346 * STATUS_SUCCESS if successful.
4347 * RPC_NT_UUID_LOCAL_ONLY if UUID is only locally unique.
4349 * NOTES
4351 * Follows RFC 4122, section 4.4 (Algorithms for Creating a UUID from
4352 * Truly Random or Pseudo-Random Numbers)
4354 NTSTATUS WINAPI ExUuidCreate(UUID *uuid)
4356 RtlGenRandom(uuid, sizeof(*uuid));
4357 /* Clear the version bits and set the version (4) */
4358 uuid->Data3 &= 0x0fff;
4359 uuid->Data3 |= (4 << 12);
4360 /* Set the topmost bits of Data4 (clock_seq_hi_and_reserved) as
4361 * specified in RFC 4122, section 4.4.
4363 uuid->Data4[0] &= 0x3f;
4364 uuid->Data4[0] |= 0x80;
4366 TRACE("%s\n", debugstr_guid(uuid));
4368 return STATUS_SUCCESS;
4371 /***********************************************************************
4372 * ExSetTimerResolution (NTOSKRNL.EXE.@)
4374 ULONG WINAPI ExSetTimerResolution(ULONG time, BOOLEAN set_resolution)
4376 FIXME("stub: %lu %d\n", time, set_resolution);
4377 return KeQueryTimeIncrement();
4380 /***********************************************************************
4381 * IoGetRequestorProcess (NTOSKRNL.EXE.@)
4383 PEPROCESS WINAPI IoGetRequestorProcess(IRP *irp)
4385 TRACE("irp %p.\n", irp);
4386 return irp->Tail.Overlay.Thread->kthread.process;
4389 #ifdef _WIN64
4390 /***********************************************************************
4391 * IoIs32bitProcess (NTOSKRNL.EXE.@)
4393 BOOLEAN WINAPI IoIs32bitProcess(IRP *irp)
4395 TRACE("irp %p.\n", irp);
4396 return irp->Tail.Overlay.Thread->kthread.process->wow64;
4398 #endif
4400 /***********************************************************************
4401 * RtlIsNtDdiVersionAvailable (NTOSKRNL.EXE.@)
4403 BOOLEAN WINAPI RtlIsNtDdiVersionAvailable(ULONG version)
4405 FIXME("stub: %ld\n", version);
4406 return FALSE;
4409 BOOLEAN WINAPI KdRefreshDebuggerNotPresent(void)
4411 TRACE(".\n");
4413 return !KdDebuggerEnabled;
4416 struct generic_call_dpc_context
4418 DEFERRED_REVERSE_BARRIER *reverse_barrier;
4419 PKDEFERRED_ROUTINE routine;
4420 ULONG *cpu_count_barrier;
4421 void *context;
4422 ULONG cpu_index;
4423 ULONG current_barrier_flag;
4424 LONG *barrier_passed_count;
4427 static void WINAPI generic_call_dpc_callback(TP_CALLBACK_INSTANCE *instance, void *context)
4429 struct generic_call_dpc_context *c = context;
4430 GROUP_AFFINITY old, new;
4432 TRACE("instance %p, context %p.\n", instance, context);
4434 NtQueryInformationThread(GetCurrentThread(), ThreadGroupInformation,
4435 &old, sizeof(old), NULL);
4437 memset(&new, 0, sizeof(new));
4439 new.Mask = 1 << c->cpu_index;
4440 NtSetInformationThread(GetCurrentThread(), ThreadGroupInformation, &new, sizeof(new));
4442 TlsSetValue(dpc_call_tls_index, context);
4443 c->routine((PKDPC)0xdeadbeef, c->context, c->cpu_count_barrier, c->reverse_barrier);
4444 TlsSetValue(dpc_call_tls_index, NULL);
4445 NtSetInformationThread(GetCurrentThread(), ThreadGroupInformation, &old, sizeof(old));
4448 void WINAPI KeGenericCallDpc(PKDEFERRED_ROUTINE routine, void *context)
4450 ULONG cpu_count = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
4451 static struct generic_call_dpc_context *contexts;
4452 DEFERRED_REVERSE_BARRIER reverse_barrier;
4453 static ULONG last_cpu_count;
4454 LONG barrier_passed_count;
4455 ULONG cpu_count_barrier;
4456 ULONG i;
4458 TRACE("routine %p, context %p.\n", routine, context);
4460 EnterCriticalSection(&dpc_call_cs);
4462 if (!dpc_call_tp)
4464 if (!(dpc_call_tp = CreateThreadpool(NULL)))
4466 ERR("Could not create thread pool.\n");
4467 LeaveCriticalSection(&dpc_call_cs);
4468 return;
4471 SetThreadpoolThreadMinimum(dpc_call_tp, cpu_count);
4472 SetThreadpoolThreadMaximum(dpc_call_tp, cpu_count);
4474 memset(&dpc_call_tpe, 0, sizeof(dpc_call_tpe));
4475 dpc_call_tpe.Version = 1;
4476 dpc_call_tpe.Pool = dpc_call_tp;
4479 reverse_barrier.Barrier = cpu_count;
4480 reverse_barrier.TotalProcessors = cpu_count;
4481 cpu_count_barrier = cpu_count;
4483 if (contexts)
4485 if (last_cpu_count < cpu_count)
4487 static struct generic_call_dpc_context *new_contexts;
4488 if (!(new_contexts = heap_realloc(contexts, sizeof(*contexts) * cpu_count)))
4490 ERR("No memory.\n");
4491 LeaveCriticalSection(&dpc_call_cs);
4492 return;
4494 contexts = new_contexts;
4495 SetThreadpoolThreadMinimum(dpc_call_tp, cpu_count);
4496 SetThreadpoolThreadMaximum(dpc_call_tp, cpu_count);
4499 else if (!(contexts = heap_alloc(sizeof(*contexts) * cpu_count)))
4501 ERR("No memory.\n");
4502 LeaveCriticalSection(&dpc_call_cs);
4503 return;
4506 memset(contexts, 0, sizeof(*contexts) * cpu_count);
4507 last_cpu_count = cpu_count;
4508 barrier_passed_count = 0;
4510 for (i = 0; i < cpu_count; ++i)
4512 contexts[i].reverse_barrier = &reverse_barrier;
4513 contexts[i].cpu_count_barrier = &cpu_count_barrier;
4514 contexts[i].routine = routine;
4515 contexts[i].context = context;
4516 contexts[i].cpu_index = i;
4517 contexts[i].barrier_passed_count = &barrier_passed_count;
4519 TrySubmitThreadpoolCallback(generic_call_dpc_callback, &contexts[i], &dpc_call_tpe);
4522 while (InterlockedCompareExchange((LONG *)&cpu_count_barrier, 0, 0))
4523 SwitchToThread();
4525 LeaveCriticalSection(&dpc_call_cs);
4529 BOOLEAN WINAPI KeSignalCallDpcSynchronize(void *barrier)
4531 struct generic_call_dpc_context *context = TlsGetValue(dpc_call_tls_index);
4532 DEFERRED_REVERSE_BARRIER *b = barrier;
4533 LONG curr_flag, comp, done_value;
4534 BOOL first;
4536 TRACE("barrier %p, context %p.\n", barrier, context);
4538 if (!context)
4540 WARN("Called outside of DPC context.\n");
4541 return FALSE;
4544 context->current_barrier_flag ^= 0x80000000;
4545 curr_flag = context->current_barrier_flag;
4547 first = !context->cpu_index;
4548 comp = curr_flag + context->cpu_index;
4549 done_value = curr_flag + b->TotalProcessors;
4551 if (first)
4552 InterlockedExchange((LONG *)&b->Barrier, comp);
4554 while (InterlockedCompareExchange((LONG *)&b->Barrier, comp + 1, comp) != done_value)
4557 InterlockedIncrement(context->barrier_passed_count);
4559 while (first && InterlockedCompareExchange(context->barrier_passed_count, 0, b->TotalProcessors))
4562 return first;
4565 void WINAPI KeSignalCallDpcDone(void *barrier)
4567 InterlockedDecrement((LONG *)barrier);
4570 void * WINAPI PsGetProcessSectionBaseAddress(PEPROCESS process)
4572 void *image_base;
4573 NTSTATUS status;
4574 SIZE_T size;
4575 HANDLE h;
4577 TRACE("process %p.\n", process);
4579 if ((status = ObOpenObjectByPointer(process, 0, NULL, PROCESS_ALL_ACCESS, NULL, KernelMode, &h)))
4581 WARN("Error opening process object, status %#lx.\n", status);
4582 return NULL;
4585 status = NtReadVirtualMemory(h, &process->info.PebBaseAddress->ImageBaseAddress,
4586 &image_base, sizeof(image_base), &size);
4588 NtClose(h);
4590 if (status || size != sizeof(image_base))
4592 WARN("Error reading process memory, status %#lx, size %Iu.\n", status, size);
4593 return NULL;
4596 TRACE("returning %p.\n", image_base);
4597 return image_base;
4600 void WINAPI KeStackAttachProcess(KPROCESS *process, KAPC_STATE *apc_state)
4602 FIXME("process %p, apc_state %p stub.\n", process, apc_state);
4605 void WINAPI KeUnstackDetachProcess(KAPC_STATE *apc_state)
4607 FIXME("apc_state %p stub.\n", apc_state);
4610 NTSTATUS WINAPI KdDisableDebugger(void)
4612 FIXME(": stub.\n");
4613 return STATUS_DEBUGGER_INACTIVE;
4616 NTSTATUS WINAPI KdEnableDebugger(void)
4618 FIXME(": stub.\n");
4619 return STATUS_DEBUGGER_INACTIVE;
4622 KPROCESSOR_MODE WINAPI ExGetPreviousMode(void)
4624 TRACE("\n");
4625 return PsIsSystemThread((PETHREAD)KeGetCurrentThread()) ? KernelMode : UserMode;
4628 #ifdef __x86_64__
4630 void WINAPI KfRaiseIrql(KIRQL new, KIRQL *old)
4632 FIXME("new %u old %p: stub.\n", new, old);
4635 void WINAPI KeLowerIrql(KIRQL new)
4637 FIXME("new %u: stub.\n", new);
4640 #endif
4642 typedef void (WINAPI *PETW_CLASSIC_CALLBACK)(
4643 const GUID *guid, UCHAR control_code, void *enable_context, void *callback_context);
4645 NTSTATUS WINAPI EtwRegisterClassicProvider(const GUID *provider, ULONG type, PETW_CLASSIC_CALLBACK callback,
4646 void *context, REGHANDLE *handle)
4648 FIXME("provider %s, type %lu, enable_callback %p, context %p, handle %p\n", debugstr_guid(provider), type,
4649 callback, context, handle);
4651 *handle = 0xdeadbeef;
4652 return STATUS_SUCCESS;
4655 NTSTATUS WINAPI EtwUnregister(REGHANDLE handle)
4657 FIXME("handle %I64x\n", handle);
4658 return STATUS_SUCCESS;
4661 /*****************************************************
4662 * DllMain
4664 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
4666 static void *handler;
4667 LARGE_INTEGER count;
4669 switch(reason)
4671 case DLL_PROCESS_ATTACH:
4672 DisableThreadLibraryCalls( inst );
4673 #if defined(__i386__) || defined(__x86_64__)
4674 handler = RtlAddVectoredExceptionHandler( TRUE, vectored_handler );
4675 #endif
4676 KeQueryTickCount( &count ); /* initialize the global KeTickCount */
4677 NtBuildNumber = NtCurrentTeb()->Peb->OSBuildNumber;
4678 ntoskrnl_heap = HeapCreate( HEAP_CREATE_ENABLE_EXECUTE, 0, 0 );
4679 dpc_call_tls_index = TlsAlloc();
4680 LdrRegisterDllNotification( 0, ldr_notify_callback, NULL, &ldr_notify_cookie );
4681 break;
4682 case DLL_PROCESS_DETACH:
4683 LdrUnregisterDllNotification( ldr_notify_cookie );
4685 if (reserved) break;
4687 if (dpc_call_tp)
4688 CloseThreadpool(dpc_call_tp);
4690 HeapDestroy( ntoskrnl_heap );
4691 RtlRemoveVectoredExceptionHandler( handler );
4692 break;
4694 return TRUE;