From 7b85e96f6dbced2fa2bb4c8f73b26abfd442dfef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Tue, 6 Jun 2017 23:42:56 +0200
Subject: [PATCH] ntoskrnl.exe: Implement ExInitializeNPagedLookasideList.

---
 dlls/ntoskrnl.exe/ntoskrnl.c     | 19 +++++++++-
 dlls/ntoskrnl.exe/tests/driver.c | 37 +++++++++++++++++--
 include/ddk/wdm.h                | 76 ++++++++++++++++++++++++++++++++++++++--
 include/winnt.h                  |  2 ++
 4 files changed, 127 insertions(+), 7 deletions(-)

diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index 14a6e82..6123a45 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -2029,7 +2029,24 @@ void WINAPI ExInitializeNPagedLookasideList(PNPAGED_LOOKASIDE_LIST Lookaside,
                                             ULONG Tag,
                                             USHORT Depth)
 {
-    FIXME( "stub: %p, %p, %p, %u, %lu, %u, %u\n", Lookaside, Allocate, Free, Flags, Size, Tag, Depth );
+    TRACE( "%p, %p, %p, %u, %lu, %u, %u\n", Lookaside, Allocate, Free, Flags, Size, Tag, Depth );
+
+    RtlInitializeSListHead( &Lookaside->L.u.ListHead );
+    Lookaside->L.Depth                 = 4;
+    Lookaside->L.MaximumDepth          = 256;
+    Lookaside->L.TotalAllocates        = 0;
+    Lookaside->L.u2.AllocateMisses     = 0;
+    Lookaside->L.TotalFrees            = 0;
+    Lookaside->L.u3.FreeMisses         = 0;
+    Lookaside->L.Type                  = NonPagedPool | Flags;
+    Lookaside->L.Tag                   = Tag;
+    Lookaside->L.Size                  = Size;
+    Lookaside->L.u4.Allocate           = Allocate ? Allocate : ExAllocatePoolWithTag;
+    Lookaside->L.u5.Free               = Free ? Free : ExFreePool;
+    Lookaside->L.LastTotalAllocates    = 0;
+    Lookaside->L.u6.LastAllocateMisses = 0;
+
+    /* FIXME: insert in global list of lookadside lists */
 }
 
 /***********************************************************************
diff --git a/dlls/ntoskrnl.exe/tests/driver.c b/dlls/ntoskrnl.exe/tests/driver.c
index 2e1107b..4f32c30 100644
--- a/dlls/ntoskrnl.exe/tests/driver.c
+++ b/dlls/ntoskrnl.exe/tests/driver.c
@@ -22,6 +22,9 @@
 
 #include <stdarg.h>
 
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+
 #include "ntstatus.h"
 #define WIN32_NO_STATUS
 #include "windef.h"
@@ -525,6 +528,33 @@ static void test_version(void)
     ok(*pNtBuildNumber == build, "Expected build number %u, got %u\n", build, *pNtBuildNumber);
 }
 
+static void test_lookaside_list(void)
+{
+    NPAGED_LOOKASIDE_LIST list;
+    ULONG tag = 0x454e4957; /* WINE */
+
+    ExInitializeNPagedLookasideList(&list, NULL, NULL, POOL_NX_ALLOCATION, LOOKASIDE_MINIMUM_BLOCK_SIZE, tag, 0);
+    ok(list.L.Depth == 4, "Expected 4 got %u\n", list.L.Depth);
+    ok(list.L.MaximumDepth == 256, "Expected 256 got %u\n", list.L.MaximumDepth);
+    ok(list.L.TotalAllocates == 0, "Expected 0 got %u\n", list.L.TotalAllocates);
+    ok(list.L.u2.AllocateMisses == 0, "Expected 0 got %u\n", list.L.u2.AllocateMisses);
+    ok(list.L.TotalFrees == 0, "Expected 0 got %u\n", list.L.TotalFrees);
+    ok(list.L.u3.FreeMisses == 0, "Expected 0 got %u\n", list.L.u3.FreeMisses);
+    ok(list.L.Type == (NonPagedPool|POOL_NX_ALLOCATION),
+       "Expected NonPagedPool|POOL_NX_ALLOCATION got %u\n", list.L.Type);
+    ok(list.L.Tag == tag, "Expected %x got %x\n", tag, list.L.Tag);
+    ok(list.L.Size == LOOKASIDE_MINIMUM_BLOCK_SIZE,
+       "Expected %u got %u\n", LOOKASIDE_MINIMUM_BLOCK_SIZE, list.L.Size);
+    ok(list.L.LastTotalAllocates == 0,"Expected 0 got %u\n", list.L.LastTotalAllocates);
+    ok(list.L.u6.LastAllocateMisses == 0,"Expected 0 got %u\n", list.L.u6.LastAllocateMisses);
+    ExDeleteNPagedLookasideList(&list);
+
+    list.L.Depth = 0;
+    ExInitializeNPagedLookasideList(&list, NULL, NULL, 0, LOOKASIDE_MINIMUM_BLOCK_SIZE, tag, 20);
+    ok(list.L.Depth == 4, "Expected 4 got %u\n", list.L.Depth);
+    ExDeleteNPagedLookasideList(&list);
+}
+
 static NTSTATUS main_test(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info)
 {
     ULONG length = stack->Parameters.DeviceIoControl.OutputBufferLength;
@@ -555,6 +585,7 @@ static NTSTATUS main_test(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info)
     test_load_driver();
     test_sync();
     test_version();
+    test_lookaside_list();
 
     /* print process report */
     if (test_input->winetest_debug)
@@ -606,7 +637,7 @@ static NTSTATUS test_load_driver_ioctl(IRP *irp, IO_STACK_LOCATION *stack, ULONG
 
 static NTSTATUS WINAPI driver_Create(DEVICE_OBJECT *device, IRP *irp)
 {
-    irp->IoStatus.Status = STATUS_SUCCESS;
+    irp->IoStatus.u.Status = STATUS_SUCCESS;
     IoCompleteRequest(irp, IO_NO_INCREMENT);
     return STATUS_SUCCESS;
 }
@@ -631,14 +662,14 @@ static NTSTATUS WINAPI driver_IoControl(DEVICE_OBJECT *device, IRP *irp)
             break;
     }
 
-    irp->IoStatus.Status = status;
+    irp->IoStatus.u.Status = status;
     IoCompleteRequest(irp, IO_NO_INCREMENT);
     return status;
 }
 
 static NTSTATUS WINAPI driver_Close(DEVICE_OBJECT *device, IRP *irp)
 {
-    irp->IoStatus.Status = STATUS_SUCCESS;
+    irp->IoStatus.u.Status = STATUS_SUCCESS;
     IoCompleteRequest(irp, IO_NO_INCREMENT);
     return STATUS_SUCCESS;
 }
diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h
index b5e4424..9ff245e 100644
--- a/include/ddk/wdm.h
+++ b/include/ddk/wdm.h
@@ -153,20 +153,18 @@ typedef struct _KWAIT_BLOCK {
     USHORT WaitType;
 } KWAIT_BLOCK, *PKWAIT_BLOCK, *RESTRICTED_POINTER PRKWAIT_BLOCK;
 
-typedef struct _ALLOCATE_FUNCTION *PALLOCATE_FUNCTION;
 typedef struct _IO_TIMER *PIO_TIMER;
 typedef struct _IO_TIMER_ROUTINE *PIO_TIMER_ROUTINE;
 typedef struct _ETHREAD *PETHREAD;
-typedef struct _FREE_FUNCTION *PFREE_FUNCTION;
 typedef struct _KTHREAD *PKTHREAD, *PRKTHREAD;
 typedef struct _EPROCESS *PEPROCESS;
 typedef struct _ERESOURCE *PERESOURCE;
 typedef struct _IO_WORKITEM *PIO_WORKITEM;
-typedef struct _NPAGED_LOOKASIDE_LIST *PNPAGED_LOOKASIDE_LIST;
 typedef struct _PAGED_LOOKASIDE_LIST *PPAGED_LOOKASIDE_LIST;
 typedef struct _OBJECT_TYPE *POBJECT_TYPE;
 typedef struct _OBJECT_HANDLE_INFORMATION *POBJECT_HANDLE_INFORMATION;
 typedef struct _ZONE_HEADER *PZONE_HEADER;
