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.

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