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.

458 lines
9.8 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. Thread.c
  5. Abstract:
  6. This file contains functions for tracking and manipulating threads
  7. Author:
  8. Dave Hastings (daveh) 18-Apr-1992
  9. Revision History:
  10. --*/
  11. #include <monitorp.h>
  12. #include <malloc.h>
  13. extern VDM_INTERRUPTHANDLER DpmiInterruptHandlers[];
  14. extern VDM_FAULTHANDLER DpmiFaultHandlers[];
  15. // Instantiated in vdpm.c
  16. extern PFAMILY_TABLE *pgDpmVdmFamTbls;
  17. //
  18. // Local Types
  19. //
  20. typedef struct _MonitorThread {
  21. struct _MonitorThread *Previous;
  22. struct _MonitorThread *Next;
  23. PVOID Teb;
  24. HANDLE Thread;
  25. VDM_TIB VdmTib;
  26. } MONITORTHREAD, *PMONITORTHREAD;
  27. //
  28. // Local Variables
  29. //
  30. PMONITORTHREAD ThreadList = NULL; // List of all threads registered
  31. VOID
  32. InitVdmTib(
  33. PVDM_TIB VdmTib
  34. )
  35. /*++
  36. Routine Description:
  37. This routine is used to initialize the VdmTib.
  38. Arguments:
  39. VdmTib - supplies a pointer to the vdm tib to be initialized
  40. Return Value:
  41. None.
  42. --*/
  43. {
  44. VdmTib->IntelMSW = 0;
  45. VdmTib->VdmContext.SegGs = 0;
  46. VdmTib->VdmContext.SegFs = 0;
  47. VdmTib->VdmContext.SegEs = 0;
  48. VdmTib->VdmContext.SegDs = 0;
  49. VdmTib->VdmContext.SegCs = 0;
  50. VdmTib->VdmContext.Eip = 0xFFF0L;
  51. VdmTib->VdmContext.EFlags = 0x02L | EFLAGS_INTERRUPT_MASK;
  52. VdmTib->MonitorContext.SegDs = KGDT_R3_DATA | RPL_MASK;
  53. VdmTib->MonitorContext.SegEs = KGDT_R3_DATA | RPL_MASK;
  54. VdmTib->MonitorContext.SegGs = 0;
  55. VdmTib->MonitorContext.SegFs = KGDT_R3_TEB | RPL_MASK;
  56. VdmTib->PrinterInfo.prt_State = NULL;
  57. VdmTib->PrinterInfo.prt_Control = NULL;
  58. VdmTib->PrinterInfo.prt_Status = NULL;
  59. VdmTib->PrinterInfo.prt_HostState = NULL;
  60. ASSERT(VDM_NUMBER_OF_LPT == 3);
  61. VdmTib->PrinterInfo.prt_Mode[0] =
  62. VdmTib->PrinterInfo.prt_Mode[1] =
  63. VdmTib->PrinterInfo.prt_Mode[2] = PRT_MODE_NO_SIMULATION;
  64. VdmTib->VdmFaultTable = DpmiFaultHandlers;
  65. VdmTib->VdmInterruptTable = DpmiInterruptHandlers;
  66. VdmTib->ContinueExecution = FALSE;
  67. VdmTib->NumTasks = -1;
  68. VdmTib->Size = sizeof(VDM_TIB);
  69. }
  70. VOID
  71. cpu_createthread(
  72. HANDLE Thread,
  73. PVDM_TIB VdmTib
  74. )
  75. /*++
  76. Routine Description:
  77. This routine adds a thread to the list of threads that could be executing
  78. in application mode.
  79. Arguments:
  80. Thread -- Supplies a thread handle
  81. VdmContext -- Supplies a pointer to the VdmContext for the new thread
  82. Return Value:
  83. None.
  84. --*/
  85. {
  86. PMONITORTHREAD NewThread, CurrentThread;
  87. THREAD_BASIC_INFORMATION ThreadInfo;
  88. HANDLE MonitorThreadHandle;
  89. NTSTATUS Status;
  90. //
  91. // Correctly initialize the floating point context for the thread
  92. //
  93. InitialContext.ContextFlags = CONTEXT_FLOATING_POINT;
  94. if (DebugContextActive)
  95. InitialContext.ContextFlags |= CONTEXT_DEBUG_REGISTERS;
  96. Status = NtSetContextThread(
  97. Thread,
  98. &InitialContext
  99. );
  100. if (!NT_SUCCESS(Status)) {
  101. #if DBG
  102. DbgPrint("NtVdm terminating : Could not set float context for\n"
  103. " thread handle 0x%x, status %lx\n", Thread, Status);
  104. DbgBreakPoint();
  105. #endif
  106. TerminateVDM();
  107. }
  108. //
  109. // Set up a structure to keep track of the new thread
  110. //
  111. NewThread = malloc(sizeof(MONITORTHREAD));
  112. if (!NewThread) {
  113. #if DBG
  114. DbgPrint("NTVDM: Could not allocate space for new thread\n");
  115. DbgBreakPoint();
  116. #endif
  117. TerminateVDM();
  118. }
  119. RtlZeroMemory(NewThread, sizeof(MONITORTHREAD));
  120. if (VdmTib == NULL) {
  121. InitVdmTib(&NewThread->VdmTib);
  122. } else {
  123. RtlCopyMemory(&NewThread->VdmTib, VdmTib, sizeof(VDM_TIB));
  124. NewThread->VdmTib.ContinueExecution = FALSE;
  125. NewThread->VdmTib.NumTasks = -1;
  126. NewThread->VdmTib.VdmContext.EFlags = 0x02L | EFLAGS_INTERRUPT_MASK;
  127. NewThread->VdmTib.MonitorContext.EFlags = 0x02L | EFLAGS_INTERRUPT_MASK;
  128. }
  129. // All tasks start with a ptr to the VDM global tables
  130. NewThread->VdmTib.pDpmFamTbls = (PFAMILY_TABLE *)pgDpmVdmFamTbls;
  131. //
  132. // Create a handle for the monitor to use
  133. //
  134. Status = NtDuplicateObject(
  135. NtCurrentProcess(),
  136. Thread,
  137. NtCurrentProcess(),
  138. &MonitorThreadHandle,
  139. 0,
  140. 0,
  141. DUPLICATE_SAME_ACCESS
  142. );
  143. if (!NT_SUCCESS(Status)) {
  144. #if DBG
  145. DbgPrint("NTVDM: Could not duplicate thread handle\n");
  146. DbgBreakPoint();
  147. #endif
  148. TerminateVDM();
  149. }
  150. NewThread->Thread = MonitorThreadHandle;
  151. Status = NtQueryInformationThread(
  152. MonitorThreadHandle,
  153. ThreadBasicInformation,
  154. &ThreadInfo,
  155. sizeof(THREAD_BASIC_INFORMATION),
  156. NULL
  157. );
  158. if (!NT_SUCCESS(Status)) {
  159. #if DBG
  160. DbgPrint("NTVDM: Could not get thread information\n");
  161. DbgBreakPoint();
  162. #endif
  163. TerminateVDM();
  164. }
  165. NewThread->Teb = ThreadInfo.TebBaseAddress;
  166. ((PTEB)(NewThread->Teb))->Vdm = &NewThread->VdmTib;
  167. //
  168. // Insert the new thread in the list. The list is sorted in ascending
  169. // order of Teb address
  170. //
  171. if (!ThreadList) {
  172. ThreadList = NewThread;
  173. NewThread->Next = NULL;
  174. NewThread->Previous = NULL;
  175. return;
  176. }
  177. CurrentThread = ThreadList;
  178. while ((CurrentThread->Next) && (CurrentThread->Teb < NewThread->Teb)) {
  179. CurrentThread = CurrentThread->Next;
  180. }
  181. if (NewThread->Teb > CurrentThread->Teb) {
  182. CurrentThread->Next = NewThread;
  183. NewThread->Previous = CurrentThread;
  184. NewThread->Next = NULL;
  185. } else {
  186. ASSERT((CurrentThread->Teb != NewThread->Teb));
  187. NewThread->Previous = CurrentThread->Previous;
  188. NewThread->Next = CurrentThread;
  189. CurrentThread->Previous = NewThread;
  190. if (NewThread->Previous) {
  191. NewThread->Previous->Next = NewThread;
  192. } else {
  193. ThreadList = NewThread;
  194. }
  195. }
  196. }
  197. VOID
  198. cpu_exitthread(
  199. VOID
  200. )
  201. /*++
  202. Routine Description:
  203. This routine frees the thread tracking information, and closes the thread
  204. handle
  205. Arguments:
  206. Return Value:
  207. None.
  208. --*/
  209. {
  210. PVOID CurrentTeb;
  211. NTSTATUS Status;
  212. PMONITORTHREAD ThreadInfo;
  213. CurrentTeb = NtCurrentTeb();
  214. ThreadInfo = ThreadList;
  215. //
  216. // Find this thread in the list
  217. //
  218. while ((ThreadInfo) && (ThreadInfo->Teb != CurrentTeb)) {
  219. ThreadInfo = ThreadInfo->Next;
  220. }
  221. if (!ThreadInfo) {
  222. #if DBG
  223. DbgPrint("NTVDM: Could not find thread in list\n");
  224. DbgBreakPoint();
  225. #endif
  226. return;
  227. }
  228. //
  229. // Close our handle to this thread
  230. //
  231. Status = NtClose(ThreadInfo->Thread);
  232. #if DBG
  233. if (!NT_SUCCESS(Status)) {
  234. DbgPrint("NTVDM: Could not close thread handle\n");
  235. }
  236. #endif
  237. //
  238. // Remove this thread from the list
  239. //
  240. if (ThreadInfo->Previous) {
  241. ThreadInfo->Previous->Next = ThreadInfo->Next;
  242. } else {
  243. ThreadList = ThreadInfo->Next;
  244. }
  245. if (ThreadInfo->Next) {
  246. ThreadInfo->Next->Previous = ThreadInfo->Previous;
  247. }
  248. free(ThreadInfo);
  249. }
  250. HANDLE
  251. ThreadLookUp(
  252. PVOID Teb
  253. )
  254. /*++
  255. Routine Description:
  256. This routine returns the handle for the specified thread.
  257. Arguments:
  258. Teb -- Supplies the teb pointer of the thread
  259. Return Value:
  260. Returns the handle of the thread, or NULL
  261. --*/
  262. {
  263. PMONITORTHREAD Thread;
  264. Thread = ThreadList;
  265. while ((Thread) && (Thread->Teb != Teb)) {
  266. Thread = Thread->Next;
  267. }
  268. if (Thread) {
  269. return Thread->Thread;
  270. } else {
  271. return NULL;
  272. }
  273. }
  274. BOOL
  275. ThreadSetDebugContext(
  276. PULONG pDebugRegisters
  277. )
  278. /*++
  279. Routine Description:
  280. This routine sets the debug registers for all the threads that the
  281. monitor knows about.
  282. Arguments:
  283. pDebugRegisters -- Pointer to 6 dwords containing the requested debug
  284. register contents.
  285. Return Value:
  286. none
  287. --*/
  288. {
  289. PMONITORTHREAD Thread;
  290. NTSTATUS Status = STATUS_SUCCESS;
  291. Thread = ThreadList;
  292. InitialContext.ContextFlags = CONTEXT_DEBUG_REGISTERS;
  293. InitialContext.Dr0 = *pDebugRegisters++;
  294. InitialContext.Dr1 = *pDebugRegisters++;
  295. InitialContext.Dr2 = *pDebugRegisters++;
  296. InitialContext.Dr3 = *pDebugRegisters++;
  297. InitialContext.Dr6 = *pDebugRegisters++;
  298. InitialContext.Dr7 = *pDebugRegisters++;
  299. while (Thread) {
  300. Status = NtSetContextThread(
  301. Thread->Thread,
  302. &InitialContext
  303. );
  304. if (!NT_SUCCESS(Status))
  305. break;
  306. Thread = Thread->Next;
  307. }
  308. if (!NT_SUCCESS(Status))
  309. return (FALSE);
  310. else {
  311. DebugContextActive = ((InitialContext.Dr7 & 0x0f) != 0);
  312. return (TRUE);
  313. }
  314. }
  315. BOOL
  316. ThreadGetDebugContext(
  317. PULONG pDebugRegisters
  318. )
  319. /*++
  320. Routine Description:
  321. This routine gets the debug registers for the current thread.
  322. Arguments:
  323. pDebugRegisters -- Pointer to 6 dwords to receive the debug
  324. register contents.
  325. Return Value:
  326. none
  327. --*/
  328. {
  329. CONTEXT CurrentContext;
  330. NTSTATUS Status;
  331. CurrentContext.ContextFlags = CONTEXT_DEBUG_REGISTERS;
  332. Status = NtGetContextThread(NtCurrentThread(), &CurrentContext);
  333. if (!NT_SUCCESS(Status)) {
  334. return FALSE;
  335. }
  336. *pDebugRegisters++ = CurrentContext.Dr0;
  337. *pDebugRegisters++ = CurrentContext.Dr1;
  338. *pDebugRegisters++ = CurrentContext.Dr2;
  339. *pDebugRegisters++ = CurrentContext.Dr3;
  340. *pDebugRegisters++ = CurrentContext.Dr6;
  341. *pDebugRegisters++ = CurrentContext.Dr7;
  342. return (TRUE);
  343. }