+typedef struct _LOOKASIDE_LIST_EX *PLOOKASIDE_LIST_EX;
 
 typedef struct _FAST_MUTEX
 {
@@ -191,6 +189,11 @@ typedef struct _VPB {
   WCHAR  VolumeLabel[MAXIMUM_VOLUME_LABEL_LENGTH / sizeof(WCHAR)];
 } VPB, *PVPB;
 
+#define POOL_QUOTA_FAIL_INSTEAD_OF_RAISE 0x8
+#define POOL_RAISE_IF_ALLOCATION_FAILURE 0x10
+#define POOL_COLD_ALLOCATION             0x100
+#define POOL_NX_ALLOCATION               0x200
+
 typedef enum _POOL_TYPE {
   NonPagedPool,
   PagedPool,
@@ -1230,6 +1233,71 @@ typedef struct _KLOCK_QUEUE_HANDLE {
     KIRQL OldIrql;
 } KLOCK_QUEUE_HANDLE, *PKLOCK_QUEUE_HANDLE;
 
+typedef void * (NTAPI *PALLOCATE_FUNCTION)(POOL_TYPE, SIZE_T, ULONG);
+typedef void * (NTAPI *PALLOCATE_FUNCTION_EX)(POOL_TYPE, SIZE_T, ULONG, PLOOKASIDE_LIST_EX);
+typedef void (NTAPI *PFREE_FUNCTION)(void *);
+typedef void (NTAPI *PFREE_FUNCTION_EX)(void *, PLOOKASIDE_LIST_EX);
+
+#ifdef _WIN64
+#define LOOKASIDE_ALIGN DECLSPEC_CACHEALIGN
+#else
+#define LOOKASIDE_ALIGN
+#endif
+
+#define LOOKASIDE_MINIMUM_BLOCK_SIZE (RTL_SIZEOF_THROUGH_FIELD(SLIST_ENTRY, Next))
+
+typedef struct LOOKASIDE_ALIGN _GENERAL_LOOKASIDE
+{
+    union
+    {
+        SLIST_HEADER ListHead;
+        SINGLE_LIST_ENTRY SingleListHead;
+    } DUMMYUNIONNAME;
+    USHORT Depth;
+    USHORT MaximumDepth;
+    ULONG TotalAllocates;
+    union
+    {
+        ULONG AllocateMisses;
+        ULONG AllocateHits;
+    } DUMMYUNIONNAME2;
+    ULONG TotalFrees;
+    union
+    {
+        ULONG FreeMisses;
+        ULONG FreeHits;
+    } DUMMYUNIONNAME3;
+    POOL_TYPE Type;
+    ULONG Tag;
+    ULONG Size;
+    union
+    {
+        PALLOCATE_FUNCTION_EX AllocateEx;
+        PALLOCATE_FUNCTION Allocate;
+    } DUMMYUNIONNAME4;
+    union
+    {
+        PFREE_FUNCTION_EX FreeEx;
+        PFREE_FUNCTION Free;
+    } DUMMYUNIONNAME5;
+    LIST_ENTRY ListEntry;
+    ULONG LastTotalAllocates;
+    union
+    {
+        ULONG LastAllocateMisses;
+        ULONG LastAllocateHits;
+    } DUMMYUNIONNAME6;
+    ULONG Future[2];
+} GENERAL_LOOKASIDE;
+
+typedef struct LOOKASIDE_ALIGN _NPAGED_LOOKASIDE_LIST
+{
+    GENERAL_LOOKASIDE L;
+#if defined(__i386__)
+    KSPIN_LOCK Lock__ObsoleteButDoNotDelete;
+#endif
+} NPAGED_LOOKASIDE_LIST, *PNPAGED_LOOKASIDE_LIST;
+
 typedef NTSTATUS (NTAPI EX_CALLBACK_FUNCTION)(void *CallbackContext, void *Argument1, void *Argument2);
 typedef EX_CALLBACK_FUNCTION *PEX_CALLBACK_FUNCTION;
 
@@ -1382,8 +1450,10 @@ PVOID     WINAPI ExAllocatePool(POOL_TYPE,SIZE_T);
 PVOID     WINAPI ExAllocatePoolWithQuota(POOL_TYPE,SIZE_T);
 PVOID     WINAPI ExAllocatePoolWithTag(POOL_TYPE,SIZE_T,ULONG);
 PVOID     WINAPI ExAllocatePoolWithQuotaTag(POOL_TYPE,SIZE_T,ULONG);
+void      WINAPI ExDeleteNPagedLookasideList(PNPAGED_LOOKASIDE_LIST);
 void      WINAPI ExFreePool(PVOID);
 void      WINAPI ExFreePoolWithTag(PVOID,ULONG);
+void      WINAPI ExInitializeNPagedLookasideList(PNPAGED_LOOKASIDE_LIST,PALLOCATE_FUNCTION,PFREE_FUNCTION,ULONG,SIZE_T,ULONG,USHORT);
 PSLIST_ENTRY WINAPI ExInterlockedPopEntrySList(PSLIST_HEADER,PKSPIN_LOCK);
 PSLIST_ENTRY WINAPI ExInterlockedPushEntrySList(PSLIST_HEADER,PSLIST_ENTRY,PKSPIN_LOCK);
 void      WINAPI ExReleaseFastMutexUnsafe(PFAST_MUTEX);
diff --git a/include/winnt.h b/include/winnt.h
index 66720a2..2b15c8c 100644
--- a/include/winnt.h
+++ b/include/winnt.h
@@ -755,6 +755,8 @@ typedef struct _MEMORY_BASIC_INFORMATION
 #define UNICODE_STRING_MAX_CHARS 32767
 
 #define FIELD_OFFSET(type, field) ((LONG)offsetof(type, field))
+#define RTL_FIELD_SIZE(type, field) (sizeof(((type *)0)->field))
+#define RTL_SIZEOF_THROUGH_FIELD(type, field) (FIELD_OFFSET(type, field) + RTL_FIELD_SIZE(type, field))
 
 #ifdef __GNUC__
 # define CONTAINING_RECORD(address, type, field) ({     \
-- 
2.7.4