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.

2080 lines
52 KiB

  1. /*++
  2. Copyright (c) 1990-2000 Microsoft Corporation
  3. Module Name:
  4. agp.c
  5. Abstract:
  6. This is the agp portion of the video port driver.
  7. Author:
  8. Erick Smith (ericks) Oct. 1997
  9. Environment:
  10. kernel mode only
  11. Revision History:
  12. --*/
  13. #include "videoprt.h"
  14. #define AGP_PAGE_SIZE PAGE_SIZE
  15. #define AGP_BLOCK_SIZE (AGP_PAGE_SIZE * 16)
  16. #define AGP_CLUSTER_SIZE (AGP_BLOCK_SIZE * 16)
  17. #define PAGES_PER_BLOCK (AGP_BLOCK_SIZE / AGP_PAGE_SIZE)
  18. #define BLOCKS_PER_CLUSTER (AGP_CLUSTER_SIZE / AGP_BLOCK_SIZE)
  19. PVOID
  20. AllocateReservedRegion(
  21. IN HANDLE ProcessHandle,
  22. IN ULONG Pages
  23. );
  24. BOOLEAN
  25. UpdateReservedRegion(
  26. IN PFDO_EXTENSION fdoExtension,
  27. IN PVIRTUAL_RESERVE_CONTEXT VirtualContext,
  28. IN ULONG Pages,
  29. IN ULONG Offset
  30. );
  31. VOID
  32. ReleaseReservedRegion(
  33. IN HANDLE ProcessHandle,
  34. IN PVOID VirtualAddress,
  35. IN ULONG Pages
  36. );
  37. #if DBG
  38. VOID
  39. DumpBitField(
  40. PREGION Region
  41. );
  42. #endif
  43. #pragma alloc_text(PAGE,VpQueryAgpInterface)
  44. #pragma alloc_text(PAGE,AgpReservePhysical)
  45. #pragma alloc_text(PAGE,AgpReleasePhysical)
  46. #pragma alloc_text(PAGE,AgpCommitPhysical)
  47. #pragma alloc_text(PAGE,AgpFreePhysical)
  48. #pragma alloc_text(PAGE,AgpReserveVirtual)
  49. #pragma alloc_text(PAGE,AgpReleaseVirtual)
  50. #pragma alloc_text(PAGE,AgpCommitVirtual)
  51. #pragma alloc_text(PAGE,AgpFreeVirtual)
  52. #pragma alloc_text(PAGE,AgpSetRate)
  53. #pragma alloc_text(PAGE,VideoPortGetAgpServices)
  54. #pragma alloc_text(PAGE,VpGetAgpServices2)
  55. #pragma alloc_text(PAGE,AllocateReservedRegion)
  56. #pragma alloc_text(PAGE,UpdateReservedRegion)
  57. #pragma alloc_text(PAGE,ReleaseReservedRegion)
  58. #pragma alloc_text(PAGE,CreateBitField)
  59. #pragma alloc_text(PAGE,ModifyRegion)
  60. #pragma alloc_text(PAGE,FindFirstRun)
  61. #if DBG
  62. #pragma alloc_text(PAGE,DumpBitField)
  63. #endif
  64. #if DBG
  65. VOID
  66. DumpBitField(
  67. PREGION Region
  68. )
  69. {
  70. ULONG i;
  71. ULONG Index = 0;
  72. USHORT Mask = 1;
  73. ASSERT(Region != NULL);
  74. for (i=0; i<Region->Length; i++) {
  75. if (Mask & Region->BitField[Index]) {
  76. pVideoDebugPrint((1, "1"));
  77. } else {
  78. pVideoDebugPrint((1, "0"));
  79. }
  80. Mask <<= 1;
  81. if (Mask == 0) {
  82. Index++;
  83. Mask = 1;
  84. }
  85. }
  86. pVideoDebugPrint((1, "\n"));
  87. }
  88. #endif
  89. BOOLEAN
  90. CreateBitField(
  91. PREGION *Region,
  92. ULONG Length
  93. )
  94. /*++
  95. Routine Description:
  96. This routine creates and initializes a bitfield.
  97. Arguments:
  98. Length - Number of items to track.
  99. Region - Location in which to store the pointer to the REGION handle.
  100. Returns:
  101. TRUE - the the bitfield was created successfully,
  102. FALSE - otherwise.
  103. --*/
  104. {
  105. ULONG NumWords = (Length + 15) / 16;
  106. BOOLEAN bRet = FALSE;
  107. PREGION Buffer;
  108. ASSERT(Length != 0);
  109. Buffer = (PREGION) ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION, sizeof(REGION) + (NumWords - 1) * sizeof(USHORT), VP_TAG);
  110. if (Buffer) {
  111. Buffer->Length = Length;
  112. Buffer->NumWords = NumWords;
  113. RtlZeroMemory(Buffer->BitField, NumWords * sizeof(USHORT));
  114. bRet = TRUE;
  115. }
  116. *Region = Buffer;
  117. return bRet;
  118. }
  119. VOID
  120. ModifyRegion(
  121. PREGION Region,
  122. ULONG Offset,
  123. ULONG Length,
  124. BOOLEAN Set
  125. )
  126. /*++
  127. Routine Description:
  128. Sets 'Length' bits starting at position 'Offset' in the bitfield.
  129. Arguments:
  130. Region - Pointer to the region to modify.
  131. Offset - Offset into the bitfield at which to start.
  132. Length - Number of bits to set.
  133. Set - TRUE if you want to set the region, FALSE to clear it.
  134. --*/
  135. {
  136. ULONG Index = Offset / 16;
  137. ULONG Count = ((Offset + Length - 1) / 16) - Index;
  138. USHORT lMask = ~((1 << (Offset & 15)) - 1);
  139. USHORT rMask = ((1 << ((Offset + Length - 1) & 15)) * 2) - 1;
  140. PUSHORT ptr = &Region->BitField[Index];
  141. ASSERT(Region != NULL);
  142. ASSERT(Length != 0);
  143. if (Count == 0) {
  144. //
  145. // Only one WORD is modified, so combine left and right masks.
  146. //
  147. lMask &= rMask;
  148. }
  149. if (Set) {
  150. *ptr++ |= lMask;
  151. while (Count > 1) {
  152. *ptr++ |= 0xFFFF;
  153. Count--;
  154. }
  155. if (Count) {
  156. *ptr |= rMask;
  157. }
  158. } else {
  159. *ptr++ &= ~lMask;
  160. while (Count > 1) {
  161. *ptr++ &= 0;
  162. Count--;
  163. }
  164. if (Count) {
  165. *ptr++ &= ~rMask;
  166. }
  167. }
  168. #if DBG
  169. pVideoDebugPrint((1, "Current BitField for Region: 0x%x\n", Region));
  170. //DumpBitField(Region);
  171. #endif
  172. }
  173. BOOLEAN
  174. FindFirstRun(
  175. PREGION Region,
  176. PULONG Offset,
  177. PULONG Length
  178. )
  179. /*++
  180. Routine Description:
  181. This routine finds the first run of bits in a bitfield.
  182. Arguments:
  183. Region - Pointer to the region to operate on.
  184. Offset - Pointer to a ULONG to hold the offset of the run.
  185. Length - Pointer to a ULONG to hold the length of a run.
  186. Returns:
  187. TRUE if a run was detected,
  188. FALSE otherwise.
  189. --*/
  190. {
  191. PUSHORT ptr = Region->BitField;
  192. ULONG Index = 0;
  193. USHORT BitMask;
  194. ULONG lsb;
  195. ULONG Count;
  196. USHORT ptrVal;
  197. ASSERT(Region != NULL);
  198. ASSERT(Offset != NULL);
  199. ASSERT(Length != NULL);
  200. while ((Index < Region->NumWords) && (*ptr == 0)) {
  201. ptr++;
  202. Index++;
  203. }
  204. if (Index == Region->NumWords) {
  205. return FALSE;
  206. }
  207. //
  208. // Find least significant bit
  209. //
  210. lsb = 0;
  211. ptrVal = *ptr;
  212. BitMask = 1;
  213. while ((ptrVal & BitMask) == 0) {
  214. BitMask <<= 1;
  215. lsb++;
  216. }
  217. *Offset = (Index * 16) + lsb;
  218. //
  219. // Determine the run length
  220. //
  221. Count = 0;
  222. while (Index < Region->NumWords) {
  223. if (ptrVal & BitMask) {
  224. BitMask <<= 1;
  225. Count++;
  226. if (BitMask == 0) {
  227. BitMask = 0x1;
  228. Index++;
  229. ptrVal = *++ptr;
  230. while ((ptrVal == 0xFFFF) && (Index < Region->NumWords)) {
  231. Index++;
  232. Count += 16;
  233. ptrVal = *ptr++;
  234. }
  235. }
  236. } else {
  237. break;
  238. }
  239. }
  240. *Length = Count;
  241. return TRUE;
  242. }
  243. BOOLEAN
  244. VpQueryAgpInterface(
  245. PFDO_EXTENSION FdoExtension,
  246. USHORT InterfaceVersion
  247. )
  248. /*++
  249. Routine Description:
  250. Send a QueryInterface Irp to our parent (the PCI bus driver) to
  251. retrieve the AGP_BUS_INTERFACE.
  252. Returns:
  253. NT_STATUS code
  254. --*/
  255. {
  256. KEVENT Event;
  257. PIRP QueryIrp = NULL;
  258. IO_STATUS_BLOCK IoStatusBlock;
  259. PIO_STACK_LOCATION NextStack;
  260. NTSTATUS Status;
  261. ASSERT(FdoExtension != NULL);
  262. KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
  263. QueryIrp = IoBuildSynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS,
  264. FdoExtension->AttachedDeviceObject,
  265. NULL,
  266. 0,
  267. NULL,
  268. &Event,
  269. &IoStatusBlock);
  270. if (QueryIrp == NULL) {
  271. return FALSE;
  272. }
  273. NextStack = IoGetNextIrpStackLocation(QueryIrp);
  274. //
  275. // Set the default error code.
  276. //
  277. QueryIrp->IoStatus.Status = IoStatusBlock.Status = STATUS_NOT_SUPPORTED;
  278. //
  279. // Set up for a QueryInterface Irp.
  280. //
  281. NextStack->MajorFunction = IRP_MJ_PNP;
  282. NextStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
  283. NextStack->Parameters.QueryInterface.InterfaceType = &GUID_AGP_BUS_INTERFACE_STANDARD;
  284. NextStack->Parameters.QueryInterface.Size = sizeof(AGP_BUS_INTERFACE_STANDARD);
  285. NextStack->Parameters.QueryInterface.Version = InterfaceVersion;
  286. NextStack->Parameters.QueryInterface.Interface = (PINTERFACE) &FdoExtension->AgpInterface;
  287. NextStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
  288. FdoExtension->AgpInterface.Size = sizeof(AGP_BUS_INTERFACE_STANDARD);
  289. FdoExtension->AgpInterface.Version = InterfaceVersion;
  290. Status = IoCallDriver(FdoExtension->AttachedDeviceObject, QueryIrp);
  291. if (Status == STATUS_PENDING) {
  292. KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
  293. Status = IoStatusBlock.Status;
  294. }
  295. return NT_SUCCESS(Status);
  296. }
  297. PHYSICAL_ADDRESS
  298. AgpReservePhysical(
  299. IN PVOID Context,
  300. IN ULONG Pages,
  301. IN VIDEO_PORT_CACHE_TYPE Caching,
  302. OUT PVOID *PhysicalReserveContext
  303. )
  304. /*++
  305. Routine Description:
  306. Reserves a range of physical addresses for AGP.
  307. Arguments:
  308. Context - The Agp Context
  309. Pages - Number of pages to reserve
  310. Caching - Specifies the type of caching to use
  311. PhysicalReserveContext - Location to store our reservation context.
  312. Returns:
  313. The base of the physical address range reserved.
  314. --*/
  315. {
  316. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(Context);
  317. PHYSICAL_ADDRESS PhysicalAddress = {0,0};
  318. NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
  319. PPHYSICAL_RESERVE_CONTEXT ReserveContext;
  320. PVOID MapHandle;
  321. ULONG Blocks;
  322. MEMORY_CACHING_TYPE CacheType;
  323. ASSERT(PhysicalReserveContext != NULL);
  324. ASSERT(Caching <= VpCached);
  325. Pages = (Pages + PAGES_PER_BLOCK - 1) & ~(PAGES_PER_BLOCK - 1);
  326. Blocks = Pages / PAGES_PER_BLOCK;
  327. pVideoDebugPrint((1, "AGP: Reserving 0x%x Pages of Address Space\n", Pages));
  328. switch (Caching) {
  329. case VpNonCached: CacheType = MmNonCached; break;
  330. case VpWriteCombined: CacheType = MmWriteCombined; break;
  331. case VpCached: CacheType = MmCached; break;
  332. }
  333. ReserveContext = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
  334. sizeof(PHYSICAL_RESERVE_CONTEXT),
  335. VP_TAG);
  336. if (ReserveContext) {
  337. RtlZeroMemory(ReserveContext, sizeof(PHYSICAL_RESERVE_CONTEXT));
  338. if (CreateBitField(&ReserveContext->MapTable, Blocks)) {
  339. if (CreateBitField(&ReserveContext->Region, Pages)) {
  340. status = fdoExtension->AgpInterface.ReserveMemory(
  341. fdoExtension->AgpInterface.AgpContext,
  342. Pages,
  343. CacheType,
  344. &MapHandle,
  345. &PhysicalAddress);
  346. if (NT_SUCCESS(status)) {
  347. ReserveContext->Pages = Pages;
  348. ReserveContext->Caching = CacheType;
  349. ReserveContext->MapHandle = MapHandle;
  350. ReserveContext->PhysicalAddress = PhysicalAddress;
  351. }
  352. }
  353. }
  354. }
  355. if (NT_SUCCESS(status) == FALSE) {
  356. if (ReserveContext) {
  357. if (ReserveContext->Region) {
  358. ExFreePool(ReserveContext->Region);
  359. }
  360. if (ReserveContext->MapTable) {
  361. ExFreePool(ReserveContext->MapTable);
  362. }
  363. ExFreePool(ReserveContext);
  364. ReserveContext = NULL;
  365. }
  366. PhysicalAddress.QuadPart = 0;
  367. }
  368. *PhysicalReserveContext = ReserveContext;
  369. return PhysicalAddress;
  370. }
  371. VOID
  372. AgpReleasePhysical(
  373. PVOID Context,
  374. PVOID PhysicalReserveContext
  375. )
  376. /*++
  377. Routine Description:
  378. Releases a range of reserved physical address.
  379. Arguments:
  380. Context - The Agp Context
  381. PhysicalReserveContext - The reservation context.
  382. Returns:
  383. none.
  384. --*/
  385. {
  386. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(Context);
  387. PPHYSICAL_RESERVE_CONTEXT ReserveContext;
  388. ULONG Pages;
  389. ULONG Offset;
  390. ASSERT(PhysicalReserveContext != NULL);
  391. ReserveContext = (PPHYSICAL_RESERVE_CONTEXT) PhysicalReserveContext;
  392. pVideoDebugPrint((1, "AGP: Releasing 0x%x Pages of Address Space\n", ReserveContext->Pages));
  393. //
  394. // Make sure all pages have been freed
  395. //
  396. while (FindFirstRun(ReserveContext->Region, &Offset, &Pages)) {
  397. AgpFreePhysical(Context, PhysicalReserveContext, Pages, Offset);
  398. }
  399. fdoExtension->AgpInterface.ReleaseMemory(fdoExtension->AgpInterface.AgpContext,
  400. ReserveContext->MapHandle);
  401. ExFreePool(ReserveContext->Region);
  402. ExFreePool(ReserveContext->MapTable);
  403. ExFreePool(ReserveContext);
  404. }
  405. BOOLEAN
  406. AgpCommitPhysical(
  407. PVOID Context,
  408. PVOID PhysicalReserveContext,
  409. ULONG Pages,
  410. ULONG Offset
  411. )
  412. /*++
  413. Routine Description:
  414. Locks down system memory and backs a portion of the reserved region.
  415. Arguments:
  416. Context - The Agp Context
  417. PhysicalReserveContext - The reservation context.
  418. Pages - Number of pages to commit.
  419. Offset - The offset into the reserved region at which to commit the pages.
  420. Returns:
  421. TRUE if successful,
  422. FALSE otherwise.
  423. --*/
  424. {
  425. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(Context);
  426. PHYSICAL_ADDRESS MemoryBase = {0,0};
  427. PPHYSICAL_RESERVE_CONTEXT ReserveContext;
  428. NTSTATUS status;
  429. PMDL Mdl;
  430. ULONG StartBlock = Offset / PAGES_PER_BLOCK;
  431. ULONG EndBlock = (Offset + Pages + PAGES_PER_BLOCK - 1) / PAGES_PER_BLOCK;
  432. ULONG i;
  433. PUSHORT MapTable;
  434. PUSHORT BitField;
  435. ASSERT(PhysicalReserveContext != NULL);
  436. ASSERT(Pages != 0);
  437. ReserveContext = (PPHYSICAL_RESERVE_CONTEXT) PhysicalReserveContext;
  438. MapTable = ReserveContext->MapTable->BitField;
  439. BitField = ReserveContext->Region->BitField;
  440. //
  441. // Try to commit the new pages. The agp filter driver handles
  442. // the case where some of these pages are already committed, so
  443. // lets try to get them all at once.
  444. //
  445. status =
  446. fdoExtension->AgpInterface.CommitMemory(
  447. fdoExtension->AgpInterface.AgpContext,
  448. ReserveContext->MapHandle,
  449. PAGES_PER_BLOCK * (EndBlock - StartBlock),
  450. Offset & ~(PAGES_PER_BLOCK - 1),
  451. NULL,
  452. &MemoryBase);
  453. if (NT_SUCCESS(status)) {
  454. ModifyRegion(ReserveContext->Region, Offset, Pages, TRUE);
  455. for (i=StartBlock; i<EndBlock; i++) {
  456. ULONG Cluster = i / BLOCKS_PER_CLUSTER;
  457. ULONG Block = 1 << (i & (BLOCKS_PER_CLUSTER - 1));
  458. //
  459. // Update the MapTable for the committed pages.
  460. //
  461. MapTable[Cluster] |= Block;
  462. }
  463. } else {
  464. pVideoDebugPrint((0, "Commit Physical failed with status: 0x%x\n", status));
  465. }
  466. return NT_SUCCESS(status);
  467. }
  468. VOID
  469. AgpFreePhysical(
  470. IN PVOID Context,
  471. IN PVOID PhysicalReserveContext,
  472. IN ULONG Pages,
  473. IN ULONG Offset
  474. )
  475. /*++
  476. Routine Description:
  477. Releases the memory used to back a portion of the reserved region.
  478. Arguments:
  479. Context - The Agp Context
  480. PhysicalReserveContext - The reservation context.
  481. Pages - Number of pages to release.
  482. Offset - The offset into the reserved region at which to release the pages.
  483. Returns:
  484. none.
  485. --*/
  486. {
  487. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(Context);
  488. PPHYSICAL_RESERVE_CONTEXT ReserveContext;
  489. PMDL Mdl;
  490. ULONG StartBlock = Offset / PAGES_PER_BLOCK;
  491. ULONG EndBlock = (Offset + Pages + PAGES_PER_BLOCK - 1) / PAGES_PER_BLOCK;
  492. ULONG i;
  493. PUSHORT MapTable;
  494. PUSHORT BitField;
  495. ASSERT(PhysicalReserveContext != NULL);
  496. ASSERT(Pages != 0);
  497. ReserveContext = (PPHYSICAL_RESERVE_CONTEXT) PhysicalReserveContext;
  498. MapTable = ReserveContext->MapTable->BitField;
  499. BitField = ReserveContext->Region->BitField;
  500. ModifyRegion(ReserveContext->Region, Offset, Pages, FALSE);
  501. //
  502. // Postion the offset to the start of the first block
  503. //
  504. Offset = Offset & ~(PAGES_PER_BLOCK - 1);
  505. for (i=StartBlock; i<EndBlock; i++) {
  506. ULONG Cluster = i / BLOCKS_PER_CLUSTER;
  507. ULONG Block = 1 << (i & (BLOCKS_PER_CLUSTER - 1));
  508. //
  509. // If this block is mapped, then release it.
  510. //
  511. if ((BitField[i] == 0) && (MapTable[Cluster] & Block)) {
  512. fdoExtension->AgpInterface.FreeMemory(
  513. fdoExtension->AgpInterface.AgpContext,
  514. ReserveContext->MapHandle,
  515. PAGES_PER_BLOCK,
  516. Offset);
  517. MapTable[Cluster] &= ~Block;
  518. }
  519. //
  520. // Go to the next 64k block
  521. //
  522. Offset += PAGES_PER_BLOCK;
  523. }
  524. }
  525. PVOID
  526. AgpReserveVirtual(
  527. IN PVOID Context,
  528. IN HANDLE ProcessHandle,
  529. IN PVOID PhysicalReserveContext,
  530. OUT PVOID *VirtualReserveContext
  531. )
  532. /*++
  533. Routine Description:
  534. Reserves a range of virtual addresses for AGP.
  535. Arguments:
  536. Context - The Agp Context
  537. ProcessHandle - The handle of the process in which to reserve the
  538. virtual address range.
  539. PhysicalReserveContext - The physical reservation context to assoctiate
  540. with the given virtual reservation.
  541. VirtualReserveContext - The location in which to store the virtual
  542. reserve context.
  543. Returns:
  544. The base of the virtual address range reserved.
  545. Notes:
  546. You can't reserve a range of kernel address space, but if you want to
  547. commit into kernel space you still need a reservation handle. Pass in
  548. NULL for the process handle in this case.
  549. For the moment, we'll commit the entire region when the do a reservation
  550. in kernel space. Then Commit and Free will be no-ops.
  551. --*/
  552. {
  553. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(Context);
  554. NTSTATUS status = STATUS_SUCCESS;
  555. ULONG Protect = PAGE_READWRITE;
  556. PVIRTUAL_RESERVE_CONTEXT ReserveContext;
  557. PPHYSICAL_RESERVE_CONTEXT PhysicalContext;
  558. PVOID VirtualAddress = NULL;
  559. PEPROCESS Process = NULL;
  560. ULONG Blocks;
  561. ASSERT(PhysicalReserveContext != NULL);
  562. ASSERT(VirtualReserveContext != NULL);
  563. PhysicalContext = (PPHYSICAL_RESERVE_CONTEXT) PhysicalReserveContext;
  564. Blocks = (PhysicalContext->Pages + PAGES_PER_BLOCK - 1) / PAGES_PER_BLOCK;
  565. ReserveContext = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
  566. sizeof(VIRTUAL_RESERVE_CONTEXT),
  567. VP_TAG);
  568. if (ReserveContext) {
  569. RtlZeroMemory(ReserveContext, sizeof(VIRTUAL_RESERVE_CONTEXT));
  570. if (CreateBitField(&ReserveContext->MapTable, Blocks)) {
  571. if (CreateBitField(&ReserveContext->Region, PhysicalContext->Pages)) {
  572. if (PhysicalContext->Caching == MmNonCached) {
  573. Protect |= PAGE_NOCACHE;
  574. }
  575. //
  576. // Make sure we have the real process handle.
  577. //
  578. if (ProcessHandle == NtCurrentProcess()) {
  579. Process = PsGetCurrentProcess();
  580. }
  581. ReserveContext->ProcessHandle = ProcessHandle;
  582. ReserveContext->Process = Process;
  583. ReserveContext->PhysicalReserveContext =
  584. (PPHYSICAL_RESERVE_CONTEXT) PhysicalReserveContext;
  585. if (ProcessHandle) {
  586. VirtualAddress =
  587. AllocateReservedRegion(
  588. ProcessHandle,
  589. PhysicalContext->Pages);
  590. } else {
  591. //
  592. // For a kernel reservation, go ahead and commit the
  593. // entire range.
  594. //
  595. if (fdoExtension->AgpInterface.Capabilities &
  596. AGP_CAPABILITIES_MAP_PHYSICAL)
  597. {
  598. //
  599. // CPU can access AGP memory through AGP aperature.
  600. //
  601. VirtualAddress =
  602. MmMapIoSpace(PhysicalContext->PhysicalAddress,
  603. PhysicalContext->Pages * AGP_PAGE_SIZE,
  604. PhysicalContext->Caching);
  605. //
  606. // Not all systems support USWC, so if we attempted to map USWC
  607. // and failed, try again with just non-cached.
  608. //
  609. if ((VirtualAddress == NULL) &&
  610. (PhysicalContext->Caching != MmNonCached)) {
  611. pVideoDebugPrint((1, "Attempt to map cached memory failed. Try uncached.\n"));
  612. VirtualAddress = MmMapIoSpace(PhysicalContext->PhysicalAddress,
  613. PhysicalContext->Pages * AGP_PAGE_SIZE,
  614. MmNonCached);
  615. }
  616. } else {
  617. PMDL Mdl;
  618. //
  619. // Get the MDL for the range we are trying to map.
  620. //
  621. Mdl = MmCreateMdl(NULL, NULL, PhysicalContext->Pages * AGP_PAGE_SIZE);
  622. if (Mdl) {
  623. fdoExtension->AgpInterface.GetMappedPages(
  624. fdoExtension->AgpInterface.AgpContext,
  625. PhysicalContext->MapHandle,
  626. PhysicalContext->Pages,
  627. 0,
  628. Mdl);
  629. Mdl->MdlFlags |= MDL_PAGES_LOCKED | MDL_MAPPING_CAN_FAIL;
  630. //
  631. // We must use the CPU's virtual memory mechanism to
  632. // make the non-contiguous MDL look contiguous.
  633. //
  634. VirtualAddress =
  635. MmMapLockedPagesSpecifyCache(
  636. Mdl,
  637. (KPROCESSOR_MODE)KernelMode,
  638. PhysicalContext->Caching,
  639. NULL,
  640. TRUE,
  641. HighPagePriority);
  642. ExFreePool(Mdl);
  643. }
  644. }
  645. }
  646. ReserveContext->VirtualAddress = VirtualAddress;
  647. }
  648. }
  649. }
  650. //
  651. // If anything failed, make sure we clean everything up.
  652. //
  653. if (VirtualAddress == NULL) {
  654. if (ReserveContext) {
  655. if (ReserveContext->Region) {
  656. ExFreePool(ReserveContext->Region);
  657. }
  658. if (ReserveContext->MapTable) {
  659. ExFreePool(ReserveContext->MapTable);
  660. }
  661. ExFreePool(ReserveContext);
  662. ReserveContext = NULL;
  663. }
  664. }
  665. *VirtualReserveContext = ReserveContext;
  666. return VirtualAddress;
  667. }
  668. VOID
  669. AgpReleaseVirtual(
  670. IN PVOID Context,
  671. IN PVOID VirtualReserveContext
  672. )
  673. /*++
  674. Routine Description:
  675. Releases a range of reserved virtual addresses.
  676. Arguments:
  677. Context - The Agp Context
  678. VirtualReserveContext - The reservation context.
  679. Returns:
  680. none.
  681. --*/
  682. {
  683. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(Context);
  684. PVIRTUAL_RESERVE_CONTEXT VirtualContext;
  685. PPHYSICAL_RESERVE_CONTEXT PhysicalContext;
  686. BOOLEAN Attached = FALSE;
  687. ULONG Offset;
  688. ULONG Pages;
  689. ASSERT(VirtualReserveContext != NULL);
  690. VirtualContext = (PVIRTUAL_RESERVE_CONTEXT) VirtualReserveContext;
  691. PhysicalContext = VirtualContext->PhysicalReserveContext;
  692. if (VirtualContext->ProcessHandle) {
  693. //
  694. // Make sure all pages have been freed
  695. //
  696. while (FindFirstRun(VirtualContext->Region, &Offset, &Pages)) {
  697. AgpFreeVirtual(Context, VirtualReserveContext, Pages, Offset);
  698. }
  699. //
  700. // Now release all the reserved pages
  701. //
  702. if (VirtualContext->ProcessHandle == NtCurrentProcess()) {
  703. if (VirtualContext->Process != PsGetCurrentProcess()) {
  704. KeAttachProcess(PEProcessToPKProcess(VirtualContext->Process));
  705. Attached = TRUE;
  706. }
  707. }
  708. ReleaseReservedRegion(
  709. VirtualContext->ProcessHandle,
  710. VirtualContext->VirtualAddress,
  711. VirtualContext->PhysicalReserveContext->Pages);
  712. if (Attached) {
  713. KeDetachProcess();
  714. }
  715. } else {
  716. //
  717. // This was kernel virtual memory, so release the memory we
  718. // committed at reserve time.
  719. //
  720. if (fdoExtension->AgpInterface.Capabilities &
  721. AGP_CAPABILITIES_MAP_PHYSICAL)
  722. {
  723. MmUnmapIoSpace(VirtualContext->VirtualAddress,
  724. PhysicalContext->Pages * AGP_PAGE_SIZE);
  725. } else {
  726. PMDL Mdl;
  727. //
  728. // Get the MDL for the range we are trying to free.
  729. //
  730. Mdl = MmCreateMdl(NULL, NULL, PhysicalContext->Pages * AGP_PAGE_SIZE);
  731. if (Mdl) {
  732. fdoExtension->AgpInterface.GetMappedPages(
  733. fdoExtension->AgpInterface.AgpContext,
  734. PhysicalContext->MapHandle,
  735. PhysicalContext->Pages,
  736. 0,
  737. Mdl);
  738. Mdl->MdlFlags |= MDL_PAGES_LOCKED;
  739. Mdl->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA;
  740. Mdl->MappedSystemVa = VirtualContext->VirtualAddress;
  741. MmUnmapLockedPages(
  742. VirtualContext->VirtualAddress,
  743. Mdl);
  744. ExFreePool(Mdl);
  745. } else {
  746. //
  747. // We couldn't free the memory because we couldn't allocate
  748. // memory for the MDL. We can free a small chunk at a time
  749. // by using a MDL on the stack.
  750. //
  751. ASSERT(FALSE);
  752. }
  753. }
  754. }
  755. ExFreePool(VirtualContext->Region);
  756. ExFreePool(VirtualContext->MapTable);
  757. ExFreePool(VirtualContext);
  758. }
  759. PVOID
  760. AllocateReservedRegion(
  761. IN HANDLE ProcessHandle,
  762. IN ULONG Pages
  763. )
  764. /*++
  765. Routine Description:
  766. Reserves a range of user mode virtual addresses.
  767. Arguments:
  768. ProcessHandle - The process in which we need to modify the mappings.
  769. Pages - The number of pages to reserve.
  770. Returns:
  771. Pointer to the reserved region of memory.
  772. --*/
  773. {
  774. NTSTATUS Status;
  775. ULONG_PTR VirtualAddress = 0;
  776. ULONG Blocks = (Pages + PAGES_PER_BLOCK - 1) / PAGES_PER_BLOCK;
  777. //
  778. // Pad the length so we can get an AGP_BLOCK_SIZE aligned region.
  779. //
  780. SIZE_T Length = Blocks * AGP_BLOCK_SIZE + AGP_BLOCK_SIZE - PAGE_SIZE;
  781. ASSERT(ProcessHandle != 0);
  782. ASSERT(Pages != 0);
  783. //
  784. // Find a chunk of virtual addresses where we can put our reserved
  785. // region.
  786. //
  787. // Note: We are using ZwAllocateVirtualMemory to reserve the memory,
  788. // but ZwMapViewOfSection to commit pages. Since ZwMapViewOfSection
  789. // wants to align to 64K, lets try to get a 64K aligned pointer.
  790. //
  791. Status =
  792. ZwAllocateVirtualMemory(
  793. ProcessHandle,
  794. (PVOID)&VirtualAddress,
  795. 0,
  796. &Length,
  797. MEM_RESERVE,
  798. PAGE_READWRITE);
  799. if (NT_SUCCESS(Status)) {
  800. ULONG_PTR NewAddress = (VirtualAddress + AGP_BLOCK_SIZE - 1) & ~(AGP_BLOCK_SIZE - 1);
  801. ULONG i;
  802. pVideoDebugPrint((1, "Reserved 0x%x, length = 0x%x\n", VirtualAddress, Length));
  803. //
  804. // We were able to reserve a region of memory. Now lets free it, and
  805. // reallocate in AGP_BLOCK_SIZE size blocks.
  806. //
  807. ZwFreeVirtualMemory(
  808. ProcessHandle,
  809. (PVOID)&VirtualAddress,
  810. &Length,
  811. MEM_RELEASE);
  812. //
  813. // Reserve the memory again in 64k chunks.
  814. //
  815. VirtualAddress = NewAddress;
  816. Length = AGP_BLOCK_SIZE;
  817. for (i=0; i<Blocks; i++) {
  818. Status =
  819. ZwAllocateVirtualMemory(
  820. ProcessHandle,
  821. (PVOID)&VirtualAddress,
  822. 0,
  823. &Length,
  824. MEM_RESERVE,
  825. PAGE_READWRITE);
  826. if (NT_SUCCESS(Status) == FALSE) {
  827. break;
  828. }
  829. VirtualAddress += AGP_BLOCK_SIZE;
  830. }
  831. if (NT_SUCCESS(Status) == FALSE) {
  832. //
  833. // clean up and return error
  834. //
  835. VirtualAddress = NewAddress;
  836. while (i--) {
  837. ZwFreeVirtualMemory(
  838. ProcessHandle,
  839. (PVOID)&VirtualAddress,
  840. &Length,
  841. MEM_RELEASE);
  842. VirtualAddress += AGP_BLOCK_SIZE;
  843. }
  844. //
  845. // Indicate we failed to reserve the memory
  846. //
  847. pVideoDebugPrint((0, "We failed to allocate the reserved region\n"));
  848. return NULL;
  849. }
  850. return (PVOID)NewAddress;
  851. } else {
  852. pVideoDebugPrint((0, "AllocateReservedRegion Failed: Status = 0x%x\n", Status));
  853. return NULL;
  854. }
  855. }
  856. VOID
  857. ReleaseReservedRegion(
  858. IN HANDLE ProcessHandle,
  859. IN PVOID VirtualAddress,
  860. IN ULONG Pages
  861. )
  862. /*++
  863. Routine Description:
  864. Reserves a range of user mode virtual addresses.
  865. Arguments:
  866. ProcessHandle - The process in which we need to modify the mappings.
  867. Pages - The number of pages to reserve.
  868. Returns:
  869. Pointer to the reserved region of memory.
  870. --*/
  871. {
  872. NTSTATUS Status;
  873. ULONG_PTR RunningVirtualAddress = (ULONG_PTR)VirtualAddress;
  874. ULONG Blocks = (Pages + PAGES_PER_BLOCK - 1) / PAGES_PER_BLOCK;
  875. ULONG i;
  876. SIZE_T Length = AGP_BLOCK_SIZE;
  877. ASSERT(ProcessHandle != 0);
  878. ASSERT(Pages != 0);
  879. //
  880. // Individually release each block we have reserved.
  881. //
  882. for (i=0; i<Blocks; i++) {
  883. Status =
  884. ZwFreeVirtualMemory(
  885. ProcessHandle,
  886. (PVOID)&RunningVirtualAddress,
  887. &Length,
  888. MEM_RELEASE);
  889. RunningVirtualAddress += AGP_BLOCK_SIZE;
  890. if (NT_SUCCESS(Status) == FALSE) {
  891. pVideoDebugPrint((0, "ReleaseReservedRegion Failed: Status = 0x%x\n", Status));
  892. ASSERT(FALSE);
  893. }
  894. }
  895. }
  896. NTSTATUS
  897. MapBlock(
  898. IN PFDO_EXTENSION fdoExtension,
  899. IN PVIRTUAL_RESERVE_CONTEXT VirtualContext,
  900. IN HANDLE ProcessHandle,
  901. IN PHYSICAL_ADDRESS *PhysicalAddress,
  902. IN PVOID VirtualAddress,
  903. IN ULONG Protect,
  904. IN BOOLEAN Release
  905. )
  906. /*++
  907. Routine Desciption:
  908. Notes:
  909. This function assumes it is being calling within the context of the
  910. correct process.
  911. --*/
  912. {
  913. NTSTATUS ntStatus;
  914. if (Release) {
  915. if (fdoExtension->AgpInterface.Capabilities &
  916. AGP_CAPABILITIES_MAP_PHYSICAL)
  917. {
  918. ZwUnmapViewOfSection(
  919. VirtualContext->ProcessHandle,
  920. VirtualAddress);
  921. } else {
  922. PMDL Mdl;
  923. //
  924. // Get the MDL for the range we are trying to map.
  925. //
  926. Mdl = MmCreateMdl(NULL, NULL, AGP_BLOCK_SIZE);
  927. if (Mdl) {
  928. ULONG Offset;
  929. //
  930. // Calculate the offset into the range
  931. //
  932. Offset = (ULONG)(((ULONG_PTR)VirtualAddress - (ULONG_PTR)VirtualContext->VirtualAddress) / PAGE_SIZE);
  933. fdoExtension->AgpInterface.GetMappedPages(
  934. fdoExtension->AgpInterface.AgpContext,
  935. VirtualContext->PhysicalReserveContext->MapHandle,
  936. AGP_BLOCK_SIZE / PAGE_SIZE,
  937. Offset,
  938. Mdl);
  939. Mdl->MdlFlags |= MDL_PAGES_LOCKED;
  940. MmUnmapLockedPages(
  941. VirtualAddress,
  942. Mdl);
  943. ExFreePool(Mdl);
  944. } else {
  945. //
  946. // We couldn't free the memory because we couldn't allocate
  947. // memory for the MDL. We can free a small chunk at a time
  948. // by using a MDL on the stack.
  949. //
  950. ASSERT(FALSE);
  951. }
  952. }
  953. ntStatus = STATUS_SUCCESS;
  954. } else {
  955. if (fdoExtension->AgpInterface.Capabilities &
  956. AGP_CAPABILITIES_MAP_PHYSICAL)
  957. {
  958. HANDLE PhysicalMemoryHandle;
  959. //
  960. // CPU can access AGP memory through AGP aperature.
  961. //
  962. //
  963. // Get a handle to the physical memory section using our pointer.
  964. // If this fails, return.
  965. //
  966. ntStatus =
  967. ObOpenObjectByPointer(
  968. PhysicalMemorySection,
  969. 0L,
  970. (PACCESS_STATE) NULL,
  971. SECTION_ALL_ACCESS,
  972. (POBJECT_TYPE) NULL,
  973. KernelMode,
  974. &PhysicalMemoryHandle);
  975. //
  976. // If successful, map the memory.
  977. //
  978. if (NT_SUCCESS(ntStatus)) {
  979. SIZE_T Length = AGP_BLOCK_SIZE;
  980. pVideoDebugPrint((2, "Mapping VA 0x%x for 0x%x bytes.\n",
  981. VirtualAddress,
  982. Length));
  983. ntStatus =
  984. ZwMapViewOfSection(
  985. PhysicalMemoryHandle,
  986. ProcessHandle,
  987. &VirtualAddress,
  988. 0,
  989. AGP_BLOCK_SIZE,
  990. PhysicalAddress,
  991. &Length,
  992. ViewUnmap,
  993. 0,
  994. Protect);
  995. if (NT_SUCCESS(ntStatus) == FALSE) {
  996. pVideoDebugPrint((1, "ntStatus = 0x%x\n", ntStatus));
  997. }
  998. ZwClose(PhysicalMemoryHandle);
  999. }
  1000. } else {
  1001. PMDL Mdl;
  1002. //
  1003. // Get the MDL for the range we are trying to map.
  1004. //
  1005. Mdl = MmCreateMdl(NULL, NULL, AGP_BLOCK_SIZE);
  1006. if (Mdl) {
  1007. ULONG Offset;
  1008. //
  1009. // Calculate the offset into the range
  1010. //
  1011. Offset = (ULONG)(((ULONG_PTR)VirtualAddress - (ULONG_PTR)VirtualContext->VirtualAddress) / PAGE_SIZE);
  1012. fdoExtension->AgpInterface.GetMappedPages(
  1013. fdoExtension->AgpInterface.AgpContext,
  1014. VirtualContext->PhysicalReserveContext->MapHandle,
  1015. AGP_BLOCK_SIZE / PAGE_SIZE,
  1016. Offset,
  1017. Mdl);
  1018. Mdl->MdlFlags |= MDL_PAGES_LOCKED | MDL_MAPPING_CAN_FAIL;
  1019. //
  1020. // We must use the CPU's virtual memory mechanism to
  1021. // make the non-contiguous MDL look contiguous.
  1022. //
  1023. VirtualAddress =
  1024. MmMapLockedPagesSpecifyCache(
  1025. Mdl,
  1026. (KPROCESSOR_MODE)UserMode,
  1027. VirtualContext->PhysicalReserveContext->Caching,
  1028. (PVOID)VirtualAddress,
  1029. TRUE,
  1030. HighPagePriority);
  1031. ASSERT(VirtualAddress);
  1032. ExFreePool(Mdl);
  1033. }
  1034. ntStatus = STATUS_SUCCESS;
  1035. }
  1036. }
  1037. return ntStatus;
  1038. }
  1039. NTSTATUS
  1040. UpdateBlock(
  1041. IN HANDLE ProcessHandle,
  1042. IN PVOID VirtualAddress,
  1043. IN ULONG Protect,
  1044. IN BOOLEAN Release
  1045. )
  1046. /*++
  1047. Routine Description:
  1048. Marks a region of user mode memory as being either reserved, or
  1049. available.
  1050. Arguments:
  1051. ProcessHandle - The process in which we need to modify the mappings.
  1052. VirtualAddress - The address to update
  1053. Protect - Caching attributes
  1054. Release - TRUE release the block, FALSE reserve it.
  1055. Returns:
  1056. Status of the operation.
  1057. --*/
  1058. {
  1059. NTSTATUS Status;
  1060. SIZE_T Length = AGP_BLOCK_SIZE;
  1061. pVideoDebugPrint((1, "Update VA 0x%x. Action = %s\n",
  1062. VirtualAddress,
  1063. Release ? "Release" : "Reserve"));
  1064. if (Release) {
  1065. Status =
  1066. ZwFreeVirtualMemory(
  1067. ProcessHandle,
  1068. &VirtualAddress,
  1069. &Length,
  1070. MEM_RELEASE);
  1071. } else {
  1072. Status =
  1073. ZwAllocateVirtualMemory(
  1074. ProcessHandle,
  1075. &VirtualAddress,
  1076. 0,
  1077. &Length,
  1078. MEM_RESERVE,
  1079. Protect);
  1080. }
  1081. return Status;
  1082. }
  1083. BOOLEAN
  1084. UpdateReservedRegion(
  1085. IN PFDO_EXTENSION fdoExtension,
  1086. IN PVIRTUAL_RESERVE_CONTEXT VirtualContext,
  1087. IN ULONG Pages,
  1088. IN ULONG Offset
  1089. )
  1090. /*++
  1091. Routine Description:
  1092. Ensure that the range of pages specified is correctly reserved/released.
  1093. Arguments:
  1094. fdoExtension - The device extension for the miniport.
  1095. VirtualContext - The context for the reserved region to update.
  1096. Pages - The number of 4K pages to reserve.
  1097. Offset - The offset into the reserved region to update.
  1098. Release - TRUE if we are releasing memory, FALSE otherwise.
  1099. Returns:
  1100. TRUE success, FALSE at least a partial failure occured.
  1101. Notes:
  1102. No cleanup is done on failure. So part of the range may ultimately
  1103. be mapped and the rest not. This is ok. The only side effect is that
  1104. even though we return a failure we did do part of the work. Our
  1105. internal data structures remain in a consistent state.
  1106. --*/
  1107. {
  1108. ULONG StartBlock = Offset / PAGES_PER_BLOCK;
  1109. ULONG EndBlock = (Offset + Pages + PAGES_PER_BLOCK - 1) / PAGES_PER_BLOCK;
  1110. ULONG Protect;
  1111. ULONG i;
  1112. NTSTATUS Status;
  1113. PUSHORT BitField = VirtualContext->Region->BitField;
  1114. PUSHORT MapTable = VirtualContext->MapTable->BitField;
  1115. HANDLE Process = VirtualContext->ProcessHandle;
  1116. PVOID VirtualAddress = (PUCHAR)VirtualContext->VirtualAddress + StartBlock * AGP_BLOCK_SIZE;
  1117. PHYSICAL_ADDRESS PhysicalAddress;
  1118. BOOLEAN bRet = TRUE;
  1119. ASSERT(VirtualContext != NULL);
  1120. ASSERT(Pages != 0);
  1121. //
  1122. // Calculate the effective Physical Address
  1123. //
  1124. PhysicalAddress = VirtualContext->PhysicalReserveContext->PhysicalAddress;
  1125. PhysicalAddress.QuadPart += StartBlock * AGP_BLOCK_SIZE;
  1126. //
  1127. // Determine the appropriate page protection
  1128. //
  1129. if (VirtualContext->PhysicalReserveContext->Caching != MmNonCached) {
  1130. Protect = PAGE_READWRITE | PAGE_WRITECOMBINE;
  1131. } else {
  1132. Protect = PAGE_READWRITE | PAGE_NOCACHE;
  1133. }
  1134. for (i=StartBlock; i<EndBlock; i++) {
  1135. ULONG Cluster = i / BLOCKS_PER_CLUSTER;
  1136. ULONG Block = 1 << (i & (BLOCKS_PER_CLUSTER - 1));
  1137. if ((BitField[i] == 0) && (MapTable[Cluster] & Block)) {
  1138. //
  1139. // Unmap user mode memory
  1140. //
  1141. Status = MapBlock(fdoExtension, VirtualContext, Process, &PhysicalAddress, VirtualAddress, Protect, TRUE);
  1142. if (NT_SUCCESS(Status) == FALSE) {
  1143. pVideoDebugPrint((0, "MapBlock(TRUE) failed. Status = 0x%x\n", Status));
  1144. ASSERT(FALSE);
  1145. bRet = FALSE;
  1146. }
  1147. //
  1148. // Reserve the memory so we can map into it again in the
  1149. // future.
  1150. //
  1151. Status = UpdateBlock(Process, VirtualAddress, PAGE_READWRITE, FALSE);
  1152. MapTable[Cluster] &= ~Block;
  1153. if (NT_SUCCESS(Status) == FALSE) {
  1154. pVideoDebugPrint((0, "UpdateBlock(FALSE) failed. Status = 0x%x\n", Status));
  1155. ASSERT(FALSE);
  1156. bRet = FALSE;
  1157. }
  1158. } else if ((BitField[i]) && ((MapTable[Cluster] & Block) == 0)) {
  1159. //
  1160. // Release claim on memory so we can map it.
  1161. //
  1162. Status = UpdateBlock(Process, VirtualAddress, PAGE_READWRITE, TRUE);
  1163. MapTable[Cluster] |= Block;
  1164. if (NT_SUCCESS(Status) == FALSE) {
  1165. pVideoDebugPrint((0, "UpdateBlock(TRUE) failed. Status = 0x%x\n", Status));
  1166. ASSERT(FALSE);
  1167. bRet = FALSE;
  1168. }
  1169. //
  1170. // Map the pages into the user mode process
  1171. //
  1172. Status = MapBlock(fdoExtension, VirtualContext, Process, &PhysicalAddress, VirtualAddress, Protect, FALSE);
  1173. if (NT_SUCCESS(Status) == FALSE) {
  1174. pVideoDebugPrint((0, "MapBlock(FALSE) failed. Status = 0x%x\n", Status));
  1175. ASSERT(FALSE);
  1176. bRet = FALSE;
  1177. }
  1178. }
  1179. //
  1180. // Go to the next 64k block
  1181. //
  1182. VirtualAddress = (PUCHAR)VirtualAddress + AGP_BLOCK_SIZE;
  1183. PhysicalAddress.QuadPart += AGP_BLOCK_SIZE;
  1184. }
  1185. return bRet;
  1186. }
  1187. PVOID
  1188. AgpCommitVirtual(
  1189. IN PVOID Context,
  1190. IN PVOID VirtualReserveContext,
  1191. IN ULONG Pages,
  1192. IN ULONG Offset
  1193. )
  1194. /*++
  1195. Routine Description:
  1196. Reserves a range of physical addresses for AGP.
  1197. Arguments:
  1198. Context - The Agp Context
  1199. VirtualReserveContext - The reservation context.
  1200. Pages - Number of pages to commit.
  1201. Offset - The offset into the reserved region at which to commit the pages.
  1202. Returns:
  1203. The virtual address for the base of the commited pages.
  1204. --*/
  1205. {
  1206. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(Context);
  1207. PVIRTUAL_RESERVE_CONTEXT VirtualContext;
  1208. PPHYSICAL_RESERVE_CONTEXT PhysicalContext;
  1209. PVOID VirtualAddress = NULL;
  1210. NTSTATUS ntStatus;
  1211. BOOLEAN Attached = FALSE;
  1212. ASSERT(VirtualReserveContext != NULL);
  1213. ASSERT(Pages >= 1);
  1214. VirtualContext = (PVIRTUAL_RESERVE_CONTEXT) VirtualReserveContext;
  1215. PhysicalContext = VirtualContext->PhysicalReserveContext;
  1216. //
  1217. // Confirm that the pages being committed fit into the reserved
  1218. // region.
  1219. //
  1220. // We only need to check the last page they are trying to commit. If
  1221. // it is not in the reserved region then we need to fail.
  1222. //
  1223. if ((Offset + Pages) > PhysicalContext->Pages) {
  1224. pVideoDebugPrint((1, "Attempt to commit pages outside of reserved region\n"));
  1225. ASSERT(FALSE);
  1226. return NULL;
  1227. }
  1228. //
  1229. // Calculate the effective virtual address.
  1230. //
  1231. VirtualAddress = ((PUCHAR)VirtualContext->VirtualAddress + Offset * AGP_PAGE_SIZE);
  1232. if (VirtualContext->ProcessHandle) {
  1233. //
  1234. // Make sure we are in the correct process context.
  1235. //
  1236. if (VirtualContext->ProcessHandle == NtCurrentProcess()) {
  1237. if (VirtualContext->Process != PsGetCurrentProcess()) {
  1238. KeAttachProcess(PEProcessToPKProcess(VirtualContext->Process));
  1239. Attached = TRUE;
  1240. }
  1241. }
  1242. ModifyRegion(VirtualContext->Region, Offset, Pages, TRUE);
  1243. //
  1244. // Update the virtual address space.
  1245. //
  1246. if (UpdateReservedRegion(fdoExtension,
  1247. VirtualContext,
  1248. Pages,
  1249. Offset) == FALSE) {
  1250. //
  1251. // Part of the commit failed. Indicate this by returning
  1252. // a NULL.
  1253. //
  1254. VirtualAddress = NULL;
  1255. }
  1256. //
  1257. // Restore initial process context.
  1258. //
  1259. if (Attached) {
  1260. KeDetachProcess();
  1261. }
  1262. } else {
  1263. //
  1264. // Kernel mode commit. Do nothing, the memory is already mapped.
  1265. //
  1266. }
  1267. return VirtualAddress;
  1268. }
  1269. VOID
  1270. AgpFreeVirtual(
  1271. IN PVOID Context,
  1272. IN PVOID VirtualReserveContext,
  1273. IN ULONG Pages,
  1274. IN ULONG Offset
  1275. )
  1276. /*++
  1277. Routine Description:
  1278. Frees a range of virtual addresses.
  1279. Arguments:
  1280. Context - The Agp Context
  1281. VirtualReserveContext - The reservation context.
  1282. Pages - Number of pages to release.
  1283. Offset - The offset into the reserved region at which to release the pages.
  1284. Returns:
  1285. none.
  1286. --*/
  1287. {
  1288. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(Context);
  1289. PVIRTUAL_RESERVE_CONTEXT VirtualContext;
  1290. PPHYSICAL_RESERVE_CONTEXT PhysicalContext;
  1291. PVOID VirtualAddress;
  1292. BOOLEAN Attached=FALSE;
  1293. NTSTATUS Status;
  1294. ASSERT(VirtualReserveContext != NULL);
  1295. VirtualContext = (PVIRTUAL_RESERVE_CONTEXT) VirtualReserveContext;
  1296. PhysicalContext = VirtualContext->PhysicalReserveContext;
  1297. VirtualAddress = (PUCHAR)((ULONG_PTR)VirtualContext->VirtualAddress + Offset * AGP_PAGE_SIZE);
  1298. //
  1299. // Make sure we are in the correct process context.
  1300. //
  1301. if (VirtualContext->ProcessHandle != NULL) {
  1302. if (VirtualContext->ProcessHandle == NtCurrentProcess()) {
  1303. if (VirtualContext->Process != PsGetCurrentProcess()) {
  1304. KeAttachProcess(PEProcessToPKProcess(VirtualContext->Process));
  1305. Attached = TRUE;
  1306. }
  1307. }
  1308. ModifyRegion(VirtualContext->Region, Offset, Pages, FALSE);
  1309. UpdateReservedRegion(fdoExtension,
  1310. VirtualContext,
  1311. Pages,
  1312. Offset);
  1313. if (Attached) {
  1314. KeDetachProcess();
  1315. }
  1316. } else {
  1317. //
  1318. // Kernel Space Free - do nothing.
  1319. //
  1320. }
  1321. }
  1322. BOOLEAN
  1323. AgpSetRate(
  1324. IN PVOID Context,
  1325. IN ULONG AgpRate
  1326. )
  1327. /*++
  1328. Routine Description:
  1329. Thsi function sets chipset's AGP rate.
  1330. Arguments:
  1331. Context - The Agp Context
  1332. AgpRate - The Agp rate to set.
  1333. Returns:
  1334. TRUE if successful,
  1335. FALSE otherwise.
  1336. --*/
  1337. {
  1338. PFDO_EXTENSION fdoExtension;
  1339. NTSTATUS ntStatus;
  1340. BOOLEAN bStatus = FALSE;
  1341. ASSERT(NULL != Context);
  1342. fdoExtension = GET_FDO_EXT(Context);
  1343. ASSERT(NULL != fdoExtension);
  1344. if (fdoExtension->AgpInterface.Version > VIDEO_PORT_AGP_INTERFACE_VERSION_1)
  1345. {
  1346. ASSERT(NULL != fdoExtension->AgpInterface.AgpContext);
  1347. //
  1348. // Try to set chipset's AGP rate.
  1349. //
  1350. ntStatus = fdoExtension->AgpInterface.SetRate(fdoExtension->AgpInterface.AgpContext, AgpRate);
  1351. bStatus = NT_SUCCESS(ntStatus);
  1352. }
  1353. return bStatus;
  1354. }
  1355. BOOLEAN
  1356. VideoPortGetAgpServices(
  1357. IN PVOID HwDeviceExtension,
  1358. OUT PVIDEO_PORT_AGP_SERVICES AgpServices
  1359. )
  1360. /*++
  1361. Routine Description:
  1362. This routine returns a set of AGP services to the caller.
  1363. Arguments:
  1364. HwDeviceExtension - Pointer to the miniports device extension
  1365. AgpServices - A buffer in which to place the AGP services.
  1366. Returns:
  1367. TRUE if successful,
  1368. FALSE otherwise.
  1369. --*/
  1370. {
  1371. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
  1372. SYSTEM_BASIC_INFORMATION basicInfo;
  1373. NTSTATUS status;
  1374. ASSERT(HwDeviceExtension != NULL);
  1375. ASSERT(AgpServices != NULL);
  1376. //
  1377. // This entry point is only valid for PnP Drivers.
  1378. //
  1379. if ((fdoExtension->Flags & LEGACY_DRIVER) == 0) {
  1380. if (VpQueryAgpInterface(fdoExtension, AGP_BUS_INTERFACE_V1)) {
  1381. //
  1382. // Fill in the list of function pointers.
  1383. //
  1384. AgpServices->AgpReservePhysical = AgpReservePhysical;
  1385. AgpServices->AgpCommitPhysical = AgpCommitPhysical;
  1386. AgpServices->AgpFreePhysical = AgpFreePhysical;
  1387. AgpServices->AgpReleasePhysical = AgpReleasePhysical;
  1388. AgpServices->AgpReserveVirtual = AgpReserveVirtual;
  1389. AgpServices->AgpCommitVirtual = AgpCommitVirtual;
  1390. AgpServices->AgpFreeVirtual = AgpFreeVirtual;
  1391. AgpServices->AgpReleaseVirtual = AgpReleaseVirtual;
  1392. AgpServices->AllocationLimit = VpSystemMemorySize / 8;
  1393. pVideoDebugPrint((Trace, "VIDEOPRT: AGP system information success.\n"));
  1394. return TRUE;
  1395. } else {
  1396. pVideoDebugPrint((0, "VIDEOPRT: Failed AGP system information.\n"));
  1397. return FALSE;
  1398. }
  1399. } else {
  1400. pVideoDebugPrint((1, "VideoPortGetAgpServices - only valid on PnP drivers\n"));
  1401. return FALSE;
  1402. }
  1403. }
  1404. VP_STATUS
  1405. VpGetAgpServices2(
  1406. IN PVOID pHwDeviceExtension,
  1407. OUT PVIDEO_PORT_AGP_INTERFACE_2 pAgpInterface
  1408. )
  1409. /*++
  1410. Routine Description:
  1411. This routine returns a set of AGP services to the caller.
  1412. Arguments:
  1413. pHwDeviceExtension - Pointer to the miniports device extension
  1414. pAgpInterface - A buffer in which to place the AGP services.
  1415. Returns:
  1416. TRUE if successful,
  1417. FALSE otherwise.
  1418. --*/
  1419. {
  1420. PFDO_EXTENSION pFdoExtension;
  1421. SYSTEM_BASIC_INFORMATION basicInfo;
  1422. NTSTATUS ntStatus;
  1423. ASSERT(NULL != pHwDeviceExtension);
  1424. ASSERT(NULL != pAgpInterface);
  1425. pFdoExtension = GET_FDO_EXT(pHwDeviceExtension);
  1426. //
  1427. // This entry point is only valid for PnP Drivers.
  1428. //
  1429. if ((pFdoExtension->Flags & LEGACY_DRIVER) == 0)
  1430. {
  1431. if (VpQueryAgpInterface(pFdoExtension, AGP_BUS_INTERFACE_V2))
  1432. {
  1433. //
  1434. // Fill in an interface structure.
  1435. //
  1436. pAgpInterface->Context = pHwDeviceExtension;
  1437. pAgpInterface->InterfaceReference = VpInterfaceDefaultReference;
  1438. pAgpInterface->InterfaceDereference = VpInterfaceDefaultDereference;
  1439. pAgpInterface->AgpReservePhysical = AgpReservePhysical;
  1440. pAgpInterface->AgpCommitPhysical = AgpCommitPhysical;
  1441. pAgpInterface->AgpFreePhysical = AgpFreePhysical;
  1442. pAgpInterface->AgpReleasePhysical = AgpReleasePhysical;
  1443. pAgpInterface->AgpReserveVirtual = AgpReserveVirtual;
  1444. pAgpInterface->AgpCommitVirtual = AgpCommitVirtual;
  1445. pAgpInterface->AgpFreeVirtual = AgpFreeVirtual;
  1446. pAgpInterface->AgpReleaseVirtual = AgpReleaseVirtual;
  1447. pAgpInterface->AgpSetRate = AgpSetRate;
  1448. pAgpInterface->AgpAllocationLimit = VpSystemMemorySize / 8;
  1449. //
  1450. // Reference the interface before handing it out.
  1451. //
  1452. pAgpInterface->InterfaceReference(pAgpInterface->Context);
  1453. pVideoDebugPrint((Trace, "VIDEOPRT!VideoPortGetAgpServices2: AGP system information success.\n"));
  1454. return NO_ERROR;
  1455. }
  1456. else
  1457. {
  1458. pVideoDebugPrint((0, "VIDEOPRT!VideoPortGetAgpServices2: Failed AGP system information.\n"));
  1459. return ERROR_DEV_NOT_EXIST;
  1460. }
  1461. }
  1462. else
  1463. {
  1464. pVideoDebugPrint((1, "VIDEOPRT!VideoPortGetAgpServices2: Only valid on PnP drivers\n"));
  1465. return ERROR_DEV_NOT_EXIST;
  1466. }
  1467. }