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.

730 lines
20 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. ixphwsup.c
  5. Abstract:
  6. This module contains the HalpXxx routines for the NT I/O system that
  7. are hardware dependent. Were these routines not hardware dependent,
  8. they would normally reside in the internal.c module.
  9. Author:
  10. Darryl E. Havens (darrylh) 11-Apr-1990
  11. Environment:
  12. Kernel mode, local to I/O system
  13. Revision History:
  14. --*/
  15. #include "halp.h"
  16. #if MCA
  17. #include "mca.h"
  18. #else
  19. #include "eisa.h"
  20. #endif
  21. #ifdef ALLOC_PRAGMA
  22. #pragma alloc_text(PAGE,HalpAllocateAdapter)
  23. #pragma alloc_text(PAGELK,HalpGrowMapBuffers)
  24. #endif
  25. //
  26. // Some devices require a physically contiguous data buffer for DMA transfers.
  27. // Map registers are used to give the appearance that all data buffers are
  28. // contiguous. In order to pool all of the map registers a master
  29. // adapter object is used. This object is allocated and saved internal to this
  30. // file. It contains a bit map for allocation of the registers and a queue
  31. // for requests which are waiting for more map registers. This object is
  32. // allocated during the first request to allocate an adapter which requires
  33. // map registers.
  34. //
  35. #if defined(_HALPAE_)
  36. MASTER_ADAPTER_OBJECT MasterAdapter24;
  37. MASTER_ADAPTER_OBJECT MasterAdapter32;
  38. #else
  39. PADAPTER_OBJECT MasterAdapterObject;
  40. #endif
  41. BOOLEAN LessThan16Mb;
  42. BOOLEAN HalpEisaDma;
  43. #define ADAPTER_BASE_MASTER ((PVOID)-1)
  44. #if !defined(_HALPAE_)
  45. //
  46. // Map buffer prameters. These are initialized in HalInitSystem.
  47. //
  48. PHYSICAL_ADDRESS HalpMapBufferPhysicalAddress;
  49. ULONG HalpMapBufferSize;
  50. #endif
  51. //
  52. // Define DMA operations structure.
  53. //
  54. const DMA_OPERATIONS HalpDmaOperations = {
  55. sizeof(DMA_OPERATIONS),
  56. (PPUT_DMA_ADAPTER) HalPutDmaAdapter,
  57. (PALLOCATE_COMMON_BUFFER) HalAllocateCommonBuffer,
  58. (PFREE_COMMON_BUFFER) HalFreeCommonBuffer,
  59. #if defined(_WIN64)
  60. (PALLOCATE_ADAPTER_CHANNEL) HalRealAllocateAdapterChannel,
  61. #else
  62. (PALLOCATE_ADAPTER_CHANNEL) IoAllocateAdapterChannel,
  63. #endif
  64. (PFLUSH_ADAPTER_BUFFERS) IoFlushAdapterBuffers,
  65. (PFREE_ADAPTER_CHANNEL) IoFreeAdapterChannel,
  66. (PFREE_MAP_REGISTERS) IoFreeMapRegisters,
  67. (PMAP_TRANSFER) IoMapTransfer,
  68. (PGET_DMA_ALIGNMENT) HalGetDmaAlignment,
  69. (PREAD_DMA_COUNTER) HalReadDmaCounter,
  70. (PGET_SCATTER_GATHER_LIST) HalGetScatterGatherList,
  71. (PPUT_SCATTER_GATHER_LIST) HalPutScatterGatherList,
  72. (PCALCULATE_SCATTER_GATHER_LIST_SIZE)HalCalculateScatterGatherListSize,
  73. (PBUILD_SCATTER_GATHER_LIST) HalBuildScatterGatherList,
  74. (PBUILD_MDL_FROM_SCATTER_GATHER_LIST) HalBuildMdlFromScatterGatherList
  75. };
  76. BOOLEAN
  77. HalpGrowMapBuffers(
  78. PADAPTER_OBJECT AdapterObject,
  79. ULONG Amount
  80. )
  81. /*++
  82. Routine Description:
  83. This function attempts to allocate additional map buffers for use by I/O
  84. devices. The map register table is updated to indicate the additional
  85. buffers.
  86. Caller owns the HalpNewAdapter event
  87. Arguments:
  88. AdapterObject - Supplies the adapter object for which the buffers are to be
  89. allocated.
  90. Amount - Indicates the size of the map buffers which should be allocated.
  91. Return Value:
  92. TRUE is returned if the memory could be allocated.
  93. FALSE is returned if the memory could not be allocated.
  94. --*/
  95. {
  96. ULONG MapBufferPhysicalAddress;
  97. PVOID MapBufferVirtualAddress;
  98. PTRANSLATION_ENTRY TranslationEntry;
  99. LONG NumberOfPages;
  100. LONG i;
  101. PHYSICAL_ADDRESS physicalAddressMinimum;
  102. PHYSICAL_ADDRESS physicalAddressMaximum;
  103. PHYSICAL_ADDRESS boundaryAddress;
  104. KIRQL Irql;
  105. PVOID CodeLockHandle;
  106. ULONG maximumBufferPages;
  107. BOOLEAN dma32Bit;
  108. ULONG bytesToAllocate;
  109. PAGED_CODE();
  110. dma32Bit = AdapterObject->Dma32BitAddresses;
  111. boundaryAddress.QuadPart = 0;
  112. NumberOfPages = BYTES_TO_PAGES(Amount);
  113. //
  114. // Make sure there is room for the additional pages. The maximum number of
  115. // slots needed is equal to NumberOfPages + Amount / 64K + 1.
  116. //
  117. maximumBufferPages =
  118. HalpMaximumMapBufferRegisters( dma32Bit );
  119. i = maximumBufferPages - (NumberOfPages +
  120. (NumberOfPages * PAGE_SIZE) / 0x10000 + 1 +
  121. AdapterObject->NumberOfMapRegisters);
  122. if (i < 0) {
  123. //
  124. // Reduce the allocation amount so it will fit.
  125. //
  126. NumberOfPages += i;
  127. }
  128. if (NumberOfPages <= 0) {
  129. //
  130. // No more memory can be allocated.
  131. //
  132. return(FALSE);
  133. }
  134. if (AdapterObject->NumberOfMapRegisters == 0 &&
  135. HalpMapBufferSize( dma32Bit )) {
  136. NumberOfPages =
  137. BYTES_TO_PAGES( HalpMapBufferSize( dma32Bit ));
  138. //
  139. // Since this is the initial allocation, use the buffer allocated by
  140. // HalInitSystem rather than allocating a new one.
  141. //
  142. MapBufferPhysicalAddress =
  143. HalpMapBufferPhysicalAddress( dma32Bit ).LowPart;
  144. //
  145. // Map the buffer for access.
  146. //
  147. MapBufferVirtualAddress = MmMapIoSpace(
  148. HalpMapBufferPhysicalAddress( dma32Bit ),
  149. HalpMapBufferSize( dma32Bit ),
  150. TRUE // Cache enable.
  151. );
  152. if (MapBufferVirtualAddress == NULL) {
  153. //
  154. // The buffer could not be mapped.
  155. //
  156. HalpMapBufferSize( dma32Bit ) = 0;
  157. return(FALSE);
  158. }
  159. } else {
  160. //
  161. // Allocate the map buffers.
  162. //
  163. physicalAddressMaximum =
  164. HalpGetAdapterMaximumPhysicalAddress( AdapterObject );
  165. if (physicalAddressMaximum.LowPart == (ULONG)-1) {
  166. //
  167. // This adapter can handle at least 32-bit addresses. In an effort
  168. // to leave memory to 24-bit adapters, try to make this allocation
  169. // above the 24 bit line.
  170. //
  171. physicalAddressMinimum.QuadPart = MAXIMUM_PHYSICAL_ADDRESS;
  172. } else {
  173. physicalAddressMinimum.QuadPart = 0;
  174. }
  175. bytesToAllocate = NumberOfPages * PAGE_SIZE;
  176. //
  177. // This loop is executed a maximum of two times.
  178. //
  179. while(TRUE) {
  180. MapBufferVirtualAddress =
  181. MmAllocateContiguousMemorySpecifyCache( bytesToAllocate,
  182. physicalAddressMinimum,
  183. physicalAddressMaximum,
  184. boundaryAddress,
  185. MmCached );
  186. if (MapBufferVirtualAddress != NULL) {
  187. //
  188. // The memory was allocated.
  189. //
  190. break;
  191. }
  192. //
  193. // The allocation attempt failed.
  194. //
  195. if (physicalAddressMinimum.QuadPart != 0) {
  196. //
  197. // We were trying to allocate memory above the 16M line as
  198. // an optimization. Relax that requirement and try again.
  199. //
  200. physicalAddressMinimum.QuadPart = 0;
  201. } else {
  202. //
  203. // The memory could not be allocated.
  204. //
  205. return FALSE;
  206. }
  207. }
  208. //
  209. // Get the physical address of the map base.
  210. //
  211. MapBufferPhysicalAddress = MmGetPhysicalAddress(
  212. MapBufferVirtualAddress
  213. ).LowPart;
  214. }
  215. //
  216. // Initialize the map registers where memory has been allocated.
  217. // Serialize with master adapter object.
  218. //
  219. CodeLockHandle = MmLockPagableCodeSection (&HalpGrowMapBuffers);
  220. KeAcquireSpinLock( &AdapterObject->SpinLock, &Irql );
  221. TranslationEntry = ((PTRANSLATION_ENTRY) AdapterObject->MapRegisterBase) +
  222. AdapterObject->NumberOfMapRegisters;
  223. for (i = 0; (LONG) i < NumberOfPages; i++) {
  224. //
  225. // Make sure the perivous entry is physically contiguous with the next
  226. // entry and that a 64K physical bountry is not crossed unless this
  227. // is an Eisa system.
  228. //
  229. if (TranslationEntry != AdapterObject->MapRegisterBase &&
  230. (((TranslationEntry - 1)->PhysicalAddress + PAGE_SIZE) !=
  231. MapBufferPhysicalAddress || (!HalpEisaDma &&
  232. ((TranslationEntry - 1)->PhysicalAddress & ~0x0ffff) !=
  233. (MapBufferPhysicalAddress & ~0x0ffff)))) {
  234. //
  235. // An entry needs to be skipped in the table. This entry will
  236. // remain marked as allocated so that no allocation of map
  237. // registers will cross this bountry.
  238. //
  239. TranslationEntry++;
  240. AdapterObject->NumberOfMapRegisters++;
  241. }
  242. //
  243. // Clear the bits where the memory has been allocated.
  244. //
  245. RtlClearBits(
  246. AdapterObject->MapRegisters,
  247. (ULONG)(TranslationEntry - (PTRANSLATION_ENTRY)
  248. AdapterObject->MapRegisterBase),
  249. 1
  250. );
  251. TranslationEntry->VirtualAddress = MapBufferVirtualAddress;
  252. TranslationEntry->PhysicalAddress = MapBufferPhysicalAddress;
  253. TranslationEntry++;
  254. (PCCHAR) MapBufferVirtualAddress += PAGE_SIZE;
  255. MapBufferPhysicalAddress += PAGE_SIZE;
  256. }
  257. //
  258. // Remember the number of pages that were allocated.
  259. //
  260. AdapterObject->NumberOfMapRegisters += NumberOfPages;
  261. //
  262. // Release master adapter object.
  263. //
  264. KeReleaseSpinLock( &AdapterObject->SpinLock, Irql );
  265. MmUnlockPagableImageSection (CodeLockHandle);
  266. return(TRUE);
  267. }
  268. #if defined(HalpAllocateAdapterEx)
  269. #undef HalpAllocateAdapterEx
  270. #endif
  271. PADAPTER_OBJECT
  272. HalpAllocateAdapterEx(
  273. IN ULONG MapRegistersPerChannel,
  274. IN PVOID AdapterBaseVa,
  275. IN PVOID ChannelNumber,
  276. IN BOOLEAN Dma32Bit
  277. )
  278. /*++
  279. Routine Description:
  280. This routine allocates and initializes an adapter object to represent an
  281. adapter or a DMA controller on the system. If no map registers are required
  282. then a standalone adapter object is allocated with no master adapter.
  283. If map registers are required, then a master adapter object is used to
  284. allocate the map registers. For Isa systems these registers are really
  285. physically contiguous memory pages.
  286. Caller owns the HalpNewAdapter event
  287. Arguments:
  288. MapRegistersPerChannel - Specifies the number of map registers that each
  289. channel provides for I/O memory mapping.
  290. AdapterBaseVa - Address of the the DMA controller or ADAPTER_BASE_MASTER.
  291. ChannelNumber - Unused.
  292. Dma32Bit - Indicates whether the adapter is 24 bit or 32 bit.
  293. Return Value:
  294. The function value is a pointer to the allocate adapter object.
  295. --*/
  296. {
  297. PADAPTER_OBJECT AdapterObject;
  298. OBJECT_ATTRIBUTES ObjectAttributes;
  299. ULONG Size;
  300. ULONG BitmapSize;
  301. HANDLE Handle;
  302. NTSTATUS Status;
  303. ULONG mapBuffers;
  304. BOOLEAN creatingMaster;
  305. UNREFERENCED_PARAMETER(ChannelNumber);
  306. PAGED_CODE();
  307. if (AdapterBaseVa == ADAPTER_BASE_MASTER) {
  308. creatingMaster = TRUE;
  309. } else {
  310. creatingMaster = FALSE;
  311. }
  312. //
  313. // Initialize the master adapter if necessary.
  314. //
  315. if (creatingMaster == FALSE &&
  316. MapRegistersPerChannel != 0) {
  317. //
  318. // This is not a recursive master adapter allocation, and map registers
  319. // are necessary. Allocate a master adapter object of the appropriate
  320. // type if necessary.
  321. //
  322. if (HalpMasterAdapter( Dma32Bit ) == NULL) {
  323. AdapterObject = HalpAllocateAdapterEx( MapRegistersPerChannel,
  324. ADAPTER_BASE_MASTER,
  325. NULL,
  326. Dma32Bit );
  327. //
  328. // If we could not allocate the master adapter then give up.
  329. //
  330. if (AdapterObject == NULL) {
  331. return NULL;
  332. }
  333. AdapterObject->Dma32BitAddresses = Dma32Bit;
  334. AdapterObject->MasterDevice = Dma32Bit;
  335. HalpMasterAdapter( Dma32Bit ) = AdapterObject;
  336. }
  337. }
  338. //
  339. // Begin by initializing the object attributes structure to be used when
  340. // creating the adapter object.
  341. //
  342. InitializeObjectAttributes( &ObjectAttributes,
  343. NULL,
  344. OBJ_PERMANENT | OBJ_KERNEL_HANDLE,
  345. (HANDLE) NULL,
  346. (PSECURITY_DESCRIPTOR) NULL
  347. );
  348. //
  349. // Determine the size of the adapter object. If this is the master object
  350. // then allocate space for the register bit map; otherwise, just allocate
  351. // an adapter object.
  352. //
  353. if (creatingMaster != FALSE) {
  354. //
  355. // Allocate a bit map large enough MAXIMUM_MAP_BUFFER_SIZE / PAGE_SIZE
  356. // of map register buffers.
  357. //
  358. mapBuffers = HalpMaximumMapBufferRegisters( Dma32Bit );
  359. BitmapSize = (((sizeof( RTL_BITMAP ) +
  360. ((mapBuffers + 7) >> 3)) + 3) & ~3);
  361. Size = sizeof( ADAPTER_OBJECT ) + BitmapSize;
  362. } else {
  363. Size = sizeof( ADAPTER_OBJECT );
  364. }
  365. //
  366. // Now create the adapter object.
  367. //
  368. Status = ObCreateObject( KernelMode,
  369. *IoAdapterObjectType,
  370. &ObjectAttributes,
  371. KernelMode,
  372. (PVOID) NULL,
  373. Size,
  374. 0,
  375. 0,
  376. (PVOID *)&AdapterObject );
  377. //
  378. // Reference the object.
  379. //
  380. if (NT_SUCCESS(Status)) {
  381. Status = ObReferenceObjectByPointer(
  382. AdapterObject,
  383. FILE_READ_DATA | FILE_WRITE_DATA,
  384. *IoAdapterObjectType,
  385. KernelMode
  386. );
  387. }
  388. //
  389. // If the adapter object was successfully created, then attempt to insert
  390. // it into the object table.
  391. //
  392. if (NT_SUCCESS( Status )) {
  393. RtlZeroMemory (AdapterObject, sizeof (ADAPTER_OBJECT));
  394. Status = ObInsertObject( AdapterObject,
  395. NULL,
  396. FILE_READ_DATA | FILE_WRITE_DATA,
  397. 0,
  398. (PVOID *) NULL,
  399. &Handle );
  400. if (NT_SUCCESS( Status )) {
  401. ZwClose( Handle );
  402. //
  403. // Initialize the adapter object itself.
  404. //
  405. AdapterObject->DmaHeader.Version = IO_TYPE_ADAPTER;
  406. AdapterObject->DmaHeader.Size = (USHORT) Size;
  407. AdapterObject->MapRegistersPerChannel = 1;
  408. AdapterObject->AdapterBaseVa = AdapterBaseVa;
  409. AdapterObject->ChannelNumber = 0xff;
  410. AdapterObject->DmaHeader.DmaOperations = (PDMA_OPERATIONS)&HalpDmaOperations;
  411. AdapterObject->Dma32BitAddresses = Dma32Bit;
  412. if (MapRegistersPerChannel) {
  413. AdapterObject->MasterAdapter = HalpMasterAdapter( Dma32Bit );
  414. } else {
  415. AdapterObject->MasterAdapter = NULL;
  416. }
  417. //
  418. // Initialize the channel wait queue for this adapter.
  419. //
  420. KeInitializeDeviceQueue( &AdapterObject->ChannelWaitQueue );
  421. //
  422. // If this is the MasterAdatper then initialize the register bit map,
  423. // AdapterQueue and the spin lock.
  424. //
  425. if (creatingMaster != FALSE) {
  426. KeInitializeSpinLock( &AdapterObject->SpinLock );
  427. InitializeListHead( &AdapterObject->AdapterQueue );
  428. AdapterObject->MapRegisters = (PVOID) ( AdapterObject + 1);
  429. RtlInitializeBitMap( AdapterObject->MapRegisters,
  430. (PULONG) (((PCHAR) (AdapterObject->MapRegisters)) + sizeof( RTL_BITMAP )),
  431. ( mapBuffers )
  432. );
  433. //
  434. // Set all the bits in the memory to indicate that memory
  435. // has not been allocated for the map buffers.
  436. //
  437. RtlSetAllBits( AdapterObject->MapRegisters );
  438. AdapterObject->NumberOfMapRegisters = 0;
  439. AdapterObject->CommittedMapRegisters = 0;
  440. //
  441. // Allocate the memory map registers.
  442. //
  443. AdapterObject->MapRegisterBase =
  444. ExAllocatePoolWithTag(
  445. NonPagedPool,
  446. mapBuffers * sizeof(TRANSLATION_ENTRY),
  447. HAL_POOL_TAG
  448. );
  449. if (AdapterObject->MapRegisterBase == NULL) {
  450. ObDereferenceObject( AdapterObject );
  451. AdapterObject = NULL;
  452. return(NULL);
  453. }
  454. //
  455. // Zero the map registers.
  456. //
  457. RtlZeroMemory(
  458. AdapterObject->MapRegisterBase,
  459. mapBuffers * sizeof(TRANSLATION_ENTRY)
  460. );
  461. if (!HalpGrowMapBuffers(AdapterObject, INITIAL_MAP_BUFFER_SMALL_SIZE))
  462. {
  463. //
  464. // If no map registers could be allocated then free the
  465. // object.
  466. //
  467. ObDereferenceObject( AdapterObject );
  468. AdapterObject = NULL;
  469. return(NULL);
  470. }
  471. }
  472. } else {
  473. //
  474. // An error was incurred for some reason. Set the return value
  475. // to NULL.
  476. //
  477. AdapterObject = (PADAPTER_OBJECT) NULL;
  478. }
  479. } else {
  480. AdapterObject = (PADAPTER_OBJECT) NULL;
  481. }
  482. return AdapterObject;
  483. }
  484. PADAPTER_OBJECT
  485. HalpAllocateAdapter(
  486. IN ULONG MapRegistersPerChannel,
  487. IN PVOID AdapterBaseVa,
  488. IN PVOID ChannelNumber
  489. )
  490. /*++
  491. Routine Description:
  492. This routine allocates and initializes an adapter object to represent an
  493. adapter or a DMA controller on the system. If no map registers are required
  494. then a standalone adapter object is allocated with no master adapter.
  495. If map registers are required, then a master adapter object is used to
  496. allocate the map registers. For Isa systems these registers are really
  497. physically contiguous memory pages.
  498. Caller owns the HalpNewAdapter event
  499. Arguments:
  500. MapRegistersPerChannel - Specifies the number of map registers that each
  501. channel provides for I/O memory mapping.
  502. AdapterBaseVa - Address of the DMA controller or ADAPTER_BASE_MASTER.
  503. ChannelNumber - Unused.
  504. Return Value:
  505. The function value is a pointer to the allocate adapter object.
  506. --*/
  507. {
  508. return HalpAllocateAdapterEx( MapRegistersPerChannel,
  509. AdapterBaseVa,
  510. ChannelNumber,
  511. FALSE );
  512. }
  513. ULONG
  514. HalGetDmaAlignment (
  515. PVOID Conext
  516. )
  517. {
  518. return HalGetDmaAlignmentRequirement();
  519. }