1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxCommonBuffer.cpp 8 9 Abstract: 10 11 WDF CommonBuffer Object 12 13 Environment: 14 15 Kernel mode only. 16 17 Notes: 18 19 20 Revision History: 21 22 --*/ 23 24 #include "fxdmapch.hpp" 25 26 extern "C" { 27 // #include "FxCommonBuffer.tmh" 28 } 29 30 FxCommonBuffer::FxCommonBuffer( 31 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 32 __in FxDmaEnabler * pDmaEnabler 33 ) : 34 FxNonPagedObject(FX_TYPE_COMMON_BUFFER, sizeof(FxCommonBuffer), FxDriverGlobals) 35 { 36 m_DmaEnabler = pDmaEnabler; 37 m_BufferRawVA = NULL; // allocated buffer base (unaligned) 38 m_BufferAlignedVA = NULL; // aligned buffer base 39 m_BufferAlignedLA.QuadPart = NULL; // aligned physical buffer base 40 m_BufferRawLA.QuadPart = NULL; // allocated buffer phy base (unaligned) 41 m_Length = 0; 42 m_RawLength = 0; 43 44 MarkDisposeOverride(ObjectDoNotLock); 45 46 // 47 // By default use the alignment of the dma enabler. 48 // 49 m_Alignment = m_DmaEnabler->GetAlignment(); 50 } 51 52 BOOLEAN 53 FxCommonBuffer::Dispose() 54 { 55 FreeCommonBuffer(); 56 return TRUE; 57 } 58 59 _Must_inspect_result_ 60 NTSTATUS 61 FxCommonBuffer::AllocateCommonBuffer( 62 __in size_t Length 63 ) 64 { 65 NTSTATUS status; 66 PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); 67 ULONGLONG offset; 68 ULONG result; 69 70 // 71 // Must be running at PASIVE_LEVEL 72 // 73 status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); 74 if (!NT_SUCCESS(status)) { 75 return status; 76 } 77 78 m_Length = Length; 79 80 // 81 // If required, add alignment to the length. 82 // If alignment is <= page-1, we actually don't need to do it b/c 83 // AllocateCommonBuffer allocates at least a page of memory, regardless 84 // of the requested Length. If driver version is < v1.11, we still add the 85 // alignment to the length for compatibility. 86 // 87 if (m_Alignment > PAGE_SIZE-1 || 88 pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11) == FALSE) { 89 90 status = RtlSizeTAdd(Length, m_Alignment, &m_RawLength); 91 if (!NT_SUCCESS(status)) { 92 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, 93 "WDFDMAENABLER %p AllocateCommonBuffer: overflow when adding Length " 94 "%I64d + Alignment %I64d", GetObjectHandle(), Length, m_Alignment); 95 FxVerifierDbgBreakPoint(pFxDriverGlobals); 96 return status; 97 } 98 } 99 else { 100 m_RawLength = Length; 101 } 102 103 m_DmaEnabler->AllocateCommonBuffer(m_RawLength, 104 &m_BufferRawVA, 105 &m_BufferRawLA); 106 if (m_BufferRawVA) { 107 108 m_BufferAlignedVA = FX_ALIGN_VIRTUAL_ADDRESS(m_BufferRawVA, m_Alignment); 109 m_BufferAlignedLA.QuadPart = FX_ALIGN_LOGICAL_ADDRESS(m_BufferRawLA, m_Alignment); 110 111 if (m_Alignment > PAGE_SIZE-1) { 112 // 113 // If the alignment mask is over a page-size then the aligned virtual 114 // and aligned logical could be pointing to different locations 115 // in memory. So ajdust the VA to match the LA address by adding 116 // the offset of alignedLA and RawLA to VA. By doing this we 117 // only guarantee alignment of LA when the page alignment exceeds PAGE_SIZE. 118 // 119 status = RtlULongLongSub(m_BufferAlignedLA.QuadPart, 120 m_BufferRawLA.QuadPart, 121 &offset); 122 if (!NT_SUCCESS(status)) { 123 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, 124 "WDFDMAENABLER %p AllocateCommonBuffer: overflow when subtracting " 125 "RawLA %I64x from AlignedLA %I64x", 126 GetObjectHandle(), m_BufferRawLA.QuadPart, m_BufferAlignedLA.QuadPart); 127 FxVerifierDbgBreakPoint(pFxDriverGlobals); 128 return status; 129 } 130 131 status = RtlULongLongToULong(offset, &result); 132 if (!NT_SUCCESS(status)) { 133 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, 134 "WDFDMAENABLER %p AllocateCommonBuffer: overflow when " 135 "converting from ULongLong %I64d to ULong", 136 GetObjectHandle(), offset); 137 FxVerifierDbgBreakPoint(pFxDriverGlobals); 138 return status; 139 } 140 141 m_BufferAlignedVA = WDF_PTR_ADD_OFFSET(m_BufferRawVA, result); 142 } 143 else { 144 ASSERT(m_BufferAlignedVA == m_BufferRawVA); 145 ASSERT(m_BufferAlignedLA.QuadPart == m_BufferRawLA.QuadPart); 146 } 147 } else { 148 m_Length = 0; 149 m_RawLength = 0; 150 m_BufferAlignedVA = NULL; 151 m_BufferAlignedLA.QuadPart = NULL; 152 return STATUS_INSUFFICIENT_RESOURCES; 153 } 154 155 return status; 156 } 157 158 VOID 159 FxCommonBuffer::FreeCommonBuffer( 160 VOID 161 ) 162 { 163 // 164 // Free this CommonBuffer per DmaEnabler 165 // 166 if (m_BufferRawVA != NULL) { 167 m_DmaEnabler->FreeCommonBuffer((ULONG) m_RawLength, 168 m_BufferRawVA, 169 m_BufferRawLA); 170 } 171 } 172 173 174