mfplat: Add MFCreateAMMediaTypeFromMFMediaType stub.
[wine.git] / dlls / ntoskrnl.exe / ntoskrnl.c
blob45b8e1ab1c1260381aa99cbbb0798fc41558717c
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, 0, &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 * ExAllocatePool (NTOSKRNL.EXE.@)
2218 PVOID WINAPI ExAllocatePool( POOL_TYPE type, SIZE_T size )
2220 return ExAllocatePoolWithTag( type, size, 0 );
2224 /***********************************************************************
2225 * ExAllocatePoolWithQuota (NTOSKRNL.EXE.@)
2227 PVOID WINAPI ExAllocatePoolWithQuota( POOL_TYPE type, SIZE_T size )
2229 return ExAllocatePoolWithTag( type, size, 0 );
2233 /***********************************************************************
2234 * ExAllocatePoolWithTag (NTOSKRNL.EXE.@)
2236 PVOID WINAPI ExAllocatePoolWithTag( POOL_TYPE type, SIZE_T size, ULONG tag )
2238 /* FIXME: handle page alignment constraints */
2239 void *ret = HeapAlloc( ntoskrnl_heap, 0, size );
2240 TRACE( "%Iu pool %u -> %p\n", size, type, ret );
2241 return ret;
2245 /***********************************************************************
2246 * ExAllocatePoolWithQuotaTag (NTOSKRNL.EXE.@)
2248 PVOID WINAPI ExAllocatePoolWithQuotaTag( POOL_TYPE type, SIZE_T size, ULONG tag )
2250 return ExAllocatePoolWithTag( type, size, tag );
2254 /***********************************************************************
2255 * ExCreateCallback (NTOSKRNL.EXE.@)
2257 NTSTATUS WINAPI ExCreateCallback(PCALLBACK_OBJECT *obj, POBJECT_ATTRIBUTES attr,
2258 BOOLEAN create, BOOLEAN allow_multiple)
2260 FIXME("(%p, %p, %u, %u): stub\n", obj, attr, create, allow_multiple);
2262 return STATUS_SUCCESS;
2265 void * WINAPI ExRegisterCallback(PCALLBACK_OBJECT callback_object,
2266 PCALLBACK_FUNCTION callback_function, void *callback_context)
2268 FIXME("callback_object %p, callback_function %p, callback_context %p stub.\n",
2269 callback_object, callback_function, callback_context);
2271 return (void *)0xdeadbeef;
2274 void WINAPI ExUnregisterCallback(void *callback_registration)
2276 FIXME("callback_registration %p stub.\n", callback_registration);
2279 /***********************************************************************
2280 * ExNotifyCallback (NTOSKRNL.EXE.@)
2282 void WINAPI ExNotifyCallback(void *obj, void *arg1, void *arg2)
2284 FIXME("(%p, %p, %p): stub\n", obj, arg1, arg2);
2287 /***********************************************************************
2288 * ExFreePool (NTOSKRNL.EXE.@)
2290 void WINAPI ExFreePool( void *ptr )
2292 ExFreePoolWithTag( ptr, 0 );
2296 /***********************************************************************
2297 * ExFreePoolWithTag (NTOSKRNL.EXE.@)
2299 void WINAPI ExFreePoolWithTag( void *ptr, ULONG tag )
2301 TRACE( "%p\n", ptr );
2302 HeapFree( ntoskrnl_heap, 0, ptr );
2305 static void initialize_lookaside_list( GENERAL_LOOKASIDE *lookaside, PALLOCATE_FUNCTION allocate, PFREE_FUNCTION free,
2306 ULONG type, SIZE_T size, ULONG tag )
2309 RtlInitializeSListHead( &lookaside->ListHead );
2310 lookaside->Depth = 4;
2311 lookaside->MaximumDepth = 256;
2312 lookaside->TotalAllocates = 0;
2313 lookaside->AllocateMisses = 0;
2314 lookaside->TotalFrees = 0;
2315 lookaside->FreeMisses = 0;
2316 lookaside->Type = type;
2317 lookaside->Tag = tag;
2318 lookaside->Size = size;
2319 lookaside->Allocate = allocate ? allocate : ExAllocatePoolWithTag;
2320 lookaside->Free = free ? free : ExFreePool;
2321 lookaside->LastTotalAllocates = 0;
2322 lookaside->LastAllocateMisses = 0;
2324 /* FIXME: insert in global list of lookadside lists */
2327 /***********************************************************************
2328 * ExInitializeNPagedLookasideList (NTOSKRNL.EXE.@)
2330 void WINAPI ExInitializeNPagedLookasideList(PNPAGED_LOOKASIDE_LIST lookaside,
2331 PALLOCATE_FUNCTION allocate,
2332 PFREE_FUNCTION free,
2333 ULONG flags,
2334 SIZE_T size,
2335 ULONG tag,
2336 USHORT depth)
2338 TRACE( "%p, %p, %p, %lu, %Iu, %lu, %u\n", lookaside, allocate, free, flags, size, tag, depth );
2339 initialize_lookaside_list( &lookaside->L, allocate, free, NonPagedPool | flags, size, tag );
2342 /***********************************************************************
2343 * ExInitializePagedLookasideList (NTOSKRNL.EXE.@)
2345 void WINAPI ExInitializePagedLookasideList(PPAGED_LOOKASIDE_LIST lookaside,
2346 PALLOCATE_FUNCTION allocate,
2347 PFREE_FUNCTION free,
2348 ULONG flags,
2349 SIZE_T size,
2350 ULONG tag,
2351 USHORT depth)
2353 TRACE( "%p, %p, %p, %lu, %Iu, %lu, %u\n", lookaside, allocate, free, flags, size, tag, depth );
2354 initialize_lookaside_list( &lookaside->L, allocate, free, PagedPool | flags, size, tag );
2357 static void delete_lookaside_list( GENERAL_LOOKASIDE *lookaside )
2359 void *entry;
2360 while ((entry = RtlInterlockedPopEntrySList(&lookaside->ListHead)))
2361 lookaside->FreeEx(entry, (LOOKASIDE_LIST_EX*)lookaside);
2364 /***********************************************************************
2365 * ExDeleteNPagedLookasideList (NTOSKRNL.EXE.@)
2367 void WINAPI ExDeleteNPagedLookasideList( PNPAGED_LOOKASIDE_LIST lookaside )
2369 TRACE( "%p\n", lookaside );
2370 delete_lookaside_list( &lookaside->L );
2374 /***********************************************************************
2375 * ExDeletePagedLookasideList (NTOSKRNL.EXE.@)
2377 void WINAPI ExDeletePagedLookasideList( PPAGED_LOOKASIDE_LIST lookaside )
2379 TRACE( "%p\n", lookaside );
2380 delete_lookaside_list( &lookaside->L );
2383 /***********************************************************************
2384 * ExInitializeZone (NTOSKRNL.EXE.@)
2386 NTSTATUS WINAPI ExInitializeZone(PZONE_HEADER Zone,
2387 ULONG BlockSize,
2388 PVOID InitialSegment,
2389 ULONG InitialSegmentSize)
2391 FIXME( "stub: %p, %lu, %p, %lu\n", Zone, BlockSize, InitialSegment, InitialSegmentSize );
2392 return STATUS_NOT_IMPLEMENTED;
2395 /***********************************************************************
2396 * FsRtlIsNameInExpression (NTOSKRNL.EXE.@)
2398 BOOLEAN WINAPI FsRtlIsNameInExpression(PUNICODE_STRING expression, PUNICODE_STRING name,
2399 BOOLEAN ignore, PWCH upcase)
2401 FIXME("stub: %p %p %d %p\n", expression, name, ignore, upcase);
2402 return FALSE;
2405 /***********************************************************************
2406 * FsRtlRegisterUncProvider (NTOSKRNL.EXE.@)
2408 NTSTATUS WINAPI FsRtlRegisterUncProvider(PHANDLE MupHandle, PUNICODE_STRING RedirDevName,
2409 BOOLEAN MailslotsSupported)
2411 FIXME("(%p %p %d): stub\n", MupHandle, RedirDevName, MailslotsSupported);
2412 return STATUS_NOT_IMPLEMENTED;
2416 static void *create_process_object( HANDLE handle )
2418 PEPROCESS process;
2420 if (!(process = alloc_kernel_object( PsProcessType, handle, sizeof(*process), 0 ))) return NULL;
2422 process->header.Type = 3;
2423 process->header.WaitListHead.Blink = INVALID_HANDLE_VALUE; /* mark as kernel object */
2424 NtQueryInformationProcess( handle, ProcessBasicInformation, &process->info, sizeof(process->info), NULL );
2425 IsWow64Process( handle, &process->wow64 );
2426 return process;
2429 static const WCHAR process_type_name[] = {'P','r','o','c','e','s','s',0};
2431 static struct _OBJECT_TYPE process_type =
2433 process_type_name,
2434 create_process_object
2437 POBJECT_TYPE PsProcessType = &process_type;
2440 /***********************************************************************
2441 * IoGetCurrentProcess / PsGetCurrentProcess (NTOSKRNL.EXE.@)
2443 PEPROCESS WINAPI IoGetCurrentProcess(void)
2445 return KeGetCurrentThread()->process;
2448 /***********************************************************************
2449 * PsLookupProcessByProcessId (NTOSKRNL.EXE.@)
2451 NTSTATUS WINAPI PsLookupProcessByProcessId( HANDLE processid, PEPROCESS *process )
2453 NTSTATUS status;
2454 HANDLE handle;
2456 TRACE( "(%p %p)\n", processid, process );
2458 if (!(handle = OpenProcess( PROCESS_ALL_ACCESS, FALSE, HandleToUlong(processid) )))
2459 return STATUS_INVALID_PARAMETER;
2461 status = ObReferenceObjectByHandle( handle, PROCESS_ALL_ACCESS, PsProcessType, KernelMode, (void**)process, NULL );
2463 NtClose( handle );
2464 return status;
2467 /*********************************************************************
2468 * PsGetProcessId (NTOSKRNL.@)
2470 HANDLE WINAPI PsGetProcessId(PEPROCESS process)
2472 TRACE( "%p -> %Ix\n", process, process->info.UniqueProcessId );
2473 return (HANDLE)process->info.UniqueProcessId;
2476 /*********************************************************************
2477 * PsGetProcessInheritedFromUniqueProcessId (NTOSKRNL.@)
2479 HANDLE WINAPI PsGetProcessInheritedFromUniqueProcessId( PEPROCESS process )
2481 HANDLE id = (HANDLE)process->info.InheritedFromUniqueProcessId;
2482 TRACE( "%p -> %p\n", process, id );
2483 return id;
2486 static void *create_thread_object( HANDLE handle )
2488 THREAD_BASIC_INFORMATION info;
2489 struct _KTHREAD *thread;
2490 HANDLE process;
2492 if (!(thread = alloc_kernel_object( PsThreadType, handle, sizeof(*thread), 0 ))) return NULL;
2494 thread->header.Type = 6;
2495 thread->header.WaitListHead.Blink = INVALID_HANDLE_VALUE; /* mark as kernel object */
2496 thread->user_affinity = 0;
2498 if (!NtQueryInformationThread( handle, ThreadBasicInformation, &info, sizeof(info), NULL ))
2500 thread->id = info.ClientId;
2501 if ((process = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, HandleToUlong(thread->id.UniqueProcess) )))
2503 kernel_object_from_handle( process, PsProcessType, (void**)&thread->process );
2504 NtClose( process );
2509 return thread;
2512 static const WCHAR thread_type_name[] = {'T','h','r','e','a','d',0};
2514 static struct _OBJECT_TYPE thread_type =
2516 thread_type_name,
2517 create_thread_object
2520 POBJECT_TYPE PsThreadType = &thread_type;
2523 /***********************************************************************
2524 * KeGetCurrentThread / PsGetCurrentThread (NTOSKRNL.EXE.@)
2526 PRKTHREAD WINAPI KeGetCurrentThread(void)
2528 struct _KTHREAD *thread = NtCurrentTeb()->Instrumentation[1];
2530 if (!thread)
2532 HANDLE handle = GetCurrentThread();
2534 /* FIXME: we shouldn't need it, GetCurrentThread() should be client thread already */
2535 if (GetCurrentThreadId() == request_thread)
2536 handle = OpenThread( THREAD_QUERY_INFORMATION, FALSE, client_tid );
2538 kernel_object_from_handle( handle, PsThreadType, (void**)&thread );
2539 if (handle != GetCurrentThread()) NtClose( handle );
2541 NtCurrentTeb()->Instrumentation[1] = thread;
2544 return thread;
2547 /*****************************************************
2548 * PsLookupThreadByThreadId (NTOSKRNL.EXE.@)
2550 NTSTATUS WINAPI PsLookupThreadByThreadId( HANDLE threadid, PETHREAD *thread )
2552 OBJECT_ATTRIBUTES attr;
2553 CLIENT_ID cid;
2554 NTSTATUS status;
2555 HANDLE handle;
2557 TRACE( "(%p %p)\n", threadid, thread );
2559 cid.UniqueProcess = 0;
2560 cid.UniqueThread = threadid;
2561 InitializeObjectAttributes( &attr, NULL, 0, NULL, NULL );
2562 status = NtOpenThread( &handle, THREAD_QUERY_INFORMATION, &attr, &cid );
2563 if (status) return status;
2565 status = ObReferenceObjectByHandle( handle, THREAD_ALL_ACCESS, PsThreadType, KernelMode, (void**)thread, NULL );
2567 NtClose( handle );
2568 return status;
2571 /*********************************************************************
2572 * PsGetThreadId (NTOSKRNL.@)
2574 HANDLE WINAPI PsGetThreadId(PETHREAD thread)
2576 TRACE( "%p -> %p\n", thread, thread->kthread.id.UniqueThread );
2577 return thread->kthread.id.UniqueThread;
2580 /*********************************************************************
2581 * PsGetThreadProcessId (NTOSKRNL.@)
2583 HANDLE WINAPI PsGetThreadProcessId( PETHREAD thread )
2585 TRACE( "%p -> %p\n", thread, thread->kthread.id.UniqueProcess );
2586 return thread->kthread.id.UniqueProcess;
2589 /***********************************************************************
2590 * KeInsertQueue (NTOSKRNL.EXE.@)
2592 LONG WINAPI KeInsertQueue(PRKQUEUE Queue, PLIST_ENTRY Entry)
2594 FIXME( "stub: %p %p\n", Queue, Entry );
2595 return 0;
2598 /***********************************************************************
2599 * KeInsertQueueDpc (NTOSKRNL.EXE.@)
2601 BOOLEAN WINAPI KeInsertQueueDpc(PRKDPC Dpc, PVOID SystemArgument1, PVOID SystemArgument2)
2603 FIXME( "stub: (%p %p %p)\n", Dpc, SystemArgument1, SystemArgument2 );
2604 return TRUE;
2607 /**********************************************************************
2608 * KeQueryActiveProcessors (NTOSKRNL.EXE.@)
2610 * Return the active Processors as bitmask
2612 * RETURNS
2613 * active Processors as bitmask
2616 KAFFINITY WINAPI KeQueryActiveProcessors( void )
2618 DWORD_PTR affinity_mask;
2620 GetProcessAffinityMask( GetCurrentProcess(), NULL, &affinity_mask);
2621 return affinity_mask;
2624 ULONG WINAPI KeQueryActiveProcessorCountEx(USHORT group_number)
2626 TRACE("group_number %u.\n", group_number);
2628 return GetActiveProcessorCount(group_number);
2631 ULONG WINAPI KeQueryActiveProcessorCount(PKAFFINITY active_processors)
2633 TRACE("active_processors %p.\n", active_processors);
2635 if(active_processors)
2636 *active_processors = KeQueryActiveProcessors();
2638 return KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
2641 /**********************************************************************
2642 * KeQueryInterruptTime (NTOSKRNL.EXE.@)
2644 * Return the interrupt time count
2647 ULONGLONG WINAPI KeQueryInterruptTime( void )
2649 LARGE_INTEGER totaltime;
2651 KeQueryTickCount(&totaltime);
2652 return totaltime.QuadPart;
2655 /***********************************************************************
2656 * KeQueryPriorityThread (NTOSKRNL.EXE.@)
2658 KPRIORITY WINAPI KeQueryPriorityThread( PKTHREAD Thread )
2660 FIXME("(%p): stub.\n", Thread);
2661 /* priority must be a value between 0 and 31 */
2662 return 15;
2665 /***********************************************************************
2666 * KeQuerySystemTime (NTOSKRNL.EXE.@)
2668 void WINAPI KeQuerySystemTime( LARGE_INTEGER *time )
2670 NtQuerySystemTime( time );
2674 /***********************************************************************
2675 * KeQueryTickCount (NTOSKRNL.EXE.@)
2677 void WINAPI KeQueryTickCount( LARGE_INTEGER *count )
2679 count->QuadPart = NtGetTickCount();
2680 /* update the global variable too */
2681 KeTickCount.LowPart = count->u.LowPart;
2682 KeTickCount.High1Time = count->u.HighPart;
2683 KeTickCount.High2Time = count->u.HighPart;
2687 /***********************************************************************
2688 * KeQueryTimeIncrement (NTOSKRNL.EXE.@)
2690 ULONG WINAPI KeQueryTimeIncrement(void)
2692 return 10000;
2696 /***********************************************************************
2697 * KeSetPriorityThread (NTOSKRNL.EXE.@)
2699 KPRIORITY WINAPI KeSetPriorityThread( PKTHREAD Thread, KPRIORITY Priority )
2701 FIXME("(%p %ld)\n", Thread, Priority);
2702 return Priority;
2705 /***********************************************************************
2706 * KeSetSystemAffinityThread (NTOSKRNL.EXE.@)
2708 VOID WINAPI KeSetSystemAffinityThread(KAFFINITY affinity)
2710 KeSetSystemAffinityThreadEx(affinity);
2713 KAFFINITY WINAPI KeSetSystemAffinityThreadEx(KAFFINITY affinity)
2715 DWORD_PTR system_affinity = KeQueryActiveProcessors();
2716 PKTHREAD thread = KeGetCurrentThread();
2717 GROUP_AFFINITY old, new;
2719 TRACE("affinity %#Ix.\n", affinity);
2721 affinity &= system_affinity;
2723 NtQueryInformationThread(GetCurrentThread(), ThreadGroupInformation,
2724 &old, sizeof(old), NULL);
2726 if (old.Mask != system_affinity)
2727 thread->user_affinity = old.Mask;
2729 memset(&new, 0, sizeof(new));
2730 new.Mask = affinity;
2732 return NtSetInformationThread(GetCurrentThread(), ThreadGroupInformation, &new, sizeof(new))
2733 ? 0 : thread->user_affinity;
2737 /***********************************************************************
2738 * KeRevertToUserAffinityThread (NTOSKRNL.EXE.@)
2740 void WINAPI KeRevertToUserAffinityThread(void)
2742 KeRevertToUserAffinityThreadEx(0);
2745 void WINAPI KeRevertToUserAffinityThreadEx(KAFFINITY affinity)
2747 DWORD_PTR system_affinity = KeQueryActiveProcessors();
2748 PRKTHREAD thread = KeGetCurrentThread();
2749 GROUP_AFFINITY new;
2751 TRACE("affinity %#Ix.\n", affinity);
2753 affinity &= system_affinity;
2755 memset(&new, 0, sizeof(new));
2756 new.Mask = affinity ? affinity
2757 : (thread->user_affinity ? thread->user_affinity : system_affinity);
2759 NtSetInformationThread(GetCurrentThread(), ThreadGroupInformation, &new, sizeof(new));
2760 thread->user_affinity = affinity;
2763 /***********************************************************************
2764 * IoRegisterFileSystem (NTOSKRNL.EXE.@)
2766 VOID WINAPI IoRegisterFileSystem(PDEVICE_OBJECT DeviceObject)
2768 FIXME("(%p): stub\n", DeviceObject);
2771 /***********************************************************************
2772 * KeExpandKernelStackAndCalloutEx (NTOSKRNL.EXE.@)
2774 NTSTATUS WINAPI KeExpandKernelStackAndCalloutEx(PEXPAND_STACK_CALLOUT callout, void *parameter, SIZE_T size,
2775 BOOLEAN wait, void *context)
2777 WARN("(%p %p %Iu %x %p) semi-stub: ignoring stack expand\n", callout, parameter, size, wait, context);
2778 callout(parameter);
2779 return STATUS_SUCCESS;
2782 /***********************************************************************
2783 * KeExpandKernelStackAndCallout (NTOSKRNL.EXE.@)
2785 NTSTATUS WINAPI KeExpandKernelStackAndCallout(PEXPAND_STACK_CALLOUT callout, void *parameter, SIZE_T size)
2787 return KeExpandKernelStackAndCalloutEx(callout, parameter, size, TRUE, NULL);
2790 /***********************************************************************
2791 * IoUnregisterFileSystem (NTOSKRNL.EXE.@)
2793 VOID WINAPI IoUnregisterFileSystem(PDEVICE_OBJECT DeviceObject)
2795 FIXME("(%p): stub\n", DeviceObject);
2798 /***********************************************************************
2799 * MmAllocateNonCachedMemory (NTOSKRNL.EXE.@)
2801 PVOID WINAPI MmAllocateNonCachedMemory( SIZE_T size )
2803 TRACE( "%Iu\n", size );
2804 return VirtualAlloc( NULL, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE|PAGE_NOCACHE );
2807 /***********************************************************************
2808 * MmAllocateContiguousMemory (NTOSKRNL.EXE.@)
2810 PVOID WINAPI MmAllocateContiguousMemory( SIZE_T size, PHYSICAL_ADDRESS highest_valid_address )
2812 FIXME( "%Iu, %s stub\n", size, wine_dbgstr_longlong(highest_valid_address.QuadPart) );
2813 return NULL;
2816 /***********************************************************************
2817 * MmAllocateContiguousMemorySpecifyCache (NTOSKRNL.EXE.@)
2819 PVOID WINAPI MmAllocateContiguousMemorySpecifyCache( SIZE_T size,
2820 PHYSICAL_ADDRESS lowest_valid_address,
2821 PHYSICAL_ADDRESS highest_valid_address,
2822 PHYSICAL_ADDRESS BoundaryAddressMultiple,
2823 MEMORY_CACHING_TYPE CacheType )
2825 FIXME(": stub\n");
2826 return NULL;
2829 /***********************************************************************
2830 * MmAllocatePagesForMdl (NTOSKRNL.EXE.@)
2832 PMDL WINAPI MmAllocatePagesForMdl(PHYSICAL_ADDRESS lowaddress, PHYSICAL_ADDRESS highaddress,
2833 PHYSICAL_ADDRESS skipbytes, SIZE_T size)
2835 FIXME("%s %s %s %Iu: stub\n", wine_dbgstr_longlong(lowaddress.QuadPart), wine_dbgstr_longlong(highaddress.QuadPart),
2836 wine_dbgstr_longlong(skipbytes.QuadPart), size);
2837 return NULL;
2840 /***********************************************************************
2841 * MmBuildMdlForNonPagedPool (NTOSKRNL.EXE.@)
2843 void WINAPI MmBuildMdlForNonPagedPool(MDL *mdl)
2845 FIXME("stub: %p\n", mdl);
2848 /***********************************************************************
2849 * MmCreateSection (NTOSKRNL.EXE.@)
2851 NTSTATUS WINAPI MmCreateSection( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
2852 LARGE_INTEGER *size, ULONG protect, ULONG alloc_attr,
2853 HANDLE file, FILE_OBJECT *file_obj )
2855 FIXME("%p %#lx %p %s %#lx %#lx %p %p: stub\n", handle, access, attr,
2856 wine_dbgstr_longlong(size->QuadPart), protect, alloc_attr, file, file_obj);
2857 return STATUS_NOT_IMPLEMENTED;
2860 /***********************************************************************
2861 * MmFreeNonCachedMemory (NTOSKRNL.EXE.@)
2863 void WINAPI MmFreeNonCachedMemory( void *addr, SIZE_T size )
2865 TRACE( "%p %Iu\n", addr, size );
2866 VirtualFree( addr, 0, MEM_RELEASE );
2869 /***********************************************************************
2870 * MmIsAddressValid (NTOSKRNL.EXE.@)
2872 * Check if the process can access the virtual address without a pagefault
2874 * PARAMS
2875 * VirtualAddress [I] Address to check
2877 * RETURNS
2878 * Failure: FALSE
2879 * Success: TRUE (Accessing the Address works without a Pagefault)
2882 BOOLEAN WINAPI MmIsAddressValid(PVOID VirtualAddress)
2884 TRACE("(%p)\n", VirtualAddress);
2885 return !IsBadReadPtr(VirtualAddress, 1);
2888 /***********************************************************************
2889 * MmGetPhysicalAddress (NTOSKRNL.EXE.@)
2891 PHYSICAL_ADDRESS WINAPI MmGetPhysicalAddress(void *virtual_address)
2893 PHYSICAL_ADDRESS ret;
2894 FIXME("(%p): semi-stub\n", virtual_address);
2895 ret.QuadPart = (ULONG_PTR)virtual_address;
2896 return ret;
2899 /***********************************************************************
2900 * MmMapIoSpace (NTOSKRNL.EXE.@)
2902 PVOID WINAPI MmMapIoSpace( PHYSICAL_ADDRESS PhysicalAddress, DWORD NumberOfBytes, DWORD CacheType )
2904 FIXME( "stub: 0x%08lx%08lx, %ld, %ld\n", PhysicalAddress.HighPart, PhysicalAddress.LowPart, NumberOfBytes, CacheType );
2905 return NULL;
2909 /***********************************************************************
2910 * MmLockPagableSectionByHandle (NTOSKRNL.EXE.@)
2912 VOID WINAPI MmLockPagableSectionByHandle(PVOID ImageSectionHandle)
2914 FIXME("stub %p\n", ImageSectionHandle);
2917 /***********************************************************************
2918 * MmMapLockedPagesSpecifyCache (NTOSKRNL.EXE.@)
2920 PVOID WINAPI MmMapLockedPagesSpecifyCache(PMDLX MemoryDescriptorList, KPROCESSOR_MODE AccessMode, MEMORY_CACHING_TYPE CacheType,
2921 PVOID BaseAddress, ULONG BugCheckOnFailure, MM_PAGE_PRIORITY Priority)
2923 FIXME("(%p, %u, %u, %p, %lu, %u): stub\n", MemoryDescriptorList, AccessMode, CacheType, BaseAddress, BugCheckOnFailure, Priority);
2925 return NULL;
2928 /***********************************************************************
2929 * MmUnmapLockedPages (NTOSKRNL.EXE.@)
2931 void WINAPI MmUnmapLockedPages( void *base, MDL *mdl )
2933 FIXME( "(%p %p_\n", base, mdl );
2936 /***********************************************************************
2937 * MmUnlockPagableImageSection (NTOSKRNL.EXE.@)
2939 VOID WINAPI MmUnlockPagableImageSection(PVOID ImageSectionHandle)
2941 FIXME("stub %p\n", ImageSectionHandle);
2944 /***********************************************************************
2945 * MmPageEntireDriver (NTOSKRNL.EXE.@)
2947 PVOID WINAPI MmPageEntireDriver(PVOID AddrInSection)
2949 TRACE("%p\n", AddrInSection);
2950 return AddrInSection;
2954 /***********************************************************************
2955 * MmProbeAndLockPages (NTOSKRNL.EXE.@)
2957 void WINAPI MmProbeAndLockPages(PMDLX MemoryDescriptorList, KPROCESSOR_MODE AccessMode, LOCK_OPERATION Operation)
2959 FIXME("(%p, %u, %u): stub\n", MemoryDescriptorList, AccessMode, Operation);
2963 /***********************************************************************
2964 * MmResetDriverPaging (NTOSKRNL.EXE.@)
2966 void WINAPI MmResetDriverPaging(PVOID AddrInSection)
2968 TRACE("%p\n", AddrInSection);
2972 /***********************************************************************
2973 * MmUnlockPages (NTOSKRNL.EXE.@)
2975 void WINAPI MmUnlockPages(PMDLX MemoryDescriptorList)
2977 FIXME("(%p): stub\n", MemoryDescriptorList);
2981 /***********************************************************************
2982 * MmUnmapIoSpace (NTOSKRNL.EXE.@)
2984 VOID WINAPI MmUnmapIoSpace( PVOID BaseAddress, SIZE_T NumberOfBytes )
2986 FIXME( "stub: %p, %Iu\n", BaseAddress, NumberOfBytes );
2990 /***********************************************************************
2991 * ObReferenceObjectByName (NTOSKRNL.EXE.@)
2993 NTSTATUS WINAPI ObReferenceObjectByName( UNICODE_STRING *ObjectName,
2994 ULONG Attributes,
2995 ACCESS_STATE *AccessState,
2996 ACCESS_MASK DesiredAccess,
2997 POBJECT_TYPE ObjectType,
2998 KPROCESSOR_MODE AccessMode,
2999 void *ParseContext,
3000 void **Object)
3002 struct wine_driver *driver;
3003 struct wine_rb_entry *entry;
3005 TRACE("mostly-stub:%s %li %p %li %p %i %p %p\n", debugstr_us(ObjectName),
3006 Attributes, AccessState, DesiredAccess, ObjectType, AccessMode,
3007 ParseContext, Object);
3009 if (AccessState) FIXME("Unhandled AccessState\n");
3010 if (DesiredAccess) FIXME("Unhandled DesiredAccess\n");
3011 if (ParseContext) FIXME("Unhandled ParseContext\n");
3012 if (ObjectType) FIXME("Unhandled ObjectType\n");
3014 if (AccessMode != KernelMode)
3016 FIXME("UserMode access not implemented\n");
3017 return STATUS_NOT_IMPLEMENTED;
3020 EnterCriticalSection(&drivers_cs);
3021 entry = wine_rb_get(&wine_drivers, ObjectName);
3022 LeaveCriticalSection(&drivers_cs);
3023 if (!entry)
3025 FIXME("Object (%s) not found, may not be tracked.\n", debugstr_us(ObjectName));
3026 return STATUS_NOT_IMPLEMENTED;
3029 driver = WINE_RB_ENTRY_VALUE(entry, struct wine_driver, entry);
3030 ObReferenceObject( *Object = &driver->driver_obj );
3031 return STATUS_SUCCESS;
3035 /********************************************************************
3036 * ObOpenObjectByName (NTOSKRNL.EXE.@)
3038 NTSTATUS WINAPI ObOpenObjectByName(POBJECT_ATTRIBUTES attr, POBJECT_TYPE type,
3039 KPROCESSOR_MODE mode, ACCESS_STATE *access_state,
3040 ACCESS_MASK access, PVOID ctx, HANDLE *handle)
3042 NTSTATUS status;
3043 void *object;
3045 TRACE( "attr(%p %s %lx) %p %u %p %lu %p %p\n", attr->RootDirectory, debugstr_us(attr->ObjectName),
3046 attr->Attributes, type, mode, access_state, access, ctx, handle );
3048 if (mode != KernelMode)
3050 FIXME( "UserMode access not implemented\n" );
3051 return STATUS_NOT_IMPLEMENTED;
3054 if (attr->RootDirectory) FIXME( "RootDirectory unhandled\n" );
3056 status = ObReferenceObjectByName(attr->ObjectName, attr->Attributes, access_state, access, type, mode, ctx, &object );
3057 if (status != STATUS_SUCCESS)
3058 return status;
3060 status = ObOpenObjectByPointer(object, attr->Attributes, access_state, access, type, mode, handle);
3062 ObDereferenceObject(object);
3063 return status;
3067 /***********************************************************************
3068 * ObReferenceObjectByPointer (NTOSKRNL.EXE.@)
3070 NTSTATUS WINAPI ObReferenceObjectByPointer(void *obj, ACCESS_MASK access,
3071 POBJECT_TYPE type,
3072 KPROCESSOR_MODE mode)
3074 FIXME("(%p, %lx, %p, %d): stub\n", obj, access, type, mode);
3076 return STATUS_NOT_IMPLEMENTED;
3080 /***********************************************************************
3081 * ObfReferenceObject (NTOSKRNL.EXE.@)
3083 DEFINE_FASTCALL1_WRAPPER( ObfReferenceObject )
3084 void FASTCALL ObfReferenceObject( void *obj )
3086 ObReferenceObject( obj );
3090 /***********************************************************************
3091 * ObfDereferenceObject (NTOSKRNL.EXE.@)
3093 DEFINE_FASTCALL1_WRAPPER( ObfDereferenceObject )
3094 void FASTCALL ObfDereferenceObject( void *obj )
3096 ObDereferenceObject( obj );
3099 /***********************************************************************
3100 * ObRegisterCallbacks (NTOSKRNL.EXE.@)
3102 NTSTATUS WINAPI ObRegisterCallbacks(POB_CALLBACK_REGISTRATION callback, void **handle)
3104 FIXME( "callback %p, handle %p.\n", callback, handle );
3106 if(handle)
3107 *handle = UlongToHandle(0xdeadbeaf);
3109 return STATUS_SUCCESS;
3112 /***********************************************************************
3113 * ObUnRegisterCallbacks (NTOSKRNL.EXE.@)
3115 void WINAPI ObUnRegisterCallbacks(void *handle)
3117 FIXME( "stub: %p\n", handle );
3120 /***********************************************************************
3121 * ObGetFilterVersion (NTOSKRNL.EXE.@)
3123 USHORT WINAPI ObGetFilterVersion(void)
3125 FIXME( "stub:\n" );
3127 return OB_FLT_REGISTRATION_VERSION;
3130 /***********************************************************************
3131 * IoGetAttachedDeviceReference (NTOSKRNL.EXE.@)
3133 DEVICE_OBJECT* WINAPI IoGetAttachedDeviceReference( DEVICE_OBJECT *device )
3135 DEVICE_OBJECT *result = IoGetAttachedDevice( device );
3136 ObReferenceObject( result );
3137 return result;
3141 /***********************************************************************
3142 * PsCreateSystemThread (NTOSKRNL.EXE.@)
3144 NTSTATUS WINAPI PsCreateSystemThread(PHANDLE ThreadHandle, ULONG DesiredAccess,
3145 POBJECT_ATTRIBUTES ObjectAttributes,
3146 HANDLE ProcessHandle, PCLIENT_ID ClientId,
3147 PKSTART_ROUTINE StartRoutine, PVOID StartContext)
3149 if (!ProcessHandle) ProcessHandle = GetCurrentProcess();
3150 return RtlCreateUserThread(ProcessHandle, 0, FALSE, 0, 0,
3151 0, StartRoutine, StartContext,
3152 ThreadHandle, ClientId);
3155 /***********************************************************************
3156 * PsGetCurrentProcessId (NTOSKRNL.EXE.@)
3158 HANDLE WINAPI PsGetCurrentProcessId(void)
3160 return KeGetCurrentThread()->id.UniqueProcess;
3163 /***********************************************************************
3164 * PsGetCurrentProcessSessionId (NTOSKRNL.EXE.@)
3166 ULONG WINAPI PsGetCurrentProcessSessionId(void)
3168 return PsGetCurrentProcess()->info.PebBaseAddress->SessionId;
3171 /***********************************************************************
3172 * PsGetCurrentThreadId (NTOSKRNL.EXE.@)
3174 HANDLE WINAPI PsGetCurrentThreadId(void)
3176 return KeGetCurrentThread()->id.UniqueThread;
3180 /***********************************************************************
3181 * PsIsSystemThread (NTOSKRNL.EXE.@)
3183 BOOLEAN WINAPI PsIsSystemThread(PETHREAD thread)
3185 return thread->kthread.process == PsInitialSystemProcess;
3189 /***********************************************************************
3190 * PsGetVersion (NTOSKRNL.EXE.@)
3192 BOOLEAN WINAPI PsGetVersion(ULONG *major, ULONG *minor, ULONG *build, UNICODE_STRING *version )
3194 RTL_OSVERSIONINFOEXW info;
3196 info.dwOSVersionInfoSize = sizeof(info);
3197 RtlGetVersion( &info );
3198 if (major) *major = info.dwMajorVersion;
3199 if (minor) *minor = info.dwMinorVersion;
3200 if (build) *build = info.dwBuildNumber;
3202 if (version)
3204 #if 0 /* FIXME: GameGuard passes an uninitialized pointer in version->Buffer */
3205 size_t len = min( lstrlenW(info.szCSDVersion)*sizeof(WCHAR), version->MaximumLength );
3206 memcpy( version->Buffer, info.szCSDVersion, len );
3207 if (len < version->MaximumLength) version->Buffer[len / sizeof(WCHAR)] = 0;
3208 version->Length = len;
3209 #endif
3211 return TRUE;
3215 /***********************************************************************
3216 * PsImpersonateClient (NTOSKRNL.EXE.@)
3218 NTSTATUS WINAPI PsImpersonateClient(PETHREAD Thread, PACCESS_TOKEN Token, BOOLEAN CopyOnOpen,
3219 BOOLEAN EffectiveOnly, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
3221 FIXME("(%p, %p, %u, %u, %u): stub\n", Thread, Token, CopyOnOpen, EffectiveOnly, ImpersonationLevel);
3223 return STATUS_NOT_IMPLEMENTED;
3227 /***********************************************************************
3228 * PsRevertToSelf (NTOSKRNL.EXE.@)
3230 void WINAPI PsRevertToSelf(void)
3232 FIXME("\n");
3236 /***********************************************************************
3237 * PsSetCreateProcessNotifyRoutine (NTOSKRNL.EXE.@)
3239 NTSTATUS WINAPI PsSetCreateProcessNotifyRoutine( PCREATE_PROCESS_NOTIFY_ROUTINE callback, BOOLEAN remove )
3241 FIXME( "stub: %p %d\n", callback, remove );
3242 return STATUS_SUCCESS;
3246 /***********************************************************************
3247 * PsSetCreateProcessNotifyRoutineEx (NTOSKRNL.EXE.@)
3249 NTSTATUS WINAPI PsSetCreateProcessNotifyRoutineEx( PCREATE_PROCESS_NOTIFY_ROUTINE_EX callback, BOOLEAN remove )
3251 FIXME( "stub: %p %d\n", callback, remove );
3252 return STATUS_SUCCESS;
3256 /***********************************************************************
3257 * PsSetCreateThreadNotifyRoutine (NTOSKRNL.EXE.@)
3259 NTSTATUS WINAPI PsSetCreateThreadNotifyRoutine( PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine )
3261 FIXME( "stub: %p\n", NotifyRoutine );
3262 return STATUS_SUCCESS;
3266 /***********************************************************************
3267 * PsRemoveCreateThreadNotifyRoutine (NTOSKRNL.EXE.@)
3269 NTSTATUS WINAPI PsRemoveCreateThreadNotifyRoutine( PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine )
3271 FIXME( "stub: %p\n", NotifyRoutine );
3272 return STATUS_SUCCESS;
3276 /***********************************************************************
3277 * PsRemoveLoadImageNotifyRoutine (NTOSKRNL.EXE.@)
3279 NTSTATUS WINAPI PsRemoveLoadImageNotifyRoutine(PLOAD_IMAGE_NOTIFY_ROUTINE routine)
3281 unsigned int i;
3283 TRACE("routine %p.\n", routine);
3285 for (i = 0; i < load_image_notify_routine_count; ++i)
3286 if (load_image_notify_routines[i] == routine)
3288 --load_image_notify_routine_count;
3289 memmove(&load_image_notify_routines[i], &load_image_notify_routines[i + 1],
3290 sizeof(*load_image_notify_routines) * (load_image_notify_routine_count - i));
3291 return STATUS_SUCCESS;
3293 return STATUS_PROCEDURE_NOT_FOUND;
3297 /***********************************************************************
3298 * PsReferenceProcessFilePointer (NTOSKRNL.EXE.@)
3300 NTSTATUS WINAPI PsReferenceProcessFilePointer(PEPROCESS process, FILE_OBJECT **file)
3302 FIXME("%p %p\n", process, file);
3303 return STATUS_NOT_IMPLEMENTED;
3307 /***********************************************************************
3308 * PsTerminateSystemThread (NTOSKRNL.EXE.@)
3310 NTSTATUS WINAPI PsTerminateSystemThread(NTSTATUS status)
3312 TRACE("status %#lx.\n", status);
3313 ExitThread( status );
3317 /***********************************************************************
3318 * PsSuspendProcess (NTOSKRNL.EXE.@)
3320 NTSTATUS WINAPI PsSuspendProcess(PEPROCESS process)
3322 FIXME("stub: %p\n", process);
3323 return STATUS_NOT_IMPLEMENTED;
3327 /***********************************************************************
3328 * PsResumeProcess (NTOSKRNL.EXE.@)
3330 NTSTATUS WINAPI PsResumeProcess(PEPROCESS process)
3332 FIXME("stub: %p\n", process);
3333 return STATUS_NOT_IMPLEMENTED;
3337 /***********************************************************************
3338 * MmGetSystemRoutineAddress (NTOSKRNL.EXE.@)
3340 PVOID WINAPI MmGetSystemRoutineAddress(PUNICODE_STRING SystemRoutineName)
3342 HMODULE hMod;
3343 STRING routineNameA;
3344 PVOID pFunc = NULL;
3346 static const WCHAR ntoskrnlW[] = {'n','t','o','s','k','r','n','l','.','e','x','e',0};
3347 static const WCHAR halW[] = {'h','a','l','.','d','l','l',0};
3349 if (!SystemRoutineName) return NULL;
3351 if (RtlUnicodeStringToAnsiString( &routineNameA, SystemRoutineName, TRUE ) == STATUS_SUCCESS)
3353 /* We only support functions exported from ntoskrnl.exe or hal.dll */
3354 hMod = GetModuleHandleW( ntoskrnlW );
3355 pFunc = GetProcAddress( hMod, routineNameA.Buffer );
3356 if (!pFunc)
3358 hMod = LoadLibraryW( halW );
3359 if (hMod) pFunc = GetProcAddress( hMod, routineNameA.Buffer );
3361 RtlFreeAnsiString( &routineNameA );
3364 if (pFunc)
3365 TRACE( "%s -> %p\n", debugstr_us(SystemRoutineName), pFunc );
3366 else
3367 FIXME( "%s not found\n", debugstr_us(SystemRoutineName) );
3368 return pFunc;
3371 /***********************************************************************
3372 * MmIsThisAnNtAsSystem (NTOSKRNL.EXE.@)
3374 BOOLEAN WINAPI MmIsThisAnNtAsSystem(void)
3376 TRACE("\n");
3377 return FALSE;
3380 /***********************************************************************
3381 * MmProtectMdlSystemAddress (NTOSKRNL.EXE.@)
3383 NTSTATUS WINAPI MmProtectMdlSystemAddress(PMDL MemoryDescriptorList, ULONG NewProtect)
3385 FIXME("(%p, %lu) stub\n", MemoryDescriptorList, NewProtect);
3386 return STATUS_SUCCESS;
3389 /***********************************************************************
3390 * MmQuerySystemSize (NTOSKRNL.EXE.@)
3392 MM_SYSTEMSIZE WINAPI MmQuerySystemSize(void)
3394 FIXME("stub\n");
3395 return MmLargeSystem;
3398 /***********************************************************************
3399 * KeInitializeDpc (NTOSKRNL.EXE.@)
3401 void WINAPI KeInitializeDpc(KDPC *dpc, PKDEFERRED_ROUTINE deferred_routine, void *deferred_context)
3403 FIXME("dpc %p, deferred_routine %p, deferred_context %p semi-stub.\n",
3404 dpc, deferred_routine, deferred_context);
3406 dpc->DeferredRoutine = deferred_routine;
3407 dpc->DeferredContext = deferred_context;
3410 /***********************************************************************
3411 * KeSetImportanceDpc (NTOSKRNL.EXE.@)
3413 VOID WINAPI KeSetImportanceDpc(PRKDPC dpc, KDPC_IMPORTANCE importance)
3415 FIXME("%p, %d stub\n", dpc, importance);
3418 /***********************************************************************
3419 * KeSetTargetProcessorDpcEx (NTOSKRNL.EXE.@)
3421 VOID WINAPI KeSetTargetProcessorDpcEx(PRKDPC dpc, PPROCESSOR_NUMBER process_number)
3423 FIXME("%p, %p stub\n", dpc, process_number);
3426 /***********************************************************************
3427 * KeSetTargetProcessorDpc (NTOSKRNL.EXE.@)
3429 VOID WINAPI KeSetTargetProcessorDpc(PRKDPC dpc, CCHAR number)
3431 FIXME("%p, %d stub\n", dpc, number);
3434 /***********************************************************************
3435 * KeGetCurrentProcessorNumberEx (NTOSKRNL.EXE.@)
3437 ULONG WINAPI KeGetCurrentProcessorNumberEx(PPROCESSOR_NUMBER process_number)
3439 ULONG cur_number = NtGetCurrentProcessorNumber();
3441 FIXME("%p semi-stub\n", process_number);
3443 if (process_number)
3445 process_number->Group = 0;
3446 process_number->Reserved = 0;
3447 process_number->Number = cur_number;
3450 return cur_number;
3453 /***********************************************************************
3454 * KeQueryMaximumProcessorCountEx (NTOSKRNL.EXE.@)
3456 ULONG WINAPI KeQueryMaximumProcessorCountEx(USHORT group_number)
3458 return GetMaximumProcessorCount(group_number);
3461 /***********************************************************************
3462 * KeQueryMaximumProcessorCount (NTOSKRNL.EXE.@)
3464 ULONG WINAPI KeQueryMaximumProcessorCount(void)
3466 return KeQueryMaximumProcessorCountEx(0);
3469 /***********************************************************************
3470 * READ_REGISTER_BUFFER_UCHAR (NTOSKRNL.EXE.@)
3472 VOID WINAPI READ_REGISTER_BUFFER_UCHAR(PUCHAR Register, PUCHAR Buffer, ULONG Count)
3474 FIXME("stub\n");
3477 /*****************************************************
3478 * IoWMIRegistrationControl (NTOSKRNL.EXE.@)
3480 NTSTATUS WINAPI IoWMIRegistrationControl(PDEVICE_OBJECT DeviceObject, ULONG Action)
3482 FIXME("(%p %lu) stub\n", DeviceObject, Action);
3483 return STATUS_SUCCESS;
3486 /*****************************************************
3487 * IoWMIOpenBlock (NTOSKRNL.EXE.@)
3489 NTSTATUS WINAPI IoWMIOpenBlock(LPCGUID guid, ULONG desired_access, PVOID *data_block_obj)
3491 FIXME("(%p %lu %p) stub\n", guid, desired_access, data_block_obj);
3492 return STATUS_NOT_IMPLEMENTED;
3495 /*****************************************************
3496 * PsSetLoadImageNotifyRoutine (NTOSKRNL.EXE.@)
3498 NTSTATUS WINAPI PsSetLoadImageNotifyRoutine(PLOAD_IMAGE_NOTIFY_ROUTINE routine)
3500 return PsSetLoadImageNotifyRoutineEx(routine, 0);
3503 /*****************************************************
3504 * PsSetLoadImageNotifyRoutineEx (NTOSKRNL.EXE.@)
3506 NTSTATUS WINAPI PsSetLoadImageNotifyRoutineEx(PLOAD_IMAGE_NOTIFY_ROUTINE routine, ULONG_PTR flags)
3508 FIXME("routine %p, flags %Ix semi-stub.\n", routine, flags);
3510 if (load_image_notify_routine_count == ARRAY_SIZE(load_image_notify_routines))
3511 return STATUS_INSUFFICIENT_RESOURCES;
3513 load_image_notify_routines[load_image_notify_routine_count++] = routine;
3515 return STATUS_SUCCESS;
3518 /*****************************************************
3519 * IoSetThreadHardErrorMode (NTOSKRNL.EXE.@)
3521 BOOLEAN WINAPI IoSetThreadHardErrorMode(BOOLEAN EnableHardErrors)
3523 FIXME("stub\n");
3524 return FALSE;
3527 /*****************************************************
3528 * Ke386IoSetAccessProcess (NTOSKRNL.EXE.@)
3530 BOOLEAN WINAPI Ke386IoSetAccessProcess(PEPROCESS *process, ULONG flag)
3532 FIXME("(%p %ld) stub\n", process, flag);
3533 return FALSE;
3536 /*****************************************************
3537 * Ke386QueryIoAccessMap (NTOSKRNL.EXE.@)
3539 BOOLEAN WINAPI Ke386QueryIoAccessMap(ULONG flag, PVOID buffer)
3541 FIXME("(%ld %p) stub\n", flag, buffer);
3542 return FALSE;
3545 /*****************************************************
3546 * Ke386SetIoAccessMap (NTOSKRNL.EXE.@)
3548 BOOLEAN WINAPI Ke386SetIoAccessMap(ULONG flag, PVOID buffer)
3550 FIXME("(%ld %p) stub\n", flag, buffer);
3551 return FALSE;
3554 /*****************************************************
3555 * IoStartNextPacket (NTOSKRNL.EXE.@)
3557 VOID WINAPI IoStartNextPacket(PDEVICE_OBJECT deviceobject, BOOLEAN cancelable)
3559 FIXME("(%p %d) stub\n", deviceobject, cancelable);
3562 /*****************************************************
3563 * ObQueryNameString (NTOSKRNL.EXE.@)
3565 NTSTATUS WINAPI ObQueryNameString( void *object, OBJECT_NAME_INFORMATION *name, ULONG size, ULONG *ret_size )
3567 HANDLE handle;
3568 NTSTATUS ret;
3570 TRACE("object %p, name %p, size %lu, ret_size %p.\n", object, name, size, ret_size);
3572 if ((ret = ObOpenObjectByPointer( object, 0, NULL, 0, NULL, KernelMode, &handle )))
3573 return ret;
3574 ret = NtQueryObject( handle, ObjectNameInformation, name, size, ret_size );
3576 NtClose( handle );
3577 return ret;
3580 /*****************************************************
3581 * IoRegisterPlugPlayNotification (NTOSKRNL.EXE.@)
3583 NTSTATUS WINAPI IoRegisterPlugPlayNotification(IO_NOTIFICATION_EVENT_CATEGORY category, ULONG flags, PVOID data,
3584 PDRIVER_OBJECT driver, PDRIVER_NOTIFICATION_CALLBACK_ROUTINE callback,
3585 PVOID context, PVOID *notification)
3587 FIXME("(%u %lu %p %p %p %p %p) stub\n", category, flags, data, driver, callback, context, notification);
3588 return STATUS_SUCCESS;
3591 /*****************************************************
3592 * IoUnregisterPlugPlayNotification (NTOSKRNL.EXE.@)
3594 NTSTATUS WINAPI IoUnregisterPlugPlayNotification(PVOID notification)
3596 FIXME("stub: %p\n", notification);
3597 return STATUS_SUCCESS;
3600 /*****************************************************
3601 * IoCsqInitialize (NTOSKRNL.EXE.@)
3603 NTSTATUS WINAPI IoCsqInitialize(PIO_CSQ csq, PIO_CSQ_INSERT_IRP insert_irp, PIO_CSQ_REMOVE_IRP remove_irp,
3604 PIO_CSQ_PEEK_NEXT_IRP peek_irp, PIO_CSQ_ACQUIRE_LOCK acquire_lock,
3605 PIO_CSQ_RELEASE_LOCK release_lock, PIO_CSQ_COMPLETE_CANCELED_IRP complete_irp)
3607 FIXME("(%p %p %p %p %p %p %p) stub\n",
3608 csq, insert_irp, remove_irp, peek_irp, acquire_lock, release_lock, complete_irp);
3609 return STATUS_SUCCESS;
3612 /***********************************************************************
3613 * KeEnterCriticalRegion (NTOSKRNL.EXE.@)
3615 void WINAPI KeEnterCriticalRegion(void)
3617 TRACE( "semi-stub\n" );
3618 KeGetCurrentThread()->critical_region++;
3621 /***********************************************************************
3622 * KeLeaveCriticalRegion (NTOSKRNL.EXE.@)
3624 void WINAPI KeLeaveCriticalRegion(void)
3626 TRACE( "semi-stub\n" );
3627 KeGetCurrentThread()->critical_region--;
3630 /***********************************************************************
3631 * KeAreApcsDisabled (NTOSKRNL.@)
3633 BOOLEAN WINAPI KeAreApcsDisabled(void)
3635 unsigned int critical_region = KeGetCurrentThread()->critical_region;
3636 TRACE( "%u\n", critical_region );
3637 return !!critical_region;
3640 /***********************************************************************
3641 * KeAreAllApcsDisabled (NTOSKRNL.@)
3643 BOOLEAN WINAPI KeAreAllApcsDisabled(void)
3645 return KeAreApcsDisabled();
3648 /***********************************************************************
3649 * KeBugCheck (NTOSKRNL.@)
3651 void WINAPI KeBugCheck(ULONG code)
3653 KeBugCheckEx(code, 0, 0, 0, 0);
3656 /***********************************************************************
3657 * KeBugCheckEx (NTOSKRNL.@)
3659 void WINAPI KeBugCheckEx(ULONG code, ULONG_PTR param1, ULONG_PTR param2, ULONG_PTR param3, ULONG_PTR param4)
3661 ERR( "%lx %Ix %Ix %Ix %Ix\n", code, param1, param2, param3, param4 );
3662 ExitProcess( code );
3665 /***********************************************************************
3666 * ProbeForRead (NTOSKRNL.EXE.@)
3668 void WINAPI ProbeForRead(void *address, SIZE_T length, ULONG alignment)
3670 FIXME("(%p %Iu %lu) stub\n", address, length, alignment);
3673 /***********************************************************************
3674 * ProbeForWrite (NTOSKRNL.EXE.@)
3676 void WINAPI ProbeForWrite(void *address, SIZE_T length, ULONG alignment)
3678 FIXME("(%p %Iu %lu) stub\n", address, length, alignment);
3681 /***********************************************************************
3682 * CmRegisterCallback (NTOSKRNL.EXE.@)
3684 NTSTATUS WINAPI CmRegisterCallback(EX_CALLBACK_FUNCTION *function, void *context, LARGE_INTEGER *cookie)
3686 FIXME("(%p %p %p): stub\n", function, context, cookie);
3687 return STATUS_NOT_IMPLEMENTED;
3690 /***********************************************************************
3691 * CmUnRegisterCallback (NTOSKRNL.EXE.@)
3693 NTSTATUS WINAPI CmUnRegisterCallback(LARGE_INTEGER cookie)
3695 FIXME("(%s): stub\n", wine_dbgstr_longlong(cookie.QuadPart));
3696 return STATUS_NOT_IMPLEMENTED;
3699 /***********************************************************************
3700 * IoAttachDevice (NTOSKRNL.EXE.@)
3702 NTSTATUS WINAPI IoAttachDevice(DEVICE_OBJECT *source, UNICODE_STRING *target, DEVICE_OBJECT *attached)
3704 FIXME("(%p, %s, %p): stub\n", source, debugstr_us(target), attached);
3705 return STATUS_NOT_IMPLEMENTED;
3709 static NTSTATUS open_driver( const UNICODE_STRING *service_name, SC_HANDLE *service )
3711 QUERY_SERVICE_CONFIGW *service_config = NULL;
3712 SC_HANDLE manager_handle;
3713 DWORD config_size = 0;
3714 WCHAR *name;
3716 if (!(name = RtlAllocateHeap( GetProcessHeap(), 0, service_name->Length + sizeof(WCHAR) )))
3717 return STATUS_NO_MEMORY;
3719 memcpy( name, service_name->Buffer, service_name->Length );
3720 name[ service_name->Length / sizeof(WCHAR) ] = 0;
3722 if (wcsncmp( name, servicesW, lstrlenW(servicesW) ))
3724 FIXME( "service name %s is not a keypath\n", debugstr_us(service_name) );
3725 RtlFreeHeap( GetProcessHeap(), 0, name );
3726 return STATUS_NOT_IMPLEMENTED;
3729 if (!(manager_handle = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT )))
3731 WARN( "failed to connect to service manager\n" );
3732 RtlFreeHeap( GetProcessHeap(), 0, name );
3733 return STATUS_NOT_SUPPORTED;
3736 *service = OpenServiceW( manager_handle, name + lstrlenW(servicesW),
3737 SERVICE_QUERY_CONFIG | SERVICE_SET_STATUS );
3738 RtlFreeHeap( GetProcessHeap(), 0, name );
3739 CloseServiceHandle( manager_handle );
3741 if (!*service)
3743 WARN( "failed to open service %s\n", debugstr_us(service_name) );
3744 return STATUS_UNSUCCESSFUL;
3747 QueryServiceConfigW( *service, NULL, 0, &config_size );
3748 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3750 WARN( "failed to query service config\n" );
3751 goto error;
3754 if (!(service_config = RtlAllocateHeap( GetProcessHeap(), 0, config_size )))
3755 goto error;
3757 if (!QueryServiceConfigW( *service, service_config, config_size, &config_size ))
3759 WARN( "failed to query service config\n" );
3760 goto error;
3763 if (service_config->dwServiceType != SERVICE_KERNEL_DRIVER &&
3764 service_config->dwServiceType != SERVICE_FILE_SYSTEM_DRIVER)
3766 WARN( "service %s is not a kernel driver\n", debugstr_us(service_name) );
3767 goto error;
3770 TRACE( "opened service for driver %s\n", debugstr_us(service_name) );
3771 RtlFreeHeap( GetProcessHeap(), 0, service_config );
3772 return STATUS_SUCCESS;
3774 error:
3775 CloseServiceHandle( *service );
3776 RtlFreeHeap( GetProcessHeap(), 0, service_config );
3777 return STATUS_UNSUCCESSFUL;
3780 /* find the LDR_DATA_TABLE_ENTRY corresponding to the driver module */
3781 static LDR_DATA_TABLE_ENTRY *find_ldr_module( HMODULE module )
3783 LDR_DATA_TABLE_ENTRY *ldr;
3784 ULONG_PTR magic;
3786 LdrLockLoaderLock( 0, NULL, &magic );
3787 if (LdrFindEntryForAddress( module, &ldr ))
3789 WARN( "module not found for %p\n", module );
3790 ldr = NULL;
3792 LdrUnlockLoaderLock( 0, magic );
3794 return ldr;
3797 /* convert PE image VirtualAddress to Real Address */
3798 static inline void *get_rva( HMODULE module, DWORD va )
3800 return (void *)((char *)module + va);
3803 static void WINAPI ldr_notify_callback(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context)
3805 const IMAGE_DATA_DIRECTORY *relocs;
3806 IMAGE_BASE_RELOCATION *rel, *end;
3807 SYSTEM_BASIC_INFORMATION info;
3808 IMAGE_NT_HEADERS *nt;
3809 INT_PTR delta;
3810 char *base;
3811 HMODULE module;
3813 if (reason != LDR_DLL_NOTIFICATION_REASON_LOADED) return;
3814 TRACE( "loading %s\n", debugstr_us(data->Loaded.BaseDllName));
3816 module = data->Loaded.DllBase;
3817 nt = RtlImageNtHeader( module );
3818 base = (char *)nt->OptionalHeader.ImageBase;
3819 if (!(delta = (char *)module - base)) return;
3821 /* the loader does not apply relocations to non page-aligned binaries or executables,
3822 * we have to do it ourselves */
3824 NtQuerySystemInformation( SystemBasicInformation, &info, sizeof(info), NULL );
3825 if (nt->OptionalHeader.SectionAlignment >= info.PageSize && (nt->FileHeader.Characteristics & IMAGE_FILE_DLL))
3826 return;
3828 if (nt->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
3830 WARN( "Need to relocate module from %p to %p, but there are no relocation records\n", base, module );
3831 return;
3834 relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
3835 if (!relocs->Size || !relocs->VirtualAddress) return;
3837 TRACE( "relocating from %p-%p to %p-%p\n", base, base + nt->OptionalHeader.SizeOfImage,
3838 module, (char *)module + nt->OptionalHeader.SizeOfImage );
3840 rel = get_rva( module, relocs->VirtualAddress );
3841 end = get_rva( module, relocs->VirtualAddress + relocs->Size );
3843 while (rel < end - 1 && rel->SizeOfBlock)
3845 char *page = get_rva( module, rel->VirtualAddress );
3846 DWORD old_prot1, old_prot2;
3848 if (rel->VirtualAddress >= nt->OptionalHeader.SizeOfImage)
3850 WARN( "invalid address %p in relocation %p\n", get_rva( module, rel->VirtualAddress ), rel );
3851 return;
3854 /* Relocation entries may hang over the end of the page, so we need to
3855 * protect two pages. */
3856 VirtualProtect( page, info.PageSize, PAGE_READWRITE, &old_prot1 );
3857 VirtualProtect( page + info.PageSize, info.PageSize, PAGE_READWRITE, &old_prot2 );
3858 rel = LdrProcessRelocationBlock( page, (rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT),
3859 (USHORT *)(rel + 1), delta );
3860 VirtualProtect( page, info.PageSize, old_prot1, &old_prot1 );
3861 VirtualProtect( page + info.PageSize, info.PageSize, old_prot2, &old_prot2 );
3862 if (!rel)
3864 WARN( "LdrProcessRelocationBlock failed\n" );
3865 return;
3870 /* load the .sys module for a device driver */
3871 static HMODULE load_driver( const WCHAR *driver_name, const UNICODE_STRING *keyname )
3873 static const WCHAR driversW[] = {'\\','d','r','i','v','e','r','s','\\',0};
3874 static const WCHAR systemrootW[] = {'\\','S','y','s','t','e','m','R','o','o','t','\\',0};
3875 static const WCHAR postfixW[] = {'.','s','y','s',0};
3876 static const WCHAR ntprefixW[] = {'\\','?','?','\\',0};
3877 static const WCHAR ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
3878 HKEY driver_hkey;
3879 HMODULE module;
3880 LPWSTR path = NULL, str;
3881 DWORD type, size;
3883 if (RegOpenKeyW( HKEY_LOCAL_MACHINE, keyname->Buffer + 18 /* skip \registry\machine */, &driver_hkey ))
3885 ERR( "cannot open key %s, err=%lu\n", wine_dbgstr_w(keyname->Buffer), GetLastError() );
3886 return NULL;
3889 /* read the executable path from memory */
3890 size = 0;
3891 if (!RegQueryValueExW( driver_hkey, ImagePathW, NULL, &type, NULL, &size ))
3893 str = HeapAlloc( GetProcessHeap(), 0, size );
3894 if (!RegQueryValueExW( driver_hkey, ImagePathW, NULL, &type, (LPBYTE)str, &size ))
3896 size = ExpandEnvironmentStringsW(str,NULL,0);
3897 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
3898 ExpandEnvironmentStringsW(str,path,size);
3900 HeapFree( GetProcessHeap(), 0, str );
3901 if (!path)
3903 RegCloseKey( driver_hkey );
3904 return NULL;
3907 if (!wcsnicmp( path, systemrootW, 12 ))
3909 WCHAR buffer[MAX_PATH];
3911 GetWindowsDirectoryW(buffer, MAX_PATH);
3913 str = HeapAlloc(GetProcessHeap(), 0, (size -11 + lstrlenW(buffer))
3914 * sizeof(WCHAR));
3915 lstrcpyW(str, buffer);
3916 lstrcatW(str, path + 11);
3917 HeapFree( GetProcessHeap(), 0, path );
3918 path = str;
3920 else if (!wcsncmp( path, ntprefixW, 4 ))
3921 str = path + 4;
3922 else
3923 str = path;
3925 else
3927 /* default is to use the driver name + ".sys" */
3928 WCHAR buffer[MAX_PATH];
3929 GetSystemDirectoryW(buffer, MAX_PATH);
3930 path = HeapAlloc(GetProcessHeap(),0,
3931 (lstrlenW(buffer) + lstrlenW(driversW) + lstrlenW(driver_name) + lstrlenW(postfixW) + 1)
3932 *sizeof(WCHAR));
3933 lstrcpyW(path, buffer);
3934 lstrcatW(path, driversW);
3935 lstrcatW(path, driver_name);
3936 lstrcatW(path, postfixW);
3937 str = path;
3939 RegCloseKey( driver_hkey );
3941 TRACE( "loading driver %s\n", wine_dbgstr_w(str) );
3943 module = LoadLibraryExW( str, 0, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS );
3945 if (module && load_image_notify_routine_count)
3947 UNICODE_STRING module_name;
3948 IMAGE_NT_HEADERS *nt;
3949 IMAGE_INFO info;
3950 unsigned int i;
3952 RtlInitUnicodeString(&module_name, str);
3953 nt = RtlImageNtHeader(module);
3954 memset(&info, 0, sizeof(info));
3955 info.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT;
3956 info.SystemModeImage = TRUE;
3957 info.ImageSize = nt->OptionalHeader.SizeOfImage;
3958 info.ImageBase = module;
3960 for (i = 0; i < load_image_notify_routine_count; ++i)
3962 TRACE("Calling image load notify %p.\n", load_image_notify_routines[i]);
3963 load_image_notify_routines[i](&module_name, NULL, &info);
3964 TRACE("Called image load notify %p.\n", load_image_notify_routines[i]);
3968 HeapFree( GetProcessHeap(), 0, path );
3969 return module;
3972 /* call the driver init entry point */
3973 static NTSTATUS WINAPI init_driver( DRIVER_OBJECT *driver_object, UNICODE_STRING *keyname )
3975 unsigned int i;
3976 NTSTATUS status;
3977 const IMAGE_NT_HEADERS *nt;
3978 const WCHAR *driver_name;
3979 HMODULE module;
3981 /* Retrieve driver name from the keyname */
3982 driver_name = wcsrchr( keyname->Buffer, '\\' );
3983 driver_name++;
3985 module = load_driver( driver_name, keyname );
3986 if (!module)
3987 return STATUS_DLL_INIT_FAILED;
3989 driver_object->DriverSection = find_ldr_module( module );
3990 driver_object->DriverStart = ((LDR_DATA_TABLE_ENTRY *)driver_object->DriverSection)->DllBase;
3991 driver_object->DriverSize = ((LDR_DATA_TABLE_ENTRY *)driver_object->DriverSection)->SizeOfImage;
3993 nt = RtlImageNtHeader( module );
3994 if (!nt->OptionalHeader.AddressOfEntryPoint) return STATUS_SUCCESS;
3995 driver_object->DriverInit = (PDRIVER_INITIALIZE)((char *)module + nt->OptionalHeader.AddressOfEntryPoint);
3997 TRACE_(relay)( "\1Call driver init %p (obj=%p,str=%s)\n",
3998 driver_object->DriverInit, driver_object, wine_dbgstr_w(keyname->Buffer) );
4000 status = driver_object->DriverInit( driver_object, keyname );
4002 TRACE_(relay)( "\1Ret driver init %p (obj=%p,str=%s) retval=%08lx\n",
4003 driver_object->DriverInit, driver_object, wine_dbgstr_w(keyname->Buffer), status );
4005 TRACE( "init done for %s obj %p\n", wine_dbgstr_w(driver_name), driver_object );
4006 TRACE( "- DriverInit = %p\n", driver_object->DriverInit );
4007 TRACE( "- DriverStartIo = %p\n", driver_object->DriverStartIo );
4008 TRACE( "- DriverUnload = %p\n", driver_object->DriverUnload );
4009 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
4010 TRACE( "- MajorFunction[%d] = %p\n", i, driver_object->MajorFunction[i] );
4012 return status;
4015 static BOOLEAN get_drv_name( UNICODE_STRING *drv_name, const UNICODE_STRING *service_name )
4017 static const WCHAR driverW[] = {'\\','D','r','i','v','e','r','\\',0};
4018 WCHAR *str;
4020 if (!(str = heap_alloc( sizeof(driverW) + service_name->Length - lstrlenW(servicesW)*sizeof(WCHAR) )))
4021 return FALSE;
4023 lstrcpyW( str, driverW );
4024 lstrcpynW( str + lstrlenW(driverW), service_name->Buffer + lstrlenW(servicesW),
4025 service_name->Length/sizeof(WCHAR) - lstrlenW(servicesW) + 1 );
4026 RtlInitUnicodeString( drv_name, str );
4027 return TRUE;
4030 /***********************************************************************
4031 * ZwLoadDriver (NTOSKRNL.EXE.@)
4033 NTSTATUS WINAPI ZwLoadDriver( const UNICODE_STRING *service_name )
4035 SERVICE_STATUS_HANDLE service_handle;
4036 struct wine_rb_entry *entry;
4037 struct wine_driver *driver;
4038 UNICODE_STRING drv_name;
4039 NTSTATUS status;
4041 TRACE( "(%s)\n", debugstr_us(service_name) );
4043 if ((status = open_driver( service_name, (SC_HANDLE *)&service_handle )) != STATUS_SUCCESS)
4044 return status;
4046 if (!get_drv_name( &drv_name, service_name ))
4048 CloseServiceHandle( (void *)service_handle );
4049 return STATUS_NO_MEMORY;
4052 if (wine_rb_get( &wine_drivers, &drv_name ))
4054 TRACE( "driver %s already loaded\n", debugstr_us(&drv_name) );
4055 RtlFreeUnicodeString( &drv_name );
4056 CloseServiceHandle( (void *)service_handle );
4057 return STATUS_IMAGE_ALREADY_LOADED;
4060 set_service_status( service_handle, SERVICE_START_PENDING, 0 );
4062 status = IoCreateDriver( &drv_name, init_driver );
4063 entry = wine_rb_get( &wine_drivers, &drv_name );
4064 RtlFreeUnicodeString( &drv_name );
4065 if (status != STATUS_SUCCESS)
4067 ERR( "failed to create driver %s: %08lx\n", debugstr_us(service_name), status );
4068 goto error;
4071 driver = WINE_RB_ENTRY_VALUE( entry, struct wine_driver, entry );
4072 driver->service_handle = service_handle;
4074 wine_enumerate_root_devices( service_name->Buffer + wcslen( servicesW ) );
4076 set_service_status( service_handle, SERVICE_RUNNING,
4077 SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN );
4078 return STATUS_SUCCESS;
4080 error:
4081 set_service_status( service_handle, SERVICE_STOPPED, 0 );
4082 CloseServiceHandle( (void *)service_handle );
4083 return status;
4086 /***********************************************************************
4087 * ZwUnloadDriver (NTOSKRNL.EXE.@)
4089 NTSTATUS WINAPI ZwUnloadDriver( const UNICODE_STRING *service_name )
4091 struct wine_rb_entry *entry;
4092 struct wine_driver *driver;
4093 UNICODE_STRING drv_name;
4095 TRACE( "(%s)\n", debugstr_us(service_name) );
4097 if (!get_drv_name( &drv_name, service_name ))
4098 return STATUS_NO_MEMORY;
4100 entry = wine_rb_get( &wine_drivers, &drv_name );
4101 RtlFreeUnicodeString( &drv_name );
4102 if (!entry)
4104 ERR( "failed to locate driver %s\n", debugstr_us(service_name) );
4105 return STATUS_OBJECT_NAME_NOT_FOUND;
4107 driver = WINE_RB_ENTRY_VALUE( entry, struct wine_driver, entry );
4109 if (!list_empty( &driver->root_pnp_devices ))
4111 ERR( "cannot unload driver %s which still has running PnP devices\n", debugstr_us(service_name) );
4112 return STATUS_UNSUCCESSFUL;
4115 unload_driver( entry, NULL );
4117 return STATUS_SUCCESS;
4120 /***********************************************************************
4121 * IoCreateFileEx (NTOSKRNL.EXE.@)
4123 NTSTATUS WINAPI IoCreateFileEx(HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
4124 IO_STATUS_BLOCK *io, LARGE_INTEGER *alloc_size, ULONG attributes, ULONG sharing,
4125 ULONG disposition, ULONG create_options, VOID *ea_buffer, ULONG ea_length,
4126 CREATE_FILE_TYPE file_type, VOID *parameters, ULONG options, void *driverctx)
4128 FIXME(": semi-stub\n");
4129 return NtCreateFile(handle, access, attr, io, alloc_size, attributes, sharing, disposition,
4130 create_options, ea_buffer, ea_length);
4133 /***********************************************************************
4134 * IoCreateFile (NTOSKRNL.EXE.@)
4136 NTSTATUS WINAPI IoCreateFile(HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
4137 IO_STATUS_BLOCK *io, LARGE_INTEGER *alloc_size, ULONG attributes, ULONG sharing,
4138 ULONG disposition, ULONG create_options, VOID *ea_buffer, ULONG ea_length,
4139 CREATE_FILE_TYPE file_type, VOID *parameters, ULONG options )
4141 FIXME(": semi-stub\n");
4142 return IoCreateFileEx(handle, access, attr, io, alloc_size, attributes, sharing, disposition,
4143 create_options, ea_buffer, ea_length, file_type, parameters, options, NULL);
4146 /**************************************************************************
4147 * __chkstk (NTOSKRNL.@)
4149 #ifdef __x86_64__
4150 /* Supposed to touch all the stack pages, but we shouldn't need that. */
4151 __ASM_GLOBAL_FUNC( __chkstk, "ret" );
4152 #elif defined(__i386__)
4153 __ASM_GLOBAL_FUNC( _chkstk,
4154 "negl %eax\n\t"
4155 "addl %esp,%eax\n\t"
4156 "xchgl %esp,%eax\n\t"
4157 "movl 0(%eax),%eax\n\t" /* copy return address from old location */
4158 "movl %eax,0(%esp)\n\t"
4159 "ret" )
4160 #elif defined(__arm__)
4161 /* Incoming r4 contains words to allocate, converting to bytes then return */
4162 __ASM_GLOBAL_FUNC( __chkstk, "lsl r4, r4, #2\n\t"
4163 "bx lr" )
4164 #elif defined(__aarch64__)
4165 /* Supposed to touch all the stack pages, but we shouldn't need that. */
4166 __ASM_GLOBAL_FUNC( __chkstk, "ret" );
4167 #endif
4169 /*********************************************************************
4170 * PsAcquireProcessExitSynchronization (NTOSKRNL.@)
4172 NTSTATUS WINAPI PsAcquireProcessExitSynchronization(PEPROCESS process)
4174 FIXME("stub: %p\n", process);
4176 return STATUS_NOT_IMPLEMENTED;
4179 /*********************************************************************
4180 * PsReleaseProcessExitSynchronization (NTOSKRNL.@)
4182 void WINAPI PsReleaseProcessExitSynchronization(PEPROCESS process)
4184 FIXME("stub: %p\n", process);
4187 typedef struct _EX_PUSH_LOCK_WAIT_BLOCK *PEX_PUSH_LOCK_WAIT_BLOCK;
4188 /*********************************************************************
4189 * ExfUnblockPushLock (NTOSKRNL.@)
4191 DEFINE_FASTCALL_WRAPPER( ExfUnblockPushLock, 8 )
4192 void FASTCALL ExfUnblockPushLock( EX_PUSH_LOCK *lock, PEX_PUSH_LOCK_WAIT_BLOCK block )
4194 FIXME( "stub: %p, %p\n", lock, block );
4197 /*********************************************************************
4198 * FsRtlRegisterFileSystemFilterCallbacks (NTOSKRNL.@)
4200 NTSTATUS WINAPI FsRtlRegisterFileSystemFilterCallbacks( DRIVER_OBJECT *object, PFS_FILTER_CALLBACKS callbacks)
4202 FIXME("stub: %p %p\n", object, callbacks);
4203 return STATUS_NOT_IMPLEMENTED;
4206 /*********************************************************************
4207 * SeSinglePrivilegeCheck (NTOSKRNL.@)
4209 BOOLEAN WINAPI SeSinglePrivilegeCheck(LUID privilege, KPROCESSOR_MODE mode)
4211 static int once;
4212 if (!once++) FIXME("stub: %08lx%08lx %u\n", privilege.HighPart, privilege.LowPart, mode);
4213 return TRUE;
4216 /*********************************************************************
4217 * SePrivilegeCheck (NTOSKRNL.@)
4219 BOOLEAN WINAPI SePrivilegeCheck(PRIVILEGE_SET *privileges, SECURITY_SUBJECT_CONTEXT *context, KPROCESSOR_MODE mode)
4221 FIXME("stub: %p %p %u\n", privileges, context, mode);
4222 return TRUE;
4225 /*********************************************************************
4226 * SeLocateProcessImageName (NTOSKRNL.@)
4228 NTSTATUS WINAPI SeLocateProcessImageName(PEPROCESS process, UNICODE_STRING **image_name)
4230 FIXME("stub: %p %p\n", process, image_name);
4231 if (image_name) *image_name = NULL;
4232 return STATUS_NOT_IMPLEMENTED;
4235 /*********************************************************************
4236 * KeFlushQueuedDpcs (NTOSKRNL.@)
4238 void WINAPI KeFlushQueuedDpcs(void)
4240 FIXME("stub!\n");
4243 /*********************************************************************
4244 * DbgQueryDebugFilterState (NTOSKRNL.@)
4246 NTSTATUS WINAPI DbgQueryDebugFilterState(ULONG component, ULONG level)
4248 FIXME("stub: %ld %ld\n", component, level);
4249 return STATUS_NOT_IMPLEMENTED;
4252 /*********************************************************************
4253 * PsGetProcessWow64Process (NTOSKRNL.@)
4255 PVOID WINAPI PsGetProcessWow64Process(PEPROCESS process)
4257 FIXME("stub: %p\n", process);
4258 return NULL;
4261 /*********************************************************************
4262 * MmCopyVirtualMemory (NTOSKRNL.@)
4264 NTSTATUS WINAPI MmCopyVirtualMemory(PEPROCESS fromprocess, void *fromaddress, PEPROCESS toprocess,
4265 void *toaddress, SIZE_T bufsize, KPROCESSOR_MODE mode,
4266 SIZE_T *copied)
4268 FIXME("fromprocess %p, fromaddress %p, toprocess %p, toaddress %p, bufsize %Iu, mode %d, copied %p stub.\n",
4269 fromprocess, fromaddress, toprocess, toaddress, bufsize, mode, copied);
4271 *copied = 0;
4272 return STATUS_NOT_IMPLEMENTED;
4275 /*********************************************************************
4276 * KeEnterGuardedRegion (NTOSKRNL.@)
4278 void WINAPI KeEnterGuardedRegion(void)
4280 FIXME("\n");
4283 /*********************************************************************
4284 * KeLeaveGuardedRegion (NTOSKRNL.@)
4286 void WINAPI KeLeaveGuardedRegion(void)
4288 FIXME("\n");
4291 static const WCHAR token_type_name[] = {'T','o','k','e','n',0};
4293 static struct _OBJECT_TYPE token_type =
4295 token_type_name
4298 POBJECT_TYPE SeTokenObjectType = &token_type;
4300 /*************************************************************************
4301 * ExUuidCreate (NTOSKRNL.@)
4303 * Creates a 128bit UUID.
4305 * RETURNS
4307 * STATUS_SUCCESS if successful.
4308 * RPC_NT_UUID_LOCAL_ONLY if UUID is only locally unique.
4310 * NOTES
4312 * Follows RFC 4122, section 4.4 (Algorithms for Creating a UUID from
4313 * Truly Random or Pseudo-Random Numbers)
4315 NTSTATUS WINAPI ExUuidCreate(UUID *uuid)
4317 RtlGenRandom(uuid, sizeof(*uuid));
4318 /* Clear the version bits and set the version (4) */
4319 uuid->Data3 &= 0x0fff;
4320 uuid->Data3 |= (4 << 12);
4321 /* Set the topmost bits of Data4 (clock_seq_hi_and_reserved) as
4322 * specified in RFC 4122, section 4.4.
4324 uuid->Data4[0] &= 0x3f;
4325 uuid->Data4[0] |= 0x80;
4327 TRACE("%s\n", debugstr_guid(uuid));
4329 return STATUS_SUCCESS;
4332 /***********************************************************************
4333 * ExSetTimerResolution (NTOSKRNL.EXE.@)
4335 ULONG WINAPI ExSetTimerResolution(ULONG time, BOOLEAN set_resolution)
4337 FIXME("stub: %lu %d\n", time, set_resolution);
4338 return KeQueryTimeIncrement();
4341 /***********************************************************************
4342 * IoGetRequestorProcess (NTOSKRNL.EXE.@)
4344 PEPROCESS WINAPI IoGetRequestorProcess(IRP *irp)
4346 TRACE("irp %p.\n", irp);
4347 return irp->Tail.Overlay.Thread->kthread.process;
4350 #ifdef _WIN64
4351 /***********************************************************************
4352 * IoIs32bitProcess (NTOSKRNL.EXE.@)
4354 BOOLEAN WINAPI IoIs32bitProcess(IRP *irp)
4356 TRACE("irp %p.\n", irp);
4357 return irp->Tail.Overlay.Thread->kthread.process->wow64;
4359 #endif
4361 /***********************************************************************
4362 * RtlIsNtDdiVersionAvailable (NTOSKRNL.EXE.@)
4364 BOOLEAN WINAPI RtlIsNtDdiVersionAvailable(ULONG version)
4366 FIXME("stub: %ld\n", version);
4367 return FALSE;
4370 BOOLEAN WINAPI KdRefreshDebuggerNotPresent(void)
4372 TRACE(".\n");
4374 return !KdDebuggerEnabled;
4377 struct generic_call_dpc_context
4379 DEFERRED_REVERSE_BARRIER *reverse_barrier;
4380 PKDEFERRED_ROUTINE routine;
4381 ULONG *cpu_count_barrier;
4382 void *context;
4383 ULONG cpu_index;
4384 ULONG current_barrier_flag;
4385 LONG *barrier_passed_count;
4388 static void WINAPI generic_call_dpc_callback(TP_CALLBACK_INSTANCE *instance, void *context)
4390 struct generic_call_dpc_context *c = context;
4391 GROUP_AFFINITY old, new;
4393 TRACE("instance %p, context %p.\n", instance, context);
4395 NtQueryInformationThread(GetCurrentThread(), ThreadGroupInformation,
4396 &old, sizeof(old), NULL);
4398 memset(&new, 0, sizeof(new));
4400 new.Mask = 1 << c->cpu_index;
4401 NtSetInformationThread(GetCurrentThread(), ThreadGroupInformation, &new, sizeof(new));
4403 TlsSetValue(dpc_call_tls_index, context);
4404 c->routine((PKDPC)0xdeadbeef, c->context, c->cpu_count_barrier, c->reverse_barrier);
4405 TlsSetValue(dpc_call_tls_index, NULL);
4406 NtSetInformationThread(GetCurrentThread(), ThreadGroupInformation, &old, sizeof(old));
4409 void WINAPI KeGenericCallDpc(PKDEFERRED_ROUTINE routine, void *context)
4411 ULONG cpu_count = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
4412 static struct generic_call_dpc_context *contexts;
4413 DEFERRED_REVERSE_BARRIER reverse_barrier;
4414 static ULONG last_cpu_count;
4415 LONG barrier_passed_count;
4416 ULONG cpu_count_barrier;
4417 ULONG i;
4419 TRACE("routine %p, context %p.\n", routine, context);
4421 EnterCriticalSection(&dpc_call_cs);
4423 if (!dpc_call_tp)
4425 if (!(dpc_call_tp = CreateThreadpool(NULL)))
4427 ERR("Could not create thread pool.\n");
4428 LeaveCriticalSection(&dpc_call_cs);
4429 return;
4432 SetThreadpoolThreadMinimum(dpc_call_tp, cpu_count);
4433 SetThreadpoolThreadMaximum(dpc_call_tp, cpu_count);
4435 memset(&dpc_call_tpe, 0, sizeof(dpc_call_tpe));
4436 dpc_call_tpe.Version = 1;
4437 dpc_call_tpe.Pool = dpc_call_tp;
4440 reverse_barrier.Barrier = cpu_count;
4441 reverse_barrier.TotalProcessors = cpu_count;
4442 cpu_count_barrier = cpu_count;
4444 if (contexts)
4446 if (last_cpu_count < cpu_count)
4448 static struct generic_call_dpc_context *new_contexts;
4449 if (!(new_contexts = heap_realloc(contexts, sizeof(*contexts) * cpu_count)))
4451 ERR("No memory.\n");
4452 LeaveCriticalSection(&dpc_call_cs);
4453 return;
4455 contexts = new_contexts;
4456 SetThreadpoolThreadMinimum(dpc_call_tp, cpu_count);
4457 SetThreadpoolThreadMaximum(dpc_call_tp, cpu_count);
4460 else if (!(contexts = heap_alloc(sizeof(*contexts) * cpu_count)))
4462 ERR("No memory.\n");
4463 LeaveCriticalSection(&dpc_call_cs);
4464 return;
4467 memset(contexts, 0, sizeof(*contexts) * cpu_count);
4468 last_cpu_count = cpu_count;
4469 barrier_passed_count = 0;
4471 for (i = 0; i < cpu_count; ++i)
4473 contexts[i].reverse_barrier = &reverse_barrier;
4474 contexts[i].cpu_count_barrier = &cpu_count_barrier;
4475 contexts[i].routine = routine;
4476 contexts[i].context = context;
4477 contexts[i].cpu_index = i;
4478 contexts[i].barrier_passed_count = &barrier_passed_count;
4480 TrySubmitThreadpoolCallback(generic_call_dpc_callback, &contexts[i], &dpc_call_tpe);
4483 while (InterlockedCompareExchange((LONG *)&cpu_count_barrier, 0, 0))
4484 SwitchToThread();
4486 LeaveCriticalSection(&dpc_call_cs);
4490 BOOLEAN WINAPI KeSignalCallDpcSynchronize(void *barrier)
4492 struct generic_call_dpc_context *context = TlsGetValue(dpc_call_tls_index);
4493 DEFERRED_REVERSE_BARRIER *b = barrier;
4494 LONG curr_flag, comp, done_value;
4495 BOOL first;
4497 TRACE("barrier %p, context %p.\n", barrier, context);
4499 if (!context)
4501 WARN("Called outside of DPC context.\n");
4502 return FALSE;
4505 context->current_barrier_flag ^= 0x80000000;
4506 curr_flag = context->current_barrier_flag;
4508 first = !context->cpu_index;
4509 comp = curr_flag + context->cpu_index;
4510 done_value = curr_flag + b->TotalProcessors;
4512 if (first)
4513 InterlockedExchange((LONG *)&b->Barrier, comp);
4515 while (InterlockedCompareExchange((LONG *)&b->Barrier, comp + 1, comp) != done_value)
4518 InterlockedIncrement(context->barrier_passed_count);
4520 while (first && InterlockedCompareExchange(context->barrier_passed_count, 0, b->TotalProcessors))
4523 return first;
4526 void WINAPI KeSignalCallDpcDone(void *barrier)
4528 InterlockedDecrement((LONG *)barrier);
4531 void * WINAPI PsGetProcessSectionBaseAddress(PEPROCESS process)
4533 void *image_base;
4534 NTSTATUS status;
4535 SIZE_T size;
4536 HANDLE h;
4538 TRACE("process %p.\n", process);
4540 if ((status = ObOpenObjectByPointer(process, 0, NULL, PROCESS_ALL_ACCESS, NULL, KernelMode, &h)))
4542 WARN("Error opening process object, status %#lx.\n", status);
4543 return NULL;
4546 status = NtReadVirtualMemory(h, &process->info.PebBaseAddress->ImageBaseAddress,
4547 &image_base, sizeof(image_base), &size);
4549 NtClose(h);
4551 if (status || size != sizeof(image_base))
4553 WARN("Error reading process memory, status %#lx, size %Iu.\n", status, size);
4554 return NULL;
4557 TRACE("returning %p.\n", image_base);
4558 return image_base;
4561 void WINAPI KeStackAttachProcess(KPROCESS *process, KAPC_STATE *apc_state)
4563 FIXME("process %p, apc_state %p stub.\n", process, apc_state);
4566 void WINAPI KeUnstackDetachProcess(KAPC_STATE *apc_state)
4568 FIXME("apc_state %p stub.\n", apc_state);
4571 NTSTATUS WINAPI KdDisableDebugger(void)
4573 FIXME(": stub.\n");
4574 return STATUS_DEBUGGER_INACTIVE;
4577 NTSTATUS WINAPI KdEnableDebugger(void)
4579 FIXME(": stub.\n");
4580 return STATUS_DEBUGGER_INACTIVE;
4583 KPROCESSOR_MODE WINAPI ExGetPreviousMode(void)
4585 TRACE("\n");
4586 return PsIsSystemThread((PETHREAD)KeGetCurrentThread()) ? KernelMode : UserMode;
4589 #ifdef __x86_64__
4591 void WINAPI KfRaiseIrql(KIRQL new, KIRQL *old)
4593 FIXME("new %u old %p: stub.\n", new, old);
4596 void WINAPI KeLowerIrql(KIRQL new)
4598 FIXME("new %u: stub.\n", new);
4601 #endif
4603 typedef void (WINAPI *PETW_CLASSIC_CALLBACK)(
4604 const GUID *guid, UCHAR control_code, void *enable_context, void *callback_context);
4606 NTSTATUS WINAPI EtwRegisterClassicProvider(const GUID *provider, ULONG type, PETW_CLASSIC_CALLBACK callback,
4607 void *context, REGHANDLE *handle)
4609 FIXME("provider %s, type %lu, enable_callback %p, context %p, handle %p\n", debugstr_guid(provider), type,
4610 callback, context, handle);
4612 *handle = 0xdeadbeef;
4613 return STATUS_SUCCESS;
4616 NTSTATUS WINAPI EtwUnregister(REGHANDLE handle)
4618 FIXME("handle %I64x\n", handle);
4619 return STATUS_SUCCESS;
4622 /*****************************************************
4623 * DllMain
4625 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
4627 static void *handler;
4628 LARGE_INTEGER count;
4630 switch(reason)
4632 case DLL_PROCESS_ATTACH:
4633 DisableThreadLibraryCalls( inst );
4634 #if defined(__i386__) || defined(__x86_64__)
4635 handler = RtlAddVectoredExceptionHandler( TRUE, vectored_handler );
4636 #endif
4637 KeQueryTickCount( &count ); /* initialize the global KeTickCount */
4638 NtBuildNumber = NtCurrentTeb()->Peb->OSBuildNumber;
4639 ntoskrnl_heap = HeapCreate( HEAP_CREATE_ENABLE_EXECUTE, 0, 0 );
4640 dpc_call_tls_index = TlsAlloc();
4641 LdrRegisterDllNotification( 0, ldr_notify_callback, NULL, &ldr_notify_cookie );
4642 break;
4643 case DLL_PROCESS_DETACH:
4644 LdrUnregisterDllNotification( ldr_notify_cookie );
4646 if (reserved) break;
4648 if (dpc_call_tp)
4649 CloseThreadpool(dpc_call_tp);
4651 HeapDestroy( ntoskrnl_heap );
4652 RtlRemoveVectoredExceptionHandler( handler );
4653 break;
4655 return TRUE;