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.

929 lines
20 KiB

  1. /*++
  2. Module Name:
  3. region.c
  4. Abstract:
  5. This module implements the region space management code.
  6. Author:
  7. Landy Wang (landyw) 18-Feb-1999
  8. Koichi Yamada (kyamada) 18-Feb-1999
  9. Environment:
  10. Kernel mode only.
  11. Revision History:
  12. --*/
  13. #include "ki.h"
  14. VOID
  15. KiSetRegionRegister (
  16. PVOID VirtualAddress,
  17. ULONGLONG Contents
  18. );
  19. #define KiMakeValidRegionRegister(Rid, Ps) \
  20. (((ULONGLONG)Rid << RR_RID) | (Ps << RR_PS) | (1 << RR_VE))
  21. ULONG KiMaximumRid = MAXIMUM_RID;
  22. VOID
  23. KiSyncNewRegionIdTarget (
  24. IN PULONG SignalDone,
  25. IN PVOID Parameter1,
  26. IN PVOID Parameter2,
  27. IN PVOID Parameter3
  28. )
  29. /*++
  30. Routine Description:
  31. This is the target function for synchronizing the region IDs.
  32. Arguments:
  33. SignalDone - Supplies a pointer to a variable that is cleared when the
  34. requested operation has been performed.
  35. Parameter1 - Not used.
  36. Parameter2 - Not used.
  37. Parameter3 - Not used.
  38. Return Value:
  39. None.
  40. --*/
  41. {
  42. #if !defined(NT_UP)
  43. PKPROCESS Process;
  44. PREGION_MAP_INFO ProcessRegion;
  45. PREGION_MAP_INFO MappedSession;
  46. //
  47. // get KPROCESS from PCR for MP synchronization
  48. //
  49. Process = (PKPROCESS)PCR->Pcb;
  50. ProcessRegion = &Process->ProcessRegion;
  51. MappedSession = Process->SessionMapInfo;
  52. KiAcquireSpinLock(&KiMasterRidLock);
  53. if (ProcessRegion->SequenceNumber != KiMasterSequence) {
  54. KiMasterRid += 1;
  55. ProcessRegion->RegionId = KiMasterRid;
  56. ProcessRegion->SequenceNumber = KiMasterSequence;
  57. }
  58. KiSetRegionRegister(MM_LOWEST_USER_ADDRESS,
  59. KiMakeValidRegionRegister(ProcessRegion->RegionId, PAGE_SHIFT));
  60. KiFlushFixedDataTb(TRUE, PDE_UTBASE);
  61. KeFillFixedEntryTb((PHARDWARE_PTE)&Process->DirectoryTableBase[0],
  62. (PVOID)PDE_UTBASE,
  63. PAGE_SHIFT,
  64. DTR_UTBASE_INDEX);
  65. if (MappedSession->SequenceNumber != KiMasterSequence) {
  66. KiMasterRid += 1;
  67. MappedSession->RegionId = KiMasterRid;
  68. MappedSession->SequenceNumber = KiMasterSequence;
  69. }
  70. KiSetRegionRegister((PVOID)SADDRESS_BASE,
  71. KiMakeValidRegionRegister(MappedSession->RegionId, PAGE_SHIFT));
  72. KiFlushFixedDataTb(TRUE, PDE_STBASE);
  73. KeFillFixedEntryTb((PHARDWARE_PTE)&Process->SessionParentBase,
  74. (PVOID)PDE_STBASE,
  75. PAGE_SHIFT,
  76. DTR_STBASE_INDEX);
  77. KiReleaseSpinLock(&KiMasterRidLock);
  78. KiIpiSignalPacketDone(SignalDone);
  79. KeFlushCurrentTb();
  80. #else
  81. UNREFERENCED_PARAMETER (SignalDone);
  82. #endif
  83. UNREFERENCED_PARAMETER (Parameter1);
  84. UNREFERENCED_PARAMETER (Parameter2);
  85. UNREFERENCED_PARAMETER (Parameter3);
  86. return;
  87. }
  88. BOOLEAN
  89. KiSyncNewRegionId(
  90. IN PREGION_MAP_INFO ProcessRegion,
  91. IN PREGION_MAP_INFO SessionRegion,
  92. IN BOOLEAN RegionFlushRequired
  93. )
  94. /*++
  95. Routine Description:
  96. Generate a new region id and synchronize the region IDs on all the
  97. processors if necessary. If the region IDs wrap then flush all
  98. processor TBs.
  99. Arguments:
  100. ProcessRegion - Supplies a REGION_MAP_INFO user space pointer.
  101. SessionRegion - Supplies a REGION_MAP_INFO session space pointer.
  102. LockHeld - KiRegionSwapLock is held by the caller
  103. Return Value:
  104. TRUE - if the region id has been recycled.
  105. FALSE -- if the region id has not been recycled.
  106. Notes:
  107. This routine called by KiSwapProcess and KeAttachSessionSpace.
  108. Environment:
  109. Kernel mode.
  110. Called at SYNCH_LEVEL
  111. --*/
  112. {
  113. ULONG i;
  114. LOGICAL RidRecycled;
  115. #if !defined(NT_UP)
  116. KAFFINITY TargetProcessors;
  117. KIRQL OldIrql;
  118. #endif
  119. ULONGLONG PrSequence;
  120. ULONGLONG SeSequence;
  121. RidRecycled = FALSE;
  122. ASSERT (KeGetCurrentIrql () == SYNCH_LEVEL);
  123. //
  124. // copy the KPROCESS pointer for MP region synchronization
  125. //
  126. PCR->Pcb = (PVOID)KeGetCurrentThread()->ApcState.Process;
  127. //
  128. // Invalidx1ate the ForwardProgressTb buffer
  129. //
  130. for (i = 0; i < MAXIMUM_FWP_BUFFER_ENTRY; i += 1) {
  131. PCR->ForwardProgressBuffer[(i*2)+1] = 0;
  132. }
  133. not_recycled:
  134. #if !defined(NT_UP)
  135. KeRaiseIrql(HIGH_LEVEL, &OldIrql);
  136. #endif
  137. PrSequence = ProcessRegion->SequenceNumber;
  138. SeSequence = SessionRegion->SequenceNumber;
  139. if ((PrSequence == KiMasterSequence) && (SeSequence == KiMasterSequence)) {
  140. KiSetRegionRegister(MM_LOWEST_USER_ADDRESS,
  141. KiMakeValidRegionRegister(ProcessRegion->RegionId,
  142. PAGE_SHIFT));
  143. KiSetRegionRegister((PVOID)SADDRESS_BASE,
  144. KiMakeValidRegionRegister(SessionRegion->RegionId,
  145. PAGE_SHIFT));
  146. #if !defined(NT_UP)
  147. KeLowerIrql(OldIrql);
  148. #endif
  149. #if !defined(NT_UP)
  150. if (RegionFlushRequired) {
  151. KiAcquireSpinLock (&KiRegionSwapLock);
  152. goto RegionFlush;
  153. }
  154. #endif
  155. UNREFERENCED_PARAMETER (RegionFlushRequired);
  156. return FALSE;
  157. }
  158. #if !defined(NT_UP)
  159. KeLowerIrql(OldIrql);
  160. KiAcquireSpinLock (&KiRegionSwapLock);
  161. #endif
  162. PrSequence = ProcessRegion->SequenceNumber;
  163. SeSequence = SessionRegion->SequenceNumber;
  164. if (PrSequence != KiMasterSequence) {
  165. if (KiMasterRid + 1 > KiMaximumRid) {
  166. RidRecycled = TRUE;
  167. } else {
  168. KiMasterRid += 1;
  169. ProcessRegion->RegionId = KiMasterRid;
  170. ProcessRegion->SequenceNumber = KiMasterSequence;
  171. }
  172. }
  173. if ((RidRecycled == FALSE) && (SeSequence != KiMasterSequence)) {
  174. if (KiMasterRid + 1 > KiMaximumRid) {
  175. RidRecycled = TRUE;
  176. } else {
  177. KiMasterRid += 1;
  178. SessionRegion->RegionId = KiMasterRid;
  179. SessionRegion->SequenceNumber = KiMasterSequence;
  180. }
  181. }
  182. if (RidRecycled == FALSE) {
  183. KiReleaseSpinLock(&KiRegionSwapLock);
  184. goto not_recycled;
  185. }
  186. //
  187. // The region ID must be recycled.
  188. //
  189. KiMasterRid = START_PROCESS_RID;
  190. //
  191. // Since KiMasterSequence is 64-bits wide, it will
  192. // not be recycled in your life time.
  193. //
  194. if (KiMasterSequence + 1 > MAXIMUM_SEQUENCE) {
  195. KiMasterSequence = START_SEQUENCE;
  196. } else {
  197. KiMasterSequence += 1;
  198. }
  199. //
  200. // Update the new process's ProcessRid and ProcessSequence.
  201. //
  202. ProcessRegion->RegionId = KiMasterRid;
  203. ProcessRegion->SequenceNumber = KiMasterSequence;
  204. KiSetRegionRegister(MM_LOWEST_USER_ADDRESS,
  205. KiMakeValidRegionRegister(ProcessRegion->RegionId, PAGE_SHIFT));
  206. KiMasterRid += 1;
  207. SessionRegion->RegionId = KiMasterRid;
  208. SessionRegion->SequenceNumber = KiMasterSequence;
  209. KiSetRegionRegister((PVOID)SADDRESS_BASE,
  210. KiMakeValidRegionRegister(SessionRegion->RegionId, PAGE_SHIFT));
  211. #if !defined(NT_UP)
  212. RegionFlush:
  213. //
  214. // Broadcast Region Id sync.
  215. //
  216. TargetProcessors = KeActiveProcessors;
  217. TargetProcessors &= PCR->NotMember;
  218. if (TargetProcessors != 0) {
  219. KiIpiSendPacket(TargetProcessors,
  220. KiSyncNewRegionIdTarget,
  221. (PVOID)TRUE,
  222. NULL,
  223. NULL);
  224. }
  225. #endif
  226. KeFlushCurrentTb();
  227. #if !defined(NT_UP)
  228. //
  229. // Wait until all target processors have finished.
  230. //
  231. if (TargetProcessors != 0) {
  232. KiIpiStallOnPacketTargets(TargetProcessors);
  233. }
  234. #endif
  235. #if !defined(NT_UP)
  236. KiReleaseSpinLock (&KiRegionSwapLock);
  237. #endif
  238. return TRUE;
  239. }
  240. VOID
  241. KeEnableSessionSharing(
  242. IN PREGION_MAP_INFO SessionMapInfo,
  243. IN PFN_NUMBER SessionParentPage
  244. )
  245. /*++
  246. Routine Description:
  247. This routine initializes a session for use. This includes :
  248. 1. Allocating a new region ID for the session.
  249. 2. Updating the current region register with this new RID.
  250. 3. Updating the SessionMapInfo fields so context switches will work.
  251. 4. Updating SessionParentBase fields so context switches will work.
  252. Upon return from this routine, the session will be available for
  253. sharing by the current and other processes.
  254. Arguments:
  255. SessionMapInfo - Supplies a session map info to be shared.
  256. SessionParentPage - Supplies the top level parent page mapping the
  257. argument session space.
  258. Return Value:
  259. None.
  260. Environment:
  261. Kernel mode.
  262. --*/
  263. {
  264. ULONG i;
  265. #if !defined(NT_UP)
  266. KAFFINITY TargetProcessors;
  267. #endif
  268. PKPROCESS Process;
  269. PKTHREAD Thread;
  270. KIRQL OldIrql;
  271. Thread = KeGetCurrentThread();
  272. Process = Thread->ApcState.Process;
  273. OldIrql = KeRaiseIrqlToSynchLevel();
  274. INITIALIZE_DIRECTORY_TABLE_BASE (&Process->SessionParentBase,
  275. SessionParentPage);
  276. //
  277. // Invalidate the ForwardProgressTb buffer.
  278. //
  279. for (i = 0; i < MAXIMUM_FWP_BUFFER_ENTRY; i += 1) {
  280. PCR->ForwardProgressBuffer[(i*2)+1] = 0;
  281. }
  282. #if !defined(NT_UP)
  283. KiAcquireSpinLock(&KiRegionSwapLock);
  284. #endif
  285. if (KiMasterRid + 1 > KiMaximumRid) {
  286. //
  287. // The region ID must be recycled.
  288. //
  289. KiMasterRid = START_PROCESS_RID;
  290. //
  291. // Since KiMasterSequence is 64-bits wide, it will
  292. // not be recycled in your life time.
  293. //
  294. if (KiMasterSequence + 1 > MAXIMUM_SEQUENCE) {
  295. KiMasterSequence = START_SEQUENCE;
  296. } else {
  297. KiMasterSequence += 1;
  298. }
  299. }
  300. //
  301. // Update the newly created session's RegionId and SequenceNumber.
  302. //
  303. KiMasterRid += 1;
  304. Process->SessionMapInfo = SessionMapInfo;
  305. SessionMapInfo->RegionId = KiMasterRid;
  306. SessionMapInfo->SequenceNumber = KiMasterSequence;
  307. KiSetRegionRegister((PVOID)SADDRESS_BASE,
  308. KiMakeValidRegionRegister(SessionMapInfo->RegionId,
  309. PAGE_SHIFT));
  310. //
  311. // Note that all processors must be notified because this thread could
  312. // context switch onto another processor. If that processor was already
  313. // running a thread from this same process, no region register update
  314. // would occur otherwise.
  315. //
  316. #if !defined(NT_UP)
  317. //
  318. // Broadcast Region Id sync.
  319. //
  320. TargetProcessors = KeActiveProcessors;
  321. TargetProcessors &= PCR->NotMember;
  322. if (TargetProcessors != 0) {
  323. KiIpiSendPacket(TargetProcessors,
  324. KiSyncNewRegionIdTarget,
  325. (PVOID)TRUE,
  326. NULL,
  327. NULL);
  328. }
  329. #endif
  330. KeFlushCurrentTb();
  331. KeFillFixedEntryTb((PHARDWARE_PTE)&Process->SessionParentBase,
  332. (PVOID)PDE_STBASE,
  333. PAGE_SHIFT,
  334. DTR_STBASE_INDEX);
  335. #if !defined(NT_UP)
  336. //
  337. // Wait until all target processors have finished.
  338. //
  339. if (TargetProcessors != 0) {
  340. KiIpiStallOnPacketTargets(TargetProcessors);
  341. }
  342. KiReleaseSpinLock(&KiRegionSwapLock);
  343. #endif
  344. KeLowerIrql(OldIrql);
  345. }
  346. VOID
  347. KeAttachSessionSpace(
  348. PREGION_MAP_INFO SessionMapInfo,
  349. IN PFN_NUMBER SessionParentPage
  350. )
  351. /*++
  352. Routine Description:
  353. This routine attaches the current process to the specified session.
  354. This includes:
  355. 1. Updating the current region register with the target RID.
  356. 2. Updating the SessionMapInfo fields so context switches will work.
  357. 3. Updating SessionParentBase fields so context switches will work.
  358. Arguments:
  359. SessionMapInfo - Supplies the target session map info.
  360. SessionParentPage - Supplies the top level parent page mapping the
  361. argument session space.
  362. Return Value:
  363. None.
  364. Environment:
  365. Kernel mode.
  366. --*/
  367. {
  368. KIRQL OldIrql;
  369. PKTHREAD Thread;
  370. PKPROCESS Process;
  371. Thread = KeGetCurrentThread();
  372. Process = Thread->ApcState.Process;
  373. OldIrql = KeRaiseIrqlToSynchLevel();
  374. ASSERT(SessionMapInfo != NULL);
  375. //
  376. // Attach to the specified session.
  377. //
  378. INITIALIZE_DIRECTORY_TABLE_BASE (&Process->SessionParentBase,
  379. SessionParentPage);
  380. Process->SessionMapInfo = SessionMapInfo;
  381. //
  382. // Note that all processors must be notified because this thread could
  383. // context switch onto another processor. If that processor was already
  384. // running a thread from this same process, no region register update
  385. // would occur. Hence KiRegionFlushRequired is set under ContextSwap lock
  386. // protection to signify this to KiSyncNewRegionId.
  387. //
  388. KiSyncNewRegionId(&Process->ProcessRegion, SessionMapInfo, TRUE);
  389. KiFlushFixedDataTb(TRUE, PDE_STBASE);
  390. KeFillFixedEntryTb((PHARDWARE_PTE)&Process->SessionParentBase,
  391. (PVOID)PDE_STBASE,
  392. PAGE_SHIFT,
  393. DTR_STBASE_INDEX);
  394. KeLowerIrql(OldIrql);
  395. }
  396. VOID
  397. KiSyncSessionTarget(
  398. IN PULONG SignalDone,
  399. IN PKPROCESS Process,
  400. IN PVOID Parameter1,
  401. IN PVOID Parameter2
  402. )
  403. /*++
  404. Routine Description:
  405. This is the target function for synchronizing the new session
  406. region ID. This routine is called when the session space is removed
  407. and all the processors need to be notified.
  408. Arguments:
  409. SignalDone - Supplies a pointer to a variable that is cleared when the
  410. requested operation has been performed.
  411. Process - Supplies a KPROCESS pointer which needs to be synchronized.
  412. Return Value:
  413. None.
  414. Environment:
  415. Kernel mode.
  416. --*/
  417. {
  418. UNREFERENCED_PARAMETER (Parameter1);
  419. UNREFERENCED_PARAMETER (Parameter2);
  420. #if !defined(NT_UP)
  421. //
  422. // Check to see if the current process is the process that needs to be
  423. // synchronized.
  424. //
  425. if (Process == (PKPROCESS)PCR->Pcb) {
  426. KiAcquireSpinLock(&KiMasterRidLock);
  427. //
  428. // Disable the session region.
  429. //
  430. KiSetRegionRegister((PVOID)SADDRESS_BASE,
  431. KiMakeValidRegionRegister(Process->SessionMapInfo->RegionId, PAGE_SHIFT));
  432. KiFlushFixedDataTb(TRUE, (PVOID)PDE_STBASE);
  433. KeFillFixedEntryTb((PHARDWARE_PTE)&Process->SessionParentBase,
  434. (PVOID)PDE_STBASE,
  435. PAGE_SHIFT,
  436. DTR_STBASE_INDEX);
  437. KiReleaseSpinLock(&KiMasterRidLock);
  438. }
  439. KiIpiSignalPacketDone(SignalDone);
  440. #else
  441. UNREFERENCED_PARAMETER (SignalDone);
  442. UNREFERENCED_PARAMETER (Process);
  443. #endif
  444. return;
  445. }
  446. VOID
  447. KeDetachSessionSpace(
  448. IN PREGION_MAP_INFO NullSessionMapInfo,
  449. IN PFN_NUMBER NullSessionPage
  450. )
  451. /*++
  452. Routine Description:
  453. This routine detaches the current process from the current session
  454. space.
  455. This includes:
  456. 1. Updating the current region register.
  457. 2. Updating the SessionMapInfo fields so context switches will work.
  458. 3. Updating SessionParentBase fields so context switches will work.
  459. Arguments:
  460. SessionMapInfo - Supplies a new session map information to use (the
  461. existing session map info is discarded). This is usually
  462. a NULL entry.
  463. NullSessionPage - Supplies the new top level parent page to use.
  464. Return Value:
  465. None.
  466. Environment:
  467. Kernel mode.
  468. --*/
  469. {
  470. KIRQL OldIrql;
  471. PKTHREAD Thread;
  472. PKPROCESS Process;
  473. #if !defined(NT_UP)
  474. KAFFINITY TargetProcessors;
  475. #endif
  476. //
  477. // Raise IRQL to DISPATCH_LEVEL and lock the dispatcher database.
  478. //
  479. Thread = KeGetCurrentThread();
  480. Process = Thread->ApcState.Process;
  481. OldIrql = KeRaiseIrqlToSynchLevel();
  482. INITIALIZE_DIRECTORY_TABLE_BASE (&Process->SessionParentBase,
  483. NullSessionPage);
  484. Process->SessionMapInfo = NullSessionMapInfo;
  485. #if !defined(NT_UP)
  486. KiAcquireSpinLock(&KiRegionSwapLock);
  487. //
  488. // Broadcast the region ID sync.
  489. //
  490. TargetProcessors = KeActiveProcessors;
  491. TargetProcessors &= PCR->NotMember;
  492. if (TargetProcessors != 0) {
  493. KiIpiSendPacket(TargetProcessors,
  494. KiSyncSessionTarget,
  495. Process,
  496. NULL,
  497. NULL);
  498. }
  499. #endif
  500. KiSetRegionRegister((PVOID)SADDRESS_BASE,
  501. KiMakeValidRegionRegister(NullSessionMapInfo->RegionId, PAGE_SHIFT));
  502. KiFlushFixedDataTb(TRUE, PDE_STBASE);
  503. KeFillFixedEntryTb((PHARDWARE_PTE)&Process->SessionParentBase,
  504. (PVOID)PDE_STBASE,
  505. PAGE_SHIFT,
  506. DTR_STBASE_INDEX);
  507. #if !defined(NT_UP)
  508. //
  509. // Wait until all target processors have finished.
  510. //
  511. if (TargetProcessors != 0) {
  512. KiIpiStallOnPacketTargets(TargetProcessors);
  513. }
  514. KiReleaseSpinLock(&KiRegionSwapLock);
  515. #endif
  516. KeLowerIrql(OldIrql);
  517. }
  518. VOID
  519. KeAddSessionSpace(
  520. IN PKPROCESS Process,
  521. IN PREGION_MAP_INFO SessionMapInfo,
  522. IN PFN_NUMBER SessionParentPage
  523. )
  524. /*++
  525. Routine Description:
  526. Add the session map info to the KPROCESS of the new process.
  527. This includes:
  528. 1. Updating the SessionMapInfo fields so context switches will work.
  529. 2. Updating SessionParentBase fields so context switches will work.
  530. Note the dispatcher lock is not needed since the process can't run yet.
  531. Arguments:
  532. Process - Supplies a pointer to the process being created.
  533. SessionMapInfo - Supplies a pointer to the SessionMapInfo.
  534. Return Value:
  535. None.
  536. Environment:
  537. Kernel mode, APCs disabled.
  538. --*/
  539. {
  540. Process->SessionMapInfo = SessionMapInfo;
  541. INITIALIZE_DIRECTORY_TABLE_BASE (&Process->SessionParentBase,
  542. SessionParentPage);
  543. }
  544. VOID
  545. KiAttachRegion(
  546. IN PKPROCESS Process
  547. )
  548. /*++
  549. Routine Description:
  550. Attaches the regions of the specified process
  551. Arguments:
  552. Process - Supplies a pointer to the process
  553. Return Value:
  554. None.
  555. Environment:
  556. Kernel mode, KiRegionSwapLock is held.
  557. --*/
  558. {
  559. PREGION_MAP_INFO ProcessRegion;
  560. PREGION_MAP_INFO MappedSession;
  561. ProcessRegion = &Process->ProcessRegion;
  562. MappedSession = Process->SessionMapInfo;
  563. //
  564. // attach the target user space
  565. //
  566. KiSetRegionRegister(MM_LOWEST_USER_ADDRESS,
  567. KiMakeValidRegionRegister(ProcessRegion->RegionId, PAGE_SHIFT));
  568. //
  569. // attach the target session space
  570. //
  571. KiSetRegionRegister((PVOID)SADDRESS_BASE,
  572. KiMakeValidRegionRegister(MappedSession->RegionId, PAGE_SHIFT));
  573. }
  574. VOID
  575. KiDetachRegion(
  576. VOID
  577. )
  578. /*++
  579. Routine Description:
  580. Restores the origial regions
  581. Arguments:
  582. VOID
  583. Return Value:
  584. None.
  585. Environment:
  586. Kernel mode, KiRegionSwapLock is held.
  587. --*/
  588. {
  589. PKPROCESS Process;
  590. PREGION_MAP_INFO ProcessRegion;
  591. PREGION_MAP_INFO MappedSession;
  592. //
  593. // use KPROCESS from PCR
  594. //
  595. Process = (PKPROCESS)PCR->Pcb;
  596. ProcessRegion = &Process->ProcessRegion;
  597. MappedSession = Process->SessionMapInfo;
  598. //
  599. // attach the original user space
  600. //
  601. KiSetRegionRegister(MM_LOWEST_USER_ADDRESS,
  602. KiMakeValidRegionRegister(ProcessRegion->RegionId, PAGE_SHIFT));
  603. //
  604. // attach the original session space
  605. //
  606. KiSetRegionRegister((PVOID)SADDRESS_BASE,
  607. KiMakeValidRegionRegister(MappedSession->RegionId, PAGE_SHIFT));
  608. }