/*++ 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))= 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 +BufferDataSizeBuffer+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->BufferLengthBufferLength) : 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