Leaked source code of windows server 2003
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.

2364 lines
66 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. ixhwsup.c
  5. Abstract:
  6. This module contains the IoXxx routines for the NT I/O system that
  7. are hardware dependent. Were these routines not hardware dependent,
  8. they would reside in the iosubs.c module.
  9. Author:
  10. Darryl E. Havens (darrylh) 11-Apr-1990
  11. Environment:
  12. Kernel mode
  13. Revision History:
  14. --*/
  15. #include "halp.h"
  16. #include "halpnpp.h"
  17. #include "mca.h"
  18. #define HAL_WCB_DRIVER_BUFFER 1
  19. typedef struct _HAL_WAIT_CONTEXT_BLOCK {
  20. ULONG Flags;
  21. PMDL Mdl;
  22. PMDL DmaMdl;
  23. PVOID MapRegisterBase;
  24. PVOID CurrentVa;
  25. ULONG Length;
  26. ULONG NumberOfMapRegisters;
  27. union {
  28. struct {
  29. WAIT_CONTEXT_BLOCK Wcb;
  30. PDRIVER_LIST_CONTROL DriverExecutionRoutine;
  31. PVOID DriverContext;
  32. PIRP CurrentIrp;
  33. PADAPTER_OBJECT AdapterObject;
  34. BOOLEAN WriteToDevice;
  35. };
  36. SCATTER_GATHER_LIST ScatterGather;
  37. };
  38. } HAL_WAIT_CONTEXT_BLOCK, *PHAL_WAIT_CONTEXT_BLOCK;
  39. IO_ALLOCATION_ACTION
  40. HalpAllocateAdapterCallback (
  41. IN struct _DEVICE_OBJECT *DeviceObject,
  42. IN struct _IRP *Irp,
  43. IN PVOID MapRegisterBase,
  44. IN PVOID Context
  45. );
  46. VOID
  47. HalpCopyBufferMap(
  48. IN PMDL Mdl,
  49. IN PTRANSLATION_ENTRY TranslationEntry,
  50. IN PVOID CurrentVa,
  51. IN ULONG Length,
  52. IN BOOLEAN WriteToDevice
  53. );
  54. static KSPIN_LOCK HalpReservedPageLock;
  55. static PVOID HalpReservedPages = NULL;
  56. static PFN_NUMBER HalpReservedPageMdl[(sizeof(MDL)/sizeof(PFN_NUMBER)) + 2];
  57. extern KEVENT HalpNewAdapter;
  58. #define ACQUIRE_NEW_ADAPTER_LOCK() \
  59. { \
  60. KeWaitForSingleObject ( \
  61. &HalpNewAdapter, \
  62. WrExecutive, \
  63. KernelMode, \
  64. FALSE, \
  65. NULL \
  66. ); \
  67. }
  68. #define RELEASE_NEW_ADAPTER_LOCK() \
  69. KeSetEvent (&HalpNewAdapter, 0, FALSE)
  70. #ifdef ALLOC_PRAGMA
  71. #pragma alloc_text(PAGE, HalpAllocateMapRegisters)
  72. #endif
  73. VOID
  74. HalpInitReservedPages(
  75. VOID
  76. )
  77. /*++
  78. Routine Description:
  79. Back pocket some PTEs so we can make forward progress during low
  80. memory conditions
  81. Aruments:
  82. None
  83. Reurn Value:
  84. None
  85. --*/
  86. {
  87. PMDL Mdl;
  88. HalpReservedPages = MmAllocateMappingAddress(PAGE_SIZE, HAL_POOL_TAG);
  89. ASSERT(HalpReservedPages);
  90. Mdl = (PMDL)&HalpReservedPageMdl;
  91. MmInitializeMdl(Mdl, NULL, PAGE_SIZE);
  92. Mdl->MdlFlags |= MDL_PAGES_LOCKED;
  93. KeInitializeSpinLock(&HalpReservedPageLock);
  94. }
  95. VOID
  96. HalpCopyBufferMapSafe(
  97. IN PMDL Mdl,
  98. IN PTRANSLATION_ENTRY TranslationEntry,
  99. IN PVOID CurrentVa,
  100. IN ULONG Length,
  101. IN BOOLEAN WriteToDevice
  102. )
  103. /*++
  104. Routine Description:
  105. This routine copies the specific data between an unmapped user buffer
  106. and the map register buffer. We will map and unmap each page of the
  107. transfer using our emergency reserved mapping
  108. Arguments:
  109. Mdl - Pointer to the MDL that describes the pages of memory that are
  110. being read or written.
  111. TranslationEntry - The address of the base map register that has been
  112. allocated to the device driver for use in mapping
  113. the transfer.
  114. CurrentVa - Current virtual address in the buffer described by the MDL
  115. that the transfer is being done to or from.
  116. Length - The length of the transfer. This determines the number of map
  117. registers that need to be written to map the transfer.
  118. WriteToDevice - Boolean value that indicates whether this is a write
  119. to the device from memory (TRUE), or vice versa.
  120. Return Value:
  121. STATUS_SUCCESS, or error
  122. --*/
  123. {
  124. PCCHAR bufferAddress;
  125. PCCHAR mapAddress;
  126. ULONG bytesLeft;
  127. ULONG bytesThisCopy;
  128. ULONG bufferPageOffset;
  129. PTRANSLATION_ENTRY translationEntry;
  130. KIRQL Irql;
  131. PMDL ReserveMdl;
  132. MEMORY_CACHING_TYPE MCFlavor;
  133. PPFN_NUMBER SrcPFrame;
  134. PPFN_NUMBER ReservePFrame;
  135. //
  136. // Synchronize access to our reserve page data structures
  137. //
  138. KeAcquireSpinLock(&HalpReservedPageLock, &Irql);
  139. //
  140. // Get local copies of Length and TranslationEntry as they will be
  141. // decremented/incremented respectively
  142. //
  143. bytesLeft = Length;
  144. translationEntry = TranslationEntry;
  145. //
  146. // Find the PFN in our caller's MDL that describes the first page in
  147. // physical memory that we need to access
  148. //
  149. SrcPFrame = (PPFN_NUMBER)(Mdl + 1);
  150. SrcPFrame += (((UINT_PTR)CurrentVa - (UINT_PTR)MmGetMdlBaseVa(Mdl)) >> PAGE_SHIFT);
  151. //
  152. // Initialize our reserve MDL's StartVa and ByteOffset
  153. //
  154. ReserveMdl = (PMDL)&HalpReservedPageMdl;
  155. ReservePFrame = (PPFN_NUMBER)(ReserveMdl + 1);
  156. ReserveMdl->StartVa = (PVOID)PAGE_ALIGN(CurrentVa);
  157. ReserveMdl->ByteOffset = BYTE_OFFSET(CurrentVa);
  158. ReserveMdl->ByteCount = PAGE_SIZE - ReserveMdl->ByteOffset;
  159. //
  160. // Copy the data one translation entry at a time.
  161. //
  162. while (bytesLeft > 0) {
  163. //
  164. // Copy current source PFN into our reserve MDL
  165. //
  166. *ReservePFrame = *SrcPFrame;
  167. //
  168. // Enumerate thru cache flavors until we get our reserve mapping
  169. //
  170. bufferAddress = NULL;
  171. for (MCFlavor = MmNonCached;
  172. MCFlavor < MmMaximumCacheType;
  173. MCFlavor++) {
  174. bufferAddress =
  175. MmMapLockedPagesWithReservedMapping(HalpReservedPages,
  176. HAL_POOL_TAG,
  177. ReserveMdl,
  178. MCFlavor);
  179. if (bufferAddress != NULL) {
  180. break;
  181. }
  182. }
  183. //
  184. // Could not establish a reserve mapping, we're totally screwed!
  185. //
  186. if (bufferAddress == NULL) {
  187. KeBugCheckEx(HAL_MEMORY_ALLOCATION,
  188. PAGE_SIZE,
  189. 0xEF02,
  190. (ULONG_PTR)__FILE__,
  191. __LINE__
  192. );
  193. }
  194. //
  195. // Find the buffer offset within the page
  196. //
  197. // N.B. bufferPageOffset can only be non-zero on the first iteration
  198. //
  199. bufferPageOffset = BYTE_OFFSET(bufferAddress);
  200. //
  201. // Copy from bufferAddress up to the next page boundary...
  202. //
  203. bytesThisCopy = PAGE_SIZE - bufferPageOffset;
  204. //
  205. // ...but no more than bytesLeft.
  206. //
  207. if (bytesThisCopy > bytesLeft) {
  208. bytesThisCopy = bytesLeft;
  209. }
  210. //
  211. // Calculate the base address of this translation entry and the
  212. // offset into it
  213. //
  214. mapAddress = (PCCHAR) translationEntry->VirtualAddress +
  215. bufferPageOffset;
  216. //
  217. // Copy up to one page
  218. //
  219. if (WriteToDevice) {
  220. RtlMoveMemory( mapAddress, bufferAddress, bytesThisCopy );
  221. } else {
  222. RtlMoveMemory( bufferAddress, mapAddress, bytesThisCopy );
  223. }
  224. //
  225. // Update locals and process the next translation entry
  226. //
  227. bytesLeft -= bytesThisCopy;
  228. translationEntry += 1;
  229. MmUnmapReservedMapping(HalpReservedPages, HAL_POOL_TAG, ReserveMdl);
  230. SrcPFrame++;
  231. ReserveMdl->ByteOffset = 0;
  232. (PCCHAR)ReserveMdl->StartVa += PAGE_SIZE;
  233. ReserveMdl->ByteCount = (PAGE_SIZE > bytesLeft) ? bytesLeft: PAGE_SIZE;
  234. }
  235. KeReleaseSpinLock(&HalpReservedPageLock, Irql);
  236. }
  237. VOID
  238. HalpCopyBufferMap(
  239. IN PMDL Mdl,
  240. IN PTRANSLATION_ENTRY TranslationEntry,
  241. IN PVOID CurrentVa,
  242. IN ULONG Length,
  243. IN BOOLEAN WriteToDevice
  244. )
  245. /*++
  246. Routine Description:
  247. This routine copies the specific data between the user's buffer and the
  248. map register buffer. First a the user buffer is mapped if necessary, then
  249. the data is copied. Finally the user buffer will be unmapped if
  250. necessary.
  251. Arguments:
  252. Mdl - Pointer to the MDL that describes the pages of memory that are
  253. being read or written.
  254. TranslationEntry - The address of the base map register that has been
  255. allocated to the device driver for use in mapping the transfer.
  256. CurrentVa - Current virtual address in the buffer described by the MDL
  257. that the transfer is being done to or from.
  258. Length - The length of the transfer. This determines the number of map
  259. registers that need to be written to map the transfer.
  260. WriteToDevice - Boolean value that indicates whether this is a write
  261. to the device from memory (TRUE), or vice versa.
  262. Return Value:
  263. None.
  264. --*/
  265. {
  266. PCCHAR bufferAddress;
  267. PCCHAR mapAddress;
  268. ULONG bytesLeft;
  269. ULONG bytesThisCopy;
  270. ULONG bufferPageOffset;
  271. PTRANSLATION_ENTRY translationEntry;
  272. //
  273. // Get the system address of the MDL, if we run out of PTEs try safe
  274. // method
  275. //
  276. bufferAddress = MmGetSystemAddressForMdlSafe(Mdl, HighPagePriority);
  277. if (bufferAddress == NULL) {
  278. //
  279. // Our caller's buffer is unmapped, and the memory manager is out
  280. // of PTEs, try to use reserve page method
  281. //
  282. if (HalpReservedPages != NULL) {
  283. HalpCopyBufferMapSafe(Mdl,
  284. TranslationEntry,
  285. CurrentVa,
  286. Length,
  287. WriteToDevice);
  288. return;
  289. }
  290. //
  291. // The DMA transfer cannot be completed, the system is now unstable
  292. //
  293. KeBugCheckEx(HAL_MEMORY_ALLOCATION,
  294. PAGE_SIZE,
  295. 0xEF01,
  296. (ULONG_PTR)__FILE__,
  297. __LINE__
  298. );
  299. }
  300. //
  301. // Calculate the actual start of the buffer based on the system VA and
  302. // the current VA.
  303. //
  304. bufferAddress += (PCCHAR) CurrentVa - (PCCHAR) MmGetMdlVirtualAddress(Mdl);
  305. //
  306. // Get local copies of Length and TranslationEntry as they will be
  307. // decremented/incremented respectively.
  308. //
  309. bytesLeft = Length;
  310. translationEntry = TranslationEntry;
  311. //
  312. // Copy the data one translation entry at a time.
  313. //
  314. while (bytesLeft > 0) {
  315. //
  316. // Find the buffer offset within the page.
  317. //
  318. // N.B. bufferPageOffset can only be non-zero on the first iteration.
  319. //
  320. bufferPageOffset = BYTE_OFFSET(bufferAddress);
  321. //
  322. // Copy from bufferAddress up to the next page boundary...
  323. //
  324. bytesThisCopy = PAGE_SIZE - bufferPageOffset;
  325. //
  326. // ...but no more than bytesLeft.
  327. //
  328. if (bytesThisCopy > bytesLeft) {
  329. bytesThisCopy = bytesLeft;
  330. }
  331. //
  332. // Calculate the base address of this translation entry and the
  333. // offset into it.
  334. //
  335. mapAddress = (PCCHAR) translationEntry->VirtualAddress +
  336. bufferPageOffset;
  337. //
  338. // Copy up to one page.
  339. //
  340. if (WriteToDevice) {
  341. RtlMoveMemory( mapAddress, bufferAddress, bytesThisCopy );
  342. } else {
  343. RtlMoveMemory( bufferAddress, mapAddress, bytesThisCopy );
  344. }
  345. //
  346. // Update locals and process the next translation entry.
  347. //
  348. bytesLeft -= bytesThisCopy;
  349. bufferAddress += bytesThisCopy;
  350. translationEntry += 1;
  351. }
  352. }
  353. PVOID
  354. HalAllocateCommonBuffer(
  355. IN PADAPTER_OBJECT AdapterObject,
  356. IN ULONG Length,
  357. OUT PPHYSICAL_ADDRESS LogicalAddress,
  358. IN BOOLEAN CacheEnabled
  359. )
  360. /*++
  361. Routine Description:
  362. This function allocates the memory for a common buffer and maps it so that
  363. it can be accessed by a master device and the CPU.
  364. Arguments:
  365. AdapterObject - Supplies a pointer to the adapter object used by this
  366. device.
  367. Length - Supplies the length of the common buffer to be allocated.
  368. LogicalAddress - Returns the logical address of the common buffer.
  369. CacheEnable - Indicates whether the memeory is cached or not.
  370. Return Value:
  371. Returns the virtual address of the common buffer. If the buffer cannot be
  372. allocated then NULL is returned.
  373. --*/
  374. {
  375. PSINGLE_LIST_ENTRY virtualAddress;
  376. PHYSICAL_ADDRESS minPhysicalAddress;
  377. PHYSICAL_ADDRESS maxPhysicalAddress;
  378. PHYSICAL_ADDRESS logicalAddress;
  379. PHYSICAL_ADDRESS boundaryPhysicalAddress;
  380. ULONGLONG boundaryMask;
  381. UNREFERENCED_PARAMETER( CacheEnabled );
  382. //
  383. // Determine the maximum physical address that this adapter can handle.
  384. //
  385. minPhysicalAddress.QuadPart = 0;
  386. maxPhysicalAddress = HalpGetAdapterMaximumPhysicalAddress( AdapterObject );
  387. //
  388. // Determine the boundary mask for this adapter.
  389. //
  390. if (AdapterObject->MasterDevice) {
  391. //
  392. // This is not an ISA system. The buffer must not cross a 4GB boundary.
  393. // It is predicted that most adapters are incapable of reliably
  394. // transferring across a 4GB boundary.
  395. //
  396. boundaryPhysicalAddress.QuadPart = 0x0000000100000000;
  397. boundaryMask = 0xFFFFFFFF00000000;
  398. } else {
  399. //
  400. // Common buffer cannot cross a 64K boundary.
  401. //
  402. boundaryPhysicalAddress.QuadPart = 0x10000;
  403. boundaryMask = 0xFFFFFFFFFFFF0000;
  404. }
  405. HalDebugPrint((HAL_INFO, "Allocate common buffer below %p\n", maxPhysicalAddress));
  406. //
  407. // Allocate a contiguous buffer.
  408. //
  409. virtualAddress = MmAllocateContiguousMemorySpecifyCache(
  410. Length,
  411. minPhysicalAddress,
  412. maxPhysicalAddress,
  413. boundaryPhysicalAddress,
  414. MmCached );
  415. if (virtualAddress != NULL) {
  416. //
  417. // Got a buffer, get the physical/logical address and see if it
  418. // meets our conditions.
  419. //
  420. logicalAddress = MmGetPhysicalAddress( virtualAddress );
  421. #if DBG
  422. ASSERT (((logicalAddress.QuadPart ^
  423. (logicalAddress.QuadPart + Length - 1)) & boundaryMask) == 0);
  424. #endif
  425. *LogicalAddress = logicalAddress;
  426. }
  427. return virtualAddress;
  428. }
  429. NTSTATUS
  430. HalpAllocateMapRegisters(
  431. IN PADAPTER_OBJECT DmaAdapter,
  432. IN ULONG NumberOfMapRegisters,
  433. IN ULONG BaseAddressCount,
  434. OUT PMAP_REGISTER_ENTRY MapRegisterArray
  435. )
  436. /*++
  437. Routine Description:
  438. Allocates a chunk of map registers for use with MapTransfer/Flush,
  439. NOTE: Caller is responsible to free map registers for each base
  440. address, same as when calling AllocateAdapterChannel if
  441. a driver's execution routine returns DeallocateObject-
  442. KeepRegisters
  443. This routine must be called at IRQL <= PASSIVE_LEVEL
  444. Arguments:
  445. DmaAdapter - Pointer to the dma adapter for this request
  446. NumberOfMapRegisters - Number of map registers per allocation
  447. BaseAddressCount - Number of base allocations
  448. MapRegisterArray - Pointer to a map register array to return base
  449. addresses of allocations
  450. Return Value:
  451. STATUS_SUCCESS or error
  452. --*/
  453. {
  454. KIRQL Irql;
  455. ULONG Index;
  456. ULONG MapRegisterNumber;
  457. PADAPTER_OBJECT MasterAdapter;
  458. PAGED_CODE();
  459. MasterAdapter = DmaAdapter->MasterAdapter;
  460. //
  461. // There shouldn't be any legacy adapters on _WIN64
  462. //
  463. #if 0
  464. //
  465. // This routine directly munges the master adapter bitmap, and does not
  466. // deal with channels, or the legacy DMA hardware
  467. //
  468. if (DmaAdapter->LegacyAdapter) {
  469. return STATUS_INVALID_DEVICE_REQUEST;
  470. }
  471. #endif
  472. //
  473. // This adapter doesn't require map registers, or they are asking
  474. // for zero, set each BaseAddress to NULL
  475. //
  476. if (((BaseAddressCount * NumberOfMapRegisters) == 0) ||
  477. (!DmaAdapter->NeedsMapRegisters)) {
  478. for (Index = 0; Index < BaseAddressCount; Index++) {
  479. MapRegisterArray[Index].MapRegister = NULL;
  480. }
  481. return STATUS_SUCCESS;
  482. }
  483. //
  484. // If this request is too piggy, or if the adapter has no map
  485. // registers, fail this request
  486. //
  487. if (((NumberOfMapRegisters * BaseAddressCount) >
  488. (4 * MAXIMUM_PCI_MAP_REGISTER)) ||
  489. (DmaAdapter->MapRegistersPerChannel == 0)) {
  490. return STATUS_INSUFFICIENT_RESOURCES;
  491. }
  492. //
  493. // Each individual allocation must not exceed the number of map
  494. // we returned from IoGetDmaAdapter
  495. //
  496. if (NumberOfMapRegisters > DmaAdapter->MapRegistersPerChannel) {
  497. return STATUS_INVALID_PARAMETER;
  498. }
  499. for (Index = 0; Index < BaseAddressCount; Index++) {
  500. MapRegisterNumber = (ULONG)-1;
  501. //
  502. // We need to lock the master adapter before we fondle its bitmap
  503. //
  504. KeAcquireSpinLock(&MasterAdapter->SpinLock, &Irql);
  505. //
  506. // This routine is meant to be called during init to allocate a wad
  507. // of map registers in one fell swoop, it's primary consumer is
  508. // NDIS, and it's primary purpose is to ease up map register
  509. // consumption, so, if there is already an adapter waiting for map
  510. // registers, then there are two possibilities, (1) a work item
  511. // has been queued to grow more translations, or (2) there are
  512. // none left and they are stuck waiting for a free, if it's the
  513. // latter then we are going to fail too, and if it's the former,
  514. // then our bid to allocate up to 64 map registers, out of
  515. // perhaps thousands, should not dramtically decrease the waiters
  516. // chances to have a reasonably sized request satisfied, moreover,
  517. // since this function is only used during init, we will not be
  518. // starving out other drivers during run time in low map register
  519. // situation, therfore, although it is rude for us to go back door
  520. // and allocate registers without checking and/or satifying any
  521. // requests made earlier during init, our cause is a noble one,
  522. // so we will ignore any queued requests
  523. //
  524. //if (IsListEmpty(&MasterAdapter->AdapterQueue)) {
  525. MapRegisterNumber = RtlFindClearBitsAndSet(
  526. MasterAdapter->MapRegisters,
  527. NumberOfMapRegisters,
  528. 0
  529. );
  530. //}
  531. KeReleaseSpinLock(&MasterAdapter->SpinLock, Irql);
  532. if (MapRegisterNumber == -1) {
  533. BOOLEAN Allocated;
  534. ULONG BytesToGrow;
  535. //
  536. // HalpGrowMapBuffers() takes a byte count
  537. //
  538. BytesToGrow = (NumberOfMapRegisters * PAGE_SIZE) +
  539. INCREMENT_MAP_BUFFER_SIZE;
  540. //
  541. // We must own this lock in order to call the grow function
  542. //
  543. ACQUIRE_NEW_ADAPTER_LOCK();
  544. Allocated = HalpGrowMapBuffers(MasterAdapter, BytesToGrow);
  545. RELEASE_NEW_ADAPTER_LOCK();
  546. if (Allocated) {
  547. //
  548. // Lock the master adapter before changing its bitmap
  549. //
  550. KeAcquireSpinLock(&MasterAdapter->SpinLock, &Irql);
  551. //
  552. // Again, we will ignore any queued requests (see note
  553. // above)
  554. //
  555. //if (IsListEmpty(&MasterAdapter->AdapterQueue)) {
  556. MapRegisterNumber = RtlFindClearBitsAndSet(
  557. MasterAdapter->MapRegisters,
  558. NumberOfMapRegisters,
  559. 0
  560. );
  561. //}
  562. KeReleaseSpinLock(&MasterAdapter->SpinLock, Irql);
  563. //
  564. // That's wierd! We grew the bitmap, and still failed ?
  565. //
  566. if (MapRegisterNumber == -1) {
  567. break;
  568. }
  569. //
  570. // We were unable to allocate additional translation
  571. // buffers
  572. //
  573. } else {
  574. break;
  575. }
  576. }
  577. //
  578. // Save the base address for these translation buffers
  579. //
  580. MapRegisterArray[Index].MapRegister =
  581. ((PTRANSLATION_ENTRY)MasterAdapter->MapRegisterBase +
  582. MapRegisterNumber);
  583. }
  584. //
  585. // Cleanup and fail, we couldn't allocate them all!
  586. //
  587. if (Index != BaseAddressCount) {
  588. while (Index > 0) {
  589. IoFreeMapRegisters(MasterAdapter,
  590. MapRegisterArray[Index - 1].MapRegister,
  591. NumberOfMapRegisters);
  592. Index--;
  593. }
  594. return STATUS_INSUFFICIENT_RESOURCES;
  595. }
  596. return STATUS_SUCCESS;
  597. }
  598. BOOLEAN
  599. HalFlushCommonBuffer(
  600. IN PADAPTER_OBJECT AdapterObject,
  601. IN ULONG Length,
  602. IN PHYSICAL_ADDRESS LogicalAddress,
  603. IN PVOID VirtualAddress
  604. )
  605. /*++
  606. Routine Description:
  607. This function is called to flush any hardware adapter buffers when the
  608. driver needs to read data written by an I/O master device to a common
  609. buffer.
  610. Arguments:
  611. AdapterObject - Supplies a pointer to the adapter object used by this
  612. device.
  613. Length - Supplies the length of the common buffer. This should be the same
  614. value used for the allocation of the buffer.
  615. LogicalAddress - Supplies the logical address of the common buffer. This
  616. must be the same value return by HalAllocateCommonBuffer.
  617. VirtualAddress - Supplies the virtual address of the common buffer. This
  618. must be the same value return by HalAllocateCommonBuffer.
  619. Return Value:
  620. Returns TRUE if no errors were detected. Otherwise, FALSE is returned.
  621. --*/
  622. {
  623. UNREFERENCED_PARAMETER( AdapterObject );
  624. UNREFERENCED_PARAMETER( Length );
  625. UNREFERENCED_PARAMETER( LogicalAddress );
  626. UNREFERENCED_PARAMETER( VirtualAddress );
  627. return(TRUE);
  628. }
  629. VOID
  630. HalFreeCommonBuffer(
  631. IN PADAPTER_OBJECT AdapterObject,
  632. IN ULONG Length,
  633. IN PHYSICAL_ADDRESS LogicalAddress,
  634. IN PVOID VirtualAddress,
  635. IN BOOLEAN CacheEnabled
  636. )
  637. /*++
  638. Routine Description:
  639. This function frees a common buffer and all of the resources it uses.
  640. Arguments:
  641. AdapterObject - Supplies a pointer to the adapter object used by this
  642. device.
  643. Length - Supplies the length of the common buffer. This should be the same
  644. value used for the allocation of the buffer.
  645. LogicalAddress - Supplies the logical address of the common buffer. This
  646. must be the same value returned by HalAllocateCommonBuffer.
  647. VirtualAddress - Supplies the virtual address of the common buffer. This
  648. must be the same value returned by HalAllocateCommonBuffer.
  649. CacheEnable - Indicates whether the memory is cached or not.
  650. Return Value:
  651. None
  652. --*/
  653. {
  654. UNREFERENCED_PARAMETER( AdapterObject );
  655. UNREFERENCED_PARAMETER( LogicalAddress );
  656. MmFreeContiguousMemorySpecifyCache(VirtualAddress,
  657. Length,
  658. MmCached);
  659. }
  660. NTSTATUS
  661. HalCalculateScatterGatherListSize(
  662. IN PADAPTER_OBJECT AdapterObject,
  663. IN OPTIONAL PMDL Mdl,
  664. IN PVOID CurrentVa,
  665. IN ULONG Length,
  666. OUT PULONG ScatterGatherListSize,
  667. OUT OPTIONAL PULONG pNumberOfMapRegisters
  668. )
  669. /*++
  670. Routine Description:
  671. This routine calculates the size of the scatter/gather list that
  672. needs to be allocated for a given virtual address range or MDL.
  673. Arguments:
  674. AdapterObject - Pointer to the adapter control object to allocate to the
  675. driver.
  676. Mdl - Pointer to the MDL that describes the pages of memory that are being
  677. read or written.
  678. CurrentVa - Current virtual address in the buffer described by the MDL
  679. that the transfer is being done to or from.
  680. Length - Supplies the length of the transfer.
  681. Return Value:
  682. Returns STATUS_SUCCESS unless too many map registers are requested or
  683. memory for the scatter/gather list could not be allocated.
  684. Notes:
  685. --*/
  686. {
  687. PHAL_WAIT_CONTEXT_BLOCK WaitBlock;
  688. PMDL TempMdl;
  689. PSCATTER_GATHER_LIST ScatterGather;
  690. PSCATTER_GATHER_ELEMENT Element;
  691. ULONG NumberOfMapRegisters;
  692. ULONG ContextSize;
  693. ULONG TransferLength;
  694. ULONG MdlLength;
  695. PUCHAR MdlVa;
  696. NTSTATUS Status;
  697. ULONG PageOffset;
  698. if (ARGUMENT_PRESENT(Mdl)) {
  699. MdlVa = MmGetMdlVirtualAddress(Mdl);
  700. //
  701. // Calculate the number of required map registers.
  702. //
  703. TempMdl = Mdl;
  704. TransferLength = TempMdl->ByteCount - (ULONG)((PUCHAR) CurrentVa - MdlVa);
  705. MdlLength = TransferLength;
  706. PageOffset = BYTE_OFFSET(CurrentVa);
  707. NumberOfMapRegisters = 0;
  708. //
  709. // The virtual address should fit in the first MDL.
  710. //
  711. ASSERT((ULONG)((PUCHAR)CurrentVa - MdlVa) <= TempMdl->ByteCount);
  712. //
  713. // Loop through the any chained MDLs accumulating the the required
  714. // number of map registers.
  715. //
  716. while (TransferLength < Length && TempMdl->Next != NULL) {
  717. NumberOfMapRegisters += (PageOffset + MdlLength + PAGE_SIZE - 1) >>
  718. PAGE_SHIFT;
  719. TempMdl = TempMdl->Next;
  720. PageOffset = TempMdl->ByteOffset;
  721. MdlLength = TempMdl->ByteCount;
  722. TransferLength += MdlLength;
  723. }
  724. if ((TransferLength + PAGE_SIZE) < (Length + PageOffset )) {
  725. ASSERT(TransferLength >= Length);
  726. return(STATUS_BUFFER_TOO_SMALL);
  727. }
  728. //
  729. // Calculate the last number of map registers based on the requested
  730. // length not the length of the last MDL.
  731. //
  732. ASSERT( TransferLength <= MdlLength + Length );
  733. NumberOfMapRegisters += (PageOffset + Length + MdlLength - TransferLength +
  734. PAGE_SIZE - 1) >> PAGE_SHIFT;
  735. if (NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel) {
  736. return(STATUS_INSUFFICIENT_RESOURCES);
  737. }
  738. } else {
  739. //
  740. // Determine the number of pages required to map the buffer described
  741. // by CurrentVa and Length.
  742. //
  743. NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(CurrentVa, Length);
  744. }
  745. //
  746. // Calculate how much memory is required for the context structure.
  747. //
  748. ContextSize = NumberOfMapRegisters * sizeof( SCATTER_GATHER_ELEMENT ) +
  749. sizeof( SCATTER_GATHER_LIST );
  750. //
  751. // If the adapter does not need map registers then most of this code
  752. // can be bypassed. Just build the scatter/gather list and give it
  753. // to the caller.
  754. //
  755. if (AdapterObject->NeedsMapRegisters) {
  756. ContextSize += FIELD_OFFSET( HAL_WAIT_CONTEXT_BLOCK, ScatterGather );
  757. if (ContextSize < sizeof( HAL_WAIT_CONTEXT_BLOCK )) {
  758. ContextSize = sizeof( HAL_WAIT_CONTEXT_BLOCK );
  759. }
  760. }
  761. //
  762. // Return the list size.
  763. //
  764. *ScatterGatherListSize = ContextSize;
  765. if (pNumberOfMapRegisters) {
  766. *pNumberOfMapRegisters = NumberOfMapRegisters;
  767. }
  768. return( STATUS_SUCCESS );
  769. }
  770. NTSTATUS
  771. HalGetScatterGatherList (
  772. IN PADAPTER_OBJECT AdapterObject,
  773. IN PDEVICE_OBJECT DeviceObject,
  774. IN PMDL Mdl,
  775. IN PVOID CurrentVa,
  776. IN ULONG Length,
  777. IN PDRIVER_LIST_CONTROL ExecutionRoutine,
  778. IN PVOID Context,
  779. IN BOOLEAN WriteToDevice
  780. )
  781. {
  782. return (HalBuildScatterGatherList(AdapterObject,
  783. DeviceObject,
  784. Mdl,
  785. CurrentVa,
  786. Length,
  787. ExecutionRoutine,
  788. Context,
  789. WriteToDevice,
  790. NULL,
  791. 0
  792. ));
  793. }
  794. NTSTATUS
  795. HalBuildScatterGatherList (
  796. IN PADAPTER_OBJECT AdapterObject,
  797. IN PDEVICE_OBJECT DeviceObject,
  798. IN PMDL Mdl,
  799. IN PVOID CurrentVa,
  800. IN ULONG Length,
  801. IN PDRIVER_LIST_CONTROL ExecutionRoutine,
  802. IN PVOID Context,
  803. IN BOOLEAN WriteToDevice,
  804. IN PVOID ScatterGatherBuffer,
  805. IN ULONG ScatterGatherBufferLength
  806. )
  807. /*++
  808. Routine Description:
  809. This routine allocates the adapter channel specified by the adapter
  810. object. Next a scatter/gather list is built based on the MDL, the
  811. CurrentVa and the requested Length. Finally the driver's execution
  812. function is called with the scatter/gather list. The adapter is
  813. released when after the execution function returns.
  814. The scatter/gather list is allocated if a buffer is not passed and is
  815. freed by calling PutScatterGatherList. If a buffer is passed its used instead
  816. and this buffer is not freed in PutScatterGatherList.
  817. Arguments:
  818. AdapterObject - Pointer to the adapter control object to allocate to the
  819. driver.
  820. DeviceObject - Pointer to the device object that is allocating the
  821. adapter.
  822. Mdl - Pointer to the MDL that describes the pages of memory that are being
  823. read or written.
  824. CurrentVa - Current virtual address in the buffer described by the MDL
  825. that the transfer is being done to or from.
  826. Length - Supplies the length of the transfer.
  827. ExecutionRoutine - The address of the driver's execution routine that is
  828. invoked once the adapter channel (and possibly map registers) have been
  829. allocated.
  830. Context - An untyped longword context parameter passed to the driver's
  831. execution routine.
  832. WriteToDevice - Supplies the value that indicates whether this is a
  833. write to the device from memory (TRUE), or vice versa.
  834. Return Value:
  835. 
  836. Returns STATUS_SUCCESS unless too many map registers are requested or
  837. memory for the scatter/gather list could not be allocated.
  838. Notes:
  839. Note that this routine MUST be invoked at DISPATCH_LEVEL or above.
  840. The data in the buffer cannot be accessed until the put scatter/gather function has been called.
  841. --*/
  842. {
  843. PHAL_WAIT_CONTEXT_BLOCK WaitBlock;
  844. PMDL TempMdl;
  845. PSCATTER_GATHER_LIST ScatterGather;
  846. PSCATTER_GATHER_ELEMENT Element;
  847. ULONG NumberOfMapRegisters;
  848. ULONG ContextSize;
  849. ULONG TransferLength;
  850. ULONG MdlLength;
  851. PUCHAR MdlVa;
  852. NTSTATUS Status;
  853. PPFN_NUMBER PageFrame;
  854. ULONG PageOffset;
  855. if (!Mdl) {
  856. return (STATUS_INVALID_PARAMETER);
  857. }
  858. //
  859. // If the adapter does not need map registers then most of this code
  860. // can be bypassed. Just build the scatter/gather list and give it
  861. // to the caller.
  862. //
  863. if (!AdapterObject->NeedsMapRegisters) {
  864. if (ScatterGatherBuffer) {
  865. //
  866. // Ensure that we at least have enough buffer length for the
  867. // header.
  868. //
  869. if (ScatterGatherBufferLength < sizeof(SCATTER_GATHER_LIST)) {
  870. return (STATUS_BUFFER_TOO_SMALL);
  871. }
  872. ScatterGather = ScatterGatherBuffer;
  873. } else {
  874. Status = HalCalculateScatterGatherListSize(AdapterObject,
  875. Mdl,
  876. CurrentVa,
  877. Length,
  878. &ContextSize,
  879. &NumberOfMapRegisters
  880. );
  881. if (!NT_SUCCESS(Status)) {
  882. return (Status);
  883. }
  884. ScatterGather = ExAllocatePoolWithTag( NonPagedPool,
  885. ContextSize,
  886. HAL_POOL_TAG );
  887. if (ScatterGather == NULL) {
  888. return( STATUS_INSUFFICIENT_RESOURCES );
  889. }
  890. }
  891. MdlVa = MmGetMdlVirtualAddress(Mdl);
  892. ScatterGather->Reserved = 0;
  893. Element = ScatterGather->Elements;
  894. TempMdl = Mdl;
  895. TransferLength = Length;
  896. MdlLength = TempMdl->ByteCount - (ULONG)((PUCHAR) CurrentVa - MdlVa);
  897. PageOffset = BYTE_OFFSET(CurrentVa);
  898. //
  899. // Calculate where to start in the MDL.
  900. //
  901. PageFrame = (PPFN_NUMBER)(TempMdl+1);
  902. PageFrame += ((UINT_PTR) CurrentVa - ((UINT_PTR) MdlVa & ~(PAGE_SIZE - 1)))
  903. >> PAGE_SHIFT;
  904. //
  905. // Loop build the list for each MDL.
  906. //
  907. while (TransferLength > 0) {
  908. if (MdlLength > TransferLength) {
  909. MdlLength = TransferLength;
  910. }
  911. TransferLength -= MdlLength;
  912. //
  913. // Loop building the list for the elements within the MDL.
  914. //
  915. while (MdlLength > 0) {
  916. //
  917. // Ensure that we never step outside the length of our buffer.
  918. // We need to validate the length because we don't validate the length at the beginning
  919. // if the buffer was allocated by the caller.
  920. //
  921. if (ScatterGatherBuffer) {
  922. if ((PUCHAR)Element >
  923. ((PUCHAR)ScatterGatherBuffer + ScatterGatherBufferLength - sizeof(SCATTER_GATHER_ELEMENT))) {
  924. return (STATUS_BUFFER_TOO_SMALL);
  925. }
  926. }
  927. //
  928. // Compute the starting address of the transfer.
  929. //
  930. Element->Address.QuadPart =
  931. (ULONGLONG)((*PageFrame << PAGE_SHIFT) + PageOffset);
  932. Element->Length = PAGE_SIZE - PageOffset;
  933. if (Element->Length > MdlLength ) {
  934. Element->Length = MdlLength;
  935. }
  936. ASSERT( (ULONG) MdlLength >= Element->Length );
  937. MdlLength -= Element->Length;
  938. //
  939. // Combine contiguous pages.
  940. //
  941. if (Element != ScatterGather->Elements ) {
  942. if (Element->Address.QuadPart ==
  943. (Element - 1)->Address.QuadPart + (Element - 1)->Length) {
  944. //
  945. // If the previous page frame is contiguous with this one,
  946. // but it crosses a 4GB boundary don't coalesce
  947. //
  948. if (((*PageFrame ^ (*PageFrame - 1)) & 0xFFFFFFFFFFF00000UI64) == 0) {
  949. //
  950. // Add the new length to the old length.
  951. //
  952. (Element - 1)->Length += Element->Length;
  953. //
  954. // Reuse the current element.
  955. //
  956. Element--;
  957. }
  958. }
  959. }
  960. PageOffset = 0;
  961. Element++;
  962. PageFrame++;
  963. }
  964. if (TempMdl->Next == NULL) {
  965. //
  966. // There are a few cases where the buffer described by the MDL
  967. // is less than the transfer length. This occurs when the
  968. // file system is transfering the last page of the file and
  969. // MM defines the MDL to be the file size and the file system
  970. // rounds the write up to a sector. This extra should never
  971. // cross a page boundary. Add this extra to the length of
  972. // the last element.
  973. //
  974. ASSERT(((Element - 1)->Length & (PAGE_SIZE - 1)) + TransferLength <= PAGE_SIZE );
  975. (Element - 1)->Length += TransferLength;
  976. break;
  977. }
  978. //
  979. // Advance to the next MDL. Update the current VA and the MdlLength.
  980. //
  981. TempMdl = TempMdl->Next;
  982. PageOffset = MmGetMdlByteOffset(TempMdl);
  983. MdlLength = TempMdl->ByteCount;
  984. PageFrame = (PPFN_NUMBER)(TempMdl+1);
  985. }
  986. //
  987. // Set the number of elements actually used.
  988. //
  989. ScatterGather->NumberOfElements = (ULONG)(Element - ScatterGather->Elements);
  990. if (ScatterGatherBuffer) {
  991. ScatterGather->Reserved = HAL_WCB_DRIVER_BUFFER;
  992. }
  993. //
  994. // Call the driver with the scatter/gather list.
  995. //
  996. ExecutionRoutine( DeviceObject,
  997. DeviceObject->CurrentIrp,
  998. ScatterGather,
  999. Context );
  1000. return STATUS_SUCCESS;
  1001. }
  1002. Status = HalCalculateScatterGatherListSize(AdapterObject,
  1003. Mdl,
  1004. CurrentVa,
  1005. Length,
  1006. &ContextSize,
  1007. &NumberOfMapRegisters
  1008. );
  1009. if (!NT_SUCCESS(Status)) {
  1010. return Status;
  1011. }
  1012. if (ScatterGatherBuffer) {
  1013. if (ScatterGatherBufferLength < ContextSize) {
  1014. return (STATUS_BUFFER_TOO_SMALL);
  1015. }
  1016. WaitBlock = ScatterGatherBuffer;
  1017. } else {
  1018. WaitBlock = ExAllocatePoolWithTag(NonPagedPool, ContextSize, HAL_POOL_TAG);
  1019. if (WaitBlock == NULL) {
  1020. return( STATUS_INSUFFICIENT_RESOURCES );
  1021. }
  1022. }
  1023. if (ScatterGatherBuffer) {
  1024. WaitBlock->Flags |= HAL_WCB_DRIVER_BUFFER;
  1025. } else {
  1026. WaitBlock->Flags = 0;
  1027. }
  1028. //
  1029. // Save the interesting data in the wait block.
  1030. //
  1031. WaitBlock->Mdl = Mdl;
  1032. WaitBlock->DmaMdl = NULL;
  1033. WaitBlock->CurrentVa = CurrentVa;
  1034. WaitBlock->Length = Length;
  1035. WaitBlock->DriverExecutionRoutine = ExecutionRoutine;
  1036. WaitBlock->DriverContext = Context;
  1037. WaitBlock->AdapterObject = AdapterObject;
  1038. WaitBlock->WriteToDevice = WriteToDevice;
  1039. WaitBlock->NumberOfMapRegisters = NumberOfMapRegisters;
  1040. WaitBlock->Wcb.DeviceContext = WaitBlock;
  1041. WaitBlock->Wcb.DeviceObject = DeviceObject;
  1042. WaitBlock->Wcb.CurrentIrp = DeviceObject->CurrentIrp;
  1043. //
  1044. // Call the HAL to allocate the adapter channel.
  1045. // HalpAllocateAdapterCallback will fill in the scatter/gather list.
  1046. //
  1047. Status = HalAllocateAdapterChannel( AdapterObject,
  1048. &WaitBlock->Wcb,
  1049. NumberOfMapRegisters,
  1050. HalpAllocateAdapterCallback );
  1051. //
  1052. // If HalAllocateAdapterChannel failed then free the wait block.
  1053. //
  1054. if (!NT_SUCCESS( Status)) {
  1055. ExFreePool( WaitBlock );
  1056. }
  1057. return( Status );
  1058. }
  1059. VOID
  1060. HalPutScatterGatherList (
  1061. IN PADAPTER_OBJECT AdapterObject,
  1062. IN PSCATTER_GATHER_LIST ScatterGather,
  1063. IN BOOLEAN WriteToDevice
  1064. )
  1065. /*++
  1066. Routine Description:
  1067. This function frees the map registers allocated for the scatter gather list. It can also free the
  1068. scatter gather buffer and any associated MDLs.
  1069. Arguments:
  1070. ScatterGather - The scatter gather buffer
  1071. WriteToDevice - Supplies the value that indicates whether this is a
  1072. write to the device from memory (TRUE), or vice versa.
  1073. Return Value:
  1074. Returns a success or error status.
  1075. --*/
  1076. {
  1077. PHAL_WAIT_CONTEXT_BLOCK WaitBlock = (PVOID) ScatterGather->Reserved;
  1078. PTRANSLATION_ENTRY TranslationEntry;
  1079. ULONG TransferLength;
  1080. ULONG MdlLength;
  1081. PMDL Mdl;
  1082. PMDL tempMdl;
  1083. PMDL nextMdl;
  1084. PUCHAR CurrentVa;
  1085. //
  1086. // If the reserved field was empty then just free the list and return.
  1087. //
  1088. if (WaitBlock == NULL) {
  1089. ASSERT(!AdapterObject->NeedsMapRegisters);
  1090. ExFreePool( ScatterGather );
  1091. return;
  1092. }
  1093. if (WaitBlock == (PVOID)HAL_WCB_DRIVER_BUFFER) {
  1094. ASSERT(!AdapterObject->NeedsMapRegisters);
  1095. return;
  1096. }
  1097. ASSERT( WaitBlock == CONTAINING_RECORD( ScatterGather, HAL_WAIT_CONTEXT_BLOCK, ScatterGather ));
  1098. //
  1099. // Setup for the first MDL. We expect the MDL pointer to be pointing
  1100. // at the first used mdl.
  1101. //
  1102. Mdl = WaitBlock->Mdl;
  1103. CurrentVa = WaitBlock->CurrentVa;
  1104. #if DBG
  1105. ASSERT( CurrentVa >= (PUCHAR) MmGetMdlVirtualAddress(Mdl));
  1106. if (MmGetMdlVirtualAddress(Mdl) < (PVOID)((PUCHAR) MmGetMdlVirtualAddress(Mdl) + Mdl->ByteCount )) {
  1107. ASSERT( CurrentVa < (PUCHAR) MmGetMdlVirtualAddress(Mdl) + Mdl->ByteCount );
  1108. }
  1109. #endif
  1110. MdlLength = Mdl->ByteCount - (ULONG)(CurrentVa - (PUCHAR) MmGetMdlVirtualAddress(Mdl));
  1111. TransferLength = WaitBlock->Length;
  1112. TranslationEntry = WaitBlock->MapRegisterBase;
  1113. //
  1114. // Loop through the used MDLs, calling IoFlushAdapterBuffers.
  1115. //
  1116. while (TransferLength > 0) {
  1117. //
  1118. // Do not perform a flush for buffers of zero length.
  1119. //
  1120. if (MdlLength > 0) {
  1121. if (MdlLength > TransferLength) {
  1122. MdlLength = TransferLength;
  1123. }
  1124. TransferLength -= MdlLength;
  1125. IoFlushAdapterBuffers( AdapterObject,
  1126. Mdl,
  1127. TranslationEntry,
  1128. CurrentVa,
  1129. MdlLength,
  1130. WriteToDevice );
  1131. TranslationEntry += ADDRESS_AND_SIZE_TO_SPAN_PAGES( CurrentVa,
  1132. MdlLength );
  1133. }
  1134. if (Mdl->Next == NULL) {
  1135. break;
  1136. }
  1137. //
  1138. // Advance to the next MDL. Update the current VA and the MdlLength.
  1139. //
  1140. Mdl = Mdl->Next;
  1141. CurrentVa = MmGetMdlVirtualAddress(Mdl);
  1142. MdlLength = Mdl->ByteCount;
  1143. }
  1144. IoFreeMapRegisters( AdapterObject,
  1145. WaitBlock->MapRegisterBase,
  1146. WaitBlock->NumberOfMapRegisters
  1147. );
  1148. if (WaitBlock->DmaMdl) {
  1149. tempMdl = WaitBlock->DmaMdl;
  1150. while (tempMdl) {
  1151. nextMdl = tempMdl->Next;
  1152. //
  1153. // If the MDL was mapped by the driver unmap it here.
  1154. //
  1155. if (tempMdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) {
  1156. MmUnmapLockedPages(tempMdl->MappedSystemVa, tempMdl);
  1157. }
  1158. IoFreeMdl(tempMdl);
  1159. tempMdl = nextMdl;
  1160. }
  1161. }
  1162. if (!(WaitBlock->Flags & HAL_WCB_DRIVER_BUFFER)) {
  1163. ExFreePool( WaitBlock );
  1164. }
  1165. }
  1166. IO_ALLOCATION_ACTION
  1167. HalpAllocateAdapterCallback (
  1168. IN struct _DEVICE_OBJECT *DeviceObject,
  1169. IN struct _IRP *Irp,
  1170. IN PVOID MapRegisterBase,
  1171. IN PVOID Context
  1172. )
  1173. /*++
  1174. Routine Description:
  1175. This routine is called when the adapter object and map registers are
  1176. available for the data transfer. This routines saves the map register
  1177. base away. If all of the required bases have not been saved then it
  1178. returns. Otherwise it routine builds the entire scatter/gather
  1179. list by calling IoMapTransfer. After the list is build it is passed to
  1180. the driver.
  1181. Arguments:
  1182. DeviceObject - Pointer to the device object that is allocating the
  1183. adapter.
  1184. Irp - Supplies the map register offset assigned for this callback.
  1185. MapRegisterBase - Supplies the map register base for use by the adapter
  1186. routines.
  1187. Context - Supplies a pointer to the xhal wait contorl block.
  1188. Return Value:
  1189. Returns DeallocateObjectKeepRegisters.
  1190. --*/
  1191. {
  1192. PHAL_WAIT_CONTEXT_BLOCK WaitBlock = Context;
  1193. ULONG TransferLength;
  1194. LONG MdlLength;
  1195. PMDL Mdl;
  1196. PUCHAR CurrentVa;
  1197. PSCATTER_GATHER_LIST ScatterGather;
  1198. PSCATTER_GATHER_ELEMENT Element;
  1199. PTRANSLATION_ENTRY TranslationEntry = MapRegisterBase;
  1200. PTRANSLATION_ENTRY NextEntry;
  1201. PDRIVER_LIST_CONTROL DriverExecutionRoutine;
  1202. PVOID DriverContext;
  1203. PIRP CurrentIrp;
  1204. PADAPTER_OBJECT AdapterObject;
  1205. BOOLEAN WriteToDevice;
  1206. //
  1207. // Save the map register base.
  1208. //
  1209. WaitBlock->MapRegisterBase = MapRegisterBase;
  1210. //
  1211. // Save the data that will be over written by the scatter gather list.
  1212. //
  1213. DriverExecutionRoutine = WaitBlock->DriverExecutionRoutine;
  1214. DriverContext = WaitBlock->DriverContext;
  1215. CurrentIrp = WaitBlock->Wcb.CurrentIrp;
  1216. AdapterObject = WaitBlock->AdapterObject;
  1217. WriteToDevice = WaitBlock->WriteToDevice;
  1218. //
  1219. // Put the scatter gatther list after wait block. Add a back pointer to
  1220. // the beginning of the wait block.
  1221. //
  1222. ScatterGather = &WaitBlock->ScatterGather;
  1223. ScatterGather->Reserved = (UINT_PTR) WaitBlock;
  1224. Element = ScatterGather->Elements;
  1225. //
  1226. // Setup for the first MDL. We expect the MDL pointer to be pointing
  1227. // at the first used MDL.
  1228. //
  1229. Mdl = WaitBlock->Mdl;
  1230. CurrentVa = WaitBlock->CurrentVa;
  1231. #if DBG
  1232. ASSERT( CurrentVa >= (PUCHAR) MmGetMdlVirtualAddress(Mdl));
  1233. if (MmGetMdlVirtualAddress(Mdl) < (PVOID)((PUCHAR) MmGetMdlVirtualAddress(Mdl) + Mdl->ByteCount )) {
  1234. ASSERT( CurrentVa < (PUCHAR) MmGetMdlVirtualAddress(Mdl) + Mdl->ByteCount );
  1235. }
  1236. #endif
  1237. MdlLength = Mdl->ByteCount - (ULONG)(CurrentVa - (PUCHAR) MmGetMdlVirtualAddress(Mdl));
  1238. TransferLength = WaitBlock->Length;
  1239. //
  1240. // Loop building the list for each MDL.
  1241. //
  1242. while (TransferLength > 0) {
  1243. if ((ULONG) MdlLength > TransferLength) {
  1244. MdlLength = TransferLength;
  1245. }
  1246. TransferLength -= MdlLength;
  1247. NextEntry = TranslationEntry;
  1248. if (MdlLength > 0) {
  1249. NextEntry += ADDRESS_AND_SIZE_TO_SPAN_PAGES( CurrentVa,
  1250. MdlLength );
  1251. }
  1252. //
  1253. // Loop building the list for the elments within an MDL.
  1254. //
  1255. while (MdlLength > 0) {
  1256. Element->Length = MdlLength;
  1257. Element->Address = IoMapTransfer( AdapterObject,
  1258. Mdl,
  1259. MapRegisterBase,
  1260. CurrentVa,
  1261. &Element->Length,
  1262. WriteToDevice );
  1263. ASSERT( (ULONG) MdlLength >= Element->Length );
  1264. MdlLength -= Element->Length;
  1265. CurrentVa += Element->Length;
  1266. Element++;
  1267. }
  1268. if (Mdl->Next == NULL) {
  1269. //
  1270. // There are a few cases where the buffer described by the MDL
  1271. // is less than the transfer length. This occurs when the
  1272. // file system transfering the last page of file and MM defines
  1273. // the MDL to be the file size and the file system rounds the write
  1274. // up to a sector. This extra should never cross a page
  1275. // boundary. Add this extra to the length of the last element.
  1276. //
  1277. ASSERT(((Element - 1)->Length & (PAGE_SIZE - 1)) + TransferLength <= PAGE_SIZE );
  1278. (Element - 1)->Length += TransferLength;
  1279. break;
  1280. }
  1281. //
  1282. // Advance to the next MDL. Update the current VA and the MdlLength.
  1283. //
  1284. Mdl = Mdl->Next;
  1285. CurrentVa = MmGetMdlVirtualAddress(Mdl);
  1286. MdlLength = Mdl->ByteCount;
  1287. TranslationEntry = NextEntry;
  1288. }
  1289. //
  1290. // Set the number of elements actually used.
  1291. //
  1292. ScatterGather->NumberOfElements = (ULONG)(Element - ScatterGather->Elements);
  1293. //
  1294. // Call the driver with the scatter/gather list.
  1295. //
  1296. DriverExecutionRoutine( DeviceObject,
  1297. CurrentIrp,
  1298. ScatterGather,
  1299. DriverContext );
  1300. return( DeallocateObjectKeepRegisters );
  1301. }
  1302. VOID
  1303. IoFreeAdapterChannel(
  1304. IN PADAPTER_OBJECT AdapterObject
  1305. )
  1306. /*++
  1307. Routine Description:
  1308. This routine is invoked to deallocate the specified adapter object.
  1309. Any map registers that were allocated are also automatically deallocated.
  1310. No checks are made to ensure that the adapter is really allocated to
  1311. a device object. However, if it is not, the kernel will bugcheck.
  1312. If another device is waiting in the queue to allocate the adapter object
  1313. it will be pulled from the queue and its execution routine will be
  1314. invoked.
  1315. Arguments:
  1316. AdapterObject - Pointer to the adapter object to be deallocated.
  1317. Return Value:
  1318. None.
  1319. --*/
  1320. {
  1321. PKDEVICE_QUEUE_ENTRY Packet;
  1322. PWAIT_CONTEXT_BLOCK Wcb;
  1323. PADAPTER_OBJECT MasterAdapter;
  1324. BOOLEAN Busy = FALSE;
  1325. IO_ALLOCATION_ACTION Action;
  1326. KIRQL Irql;
  1327. LONG MapRegisterNumber;
  1328. //
  1329. // Begin by getting the address of the master adapter.
  1330. //
  1331. MasterAdapter = AdapterObject->MasterAdapter;
  1332. //
  1333. // Pull requests of the adapter's device wait queue as long as the
  1334. // adapter is free and there are sufficient map registers available.
  1335. //
  1336. while( TRUE ) {
  1337. //
  1338. // Begin by checking to see whether there are any map registers that
  1339. // need to be deallocated. If so, then deallocate them now.
  1340. //
  1341. if (AdapterObject->NumberOfMapRegisters != 0) {
  1342. IoFreeMapRegisters( AdapterObject,
  1343. AdapterObject->MapRegisterBase,
  1344. AdapterObject->NumberOfMapRegisters
  1345. );
  1346. }
  1347. //
  1348. // Simply remove the next entry from the adapter's device wait queue.
  1349. // If one was successfully removed, allocate any map registers that it
  1350. // requires and invoke its execution routine.
  1351. //
  1352. Packet = KeRemoveDeviceQueue( &AdapterObject->ChannelWaitQueue );
  1353. if (Packet == NULL) {
  1354. //
  1355. // There are no more requests - break out of the loop.
  1356. //
  1357. break;
  1358. }
  1359. Wcb = CONTAINING_RECORD( Packet,
  1360. WAIT_CONTEXT_BLOCK,
  1361. WaitQueueEntry );
  1362. AdapterObject->CurrentWcb = Wcb;
  1363. AdapterObject->NumberOfMapRegisters = Wcb->NumberOfMapRegisters;
  1364. //
  1365. // Check to see whether this driver wishes to allocate any map
  1366. // registers. If so, then queue the device object to the master
  1367. // adapter queue to wait for them to become available. If the driver
  1368. // wants map registers, ensure that this adapter has enough total
  1369. // map registers to satisfy the request.
  1370. //
  1371. if (Wcb->NumberOfMapRegisters != 0 &&
  1372. AdapterObject->MasterAdapter != NULL) {
  1373. //
  1374. // Lock the map register bit map and the adapter queue in the
  1375. // master adapter object. The channel structure offset is used as
  1376. // a hint for the register search.
  1377. //
  1378. KeAcquireSpinLock( &MasterAdapter->SpinLock, &Irql );
  1379. MapRegisterNumber = -1;
  1380. if (IsListEmpty( &MasterAdapter->AdapterQueue)) {
  1381. MapRegisterNumber = RtlFindClearBitsAndSet( MasterAdapter->MapRegisters,
  1382. Wcb->NumberOfMapRegisters,
  1383. 0
  1384. );
  1385. }
  1386. if (MapRegisterNumber == -1) {
  1387. //
  1388. // There were not enough free map registers. Queue this request
  1389. // on the master adapter where it will wait until some registers
  1390. // are deallocated.
  1391. //
  1392. InsertTailList( &MasterAdapter->AdapterQueue,
  1393. &AdapterObject->AdapterQueue
  1394. );
  1395. Busy = 1;
  1396. } else {
  1397. AdapterObject->MapRegisterBase = ((PTRANSLATION_ENTRY)
  1398. MasterAdapter->MapRegisterBase + MapRegisterNumber);
  1399. //
  1400. // Set the no scatter/gather flag if scatter/gather is not
  1401. // supported.
  1402. //
  1403. if (!AdapterObject->ScatterGather) {
  1404. AdapterObject->MapRegisterBase = (PVOID)
  1405. ((UINT_PTR) AdapterObject->MapRegisterBase | NO_SCATTER_GATHER);
  1406. }
  1407. }
  1408. KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql );
  1409. } else {
  1410. AdapterObject->MapRegisterBase = NULL;
  1411. AdapterObject->NumberOfMapRegisters = 0;
  1412. }
  1413. //
  1414. // If there were either enough map registers available or no map
  1415. // registers needed to be allocated, invoke the driver's execution
  1416. // routine now.
  1417. //
  1418. if (!Busy) {
  1419. AdapterObject->CurrentWcb = Wcb;
  1420. Action = Wcb->DeviceRoutine( Wcb->DeviceObject,
  1421. Wcb->CurrentIrp,
  1422. AdapterObject->MapRegisterBase,
  1423. Wcb->DeviceContext );
  1424. //
  1425. // If the execution routine would like to have the adapter
  1426. // deallocated, then release the adapter object.
  1427. //
  1428. if (Action == KeepObject) {
  1429. //
  1430. // This request wants to keep the channel a while so break
  1431. // out of the loop.
  1432. //
  1433. break;
  1434. }
  1435. //
  1436. // If the driver wants to keep the map registers then set the
  1437. // number allocated to 0. This keeps the deallocation routine
  1438. // from deallocating them.
  1439. //
  1440. if (Action == DeallocateObjectKeepRegisters) {
  1441. AdapterObject->NumberOfMapRegisters = 0;
  1442. }
  1443. } else {
  1444. //
  1445. // This request did not get the requested number of map registers so
  1446. // break out of the loop.
  1447. //
  1448. break;
  1449. }
  1450. }
  1451. }
  1452. VOID
  1453. IoFreeMapRegisters(
  1454. PADAPTER_OBJECT AdapterObject,
  1455. PVOID MapRegisterBase,
  1456. ULONG NumberOfMapRegisters
  1457. )
  1458. /*++
  1459. Routine Description:
  1460. If NumberOfMapRegisters != 0, this routine deallocates the map registers
  1461. for the adapter.
  1462. If there are any queued adapters waiting then an attempt is made to allocate
  1463. the next entry.
  1464. Arguments:
  1465. AdapterObject - The adapter object where the map registers should be
  1466. returned to.
  1467. MapRegisterBase - The map register base of the registers to be deallocated.
  1468. NumberOfMapRegisters - The number of registers to be deallocated.
  1469. Return Value:
  1470. None
  1471. --+*/
  1472. {
  1473. PADAPTER_OBJECT MasterAdapter;
  1474. LONG MapRegisterNumber;
  1475. PWAIT_CONTEXT_BLOCK Wcb;
  1476. PLIST_ENTRY Packet;
  1477. IO_ALLOCATION_ACTION Action;
  1478. KIRQL Irql;
  1479. //
  1480. // Begin by getting the address of the master adapter.
  1481. //
  1482. if (AdapterObject->MasterAdapter != NULL && MapRegisterBase != NULL) {
  1483. MasterAdapter = AdapterObject->MasterAdapter;
  1484. } else {
  1485. //
  1486. // There are no map registers to return.
  1487. //
  1488. return;
  1489. }
  1490. if (NumberOfMapRegisters != 0) {
  1491. //
  1492. // Strip the no scatter/gather flag.
  1493. //
  1494. MapRegisterBase = (PVOID) ((UINT_PTR) MapRegisterBase & ~NO_SCATTER_GATHER);
  1495. MapRegisterNumber = (LONG)((PTRANSLATION_ENTRY) MapRegisterBase -
  1496. (PTRANSLATION_ENTRY) MasterAdapter->MapRegisterBase);
  1497. //
  1498. // Acquire the master adapter spinlock which locks the adapter queue and the
  1499. // bit map for the map registers.
  1500. //
  1501. KeAcquireSpinLock(&MasterAdapter->SpinLock, &Irql);
  1502. //
  1503. // Return the registers to the bit map.
  1504. //
  1505. RtlClearBits( MasterAdapter->MapRegisters,
  1506. MapRegisterNumber,
  1507. NumberOfMapRegisters
  1508. );
  1509. } else {
  1510. KeAcquireSpinLock(&MasterAdapter->SpinLock, &Irql);
  1511. }
  1512. //
  1513. // Process any requests waiting for map registers in the adapter queue.
  1514. // Requests are processed until a request cannot be satisfied or until
  1515. // there are no more requests in the queue.
  1516. //
  1517. while(TRUE) {
  1518. if ( IsListEmpty(&MasterAdapter->AdapterQueue) ){
  1519. break;
  1520. }
  1521. Packet = RemoveHeadList( &MasterAdapter->AdapterQueue );
  1522. AdapterObject = CONTAINING_RECORD( Packet,
  1523. ADAPTER_OBJECT,
  1524. AdapterQueue
  1525. );
  1526. Wcb = AdapterObject->CurrentWcb;
  1527. //
  1528. // Attempt to allocate map registers for this request. Use the previous
  1529. // register base as a hint.
  1530. //
  1531. MapRegisterNumber = RtlFindClearBitsAndSet( MasterAdapter->MapRegisters,
  1532. AdapterObject->NumberOfMapRegisters,
  1533. MasterAdapter->NumberOfMapRegisters
  1534. );
  1535. if (MapRegisterNumber == -1) {
  1536. //
  1537. // There were not enough free map registers. Put this request back on
  1538. // the adapter queue where is came from.
  1539. //
  1540. InsertHeadList( &MasterAdapter->AdapterQueue,
  1541. &AdapterObject->AdapterQueue
  1542. );
  1543. break;
  1544. }
  1545. KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql );
  1546. AdapterObject->MapRegisterBase = (PVOID) ((PTRANSLATION_ENTRY)
  1547. MasterAdapter->MapRegisterBase + MapRegisterNumber);
  1548. //
  1549. // Set the no scatter/gather flag if scatter/gather not
  1550. // supported.
  1551. //
  1552. if (!AdapterObject->ScatterGather) {
  1553. AdapterObject->MapRegisterBase = (PVOID)
  1554. ((UINT_PTR) AdapterObject->MapRegisterBase | NO_SCATTER_GATHER);
  1555. }
  1556. //
  1557. // Invoke the driver's execution routine now.
  1558. //
  1559. Action = Wcb->DeviceRoutine( Wcb->DeviceObject,
  1560. Wcb->CurrentIrp,
  1561. AdapterObject->MapRegisterBase,
  1562. Wcb->DeviceContext );
  1563. //
  1564. // If the driver wishes to keep the map registers then set the number
  1565. // allocated to zero and set the action to deallocate object.
  1566. //
  1567. if (Action == DeallocateObjectKeepRegisters) {
  1568. AdapterObject->NumberOfMapRegisters = 0;
  1569. Action = DeallocateObject;
  1570. }
  1571. //
  1572. // If the driver would like to have the adapter deallocated,
  1573. // then deallocate any map registers allocated and then release
  1574. // the adapter object.
  1575. //
  1576. if (Action == DeallocateObject) {
  1577. //
  1578. // The map registers registers are deallocated here rather than in
  1579. // IoFreeAdapterChannel. This limits the number of times
  1580. // this routine can be called recursively possibly overflowing
  1581. // the stack. The worst case occurs if there is a pending
  1582. // request for the adapter that uses map registers and whos
  1583. // excution routine decallocates the adapter. In that case if there
  1584. // are no requests in the master adapter queue, then IoFreeMapRegisters
  1585. // will get called again.
  1586. //
  1587. if (AdapterObject->NumberOfMapRegisters != 0) {
  1588. //
  1589. // Deallocate the map registers and clear the count so that
  1590. // IoFreeAdapterChannel will not deallocate them again.
  1591. //
  1592. KeAcquireSpinLock( &MasterAdapter->SpinLock, &Irql);
  1593. RtlClearBits( MasterAdapter->MapRegisters,
  1594. MapRegisterNumber,
  1595. AdapterObject->NumberOfMapRegisters
  1596. );
  1597. AdapterObject->NumberOfMapRegisters = 0;
  1598. KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql );
  1599. }
  1600. IoFreeAdapterChannel( AdapterObject );
  1601. }
  1602. KeAcquireSpinLock( &MasterAdapter->SpinLock, &Irql);
  1603. }
  1604. KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql );
  1605. }
  1606. VOID
  1607. HalPutDmaAdapter(
  1608. IN PADAPTER_OBJECT AdapterObject
  1609. )
  1610. /*++
  1611. Routine Description:
  1612. This routine frees the DMA adapter.
  1613. Arguments:
  1614. AdapterObject - Supplies a pointer to the DMA adapter to be freed.
  1615. Return Value:
  1616. None.
  1617. --*/
  1618. {
  1619. ASSERT( AdapterObject->ChannelNumber == 0xFF );
  1620. //
  1621. // This adapter can be freed if the channel number is zero and
  1622. // it is not the channel zero adapter.
  1623. //
  1624. if ( AdapterObject->ChannelNumber == 0xFF ) {
  1625. ObDereferenceObject( AdapterObject );
  1626. }
  1627. }
  1628. struct _DMA_ADAPTER *
  1629. HaliGetDmaAdapter(
  1630. IN PVOID Context,
  1631. IN struct _DEVICE_DESCRIPTION *DeviceDescriptor,
  1632. OUT PULONG NumberOfMapRegisters
  1633. )
  1634. /*++
  1635. Routine Description:
  1636. This function is a wrapper for HalGetAdapter. Is is called through
  1637. the HAL dispatch table.
  1638. Arguments:
  1639. Context - Unused.
  1640. DeviceDescriptor - Supplies the device descriptor used to allocate the dma
  1641. adapter object.
  1642. NubmerOfMapRegisters - Returns the maximum number of map registers a device
  1643. can allocate at one time.
  1644. Return Value:
  1645. Returns a DMA adapter or NULL.
  1646. --*/
  1647. {
  1648. return (PDMA_ADAPTER) HalGetAdapter( DeviceDescriptor, NumberOfMapRegisters );
  1649. }
  1650. NTSTATUS
  1651. HalBuildMdlFromScatterGatherList(
  1652. IN PADAPTER_OBJECT AdapterObject,
  1653. IN PSCATTER_GATHER_LIST ScatterGather,
  1654. IN PMDL OriginalMdl,
  1655. OUT PMDL *TargetMdl
  1656. )
  1657. /*++
  1658. Routine Description:
  1659. This function builds an MDL from the scatter gather list. This is so if a driver wants to
  1660. construct a virtual address for the DMA buffer and write to it. The target MDL is freed when the
  1661. caller calls HalPutScatterGatherList.
  1662. Arguments:
  1663. ScatterGather - The scatter gather buffer from which to build the MDL.
  1664. OriginalMdl - The MDL used to build the scatter gather list (using HalGet or HalBuild API)
  1665. TargetMdl - Returns the new MDL in this.
  1666. Return Value:
  1667. Returns a success or error status.
  1668. --*/
  1669. {
  1670. PMDL tempMdl;
  1671. PMDL newMdl;
  1672. PMDL targetMdl;
  1673. PMDL prevMdl;
  1674. PMDL nextMdl;
  1675. CSHORT mdlFlags;
  1676. PHAL_WAIT_CONTEXT_BLOCK WaitBlock = (PVOID) ScatterGather->Reserved;
  1677. ULONG i,j;
  1678. PSCATTER_GATHER_ELEMENT element;
  1679. PPFN_NUMBER pfnArray;
  1680. PFN_NUMBER pageFrame;
  1681. ULONG nPages;
  1682. if (!OriginalMdl) {
  1683. return STATUS_INVALID_PARAMETER;
  1684. }
  1685. if (!AdapterObject->NeedsMapRegisters) {
  1686. *TargetMdl = OriginalMdl;
  1687. return STATUS_SUCCESS;
  1688. }
  1689. //
  1690. // If this API is called more than once
  1691. if (WaitBlock && WaitBlock->DmaMdl) {
  1692. return (STATUS_NONE_MAPPED);
  1693. }
  1694. //
  1695. // Allocate a chain of target MDLs
  1696. //
  1697. prevMdl = NULL;
  1698. targetMdl = NULL;
  1699. for (tempMdl = OriginalMdl; tempMdl; tempMdl = tempMdl->Next) {
  1700. PVOID va;
  1701. ULONG byteCount;
  1702. if(tempMdl == OriginalMdl) {
  1703. va = WaitBlock->CurrentVa;
  1704. byteCount = MmGetMdlByteCount(tempMdl);
  1705. } else {
  1706. va = MmGetMdlVirtualAddress(tempMdl);
  1707. byteCount = MmGetMdlByteCount(tempMdl);
  1708. }
  1709. newMdl = IoAllocateMdl(va, byteCount, FALSE, FALSE, NULL);
  1710. if (!newMdl) {
  1711. //
  1712. // Clean up previous allocated MDLs
  1713. //
  1714. tempMdl = targetMdl;
  1715. while (tempMdl) {
  1716. nextMdl = tempMdl->Next;
  1717. IoFreeMdl(tempMdl);
  1718. tempMdl = nextMdl;
  1719. }
  1720. return (STATUS_INSUFFICIENT_RESOURCES);
  1721. }
  1722. if (!prevMdl) {
  1723. prevMdl = newMdl;
  1724. targetMdl = newMdl;
  1725. } else {
  1726. prevMdl->Next = newMdl;
  1727. prevMdl = newMdl;
  1728. }
  1729. }
  1730. tempMdl = OriginalMdl;
  1731. element = ScatterGather->Elements;
  1732. for (tempMdl = targetMdl; tempMdl; tempMdl = tempMdl->Next) {
  1733. targetMdl->MdlFlags |= MDL_PAGES_LOCKED;
  1734. pfnArray = MmGetMdlPfnArray(tempMdl);
  1735. for (i = 0; i < ScatterGather->NumberOfElements; i++, element++) {
  1736. nPages = BYTES_TO_PAGES(BYTE_OFFSET(element->Address.QuadPart) + element->Length);
  1737. pageFrame = (ULONG)(element->Address.QuadPart >> PAGE_SHIFT);
  1738. for (j = 0; j < nPages; j++) {
  1739. *pfnArray = pageFrame + j;
  1740. pfnArray++;
  1741. ASSERT((PVOID)pfnArray <= (PVOID)((PCHAR)tempMdl + tempMdl->Size));
  1742. }
  1743. }
  1744. }
  1745. *TargetMdl = targetMdl;
  1746. if (WaitBlock) {
  1747. WaitBlock->DmaMdl = targetMdl;
  1748. }
  1749. return STATUS_SUCCESS;
  1750. }