Source code of Windows XP (NT5)
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.

790 lines
17 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Copyright (c) 1990 Microsoft Corporation
  4. Module Name:
  5. tbflush.c
  6. Abstract:
  7. This module implements machine dependent functions to flush
  8. the translation buffers in an Intel x86 system.
  9. N.B. This module contains only MP versions of the TB flush routines.
  10. The UP versions are macros in ke.h
  11. KeFlushEntireTb remains a routine for the UP system since it is
  12. exported from the kernel for backwards compatibility.
  13. Author:
  14. David N. Cutler (davec) 13-May-1989
  15. Environment:
  16. Kernel mode only.
  17. Revision History:
  18. Shie-Lin Tzong (shielint) 30-Aug-1990
  19. Implement MP version of KeFlushSingleTb and KeFlushEntireTb.
  20. --*/
  21. #include "ki.h"
  22. VOID
  23. KiFlushTargetEntireTb (
  24. IN PKIPI_CONTEXT SignalDone,
  25. IN PVOID Invalid,
  26. IN PVOID Parameter2,
  27. IN PVOID Parameter3
  28. );
  29. VOID
  30. KiFlushTargetMultipleTb (
  31. IN PKIPI_CONTEXT SignalDone,
  32. IN PVOID Parameter1,
  33. IN PVOID Parameter2,
  34. IN PVOID Parameter3
  35. );
  36. VOID
  37. KiFlushTargetSingleTb (
  38. IN PKIPI_CONTEXT SignalDone,
  39. IN PVOID Parameter1,
  40. IN PVOID Parameter2,
  41. IN PVOID Parameter3
  42. );
  43. HARDWARE_PTE
  44. KiFlushSingleTbSynchronous (
  45. IN PVOID Virtual,
  46. IN BOOLEAN Invalid,
  47. IN BOOLEAN AllProcessors,
  48. IN PHARDWARE_PTE PtePointer,
  49. IN HARDWARE_PTE PteValue
  50. );
  51. VOID
  52. KiFlushTargetSingleTbSynchronous (
  53. IN PKIPI_CONTEXT SignalDone,
  54. IN PVOID Parameter1,
  55. IN PVOID Parameter2,
  56. IN PVOID Parameter3
  57. );
  58. VOID
  59. Ki386UseSynchronousTbFlush (
  60. IN volatile PLONG Number
  61. );
  62. #ifdef ALLOC_PRAGMA
  63. #pragma alloc_text(INIT,Ki386UseSynchronousTbFlush)
  64. #endif
  65. #if !defined(NT_UP)
  66. VOID
  67. KeFlushEntireTb (
  68. IN BOOLEAN Invalid,
  69. IN BOOLEAN AllProcessors
  70. )
  71. /*++
  72. Routine Description:
  73. This function flushes the entire translation buffer (TB) on all processors
  74. that are currently running threads which are child of the current process
  75. or flushes the entire translation buffer on all processors in the host
  76. configuration.
  77. Arguments:
  78. Invalid - Supplies a boolean value that specifies the reason for flushing
  79. the translation buffer.
  80. AllProcessors - Supplies a boolean value that determines which translation
  81. buffers are to be flushed.
  82. Return Value:
  83. None.
  84. --*/
  85. {
  86. KAFFINITY EntireSet;
  87. KIRQL OldIrql;
  88. PKPRCB Prcb;
  89. PKPROCESS Process;
  90. KAFFINITY TargetProcessors;
  91. //
  92. // Compute the target set of processors, disable context switching,
  93. // and send the flush entire parameters to the target processors,
  94. // if any, for execution.
  95. //
  96. if (AllProcessors != FALSE) {
  97. OldIrql = KeRaiseIrqlToSynchLevel();
  98. Prcb = KeGetCurrentPrcb();
  99. TargetProcessors = KeActiveProcessors;
  100. } else {
  101. KiLockContextSwap(&OldIrql);
  102. Prcb = KeGetCurrentPrcb();
  103. Process = Prcb->CurrentThread->ApcState.Process;
  104. TargetProcessors = Process->ActiveProcessors;
  105. }
  106. EntireSet = KeActiveProcessors & ~Prcb->SetMember;
  107. TargetProcessors &= ~Prcb->SetMember;
  108. //
  109. // If the target set of processors is equal to the full set of processors,
  110. // then set the TB flush time stamp busy.
  111. //
  112. if (TargetProcessors == EntireSet) {
  113. KiSetTbFlushTimeStampBusy();
  114. }
  115. //
  116. // Send packet to target processors.
  117. //
  118. if (TargetProcessors != 0) {
  119. KiIpiSendPacket(TargetProcessors,
  120. KiFlushTargetEntireTb,
  121. NULL,
  122. NULL,
  123. NULL);
  124. IPI_INSTRUMENT_COUNT (Prcb->Number, FlushEntireTb);
  125. }
  126. //
  127. // Flush TB on current processor.
  128. //
  129. KeFlushCurrentTb();
  130. //
  131. // Wait until all target processors have finished and complete packet.
  132. //
  133. if (TargetProcessors != 0) {
  134. KiIpiStallOnPacketTargets(TargetProcessors);
  135. }
  136. //
  137. // If the target set of processors is equal to the full set of processors,
  138. // then clear the TB flush time stamp busy.
  139. //
  140. if (TargetProcessors == EntireSet) {
  141. KiClearTbFlushTimeStampBusy();
  142. }
  143. //
  144. // Lower IRQL and unlock as appropriate.
  145. //
  146. if (AllProcessors != FALSE) {
  147. KeLowerIrql(OldIrql);
  148. } else {
  149. KiUnlockContextSwap(OldIrql);
  150. }
  151. return;
  152. }
  153. VOID
  154. KiFlushTargetEntireTb (
  155. IN PKIPI_CONTEXT SignalDone,
  156. IN PVOID Parameter1,
  157. IN PVOID Parameter2,
  158. IN PVOID Parameter3
  159. )
  160. /*++
  161. Routine Description:
  162. This is the target function for flushing the entire TB.
  163. Arguments:
  164. SignalDone - Supplies a pointer to a variable that is cleared when the
  165. requested operation has been performed.
  166. Parameter1 - Parameter3 - Not used.
  167. Return Value:
  168. None.
  169. --*/
  170. {
  171. //
  172. // Flush the entire TB on the current processor.
  173. //
  174. KiIpiSignalPacketDone(SignalDone);
  175. KeFlushCurrentTb();
  176. return;
  177. }
  178. VOID
  179. KeFlushMultipleTb (
  180. IN ULONG Number,
  181. IN PVOID *Virtual,
  182. IN BOOLEAN Invalid,
  183. IN BOOLEAN AllProcessors,
  184. IN PHARDWARE_PTE *PtePointer OPTIONAL,
  185. IN HARDWARE_PTE PteValue
  186. )
  187. /*++
  188. Routine Description:
  189. This function flushes multiple entries from the translation buffer
  190. on all processors that are currently running threads which are
  191. children of the current process or flushes a multiple entries from
  192. the translation buffer on all processors in the host configuration.
  193. Arguments:
  194. Number - Supplies the number of TB entries to flush.
  195. Virtual - Supplies a pointer to an array of virtual addresses that
  196. are within the pages whose translation buffer entries are to be
  197. flushed.
  198. Invalid - Supplies a boolean value that specifies the reason for
  199. flushing the translation buffer.
  200. AllProcessors - Supplies a boolean value that determines which
  201. translation buffers are to be flushed.
  202. PtePointer - Supplies an optional pointer to an array of pointers to
  203. page table entries that receive the specified page table entry
  204. value.
  205. PteValue - Supplies the the new page table entry value.
  206. Return Value:
  207. The previous contents of the specified page table entry is returned
  208. as the function value.
  209. --*/
  210. {
  211. ULONG Index;
  212. KIRQL OldIrql;
  213. PKPRCB Prcb;
  214. PKPROCESS Process;
  215. KAFFINITY TargetProcessors;
  216. //
  217. // Compute target set of processors.
  218. //
  219. if (AllProcessors != FALSE) {
  220. OldIrql = KeRaiseIrqlToSynchLevel();
  221. Prcb = KeGetCurrentPrcb();
  222. TargetProcessors = KeActiveProcessors;
  223. } else {
  224. KiLockContextSwap(&OldIrql);
  225. Prcb = KeGetCurrentPrcb();
  226. Process = Prcb->CurrentThread->ApcState.Process;
  227. TargetProcessors = Process->ActiveProcessors;
  228. }
  229. TargetProcessors &= ~Prcb->SetMember;
  230. //
  231. // If a page table entry address array is specified, then set the
  232. // specified page table entries to the specific value.
  233. //
  234. if (ARGUMENT_PRESENT(PtePointer)) {
  235. for (Index = 0; Index < Number; Index += 1) {
  236. KI_FILL_PTE(PtePointer[Index], PteValue);
  237. }
  238. }
  239. //
  240. // If any target processors are specified, then send a flush multiple
  241. // packet to the target set of processors.
  242. //
  243. if (TargetProcessors != 0) {
  244. KiIpiSendPacket(TargetProcessors,
  245. KiFlushTargetMultipleTb,
  246. (PVOID)Invalid,
  247. (PVOID)Number,
  248. (PVOID)Virtual);
  249. IPI_INSTRUMENT_COUNT (Prcb->Number, FlushMultipleTb);
  250. }
  251. //
  252. // Flush the specified entries from the TB on the current processor.
  253. //
  254. for (Index = 0; Index < Number; Index += 1) {
  255. KiFlushSingleTb(Invalid, Virtual[Index]);
  256. }
  257. //
  258. // Wait until all target processors have finished and complete packet.
  259. //
  260. if (TargetProcessors != 0) {
  261. KiIpiStallOnPacketTargets(TargetProcessors);
  262. }
  263. //
  264. // Release the context swap lock.
  265. //
  266. if (AllProcessors != FALSE) {
  267. KeLowerIrql(OldIrql);
  268. } else {
  269. KiUnlockContextSwap(OldIrql);
  270. }
  271. return;
  272. }
  273. VOID
  274. KiFlushTargetMultipleTb (
  275. IN PKIPI_CONTEXT SignalDone,
  276. IN PVOID Invalid,
  277. IN PVOID Number,
  278. IN PVOID Virtual
  279. )
  280. /*++
  281. Routine Description:
  282. This is the target function for flushing multiple TB entries.
  283. Arguments:
  284. SignalDone - Supplies a pointer to a variable that is cleared when the
  285. requested operation has been performed.
  286. Invalid - Supplies a bollean value that determines whether the virtual
  287. address is invalid.
  288. Number - Supplies the number of TB entries to flush.
  289. Virtual - Supplies a pointer to an array of virtual addresses that
  290. are within the pages whose translation buffer entries are to be
  291. flushed.
  292. Return Value:
  293. None.
  294. --*/
  295. {
  296. ULONG Index;
  297. PVOID VirtualAddress[FLUSH_MULTIPLE_MAXIMUM];
  298. //
  299. // Capture the virtual addresses that are to be flushed from the TB
  300. // on the current processor and signal pack done.
  301. //
  302. for (Index = 0; Index < (ULONG) Number; Index += 1) {
  303. VirtualAddress[Index] = ((PVOID *)(Virtual))[Index];
  304. }
  305. KiIpiSignalPacketDone(SignalDone);
  306. //
  307. // Flush the specified virtual address for the TB on the current
  308. // processor.
  309. //
  310. for (Index = 0; Index < (ULONG) Number; Index += 1) {
  311. KiFlushSingleTb((BOOLEAN)Invalid, VirtualAddress [Index]);
  312. }
  313. }
  314. HARDWARE_PTE
  315. KeFlushSingleTb (
  316. IN PVOID Virtual,
  317. IN BOOLEAN Invalid,
  318. IN BOOLEAN AllProcessors,
  319. IN PHARDWARE_PTE PtePointer,
  320. IN HARDWARE_PTE PteValue
  321. )
  322. /*++
  323. Routine Description:
  324. This function flushes a single entry from translation buffer (TB) on all
  325. processors that are currently running threads which are child of the current
  326. process or flushes the entire translation buffer on all processors in the
  327. host configuration.
  328. Arguments:
  329. Virtual - Supplies a virtual address that is within the page whose
  330. translation buffer entry is to be flushed.
  331. Invalid - Supplies a boolean value that specifies the reason for flushing
  332. the translation buffer.
  333. AllProcessors - Supplies a boolean value that determines which translation
  334. buffers are to be flushed.
  335. PtePointer - Address of Pte to update with new value.
  336. PteValue - New value to put in the Pte. Will simply be assigned to
  337. *PtePointer, in a fashion correct for the hardware.
  338. Return Value:
  339. Returns the contents of the PtePointer before the new value
  340. is stored.
  341. --*/
  342. {
  343. KIRQL OldIrql;
  344. PKPRCB Prcb;
  345. PKPROCESS Process;
  346. HARDWARE_PTE OldPteValue;
  347. KAFFINITY TargetProcessors;
  348. //
  349. // Compute target set of processors.
  350. //
  351. if (AllProcessors != FALSE) {
  352. OldIrql = KeRaiseIrqlToSynchLevel();
  353. Prcb = KeGetCurrentPrcb();
  354. TargetProcessors = KeActiveProcessors;
  355. } else {
  356. KiLockContextSwap(&OldIrql);
  357. Prcb = KeGetCurrentPrcb();
  358. Process = Prcb->CurrentThread->ApcState.Process;
  359. TargetProcessors = Process->ActiveProcessors;
  360. }
  361. TargetProcessors &= ~Prcb->SetMember;
  362. //
  363. // Capture the previous contents of the page table entry and set the
  364. // page table entry to the new value.
  365. //
  366. KI_SWAP_PTE(PtePointer, PteValue, OldPteValue);
  367. //
  368. // If any target processors are specified, then send a flush single
  369. // packet to the target set of processors.
  370. //
  371. if (TargetProcessors != 0) {
  372. KiIpiSendPacket(TargetProcessors,
  373. KiFlushTargetSingleTb,
  374. (PVOID)Invalid,
  375. (PVOID)Virtual,
  376. NULL);
  377. IPI_INSTRUMENT_COUNT(Prcb->Number, FlushSingleTb);
  378. }
  379. //
  380. // Flush the specified entry from the TB on the current processor.
  381. //
  382. KiFlushSingleTb(Invalid, Virtual);
  383. //
  384. // Wait until all target processors have finished and complete packet.
  385. //
  386. if (TargetProcessors != 0) {
  387. KiIpiStallOnPacketTargets(TargetProcessors);
  388. }
  389. //
  390. // Release the context swap lock.
  391. //
  392. if (AllProcessors != FALSE) {
  393. KeLowerIrql(OldIrql);
  394. } else {
  395. KiUnlockContextSwap(OldIrql);
  396. }
  397. return(OldPteValue);
  398. }
  399. VOID
  400. KiFlushTargetSingleTb (
  401. IN PKIPI_CONTEXT SignalDone,
  402. IN PVOID Invalid,
  403. IN PVOID VirtualAddress,
  404. IN PVOID Parameter3
  405. )
  406. /*++
  407. Routine Description:
  408. This is the target function for flushing a single TB entry.
  409. Arguments:
  410. SignalDone Supplies a pointer to a variable that is cleared when the
  411. requested operation has been performed.
  412. Invalid - Supplies a bollean value that determines whether the virtual
  413. address is invalid.
  414. Virtual - Supplies a virtual address that is within the page whose
  415. translation buffer entry is to be flushed.
  416. Parameter3 - Not used.
  417. Return Value:
  418. None.
  419. --*/
  420. {
  421. //
  422. // Flush a single entry from the TB on the current processor.
  423. //
  424. KiIpiSignalPacketDone(SignalDone);
  425. KiFlushSingleTb((BOOLEAN)Invalid, (PVOID)VirtualAddress);
  426. }
  427. HARDWARE_PTE
  428. KiFlushSingleTbSynchronous (
  429. IN PVOID Virtual,
  430. IN BOOLEAN Invalid,
  431. IN BOOLEAN AllProcessors,
  432. IN PHARDWARE_PTE PtePointer,
  433. IN HARDWARE_PTE PteValue
  434. )
  435. /*++
  436. Routine Description:
  437. This function is a slow synchronous version of KeFlushSingleTb. We need
  438. this function as many P6's don't actually know how to deal with PTEs in
  439. an MP safe manner.
  440. Arguments:
  441. See KeFlushSingleTb
  442. Return Value:
  443. See KeFlushSingleTb
  444. --*/
  445. {
  446. KIRQL OldIrql;
  447. PKPRCB Prcb;
  448. PKPROCESS Process;
  449. HARDWARE_PTE OldPteValue;
  450. KAFFINITY TargetProcessors;
  451. //
  452. // Synchronize will all other single flush calls (and other
  453. // IPIs which use reverse stalls)
  454. //
  455. KiLockContextSwap(&OldIrql);
  456. //
  457. // Compute target set of processors.
  458. //
  459. Prcb = KeGetCurrentPrcb();
  460. if (AllProcessors != FALSE) {
  461. TargetProcessors = KeActiveProcessors;
  462. } else {
  463. Process = Prcb->CurrentThread->ApcState.Process;
  464. TargetProcessors = Process->ActiveProcessors;
  465. }
  466. TargetProcessors &= ~Prcb->SetMember;
  467. //
  468. // If any target processors are specified, then send a flush single
  469. // packet to the target set of processors.
  470. //
  471. if (TargetProcessors != 0) {
  472. KiIpiSendSynchronousPacket(Prcb,
  473. TargetProcessors,
  474. KiFlushTargetSingleTbSynchronous,
  475. (PVOID)Invalid,
  476. (PVOID)Virtual,
  477. (PVOID)&Prcb->ReverseStall
  478. );
  479. IPI_INSTRUMENT_COUNT(Prcb->Number, FlushSingleTb);
  480. //
  481. // Wait for the target processors to stall
  482. //
  483. KiIpiStallOnPacketTargets(TargetProcessors);
  484. //
  485. // Capture the previous contents of the page table entry and set the
  486. // page table entry to the new value.
  487. //
  488. KI_SWAP_PTE(PtePointer, PteValue, OldPteValue);
  489. //
  490. // Notify all prcessors it's time to go
  491. //
  492. Prcb->ReverseStall += 1;
  493. } else {
  494. //
  495. // Capture the previous contents of the page table entry and set the
  496. // page table entry to the new value.
  497. //
  498. KI_SWAP_PTE(PtePointer, PteValue, OldPteValue);
  499. }
  500. //
  501. // Flush the specified entry from the TB on the current processor.
  502. //
  503. KiFlushSingleTb(Invalid, Virtual);
  504. //
  505. // Done
  506. //
  507. KiUnlockContextSwap(OldIrql);
  508. return(OldPteValue);
  509. }
  510. VOID
  511. KiFlushTargetSingleTbSynchronous (
  512. IN PKIPI_CONTEXT SignalDone,
  513. IN PVOID Invalid,
  514. IN PVOID VirtualAddress,
  515. IN PVOID Proceed
  516. )
  517. /*++
  518. Routine Description:
  519. This is the target function for flushing a single TB entry synchronously.
  520. Arguments:
  521. SignalDone Supplies a pointer to a variable that is cleared when the
  522. requested operation has been performed.
  523. Invalid - Supplies a bollean value that determines whether the virtual
  524. address is invalid.
  525. Virtual - Supplies a virtual address that is within the page whose
  526. translation buffer entry is to be flushed.
  527. Parameter3 - Not used.
  528. Return Value:
  529. None.
  530. --*/
  531. {
  532. //
  533. // Flush a single entry from the TB on the current processor.
  534. //
  535. KiIpiSignalPacketDoneAndStall(SignalDone, Proceed);
  536. KiFlushSingleTb((BOOLEAN)Invalid, (PVOID)VirtualAddress);
  537. }
  538. VOID
  539. Ki386UseSynchronousTbFlush (
  540. IN volatile PLONG Number
  541. )
  542. {
  543. PKPRCB Prcb;
  544. volatile PUCHAR Patch;
  545. Prcb = KeGetCurrentPrcb();
  546. Patch = (PUCHAR) KeFlushSingleTb;
  547. //
  548. // Signal we're here and wait for others
  549. //
  550. InterlockedDecrement (Number);
  551. while (*Number) ;
  552. //
  553. // If this is processor 0 apply the patch
  554. //
  555. if (Prcb->Number == 0) {
  556. *((PULONG) &Patch[1]) = ((ULONG) &KiFlushSingleTbSynchronous) - ((ULONG) Patch) - 5;
  557. Patch[0] = 0xe9;
  558. }
  559. //
  560. // Wait for processor 0 to complete installation of handler
  561. //
  562. while (Patch[0] != 0xe9) ;
  563. }
  564. #endif