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.

388 lines
8.2 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. PKDPC Dpc,
  32. IN PVOID DeferredContext,
  33. IN PVOID SystemArgument1,
  34. IN PVOID SystemArgument2
  35. );
  36. VOID
  37. Ki386FlushTargetDescriptors (
  38. PKDPC Dpc,
  39. IN PVOID DeferredContext,
  40. IN PVOID SystemArgument1,
  41. IN PVOID SystemArgument2
  42. );
  43. typedef struct _LDTINFO {
  44. PKPROCESS Process;
  45. KGDTENTRY LdtDescriptor;
  46. ULONG Offset;
  47. LDT_ENTRY LdtEntry;
  48. PLDT_ENTRY Ldt;
  49. } LDTINFO, *PLDTINFO;
  50. VOID
  51. Ke386SetLdtProcess (
  52. IN PKPROCESS Process,
  53. IN PLDT_ENTRY Ldt,
  54. IN ULONG Limit
  55. )
  56. /*++
  57. Routine Description:
  58. The specified LDT (which may be null) will be made the active Ldt of
  59. the specified process, for all threads thereof, on whichever
  60. processors they are running. The change will take effect before the
  61. call returns.
  62. An Ldt address of NULL or a Limit of 0 will cause the process to
  63. receive the NULL Ldt.
  64. This function only exists on i386 and i386 compatible processors.
  65. No checking is done on the validity of Ldt entries.
  66. N.B.
  67. While a single Ldt structure can be shared amoung processes, any
  68. edits to the Ldt of one of those processes will only be synchronized
  69. for that process. Thus, processes other than the one the change is
  70. applied to may not see the change correctly.
  71. Arguments:
  72. Process - Pointer to KPROCESS object describing the process for
  73. which the Ldt is to be set.
  74. Ldt - Pointer to an array of LDT_ENTRYs (that is, a pointer to an
  75. Ldt.)
  76. Limit - Ldt limit (must be 0 mod 8)
  77. Return Value:
  78. None.
  79. --*/
  80. {
  81. LDTINFO LdtInfo;
  82. KGDTENTRY LdtDescriptor;
  83. //
  84. // Compute the contents of the Ldt descriptor
  85. //
  86. if ((Ldt == NULL) || (Limit == 0)) {
  87. //
  88. // Set up an empty descriptor
  89. //
  90. LdtDescriptor.LimitLow = 0;
  91. LdtDescriptor.BaseLow = 0;
  92. LdtDescriptor.HighWord.Bytes.BaseMid = 0;
  93. LdtDescriptor.HighWord.Bytes.Flags1 = 0;
  94. LdtDescriptor.HighWord.Bytes.Flags2 = 0;
  95. LdtDescriptor.HighWord.Bytes.BaseHi = 0;
  96. } else {
  97. //
  98. // Insure that the unfilled fields of the selector are zero
  99. // N.B. If this is not done, random values appear in the high
  100. // portion of the Ldt limit.
  101. //
  102. LdtDescriptor.HighWord.Bytes.Flags1 = 0;
  103. LdtDescriptor.HighWord.Bytes.Flags2 = 0;
  104. //
  105. // Set the limit and base
  106. //
  107. LdtDescriptor.LimitLow = (USHORT) ((ULONG) Limit - 1);
  108. LdtDescriptor.BaseLow = (USHORT) ((ULONG) Ldt & 0xffff);
  109. LdtDescriptor.HighWord.Bytes.BaseMid = (UCHAR) (((ULONG)Ldt & 0xff0000) >> 16);
  110. LdtDescriptor.HighWord.Bytes.BaseHi = (UCHAR) (((ULONG)Ldt & 0xff000000) >> 24);
  111. //
  112. // Type is LDT, DPL = 0
  113. //
  114. LdtDescriptor.HighWord.Bits.Type = TYPE_LDT;
  115. LdtDescriptor.HighWord.Bits.Dpl = DPL_SYSTEM;
  116. //
  117. // Make it present
  118. //
  119. LdtDescriptor.HighWord.Bits.Pres = 1;
  120. }
  121. LdtInfo.Process = Process;
  122. LdtInfo.LdtDescriptor = LdtDescriptor;
  123. KeGenericCallDpc (Ki386LoadTargetLdtr,
  124. &LdtInfo);
  125. return;
  126. }
  127. VOID
  128. Ki386LoadTargetLdtr (
  129. PKDPC Dpc,
  130. IN PVOID DeferredContext,
  131. IN PVOID SystemArgument1,
  132. IN PVOID SystemArgument2
  133. )
  134. /*++
  135. Routine Description:
  136. Reload local Ldt register and clear signal bit in TargetProcessor mask
  137. Arguments:
  138. Dpc - DPC used to initiate this call
  139. DeferredContext - Context
  140. SystemArgument1 - System context, Used to signal completion of this call
  141. SystemArgument2 - System context
  142. Return Value:
  143. none.
  144. --*/
  145. {
  146. PLDTINFO LdtInfo;
  147. UNREFERENCED_PARAMETER (Dpc);
  148. LdtInfo = DeferredContext;
  149. //
  150. // Make sure all DPC's are running so a load of the process
  151. // LdtDescriptor field can't be torn
  152. //
  153. if (KeSignalCallDpcSynchronize (SystemArgument2)) {
  154. //
  155. // Set the Ldt fields in the process object.
  156. //
  157. LdtInfo->Process->LdtDescriptor = LdtInfo->LdtDescriptor;
  158. }
  159. //
  160. // Make sure the field has been updated before we continue
  161. //
  162. KeSignalCallDpcSynchronize (SystemArgument2);
  163. //
  164. // Reload the LDTR register from currently active process object
  165. //
  166. KiLoadLdtr();
  167. //
  168. // Signal that all processing has been done
  169. //
  170. KeSignalCallDpcDone (SystemArgument1);
  171. return;
  172. }
  173. VOID
  174. Ke386SetDescriptorProcess (
  175. IN PKPROCESS Process,
  176. IN ULONG Offset,
  177. IN LDT_ENTRY LdtEntry
  178. )
  179. /*++
  180. Routine Description:
  181. The specified LdtEntry (which could be 0, not present, etc) will be
  182. edited into the specified Offset in the Ldt of the specified Process.
  183. This will be synchronzied across all the processors executing the
  184. process. The edit will take affect on all processors before the call
  185. returns.
  186. N.B.
  187. Editing an Ldt descriptor requires stalling all processors active
  188. for the process, to prevent accidental loading of descriptors in
  189. an inconsistent state.
  190. Arguments:
  191. Process - Pointer to KPROCESS object describing the process for
  192. which the descriptor edit is to be performed.
  193. Offset - Byte offset into the Ldt of the descriptor to edit.
  194. Must be 0 mod 8.
  195. LdtEntry - Value to edit into the descriptor in hardware format.
  196. No checking is done on the validity of this item.
  197. Return Value:
  198. none.
  199. --*/
  200. {
  201. PLDT_ENTRY Ldt;
  202. LDTINFO LdtInfo;
  203. //
  204. // Compute address of descriptor to edit. It is safe to fetch the process
  205. // LdtDescriptor here as we are always called with the PS LdtMutex held.
  206. //
  207. Ldt =
  208. (PLDT_ENTRY)
  209. ((Process->LdtDescriptor.HighWord.Bytes.BaseHi << 24) |
  210. ((Process->LdtDescriptor.HighWord.Bytes.BaseMid << 16) & 0xff0000) |
  211. (Process->LdtDescriptor.BaseLow & 0xffff));
  212. Offset = Offset / 8;
  213. LdtInfo.Process = Process;
  214. LdtInfo.Offset = Offset;
  215. LdtInfo.Ldt = Ldt;
  216. LdtInfo.LdtEntry = LdtEntry;
  217. KeGenericCallDpc (Ki386FlushTargetDescriptors,
  218. &LdtInfo);
  219. return;
  220. }
  221. VOID
  222. Ki386FlushTargetDescriptors (
  223. PKDPC Dpc,
  224. IN PVOID DeferredContext,
  225. IN PVOID SystemArgument1,
  226. IN PVOID SystemArgument2
  227. )
  228. /*++
  229. Routine Description:
  230. This function flushes the segment descriptors on the current processor.
  231. Arguments:
  232. Dpc - DPC used to initiate this call
  233. DeferredContext - Context
  234. SystemArgument1 - System context, Used to signal completion of this call
  235. SystemArgument2 - System context
  236. Return Value:
  237. none.
  238. --*/
  239. {
  240. PLDTINFO LdtInfo;
  241. UNREFERENCED_PARAMETER (Dpc);
  242. LdtInfo = DeferredContext;
  243. //
  244. // Flush the segment descriptors on the current processor.
  245. // This call removes all possible references to the LDT from
  246. // the segment registers.
  247. //
  248. KiFlushDescriptors ();
  249. //
  250. // Make sure all DPC's are running so a load of the process
  251. // LdtDescriptor field can't be torn
  252. //
  253. if (KeSignalCallDpcSynchronize (SystemArgument2)) {
  254. //
  255. // Update the LDT entry
  256. //
  257. LdtInfo->Ldt[LdtInfo->Offset] = LdtInfo->LdtEntry;
  258. }
  259. //
  260. // Wait until everyone has got to this point before continuing
  261. //
  262. KeSignalCallDpcSynchronize (SystemArgument2);
  263. //
  264. // Signal that all processing has been done
  265. //
  266. KeSignalCallDpcDone (SystemArgument1);
  267. return;
  268. }