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.

392 lines
7.8 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. ldtsup.c
  5. Abstract:
  6. This module implements interfaces that support manipulation of i386 Ldts.
  7. These entry points only exist on i386 machines.
  8. Author:
  9. Bryan M. Willman (bryanwi) 14-May-1991
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. --*/
  14. #include "ki.h"
  15. //
  16. // Low level assembler support procedures
  17. //
  18. VOID
  19. KiLoadLdtr(
  20. VOID
  21. );
  22. VOID
  23. KiFlushDescriptors(
  24. VOID
  25. );
  26. //
  27. // Local service procedures
  28. //
  29. VOID
  30. Ki386LoadTargetLdtr (
  31. IN PKIPI_CONTEXT SignalDone,
  32. IN PVOID Parameter1,
  33. IN PVOID Parameter2,
  34. IN PVOID Parameter3
  35. );
  36. VOID
  37. Ki386FlushTargetDescriptors (
  38. IN PKIPI_CONTEXT SignalDone,
  39. IN PVOID Parameter1,
  40. IN PVOID Parameter2,
  41. IN PVOID Parameter3
  42. );
  43. VOID
  44. Ke386SetLdtProcess (
  45. IN PKPROCESS Process,
  46. IN PLDT_ENTRY Ldt,
  47. IN ULONG Limit
  48. )
  49. /*++
  50. Routine Description:
  51. The specified LDT (which may be null) will be made the active Ldt of
  52. the specified process, for all threads thereof, on whichever
  53. processors they are running. The change will take effect before the
  54. call returns.
  55. An Ldt address of NULL or a Limit of 0 will cause the process to
  56. receive the NULL Ldt.
  57. This function only exists on i386 and i386 compatible processors.
  58. No checking is done on the validity of Ldt entries.
  59. N.B.
  60. While a single Ldt structure can be shared amoung processes, any
  61. edits to the Ldt of one of those processes will only be synchronized
  62. for that process. Thus, processes other than the one the change is
  63. applied to may not see the change correctly.
  64. Arguments:
  65. Process - Pointer to KPROCESS object describing the process for
  66. which the Ldt is to be set.
  67. Ldt - Pointer to an array of LDT_ENTRYs (that is, a pointer to an
  68. Ldt.)
  69. Limit - Ldt limit (must be 0 mod 8)
  70. Return Value:
  71. None.
  72. --*/
  73. {
  74. KGDTENTRY LdtDescriptor;
  75. BOOLEAN LocalProcessor;
  76. KIRQL OldIrql;
  77. PKPRCB Prcb;
  78. KAFFINITY TargetProcessors;
  79. //
  80. // Compute the contents of the Ldt descriptor
  81. //
  82. if ((Ldt == NULL) || (Limit == 0)) {
  83. //
  84. // Set up an empty descriptor
  85. //
  86. LdtDescriptor.LimitLow = 0;
  87. LdtDescriptor.BaseLow = 0;
  88. LdtDescriptor.HighWord.Bytes.BaseMid = 0;
  89. LdtDescriptor.HighWord.Bytes.Flags1 = 0;
  90. LdtDescriptor.HighWord.Bytes.Flags2 = 0;
  91. LdtDescriptor.HighWord.Bytes.BaseHi = 0;
  92. } else {
  93. //
  94. // Insure that the unfilled fields of the selector are zero
  95. // N.B. If this is not done, random values appear in the high
  96. // portion of the Ldt limit.
  97. //
  98. LdtDescriptor.HighWord.Bytes.Flags1 = 0;
  99. LdtDescriptor.HighWord.Bytes.Flags2 = 0;
  100. //
  101. // Set the limit and base
  102. //
  103. LdtDescriptor.LimitLow = (USHORT) ((ULONG) Limit - 1);
  104. LdtDescriptor.BaseLow = (USHORT) ((ULONG) Ldt & 0xffff);
  105. LdtDescriptor.HighWord.Bytes.BaseMid = (UCHAR) (((ULONG)Ldt & 0xff0000) >> 16);
  106. LdtDescriptor.HighWord.Bytes.BaseHi = (UCHAR) (((ULONG)Ldt & 0xff000000) >> 24);
  107. //
  108. // Type is LDT, DPL = 0
  109. //
  110. LdtDescriptor.HighWord.Bits.Type = TYPE_LDT;
  111. LdtDescriptor.HighWord.Bits.Dpl = DPL_SYSTEM;
  112. //
  113. // Make it present
  114. //
  115. LdtDescriptor.HighWord.Bits.Pres = 1;
  116. }
  117. //
  118. // Acquire the context swap lock so a context switch cannot occur.
  119. //
  120. KiLockContextSwap(&OldIrql);
  121. //
  122. // Set the Ldt fields in the process object.
  123. //
  124. Process->LdtDescriptor = LdtDescriptor;
  125. //
  126. // Tell all processors active for this process to reload their LDTs
  127. //
  128. #ifdef NT_UP
  129. KiLoadLdtr();
  130. #else
  131. Prcb = KeGetCurrentPrcb();
  132. TargetProcessors = Process->ActiveProcessors & ~Prcb->SetMember;
  133. if (TargetProcessors != 0) {
  134. KiIpiSendPacket(TargetProcessors,
  135. Ki386LoadTargetLdtr,
  136. NULL,
  137. NULL,
  138. NULL);
  139. }
  140. KiLoadLdtr();
  141. if (TargetProcessors != 0) {
  142. //
  143. // Stall until target processor(s) release us
  144. //
  145. KiIpiStallOnPacketTargets(TargetProcessors);
  146. }
  147. #endif
  148. //
  149. // Restore IRQL and release the context swap lock.
  150. //
  151. KiUnlockContextSwap(OldIrql);
  152. return;
  153. }
  154. VOID
  155. Ki386LoadTargetLdtr (
  156. IN PKIPI_CONTEXT SignalDone,
  157. IN PVOID Parameter1,
  158. IN PVOID Parameter2,
  159. IN PVOID Parameter3
  160. )
  161. /*++
  162. Routine Description:
  163. Reload local Ldt register and clear signal bit in TargetProcessor mask
  164. Arguments:
  165. Argument - pointer to a ipi packet structure.
  166. ReadyFlag - Pointer to flag to be set once LDTR has been reloaded
  167. Return Value:
  168. none.
  169. --*/
  170. {
  171. //
  172. // Reload the LDTR register from currently active process object
  173. //
  174. KiLoadLdtr();
  175. KiIpiSignalPacketDone(SignalDone);
  176. return;
  177. }
  178. VOID
  179. Ke386SetDescriptorProcess (
  180. IN PKPROCESS Process,
  181. IN ULONG Offset,
  182. IN LDT_ENTRY LdtEntry
  183. )
  184. /*++
  185. Routine Description:
  186. The specified LdtEntry (which could be 0, not present, etc) will be
  187. edited into the specified Offset in the Ldt of the specified Process.
  188. This will be synchronzied accross all the processors executing the
  189. process. The edit will take affect on all processors before the call
  190. returns.
  191. N.B.
  192. Editing an Ldt descriptor requires stalling all processors active
  193. for the process, to prevent accidental loading of descriptors in
  194. an inconsistent state.
  195. Arguments:
  196. Process - Pointer to KPROCESS object describing the process for
  197. which the descriptor edit is to be performed.
  198. Offset - Byte offset into the Ldt of the descriptor to edit.
  199. Must be 0 mod 8.
  200. LdtEntry - Value to edit into the descriptor in hardware format.
  201. No checking is done on the validity of this item.
  202. Return Value:
  203. none.
  204. --*/
  205. {
  206. PLDT_ENTRY Ldt;
  207. KIRQL OldIrql;
  208. PKPRCB Prcb;
  209. KAFFINITY TargetProcessors;
  210. //
  211. // Compute address of descriptor to edit.
  212. //
  213. Ldt =
  214. (PLDT_ENTRY)
  215. ((Process->LdtDescriptor.HighWord.Bytes.BaseHi << 24) |
  216. ((Process->LdtDescriptor.HighWord.Bytes.BaseMid << 16) & 0xff0000) |
  217. (Process->LdtDescriptor.BaseLow & 0xffff));
  218. Offset = Offset / 8;
  219. KiLockContextSwap(&OldIrql);
  220. #ifdef NT_UP
  221. //
  222. // Edit the Ldt.
  223. //
  224. Ldt[Offset] = LdtEntry;
  225. #else
  226. Prcb = KeGetCurrentPrcb();
  227. TargetProcessors = Process->ActiveProcessors & ~Prcb->SetMember;
  228. if (TargetProcessors != 0) {
  229. KiIpiSendSynchronousPacket(
  230. Prcb,
  231. TargetProcessors,
  232. Ki386FlushTargetDescriptors,
  233. (PVOID)&Prcb->ReverseStall,
  234. NULL,
  235. NULL);
  236. KiIpiStallOnPacketTargets(TargetProcessors);
  237. }
  238. //
  239. // All target processors have flushed the segment descriptors and
  240. // are waiting to proceed. Edit the ldt on the current processor,
  241. // then continue the execution of target processors.
  242. //
  243. Ldt[Offset] = LdtEntry;
  244. if (TargetProcessors != 0) {
  245. Prcb->ReverseStall += 1;
  246. }
  247. #endif
  248. //
  249. // Restore IRQL and release the context swap lock.
  250. //
  251. KiUnlockContextSwap(OldIrql);
  252. return;
  253. }
  254. VOID
  255. Ki386FlushTargetDescriptors (
  256. IN PKIPI_CONTEXT SignalDone,
  257. IN PVOID Proceed,
  258. IN PVOID Parameter2,
  259. IN PVOID Parameter3
  260. )
  261. /*++
  262. Routine Description:
  263. This function flushes the segment descriptors on the current processor.
  264. Arguments:
  265. Argument - pointer to a _KIPI_FLUSH_DESCRIPTOR structure.
  266. ReadyFlag - pointer to flag to syncroize with
  267. Return Value:
  268. none.
  269. --*/
  270. {
  271. //
  272. // Flush the segment descriptors on the current processor and signal that
  273. // the descriptors have been flushed.
  274. //
  275. KiFlushDescriptors();
  276. KiIpiSignalPacketDoneAndStall (SignalDone, Proceed);
  277. return;
  278. }