You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1418 lines
44 KiB
1418 lines
44 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
buffer.c
|
|
|
|
Abstract:
|
|
|
|
This module contains routines for handling non-bufferring TDI
|
|
providers. The AFD interface assumes that bufferring will be done
|
|
below AFD; if the TDI provider doesn't buffer, then AFD must.
|
|
|
|
Author:
|
|
|
|
David Treadwell (davidtr) 21-Feb-1992
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "afdp.h"
|
|
|
|
PAFD_BUFFER
|
|
AfdInitializeBuffer (
|
|
IN PVOID MemBlock,
|
|
IN ULONG BufferDataSize,
|
|
IN ULONG AddressSize,
|
|
IN CCHAR StackSize
|
|
);
|
|
|
|
VOID
|
|
AfdInitializeBufferTag (
|
|
IN PAFD_BUFFER_TAG AfdBufferTag,
|
|
IN ULONG AddressSize
|
|
);
|
|
|
|
PAFD_BUFFER
|
|
AfdGetBufferSlow (
|
|
IN ULONG BufferDataSize,
|
|
IN ULONG AddressSize,
|
|
IN PEPROCESS Process,
|
|
IN CCHAR StackSize
|
|
);
|
|
|
|
|
|
#if DBG
|
|
VOID
|
|
AfdFreeBufferReal (
|
|
PVOID AfdBuffer
|
|
);
|
|
#endif
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGEAFD, AfdAllocateBuffer )
|
|
#pragma alloc_text( PAGEAFD, AfdFreeBuffer )
|
|
#if DBG
|
|
#pragma alloc_text( PAGEAFD, AfdFreeBufferReal )
|
|
#endif
|
|
#pragma alloc_text( PAGEAFD, AfdCalculateBufferSize )
|
|
#pragma alloc_text( PAGEAFD, AfdInitializeBuffer )
|
|
#pragma alloc_text( PAGEAFD, AfdGetBufferFast )
|
|
#ifdef _AFD_VARIABLE_STACK_
|
|
#pragma alloc_text( PAGEAFD, AfdGetBufferWithMaxStackSize )
|
|
#endif //_AFD_VARIABLE_STACK_
|
|
#pragma alloc_text( PAGEAFD, AfdGetBufferSlow )
|
|
#pragma alloc_text( PAGEAFD, AfdReturnBuffer )
|
|
#pragma alloc_text( PAGEAFD, AfdAllocateBufferTag )
|
|
#pragma alloc_text( PAGEAFD, AfdFreeBufferTag )
|
|
#pragma alloc_text( PAGEAFD, AfdAllocateRemoteAddress )
|
|
#pragma alloc_text( PAGEAFD, AfdFreeRemoteAddress )
|
|
#pragma alloc_text( PAGEAFD, AfdInitializeBufferTag )
|
|
#pragma alloc_text( PAGEAFD, AfdGetBufferTag )
|
|
#pragma alloc_text( INIT, AfdInitializeBufferManager)
|
|
#endif
|
|
|
|
|
|
PVOID
|
|
AfdAllocateBuffer (
|
|
IN POOL_TYPE PoolType,
|
|
IN SIZE_T NumberOfBytes,
|
|
IN ULONG Tag
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Used by the lookaside list allocation function to allocate a new
|
|
AFD buffer structure. The returned structure will be fully
|
|
initialized.
|
|
|
|
Arguments:
|
|
|
|
PoolType - passed to ExAllocatePoolWithTag.
|
|
|
|
NumberOfBytes - the number of bytes required for the data buffer
|
|
portion of the AFD buffer.
|
|
|
|
Tag - passed to ExAllocatePoolWithTag.
|
|
|
|
Return Value:
|
|
|
|
PVOID - a fully initialized PAFD_BUFFER, or NULL if the allocation
|
|
attempt fails.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG dataLength;
|
|
PVOID memBlock;
|
|
|
|
//
|
|
// Get nonpaged pool for the buffer.
|
|
//
|
|
|
|
memBlock = AFD_ALLOCATE_POOL( PoolType, NumberOfBytes, Tag );
|
|
if ( memBlock == NULL ) {
|
|
return NULL;
|
|
}
|
|
|
|
if (NumberOfBytes==AfdLookasideLists->SmallBufferList.L.Size) {
|
|
dataLength = AfdSmallBufferSize;
|
|
}
|
|
else if (NumberOfBytes==AfdLookasideLists->MediumBufferList.L.Size) {
|
|
dataLength = AfdMediumBufferSize;
|
|
}
|
|
else if (NumberOfBytes==AfdLookasideLists->LargeBufferList.L.Size) {
|
|
dataLength = AfdLargeBufferSize;
|
|
}
|
|
else {
|
|
ASSERT (!"Unknown buffer length");
|
|
return NULL;
|
|
}
|
|
//
|
|
// Initialize the buffer and return a pointer to it.
|
|
//
|
|
#if DBG
|
|
{
|
|
PAFD_BUFFER afdBuffer = AfdInitializeBuffer( memBlock,
|
|
dataLength,
|
|
AfdStandardAddressLength,
|
|
AfdTdiStackSize );
|
|
ASSERT ((PCHAR)afdBuffer+sizeof (AFD_BUFFER)<=(PCHAR)memBlock+NumberOfBytes &&
|
|
(PCHAR)afdBuffer->Buffer+dataLength<=(PCHAR)memBlock+NumberOfBytes &&
|
|
(PCHAR)afdBuffer->Irp+IoSizeOfIrp(AfdTdiStackSize)<=(PCHAR)memBlock+NumberOfBytes &&
|
|
(PCHAR)afdBuffer->Mdl+MmSizeOfMdl(afdBuffer->Buffer, dataLength)<=(PCHAR)memBlock+NumberOfBytes &&
|
|
(PCHAR)afdBuffer->TdiInfo.RemoteAddress+AfdStandardAddressLength<=(PCHAR)memBlock+NumberOfBytes);
|
|
return afdBuffer;
|
|
}
|
|
#else
|
|
return AfdInitializeBuffer( memBlock, dataLength, AfdStandardAddressLength, AfdTdiStackSize );
|
|
#endif
|
|
|
|
|
|
} // AfdAllocateBuffer
|
|
|
|
|
|
VOID
|
|
NTAPI
|
|
AfdFreeBuffer (
|
|
PVOID AfdBuffer
|
|
)
|
|
{
|
|
ASSERT( ((PAFD_BUFFER)AfdBuffer)->BufferLength == AfdSmallBufferSize ||
|
|
((PAFD_BUFFER)AfdBuffer)->BufferLength == AfdMediumBufferSize ||
|
|
((PAFD_BUFFER)AfdBuffer)->BufferLength == AfdLargeBufferSize );
|
|
#if DBG
|
|
AfdFreeBufferReal (AfdBuffer);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
AfdFreeBufferReal (
|
|
PVOID AfdBuffer
|
|
)
|
|
{
|
|
#endif
|
|
{
|
|
PAFD_BUFFER hdr = AfdBuffer;
|
|
switch (hdr->Placement) {
|
|
case AFD_PLACEMENT_BUFFER:
|
|
AfdBuffer = hdr->Buffer;
|
|
break;
|
|
case AFD_PLACEMENT_HDR:
|
|
AfdBuffer = hdr;
|
|
break;
|
|
case AFD_PLACEMENT_MDL:
|
|
AfdBuffer = hdr->Mdl;
|
|
break;
|
|
case AFD_PLACEMENT_IRP:
|
|
AfdBuffer = hdr->Irp;
|
|
break;
|
|
default:
|
|
ASSERT (!"Unknown placement!");
|
|
__assume (0);
|
|
}
|
|
if (hdr->AlignmentAdjusted) {
|
|
//
|
|
// The original memory block was adjusted to meet alignment
|
|
// requirement of AFD buffers.
|
|
// The amount of adjustment should be stored in the space
|
|
// used for adjustment (right below the first piece).
|
|
//
|
|
ASSERT ((*(((PSIZE_T)AfdBuffer)-1))>0 &&
|
|
(*(((PSIZE_T)AfdBuffer)-1))<AfdBufferAlignment);
|
|
AfdBuffer = (PUCHAR)AfdBuffer - (*(((PSIZE_T)AfdBuffer)-1));
|
|
}
|
|
AFD_FREE_POOL (AfdBuffer, AFD_DATA_BUFFER_POOL_TAG);
|
|
}
|
|
}
|
|
|
|
|
|
PVOID
|
|
AfdAllocateBufferTag (
|
|
IN POOL_TYPE PoolType,
|
|
IN SIZE_T NumberOfBytes,
|
|
IN ULONG Tag
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Used by the lookaside list allocation function to allocate a new
|
|
AFD buffer tag structure. The returned structure will be fully
|
|
initialized.
|
|
|
|
Arguments:
|
|
|
|
PoolType - passed to ExAllocatePoolWithTag.
|
|
|
|
NumberOfBytes - the number of bytes required for the data buffer
|
|
portion of the AFD buffer tag (0).
|
|
|
|
Tag - passed to ExAllocatePoolWithTag.
|
|
|
|
Return Value:
|
|
|
|
PVOID - a fully initialized PAFD_BUFFER_TAG, or NULL if the allocation
|
|
attempt fails.
|
|
|
|
--*/
|
|
|
|
{
|
|
PAFD_BUFFER_TAG afdBufferTag;
|
|
|
|
//
|
|
// The requested length must be the same as buffer tag size
|
|
//
|
|
|
|
ASSERT(NumberOfBytes == sizeof (AFD_BUFFER_TAG) );
|
|
|
|
//
|
|
// Get nonpaged pool for the buffer tag.
|
|
//
|
|
|
|
afdBufferTag = AFD_ALLOCATE_POOL( PoolType, NumberOfBytes, Tag );
|
|
if ( afdBufferTag == NULL ) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Initialize the buffer tag and return a pointer to it.
|
|
//
|
|
|
|
AfdInitializeBufferTag( afdBufferTag, 0 );
|
|
|
|
return afdBufferTag;
|
|
|
|
|
|
} // AfdAllocateBufferTag
|
|
|
|
VOID
|
|
NTAPI
|
|
AfdFreeBufferTag (
|
|
PVOID AfdBufferTag
|
|
)
|
|
{
|
|
AFD_FREE_POOL (AfdBufferTag, AFD_DATA_BUFFER_POOL_TAG);
|
|
}
|
|
|
|
|
|
PVOID
|
|
AfdAllocateRemoteAddress (
|
|
IN POOL_TYPE PoolType,
|
|
IN SIZE_T NumberOfBytes,
|
|
IN ULONG Tag
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Used by the lookaside list allocation function to allocate a new
|
|
remote address structure. The returned structure will be fully
|
|
initialized.
|
|
|
|
Arguments:
|
|
|
|
PoolType - passed to ExAllocatePoolWithTag.
|
|
|
|
NumberOfBytes - the number of bytes required for the data buffer
|
|
portion of the AFD buffer tag (0).
|
|
|
|
Tag - passed to ExAllocatePoolWithTag.
|
|
|
|
Return Value:
|
|
|
|
PVOID - a fully initialized remote address, or NULL if the allocation
|
|
attempt fails.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// The requested length must be the same as standard address size
|
|
//
|
|
|
|
ASSERT(NumberOfBytes == AfdStandardAddressLength );
|
|
|
|
//
|
|
// Get nonpaged pool for the remote address.
|
|
//
|
|
|
|
return AFD_ALLOCATE_POOL( PoolType, NumberOfBytes, Tag );
|
|
|
|
|
|
} // AfdAllocateRemoteAddress
|
|
|
|
VOID
|
|
NTAPI
|
|
AfdFreeRemoteAddress (
|
|
PVOID AfdBufferTag
|
|
)
|
|
{
|
|
AFD_FREE_POOL (AfdBufferTag, AFD_REMOTE_ADDRESS_POOL_TAG);
|
|
}
|
|
|
|
|
|
ULONG
|
|
AfdCalculateBufferSize (
|
|
IN ULONG BufferDataSize,
|
|
IN ULONG AddressSize,
|
|
IN CCHAR StackSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determines the size of an AFD buffer structure given the amount of
|
|
data that the buffer contains.
|
|
|
|
Arguments:
|
|
|
|
BufferDataSize - data length of the buffer.
|
|
|
|
AddressSize - length of address structure for the buffer.
|
|
|
|
Return Value:
|
|
|
|
Number of bytes needed for an AFD_BUFFER structure for data of
|
|
this size.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG irpSize;
|
|
ULONG mdlSize;
|
|
ULONG hdrSize;
|
|
ULONG size;
|
|
|
|
//
|
|
// Determine the sizes of the various components of an AFD_BUFFER
|
|
// structure.
|
|
//
|
|
|
|
hdrSize = sizeof (AFD_BUFFER);
|
|
irpSize = IoSizeOfIrp( StackSize );
|
|
//
|
|
// For mdl size calculation we rely on ex guarantee that buffer will be
|
|
// aligned on the page boundary (for allocations >= PAGE_SIZE)
|
|
// or will not spawn pages (for allocations < PAGE_SIZE).
|
|
//
|
|
mdlSize = (CLONG)MmSizeOfMdl( NULL, BufferDataSize );
|
|
|
|
size = ALIGN_UP_A(hdrSize,AFD_MINIMUM_BUFFER_ALIGNMENT) +
|
|
ALIGN_UP_A(irpSize,AFD_MINIMUM_BUFFER_ALIGNMENT) +
|
|
ALIGN_UP_A(mdlSize,AFD_MINIMUM_BUFFER_ALIGNMENT) +
|
|
ALIGN_UP_A(BufferDataSize,AFD_MINIMUM_BUFFER_ALIGNMENT) +
|
|
AddressSize;
|
|
if (size>=PAGE_SIZE) {
|
|
return size;
|
|
}
|
|
else {
|
|
if (StackSize==AfdTdiStackSize) {
|
|
size += AfdAlignmentOverhead;
|
|
}
|
|
else {
|
|
size += AfdBufferAlignment-AFD_MINIMUM_BUFFER_ALIGNMENT;
|
|
}
|
|
|
|
if (size>=PAGE_SIZE) {
|
|
//
|
|
// PAGE_SIZE allocations are aligned, ignore any extra overhead
|
|
//
|
|
return PAGE_SIZE;
|
|
}
|
|
else {
|
|
return size;
|
|
}
|
|
}
|
|
} // AfdCalculateBufferSize
|
|
|
|
|
|
PAFD_BUFFER
|
|
FASTCALL
|
|
AfdGetBufferFast (
|
|
IN ULONG BufferDataSize,
|
|
IN ULONG AddressSize,
|
|
IN PEPROCESS Process
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Obtains a buffer of the appropriate size for the caller. Uses
|
|
the preallocated buffers if possible, or else allocates a new buffer
|
|
structure if required.
|
|
|
|
Arguments:
|
|
|
|
BufferDataSize - the size of the data buffer that goes along with the
|
|
buffer structure.
|
|
|
|
AddressSize - size of the address field required for the buffer.
|
|
|
|
Return Value:
|
|
|
|
PAFD_BUFFER - a pointer to an AFD_BUFFER structure, or NULL if one
|
|
was not available or could not be allocated.
|
|
|
|
--*/
|
|
|
|
{
|
|
PAFD_BUFFER afdBuffer;
|
|
NTSTATUS status;
|
|
|
|
//
|
|
// If possible, allocate the buffer from one of the lookaside lists.
|
|
//
|
|
|
|
if ( AddressSize <= AfdStandardAddressLength &&
|
|
BufferDataSize <= AfdLargeBufferSize ) {
|
|
PNPAGED_LOOKASIDE_LIST lookasideList;
|
|
|
|
if ( BufferDataSize <= AfdSmallBufferSize ) {
|
|
|
|
lookasideList = &AfdLookasideLists->SmallBufferList;
|
|
|
|
} else if ( BufferDataSize <= AfdMediumBufferSize ) {
|
|
|
|
lookasideList = &AfdLookasideLists->MediumBufferList;
|
|
|
|
} else {
|
|
|
|
lookasideList = &AfdLookasideLists->LargeBufferList;
|
|
}
|
|
|
|
afdBuffer = ExAllocateFromNPagedLookasideList( lookasideList );
|
|
if ( afdBuffer != NULL) {
|
|
|
|
if (!afdBuffer->Lookaside) {
|
|
status = PsChargeProcessPoolQuota (
|
|
(PEPROCESS)((ULONG_PTR)Process & (~AFDB_RAISE_ON_FAILURE)),
|
|
NonPagedPool,
|
|
lookasideList->L.Size);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
AfdFreeBuffer (afdBuffer);
|
|
goto ExitQuotaFailure;
|
|
}
|
|
|
|
AfdRecordQuotaHistory(
|
|
process,
|
|
(LONG)lookasideList->L.Size,
|
|
"BuffAlloc ",
|
|
afdBuffer
|
|
);
|
|
AfdRecordPoolQuotaCharged(lookasideList->L.Size);
|
|
}
|
|
|
|
#if DBG
|
|
RtlGetCallersAddress(
|
|
&afdBuffer->Caller,
|
|
&afdBuffer->CallersCaller
|
|
);
|
|
#endif
|
|
return afdBuffer;
|
|
}
|
|
}
|
|
else {
|
|
afdBuffer = AfdGetBufferSlow (BufferDataSize, AddressSize, Process, AfdTdiStackSize);
|
|
#if DBG
|
|
if (afdBuffer!=NULL) {
|
|
RtlGetCallersAddress(
|
|
&afdBuffer->Caller,
|
|
&afdBuffer->CallersCaller
|
|
);
|
|
}
|
|
#endif
|
|
return afdBuffer;
|
|
}
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
ExitQuotaFailure:
|
|
if ((ULONG_PTR)Process & AFDB_RAISE_ON_FAILURE) {
|
|
ExRaiseStatus (status);
|
|
}
|
|
|
|
return NULL;
|
|
} // AfdGetBuffer
|
|
|
|
#ifdef _AFD_VARIABLE_STACK_
|
|
PAFD_BUFFER
|
|
FASTCALL
|
|
AfdGetBufferWithMaxStackSize (
|
|
IN ULONG BufferDataSize,
|
|
IN ULONG AddressSize,
|
|
IN PEPROCESS Process
|
|
)
|
|
{
|
|
PAFD_BUFFER afdBuffer;
|
|
|
|
afdBuffer = AfdGetBufferSlow (BufferDataSize, AddressSize, Process, AfdMaxStackSize);
|
|
#if DBG
|
|
if (afdBuffer!=NULL) {
|
|
RtlGetCallersAddress(
|
|
&afdBuffer->Caller,
|
|
&afdBuffer->CallersCaller
|
|
);
|
|
}
|
|
#endif
|
|
return afdBuffer;
|
|
}
|
|
#endif // _AFD_VARIABLE_STACK_
|
|
|
|
PAFD_BUFFER
|
|
AfdGetBufferSlow (
|
|
IN ULONG BufferDataSize,
|
|
IN ULONG AddressSize,
|
|
IN PEPROCESS Process,
|
|
IN CCHAR StackSize
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
if (AddressSize<=0xFFFF) {
|
|
PVOID memBlock;
|
|
LONG sz;
|
|
ULONG bufferSize;
|
|
|
|
//
|
|
// Couldn't find an appropriate buffer that was preallocated.
|
|
// Allocate one manually. If the buffer size requested was
|
|
// zero bytes, give them four bytes. This is because some of
|
|
// the routines like MmSizeOfMdl() cannot handle getting passed
|
|
// in a length of zero.
|
|
//
|
|
// !!! It would be good to ROUND_TO_PAGES for this allocation
|
|
// if appropriate, then use entire buffer size.
|
|
//
|
|
|
|
if ( BufferDataSize == 0 ) {
|
|
BufferDataSize = sizeof(ULONG);
|
|
}
|
|
|
|
bufferSize = AfdCalculateBufferSize( BufferDataSize, AddressSize, StackSize );
|
|
|
|
//
|
|
// Check for overflow (stack size comes from trusted source - no need to check
|
|
// for overflow).
|
|
//
|
|
if (bufferSize>=BufferDataSize && bufferSize>=AddressSize) {
|
|
|
|
memBlock = AFD_ALLOCATE_POOL(
|
|
NonPagedPool,
|
|
bufferSize,
|
|
AFD_DATA_BUFFER_POOL_TAG
|
|
);
|
|
|
|
if ( memBlock != NULL) {
|
|
status = PsChargeProcessPoolQuota (
|
|
(PEPROCESS)((ULONG_PTR)Process & (~AFDB_RAISE_ON_FAILURE)),
|
|
NonPagedPool,
|
|
sz = BufferDataSize
|
|
+AfdBufferOverhead
|
|
+AddressSize
|
|
-AfdStandardAddressLength
|
|
+BufferDataSize<PAGE_SIZE
|
|
? min (AfdAlignmentOverhead, PAGE_SIZE-BufferDataSize)
|
|
: 0);
|
|
if (NT_SUCCESS (status)) {
|
|
PAFD_BUFFER afdBuffer;
|
|
|
|
//
|
|
// Initialize the AFD buffer structure and return it.
|
|
//
|
|
|
|
afdBuffer = AfdInitializeBuffer( memBlock,
|
|
BufferDataSize,
|
|
AddressSize,
|
|
StackSize);
|
|
|
|
ASSERT ((PCHAR)afdBuffer+sizeof (AFD_BUFFER)<=(PCHAR)memBlock+bufferSize &&
|
|
(PCHAR)afdBuffer->Buffer+BufferDataSize<=(PCHAR)memBlock+bufferSize &&
|
|
(PCHAR)afdBuffer->Irp+IoSizeOfIrp(StackSize)<=(PCHAR)memBlock+bufferSize &&
|
|
(PCHAR)afdBuffer->Mdl+MmSizeOfMdl(afdBuffer->Buffer, BufferDataSize)<=(PCHAR)memBlock+bufferSize &&
|
|
(PCHAR)afdBuffer->TdiInfo.RemoteAddress+AddressSize<=(PCHAR)memBlock+bufferSize);
|
|
|
|
AfdRecordPoolQuotaCharged(sz);
|
|
|
|
AfdRecordQuotaHistory(
|
|
process,
|
|
sz,
|
|
"BuffAlloc ",
|
|
afdBuffer
|
|
);
|
|
|
|
return afdBuffer;
|
|
}
|
|
else {
|
|
AFD_FREE_POOL (memBlock, AFD_DATA_BUFFER_POOL_TAG);
|
|
goto ExitQuotaFailure;
|
|
}
|
|
} // memblock==NULL
|
|
} // overflow
|
|
}
|
|
else {
|
|
// TDI does not support addresses > USHORT
|
|
ASSERT (FALSE);
|
|
}
|
|
|
|
//
|
|
// This is default status code.
|
|
// Quota failures jump directly to the
|
|
// label below to raise the status returned by
|
|
// the quota charging code if requested by the caller..
|
|
//
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
ExitQuotaFailure:
|
|
if ((ULONG_PTR)Process & AFDB_RAISE_ON_FAILURE) {
|
|
ExRaiseStatus (status);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
PAFD_BUFFER_TAG
|
|
AfdGetBufferTag (
|
|
IN ULONG AddressSize,
|
|
IN PEPROCESS Process
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Obtains a buffer for tagging TDSU received via chained indication. Uses
|
|
the preallocated buffers if possible, or else allocates a new buffer
|
|
structure if required.
|
|
|
|
Arguments:
|
|
|
|
AddressSize - size of the address field required for the buffer.
|
|
|
|
Return Value:
|
|
|
|
PAFD_BUFFER_TAG - a pointer to an AFD_BUFFER_TAG structure, or NULL if one
|
|
was not available or could not be allocated.
|
|
|
|
--*/
|
|
|
|
{
|
|
PAFD_BUFFER_TAG afdBufferTag;
|
|
ULONG bufferSize;
|
|
NTSTATUS status;
|
|
|
|
if ( AddressSize <= AfdStandardAddressLength) {
|
|
if (AddressSize>0)
|
|
AddressSize = AfdStandardAddressLength;
|
|
afdBufferTag = ExAllocateFromNPagedLookasideList(
|
|
&AfdLookasideLists->BufferTagList );
|
|
if ( afdBufferTag != NULL &&
|
|
( AddressSize==0 ||
|
|
(afdBufferTag->TdiInfo.RemoteAddress =
|
|
ExAllocateFromNPagedLookasideList(
|
|
&AfdLookasideLists->RemoteAddrList ))!=NULL ) ) {
|
|
|
|
afdBufferTag->AllocatedAddressLength = (USHORT)AddressSize;
|
|
if (!afdBufferTag->Lookaside) {
|
|
status = PsChargeProcessPoolQuota (
|
|
(PEPROCESS)((ULONG_PTR)Process & (~AFDB_RAISE_ON_FAILURE)),
|
|
NonPagedPool,
|
|
sizeof (AFD_BUFFER_TAG)+AddressSize);
|
|
if (!NT_SUCCESS (status)) {
|
|
if ((afdBufferTag->TdiInfo.RemoteAddress!=NULL) &&
|
|
(afdBufferTag->TdiInfo.RemoteAddress != (PVOID)(afdBufferTag+1))) {
|
|
ExFreeToNPagedLookasideList( &AfdLookasideLists->RemoteAddrList,
|
|
afdBufferTag->TdiInfo.RemoteAddress );
|
|
}
|
|
AFD_FREE_POOL (afdBufferTag, AFD_DATA_BUFFER_POOL_TAG);
|
|
goto ExitQuotaFailure;
|
|
}
|
|
|
|
AfdRecordQuotaHistory(
|
|
process,
|
|
(LONG)(sizeof (AFD_BUFFER_TAG)+AddressSize),
|
|
"BuffAlloc ",
|
|
afdBufferTag
|
|
);
|
|
AfdRecordPoolQuotaCharged(sizeof (AFD_BUFFER_TAG)+AddressSize);
|
|
}
|
|
#if DBG
|
|
RtlGetCallersAddress(
|
|
&afdBufferTag->Caller,
|
|
&afdBufferTag->CallersCaller
|
|
);
|
|
#endif
|
|
return afdBufferTag;
|
|
} // afdBufferTag==NULL || RemoteAddress==NULL
|
|
}
|
|
else if (AddressSize<=0xFFFF) {
|
|
bufferSize = sizeof (AFD_BUFFER_TAG) + AddressSize;
|
|
|
|
afdBufferTag = AFD_ALLOCATE_POOL(
|
|
NonPagedPool,
|
|
bufferSize,
|
|
AFD_DATA_BUFFER_POOL_TAG
|
|
);
|
|
|
|
if (afdBufferTag!=NULL) {
|
|
status = PsChargeProcessPoolQuota (
|
|
(PEPROCESS)((ULONG_PTR)Process & (~AFDB_RAISE_ON_FAILURE)),
|
|
NonPagedPool,
|
|
bufferSize);
|
|
if (NT_SUCCESS (status)) {
|
|
|
|
//
|
|
// Initialize the AFD buffer structure and return it.
|
|
//
|
|
|
|
AfdInitializeBufferTag (afdBufferTag, AddressSize);
|
|
AfdRecordQuotaHistory(
|
|
process,
|
|
(LONG)bufferSize,
|
|
"BuffAlloc ",
|
|
afdBufferTag
|
|
);
|
|
|
|
AfdRecordPoolQuotaCharged(bufferSize);
|
|
#if DBG
|
|
RtlGetCallersAddress(
|
|
&afdBufferTag->Caller,
|
|
&afdBufferTag->CallersCaller
|
|
);
|
|
#endif
|
|
return afdBufferTag;
|
|
}
|
|
else {
|
|
AFD_FREE_POOL (afdBufferTag, AFD_DATA_BUFFER_POOL_TAG);
|
|
goto ExitQuotaFailure;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// TDI does not support addresses > USHORT
|
|
ASSERT (FALSE);
|
|
}
|
|
|
|
//
|
|
// This is default status code.
|
|
// Quota failures jump directly to the
|
|
// label below to raise the status returned by
|
|
// the quota charging code if requested by the caller..
|
|
//
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
ExitQuotaFailure:
|
|
|
|
if ((ULONG_PTR)Process & AFDB_RAISE_ON_FAILURE) {
|
|
ExRaiseStatus (status);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
VOID
|
|
AfdReturnBuffer (
|
|
IN PAFD_BUFFER_HEADER AfdBufferHeader,
|
|
IN PEPROCESS Process
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns an AFD buffer to the appropriate global list, or frees
|
|
it if necessary.
|
|
|
|
Arguments:
|
|
|
|
AfdBufferHeader - points to the AFD_BUFFER_HEADER structure to return or free.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
|
|
if (AfdBufferHeader->BufferLength!=AfdBufferTagSize) {
|
|
PNPAGED_LOOKASIDE_LIST lookasideList;
|
|
PAFD_BUFFER AfdBuffer = CONTAINING_RECORD (AfdBufferHeader, AFD_BUFFER, Header);
|
|
|
|
ASSERT (IS_VALID_AFD_BUFFER (AfdBuffer));
|
|
|
|
//
|
|
// Most of the AFD buffer must be zeroed when returning the buffer.
|
|
//
|
|
|
|
ASSERT( !AfdBuffer->ExpeditedData );
|
|
ASSERT( AfdBuffer->Mdl->ByteCount == AfdBuffer->BufferLength );
|
|
ASSERT( AfdBuffer->Mdl->Next == NULL );
|
|
|
|
//
|
|
// If appropriate, return the buffer to one of the AFD buffer
|
|
// lookaside lists.
|
|
//
|
|
#ifdef _AFD_VARIABLE_STACK_
|
|
if (AfdBuffer->Irp->StackCount==AfdTdiStackSize &&
|
|
AfdBuffer->AllocatedAddressLength == AfdStandardAddressLength &&
|
|
AfdBuffer->BufferLength <= AfdLargeBufferSize) {
|
|
#else // _AFD_VARIABLE_STACK_
|
|
ASSERT (AfdBuffer->Irp->StackCount==AfdTdiStackSize);
|
|
if (AfdBuffer->AllocatedAddressLength == AfdStandardAddressLength &&
|
|
AfdBuffer->BufferLength <= AfdLargeBufferSize) {
|
|
#endif // _AFD_VARIABLE_STACK_
|
|
|
|
if (AfdBuffer->BufferLength==AfdSmallBufferSize) {
|
|
lookasideList = &AfdLookasideLists->SmallBufferList;
|
|
} else if (AfdBuffer->BufferLength == AfdMediumBufferSize) {
|
|
lookasideList = &AfdLookasideLists->MediumBufferList;
|
|
} else {
|
|
ASSERT (AfdBuffer->BufferLength==AfdLargeBufferSize);
|
|
lookasideList = &AfdLookasideLists->LargeBufferList;
|
|
}
|
|
|
|
if (!AfdBuffer->Lookaside) {
|
|
PsReturnPoolQuota (Process, NonPagedPool, lookasideList->L.Size);
|
|
AfdRecordQuotaHistory(
|
|
Process,
|
|
-(LONG)lookasideList->L.Size,
|
|
"BuffDealloc ",
|
|
AfdBuffer
|
|
);
|
|
AfdRecordPoolQuotaReturned(
|
|
lookasideList->L.Size
|
|
);
|
|
AfdBuffer->Lookaside = TRUE;
|
|
}
|
|
ExFreeToNPagedLookasideList( lookasideList, AfdBuffer );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// The buffer was not from a lookaside list allocation, so just free
|
|
// the pool we used for it.
|
|
//
|
|
|
|
#ifdef _AFD_VARIABLE_STACK_
|
|
ASSERT (AfdBuffer->Irp->StackCount>=AfdTdiStackSize &&
|
|
AfdBuffer->Irp->StackCount<=AfdMaxStackSize);
|
|
#endif // _AFD_VARIABLE_STACK_
|
|
ASSERT (AfdBuffer->Lookaside==FALSE);
|
|
{
|
|
LONG sz;
|
|
PsReturnPoolQuota (Process,
|
|
NonPagedPool,
|
|
sz=AfdBuffer->BufferLength
|
|
+AfdBufferOverhead
|
|
+AfdBuffer->AllocatedAddressLength
|
|
-AfdStandardAddressLength
|
|
+AfdBuffer->BufferLength<PAGE_SIZE
|
|
? min (AfdAlignmentOverhead, PAGE_SIZE-AfdBuffer->BufferLength)
|
|
: 0);
|
|
AfdRecordQuotaHistory(
|
|
Process,
|
|
-(LONG)sz,
|
|
"BuffDealloc ",
|
|
AfdBuffer
|
|
);
|
|
AfdRecordPoolQuotaReturned(
|
|
sz
|
|
);
|
|
}
|
|
#if DBG
|
|
AfdFreeBufferReal (AfdBuffer);
|
|
#else
|
|
AfdFreeBuffer (AfdBuffer);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
else {
|
|
PAFD_BUFFER_TAG AfdBufferTag = CONTAINING_RECORD (AfdBufferHeader, AFD_BUFFER_TAG, Header);
|
|
|
|
ASSERT( !AfdBufferTag->ExpeditedData );
|
|
|
|
if (AfdBufferTag->NdisPacket) {
|
|
AfdBufferTag->NdisPacket = FALSE;
|
|
TdiReturnChainedReceives (&AfdBufferTag->Context, 1);
|
|
}
|
|
|
|
if (AfdBufferTag->TdiInfo.RemoteAddress != (PVOID)(AfdBufferTag+1)) {
|
|
if (AfdBufferTag->TdiInfo.RemoteAddress!=NULL) {
|
|
ASSERT (AfdBufferTag->AllocatedAddressLength==AfdStandardAddressLength);
|
|
ExFreeToNPagedLookasideList( &AfdLookasideLists->RemoteAddrList,
|
|
AfdBufferTag->TdiInfo.RemoteAddress );
|
|
AfdBufferTag->TdiInfo.RemoteAddress = NULL;
|
|
}
|
|
else {
|
|
ASSERT (AfdBufferTag->AllocatedAddressLength==0);
|
|
}
|
|
|
|
if (!AfdBufferTag->Lookaside) {
|
|
LONG sz;
|
|
PsReturnPoolQuota (
|
|
Process,
|
|
NonPagedPool,
|
|
sz=sizeof (AFD_BUFFER_TAG)
|
|
+ AfdBufferTag->AllocatedAddressLength);
|
|
AfdRecordQuotaHistory(
|
|
Process,
|
|
-(LONG)sz,
|
|
"BuffDealloc ",
|
|
AfdBufferTag
|
|
);
|
|
AfdRecordPoolQuotaReturned(
|
|
sz
|
|
);
|
|
AfdBufferTag->Lookaside = TRUE;
|
|
}
|
|
ExFreeToNPagedLookasideList( &AfdLookasideLists->BufferTagList, AfdBufferTag );
|
|
}
|
|
else {
|
|
LONG sz;
|
|
ASSERT (AfdBufferTag->AllocatedAddressLength>AfdStandardAddressLength);
|
|
ASSERT (AfdBufferTag->Lookaside == FALSE);
|
|
PsReturnPoolQuota (
|
|
Process,
|
|
NonPagedPool,
|
|
sz = sizeof (AFD_BUFFER_TAG)
|
|
+ AfdBufferTag->AllocatedAddressLength);
|
|
AfdRecordQuotaHistory(
|
|
Process,
|
|
-(LONG)sz,
|
|
"BuffDealloc ",
|
|
AfdBufferTag
|
|
);
|
|
AfdRecordPoolQuotaReturned(
|
|
sz
|
|
);
|
|
AFD_FREE_POOL(
|
|
AfdBufferTag,
|
|
AFD_DATA_BUFFER_POOL_TAG
|
|
);
|
|
}
|
|
}
|
|
|
|
} // AfdReturnBuffer
|
|
|
|
|
|
|
|
|
|
|
|
PAFD_BUFFER
|
|
AfdInitializeBuffer (
|
|
IN PVOID MemoryBlock,
|
|
IN ULONG BufferDataSize,
|
|
IN ULONG AddressSize,
|
|
IN CCHAR StackSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes an AFD buffer. Sets up fields in the actual AFD_BUFFER
|
|
structure and initializes the IRP and MDL associated with the
|
|
buffer. This routine assumes that the caller has properly allocated
|
|
sufficient space for all this.
|
|
|
|
Arguments:
|
|
|
|
AfdBuffer - points to the AFD_BUFFER structure to initialize.
|
|
|
|
BufferDataSize - the size of the data buffer that goes along with the
|
|
buffer structure.
|
|
|
|
AddressSize - the size of data allocated for the address buffer.
|
|
|
|
ListHead - the global list this buffer belongs to, or NULL if it
|
|
doesn't belong on any list. This routine does NOT place the
|
|
buffer structure on the list.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
USHORT irpSize;
|
|
SIZE_T mdlSize;
|
|
SIZE_T hdrSize;
|
|
PAFD_BUFFER hdr;
|
|
PMDL mdl;
|
|
PIRP irp;
|
|
PVOID buf;
|
|
PVOID addr;
|
|
UCHAR placement;
|
|
SIZE_T alignment;
|
|
#ifdef AFD_CHECK_ALIGNMENT
|
|
PLONG alignmentCounters = (PLONG)&AfdAlignmentTable[AfdAlignmentTableSize];
|
|
#endif
|
|
irpSize = IoSizeOfIrp( StackSize );
|
|
mdlSize = (ULONG)MmSizeOfMdl( NULL, BufferDataSize );
|
|
hdrSize = sizeof (AFD_BUFFER);
|
|
|
|
//
|
|
// Compute the index into (mis)alignment table to determine
|
|
// what placement of the buffer block elements (e.g. hdr, IRP, MDL,
|
|
// and data buffer itself) we need to choose to compensate and
|
|
// align data buffer on AfdBufferAlignment boundary.
|
|
//
|
|
ASSERT ((PtrToUlong(MemoryBlock)%AFD_MINIMUM_BUFFER_ALIGNMENT)==0);
|
|
#ifdef _AFD_VARIABLE_STACK_
|
|
if (PAGE_ALIGN (MemoryBlock)==MemoryBlock || StackSize!=AfdTdiStackSize) {
|
|
ASSERT (StackSize>=AfdTdiStackSize && StackSize<=AfdMaxStackSize);
|
|
#else // _AFD_VARIABLE_STACK
|
|
if (PAGE_ALIGN (MemoryBlock)==MemoryBlock) {
|
|
#endif // _AFD_VARIABLE_STACK
|
|
//
|
|
// For page-aligned blocks (which are >= page size),
|
|
// we always place the buffer first.
|
|
// Same thing for big IRP stacks - allocate more memory to
|
|
// compensate for alignment.
|
|
//
|
|
placement = AFD_PLACEMENT_BUFFER;
|
|
}
|
|
else {
|
|
placement = AfdAlignmentTable[
|
|
(PtrToUlong(MemoryBlock)&(AfdBufferAlignment-1))/AFD_MINIMUM_BUFFER_ALIGNMENT];
|
|
}
|
|
|
|
#ifdef AFD_CHECK_ALIGNMENT
|
|
InterlockedIncrement (&alignmentCounters[
|
|
(PtrToUlong(MemoryBlock)&(AfdBufferAlignment-1))/AFD_MINIMUM_BUFFER_ALIGNMENT]);
|
|
#endif
|
|
|
|
switch (placement) {
|
|
case AFD_PLACEMENT_BUFFER:
|
|
//
|
|
// Perfect case: the memory is aready aligned as we need it.
|
|
//
|
|
buf = ALIGN_UP_A_POINTER(MemoryBlock, AfdBufferAlignment);
|
|
alignment = (PUCHAR)buf-(PUCHAR)MemoryBlock;
|
|
#ifdef _AFD_VARIABLE_STACK_
|
|
ASSERT (alignment<=AfdAlignmentOverhead || (StackSize!=AfdTdiStackSize));
|
|
#else // _AFD_VARIABLE_STACK_
|
|
ASSERT (alignment<=AfdAlignmentOverhead);
|
|
#endif // _AFD_VARIABLE_STACK_
|
|
hdr = ALIGN_UP_TO_TYPE_POINTER((PCHAR)buf+BufferDataSize, AFD_BUFFER);
|
|
irp = ALIGN_UP_TO_TYPE_POINTER((PCHAR)hdr+hdrSize, IRP);
|
|
mdl = ALIGN_UP_TO_TYPE_POINTER((PCHAR)irp+irpSize, MDL);
|
|
addr = (PCHAR)mdl+mdlSize;
|
|
break;
|
|
|
|
//
|
|
// Other cases, we use hdr, mdl, and IRP to try to compensate
|
|
// and have the data buffer aligned at the AfdBufferAlignment
|
|
// boundary.
|
|
//
|
|
case AFD_PLACEMENT_HDR:
|
|
hdr = ALIGN_UP_TO_TYPE_POINTER(MemoryBlock, AFD_BUFFER);
|
|
alignment = (PUCHAR)hdr-(PUCHAR)MemoryBlock;
|
|
ASSERT (alignment<=AfdAlignmentOverhead);
|
|
buf = ALIGN_UP_A_POINTER((PCHAR)hdr+hdrSize, AfdBufferAlignment);
|
|
irp = ALIGN_UP_TO_TYPE_POINTER((PCHAR)buf+BufferDataSize, IRP);
|
|
mdl = ALIGN_UP_TO_TYPE_POINTER((PCHAR)irp+irpSize, MDL);
|
|
addr = (PCHAR)mdl+mdlSize;
|
|
break;
|
|
|
|
case AFD_PLACEMENT_MDL:
|
|
mdl = ALIGN_UP_TO_TYPE_POINTER(MemoryBlock, MDL);
|
|
alignment = (PUCHAR)mdl-(PUCHAR)MemoryBlock;
|
|
ASSERT (alignment<=AfdAlignmentOverhead);
|
|
buf = ALIGN_UP_A_POINTER((PCHAR)mdl+mdlSize, AfdBufferAlignment);
|
|
hdr = ALIGN_UP_TO_TYPE_POINTER((PCHAR)buf+BufferDataSize, AFD_BUFFER);
|
|
irp = ALIGN_UP_TO_TYPE_POINTER((PCHAR)hdr+hdrSize, IRP);
|
|
addr = (PCHAR)irp+irpSize;
|
|
break;
|
|
case AFD_PLACEMENT_IRP:
|
|
irp = ALIGN_UP_TO_TYPE_POINTER(MemoryBlock, IRP);
|
|
alignment = (PUCHAR)irp-(PUCHAR)MemoryBlock;
|
|
ASSERT (alignment<=AfdAlignmentOverhead);
|
|
buf = ALIGN_UP_A_POINTER((PCHAR)irp+irpSize, AfdBufferAlignment);
|
|
hdr = ALIGN_UP_TO_TYPE_POINTER((PCHAR)buf+BufferDataSize, AFD_BUFFER);
|
|
mdl = ALIGN_UP_TO_TYPE_POINTER((PCHAR)hdr+hdrSize, MDL);
|
|
addr = (PCHAR)mdl+mdlSize;
|
|
break;
|
|
case AFD_PLACEMENT_HDR_IRP:
|
|
hdr = ALIGN_UP_TO_TYPE_POINTER(MemoryBlock, AFD_BUFFER);
|
|
alignment = (PUCHAR)hdr-(PUCHAR)MemoryBlock;
|
|
ASSERT (alignment<=AfdAlignmentOverhead);
|
|
irp = ALIGN_UP_TO_TYPE_POINTER((PCHAR)hdr+hdrSize, IRP);
|
|
buf = ALIGN_UP_A_POINTER((PCHAR)irp+irpSize, AfdBufferAlignment);
|
|
mdl = ALIGN_UP_TO_TYPE_POINTER((PCHAR)buf+BufferDataSize, MDL);
|
|
addr = (PCHAR)mdl+mdlSize;
|
|
break;
|
|
case AFD_PLACEMENT_HDR_MDL:
|
|
hdr = ALIGN_UP_TO_TYPE_POINTER(MemoryBlock, AFD_BUFFER);
|
|
alignment = (PUCHAR)hdr-(PUCHAR)MemoryBlock;
|
|
ASSERT (alignment<=AfdAlignmentOverhead);
|
|
mdl = ALIGN_UP_TO_TYPE_POINTER((PCHAR)hdr+hdrSize, MDL);
|
|
buf = ALIGN_UP_A_POINTER((PCHAR)mdl+mdlSize, AfdBufferAlignment);
|
|
irp = ALIGN_UP_TO_TYPE_POINTER((PCHAR)buf+BufferDataSize, IRP);
|
|
addr = (PCHAR)irp+irpSize;
|
|
break;
|
|
case AFD_PLACEMENT_IRP_MDL:
|
|
irp = ALIGN_UP_TO_TYPE_POINTER(MemoryBlock, IRP);
|
|
alignment = (PUCHAR)irp-(PUCHAR)MemoryBlock;
|
|
ASSERT (alignment<=AfdAlignmentOverhead);
|
|
mdl = ALIGN_UP_TO_TYPE_POINTER((PCHAR)irp+irpSize, MDL);
|
|
buf = ALIGN_UP_A_POINTER((PCHAR)mdl+mdlSize, AfdBufferAlignment);
|
|
hdr = ALIGN_UP_TO_TYPE_POINTER((PCHAR)buf+BufferDataSize, AFD_BUFFER);
|
|
addr = (PCHAR)hdr+hdrSize;
|
|
break;
|
|
case AFD_PLACEMENT_HDR_IRP_MDL:
|
|
hdr = ALIGN_UP_TO_TYPE_POINTER(MemoryBlock, AFD_BUFFER);
|
|
alignment = (PUCHAR)hdr-(PUCHAR)MemoryBlock;
|
|
ASSERT (alignment<=AfdAlignmentOverhead);
|
|
irp = ALIGN_UP_TO_TYPE_POINTER((PCHAR)hdr+hdrSize, IRP);
|
|
mdl = ALIGN_UP_TO_TYPE_POINTER((PCHAR)irp+irpSize, MDL);
|
|
buf = ALIGN_UP_A_POINTER((PCHAR)mdl+mdlSize, AfdBufferAlignment);
|
|
addr = (PCHAR)buf+BufferDataSize;
|
|
break;
|
|
default:
|
|
ASSERT (!"Unknown placement!");
|
|
__assume (0);
|
|
}
|
|
|
|
|
|
//
|
|
// Initialize the AfdBuffer - most fields need to be 0.
|
|
//
|
|
|
|
RtlZeroMemory( hdr, sizeof(*hdr) );
|
|
|
|
//
|
|
// Setup buffer
|
|
//
|
|
hdr->Buffer = buf;
|
|
hdr->BufferLength = BufferDataSize;
|
|
|
|
//
|
|
// We just need to store first two bits of placement
|
|
// so we know which part comes first to free it properly.
|
|
//
|
|
hdr->Placement = placement & 3;
|
|
|
|
//
|
|
// If we have to align the memory block to meet the requirement
|
|
// store this information right below the first piece.
|
|
//
|
|
if (alignment!=0) {
|
|
C_ASSERT (AFD_MINIMUM_BUFFER_ALIGNMENT>=sizeof (SIZE_T));
|
|
C_ASSERT ((AFD_MINIMUM_BUFFER_ALIGNMENT & (sizeof(SIZE_T)-1))==0);
|
|
ASSERT (alignment>=sizeof (SIZE_T));
|
|
hdr->AlignmentAdjusted = TRUE;
|
|
*(((PSIZE_T)(((PUCHAR)MemoryBlock)+alignment))-1) = alignment;
|
|
}
|
|
|
|
|
|
//
|
|
// Initialize the IRP pointer.
|
|
//
|
|
|
|
hdr->Irp = irp;
|
|
IoInitializeIrp( hdr->Irp, irpSize, StackSize );
|
|
hdr->Irp->MdlAddress = mdl;
|
|
|
|
//
|
|
// Set up the MDL pointer.
|
|
//
|
|
|
|
hdr->Mdl = mdl;
|
|
MmInitializeMdl( hdr->Mdl, buf, BufferDataSize );
|
|
MmBuildMdlForNonPagedPool( hdr->Mdl );
|
|
|
|
//
|
|
// Set up the address buffer pointer.
|
|
//
|
|
|
|
if (AddressSize>0) {
|
|
hdr->TdiInfo.RemoteAddress = ALIGN_UP_TO_TYPE_POINTER(addr, TRANSPORT_ADDRESS);;
|
|
hdr->AllocatedAddressLength = (USHORT)AddressSize;
|
|
}
|
|
|
|
|
|
#if DBG
|
|
hdr->BufferListEntry.Flink = UIntToPtr( 0xE0E1E2E3 );
|
|
hdr->BufferListEntry.Blink = UIntToPtr( 0xE4E5E6E7 );
|
|
#endif
|
|
|
|
return hdr;
|
|
|
|
} // AfdInitializeBuffer
|
|
|
|
|
|
VOID
|
|
AfdInitializeBufferTag (
|
|
IN PAFD_BUFFER_TAG AfdBufferTag,
|
|
IN CLONG AddressSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes an AFD buffer. Sets up fields in the actual AFD_BUFFER
|
|
structure and initializes the IRP and MDL associated with the
|
|
buffer. This routine assumes that the caller has properly allocated
|
|
sufficient space for all this.
|
|
|
|
Arguments:
|
|
|
|
AfdBuffer - points to the AFD_BUFFER structure to initialize.
|
|
|
|
BufferDataSize - the size of the data buffer that goes along with the
|
|
buffer structure.
|
|
|
|
AddressSize - the size of data allocated for the address buffer.
|
|
|
|
ListHead - the global list this buffer belongs to, or NULL if it
|
|
doesn't belong on any list. This routine does NOT place the
|
|
buffer structure on the list.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
AfdBufferTag->Mdl = NULL;
|
|
AfdBufferTag->BufferLength = AfdBufferTagSize;
|
|
AfdBufferTag->TdiInfo.RemoteAddress = AddressSize ? AfdBufferTag+1 : NULL;
|
|
AfdBufferTag->AllocatedAddressLength = (USHORT)AddressSize;
|
|
AfdBufferTag->Flags = 0;
|
|
|
|
#if DBG
|
|
AfdBufferTag->BufferListEntry.Flink = UIntToPtr( 0xE0E1E2E3 );
|
|
AfdBufferTag->BufferListEntry.Blink = UIntToPtr( 0xE4E5E6E7 );
|
|
AfdBufferTag->Caller = NULL;
|
|
AfdBufferTag->CallersCaller = NULL;
|
|
#endif
|
|
}
|
|
|
|
|
|
VOID
|
|
AfdInitializeBufferManager (
|
|
VOID
|
|
)
|
|
{
|
|
SIZE_T irpSize = ALIGN_UP_A(IoSizeOfIrp (AfdTdiStackSize), AFD_MINIMUM_BUFFER_ALIGNMENT);
|
|
SIZE_T hdrSize = ALIGN_UP_A(sizeof (AFD_BUFFER), AFD_MINIMUM_BUFFER_ALIGNMENT);
|
|
SIZE_T mdlSize = ALIGN_UP_A(MmSizeOfMdl (NULL, PAGE_SIZE),AFD_MINIMUM_BUFFER_ALIGNMENT);
|
|
UCHAR placement;
|
|
ULONG i;
|
|
ULONG currentOverhead;
|
|
|
|
//
|
|
// Initialize the alignment table.
|
|
// This table is used to determine what kind of element
|
|
// placement to use in AFD_BUFFER depending on the alignment
|
|
// of the memory block returned by the executive pool manager.
|
|
// The goal is to align the data buffer on the cache line
|
|
// boundary. However, since executive only guarantees alignment of
|
|
// it's blocks at the CPU alignment requirements, we need to
|
|
// adjust and potentially waste up to CACHE_LIST_SIZE-CPU_ALIGNMENT_SIZE.
|
|
// With some machines having cache line alignment at 128 such memory
|
|
// waste is prohibitive (small buffers with default size of 128 will double
|
|
// in size).
|
|
// The table below allows us to rearrange pieces in AFD_BUFFER structure,
|
|
// namely, the header, IRP, MDL, and data buffer, so that pieces with
|
|
// lower alignment requirement can be used to consume the space needed
|
|
// to adjust the memory block to the cache line boundary.
|
|
|
|
//
|
|
// AfdAlignmentTable has an entry for each possible case of memory block
|
|
// misaligned against cache line size. For example, in typical X86 system
|
|
// case executive pool manager always returns blocks aligned on 8 byte bounday,
|
|
// while cache lines are typically 64 bytes long, so memory manager can
|
|
// theoretically return blocks misaligned against cache by:
|
|
// 8, 16, 24, 32, 40, 48, 56.
|
|
// For each of these cases we will try to adjust the alignment by using
|
|
// any possible combination of header, IRP, and MDL. There will be some
|
|
// cases that cannot be adjusted exactly, and we will have to pad.
|
|
//
|
|
|
|
//
|
|
// First initialize the table assuming the data buffer is placed first.
|
|
//
|
|
RtlFillMemory (AfdAlignmentTable, AfdAlignmentTableSize, AFD_PLACEMENT_BUFFER);
|
|
#ifdef AFD_CHECK_ALIGNMENT
|
|
RtlZeroMemory (&AfdAlignmentTable[AfdAlignmentTableSize],
|
|
AfdAlignmentTableSize*sizeof(LONG));
|
|
#endif
|
|
//
|
|
// Now identify the entries that can be padded with some combination of
|
|
// header, IRP, and MDL:
|
|
// extract the bits that can be used for padding
|
|
// reverse to get corresponding memory block alignments
|
|
// divide by the step of the alignment table
|
|
// make sure we won't go past table size (last entry => 0 entry).
|
|
//
|
|
#define AfdInitAlignmentTableRow(_size,_plcmnt) \
|
|
AfdAlignmentTable[ \
|
|
((AfdBufferAlignment-(_size&(AfdBufferAlignment-1))) \
|
|
/AFD_MINIMUM_BUFFER_ALIGNMENT) \
|
|
&(AfdAlignmentTableSize-1)] = _plcmnt
|
|
|
|
//
|
|
// We let placements beginning with header override others,
|
|
// since it is more natural and easier to debug (header has references
|
|
// to other pieces).
|
|
//
|
|
|
|
AfdInitAlignmentTableRow(mdlSize,AFD_PLACEMENT_MDL);
|
|
AfdInitAlignmentTableRow(irpSize,AFD_PLACEMENT_IRP);
|
|
AfdInitAlignmentTableRow((irpSize+mdlSize),AFD_PLACEMENT_IRP_MDL);
|
|
AfdInitAlignmentTableRow((hdrSize+mdlSize),AFD_PLACEMENT_HDR_MDL);
|
|
AfdInitAlignmentTableRow((hdrSize+irpSize),AFD_PLACEMENT_HDR_IRP);
|
|
AfdInitAlignmentTableRow((hdrSize+irpSize+mdlSize),AFD_PLACEMENT_HDR_IRP_MDL);
|
|
AfdInitAlignmentTableRow(hdrSize,AFD_PLACEMENT_HDR);
|
|
|
|
//
|
|
// Now scan the table from top to bottom and fill entries that do not have
|
|
// exact match using the above combinations. Use the closest entry above and
|
|
// in the process compute how much do we need to pad in addition to padding
|
|
// achieved via placement.
|
|
//
|
|
AfdAlignmentOverhead = 0;
|
|
currentOverhead = 0;
|
|
//
|
|
// By default use the placement of aligned block.
|
|
//
|
|
placement = AfdAlignmentTable[0];
|
|
for (i=AfdAlignmentTableSize-1; i>0; i--) {
|
|
if (AfdAlignmentTable[i]==AFD_PLACEMENT_BUFFER) {
|
|
AfdAlignmentTable[i] = placement;
|
|
currentOverhead += AFD_MINIMUM_BUFFER_ALIGNMENT;
|
|
}
|
|
else {
|
|
placement = AfdAlignmentTable[i];
|
|
if (AfdAlignmentOverhead<currentOverhead) {
|
|
AfdAlignmentOverhead = currentOverhead;
|
|
}
|
|
currentOverhead = 0;
|
|
}
|
|
}
|
|
if (AfdAlignmentOverhead<currentOverhead) {
|
|
AfdAlignmentOverhead = currentOverhead;
|
|
}
|
|
|
|
|
|
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
|
|
"AfdInitializeBufferManager: Alignment requirements: MM-%d, cache-%d, overhead-%d\n",
|
|
AFD_MINIMUM_BUFFER_ALIGNMENT,
|
|
AfdBufferAlignment,
|
|
AfdAlignmentOverhead));
|
|
{
|
|
CLONG oldBufferLengthForOnePage = AfdBufferLengthForOnePage;
|
|
|
|
AfdBufferOverhead = AfdCalculateBufferSize(
|
|
PAGE_SIZE,
|
|
AfdStandardAddressLength,
|
|
AfdTdiStackSize) - PAGE_SIZE;
|
|
AfdBufferLengthForOnePage = ALIGN_DOWN_A(
|
|
PAGE_SIZE-AfdBufferOverhead,
|
|
AFD_MINIMUM_BUFFER_ALIGNMENT);
|
|
if (AfdLargeBufferSize==oldBufferLengthForOnePage) {
|
|
AfdLargeBufferSize = AfdBufferLengthForOnePage;
|
|
}
|
|
}
|
|
}
|