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
FxCommonBuffer(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in FxDmaEnabler * pDmaEnabler)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
Dispose()53 FxCommonBuffer::Dispose()
54 {
55 FreeCommonBuffer();
56 return TRUE;
57 }
58
59 _Must_inspect_result_
60 NTSTATUS
AllocateCommonBuffer(__in size_t Length)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
FreeCommonBuffer(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