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.

412 lines
9.9 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. emulate.c
  5. Abstract:
  6. This module implements an instruction level emulator for the execution
  7. of x86 code. It is a complete 386/486 emulator, but only implements
  8. real mode execution. Thus 32-bit addressing and operands are supported,
  9. but paging and protected mode operations are not supported. The code is
  10. written with the primary goals of being complete and small. Thus speed
  11. of emulation is not important.
  12. Author:
  13. David N. Cutler (davec) 2-Sep-1994
  14. Environment:
  15. Kernel mode only.
  16. Revision History:
  17. --*/
  18. #include "nthal.h"
  19. #include "emulate.h"
  20. VOID
  21. XmInitializeEmulator (
  22. IN USHORT StackSegment,
  23. IN USHORT StackOffset,
  24. IN PXM_READ_IO_SPACE ReadIoSpace,
  25. IN PXM_WRITE_IO_SPACE WriteIoSpace,
  26. IN PXM_TRANSLATE_ADDRESS TranslateAddress
  27. )
  28. /*++
  29. Routine Description:
  30. This function initializes the state of the x86 emulator.
  31. Arguments:
  32. StackSegment - Supplies the stack segment value.
  33. StackOffset - Supplies the stack offset value.
  34. ReadIoSpace - Supplies a pointer to a the function that reads from
  35. I/O space given a datatype and port number.
  36. WriteIoSpace - Supplies a pointer to a function that writes to I/O
  37. space given a datatype, port number, and value.
  38. TranslateAddress - Supplies a pointer to the function that translates
  39. segment/offset address pairs into a pointer to memory or I/O space.
  40. Return Value:
  41. None.
  42. --*/
  43. {
  44. LONG Index;
  45. PRXM_CONTEXT P = &XmContext;
  46. PULONG Vector;
  47. //
  48. // Clear the emulator context.
  49. //
  50. memset((PCHAR)P, 0, sizeof(XM_CONTEXT));
  51. //
  52. // Initialize the segment registers.
  53. //
  54. Index = GS;
  55. do {
  56. P->SegmentLimit[Index] = 0xffff;
  57. Index -= 1;
  58. } while (Index >= ES);
  59. //
  60. // Initialize the stack segment register and offset.
  61. //
  62. P->SegmentRegister[SS] = StackSegment;
  63. P->Gpr[ESP].Exx = StackOffset;
  64. //
  65. // Set the address of the read I/O space, write I/O space, and translate
  66. // functions.
  67. //
  68. P->ReadIoSpace = ReadIoSpace;
  69. P->WriteIoSpace = WriteIoSpace;
  70. P->TranslateAddress = TranslateAddress;
  71. //
  72. // Get address of interrupt vector table and initialize all vector to
  73. // point to an iret instruction at location 0x500.
  74. //
  75. //
  76. // N.B. It is assumed that the vector table is contiguous in emulated
  77. // memory.
  78. //
  79. Vector = (PULONG)(P->TranslateAddress)(0, 0);
  80. Vector[0x500 / 4] = 0x000000cf;
  81. Index = 0;
  82. do {
  83. Vector[Index] = 0x00000500;
  84. Index += 1;
  85. } while (Index < 256);
  86. XmEmulatorInitialized = TRUE;
  87. return;
  88. }
  89. XM_STATUS
  90. XmEmulateFarCall (
  91. IN USHORT Segment,
  92. IN USHORT Offset,
  93. IN OUT PXM86_CONTEXT Context
  94. )
  95. /*++
  96. Routine Description:
  97. This function emulates a far call by pushing a special exit
  98. sequence on the stack and then starting instruction execution
  99. at the address specified by the respective segment and offset.
  100. Arguments:
  101. Segment - Supplies the segment in which to start execution.
  102. Offset - Supplies the offset within the code segment to start
  103. execution.
  104. Context - Supplies a pointer to an x86 context structure.
  105. Return Value:
  106. The emulation completion status.
  107. --*/
  108. {
  109. PRXM_CONTEXT P = &XmContext;
  110. PUSHORT Stack;
  111. //
  112. // If the emulator has not been initialized, return an error.
  113. //
  114. if (XmEmulatorInitialized == FALSE) {
  115. return XM_EMULATOR_NOT_INITIALIZED;
  116. }
  117. //
  118. // Get address of current stack pointer, push exit markers, and
  119. // update stack pointer.
  120. //
  121. // N.B. It is assumed that the stack pointer is within range and
  122. // contiguous in emulated memory.
  123. //
  124. Stack = (PUSHORT)(P->TranslateAddress)(P->SegmentRegister[SS], P->Gpr[SP].Xx);
  125. *--Stack = 0xffff;
  126. *--Stack = 0xffff;
  127. P->Gpr[SP].Xx -= 4;
  128. //
  129. // Emulate the specified instruction stream and return the final status.
  130. //
  131. return XmEmulateStream(&XmContext, Segment, Offset, Context);
  132. }
  133. XM_STATUS
  134. XmEmulateInterrupt (
  135. IN UCHAR Interrupt,
  136. IN OUT PXM86_CONTEXT Context
  137. )
  138. /*++
  139. Routine Description:
  140. This function emulates an interrrupt by pushing a special exit
  141. sequence on the stack and then starting instruction execution
  142. at the address specified by the respective interrupt vector.
  143. Arguments:
  144. Interrupt - Supplies the number of the interrupt that is emulated.
  145. Context - Supplies a pointer to an x86 context structure.
  146. Return Value:
  147. The emulation completion status.
  148. --*/
  149. {
  150. PRXM_CONTEXT P = &XmContext;
  151. USHORT Segment;
  152. USHORT Offset;
  153. PUSHORT Stack;
  154. PULONG Vector;
  155. //
  156. // If the emulator has not been initialized, return an error.
  157. //
  158. if (XmEmulatorInitialized == FALSE) {
  159. return XM_EMULATOR_NOT_INITIALIZED;
  160. }
  161. //
  162. // Get address of current stack pointer, push exit markers, and
  163. // update stack pointer.
  164. //
  165. // N.B. It is assumed that the stack pointer is within range and
  166. // contiguous in emulated memory.
  167. //
  168. Stack = (PUSHORT)(P->TranslateAddress)(P->SegmentRegister[SS], P->Gpr[SP].Xx);
  169. *--Stack = 0;
  170. *--Stack = 0xffff;
  171. *--Stack = 0xffff;
  172. P->Gpr[SP].Xx -= 6;
  173. //
  174. // Get address of interrupt vector table and set code segment and IP
  175. // values.
  176. //
  177. //
  178. // N.B. It is assumed that the vector table is contiguous in emulated
  179. // memory.
  180. //
  181. Vector = (PULONG)(P->TranslateAddress)(0, 0);
  182. Segment = (USHORT)(Vector[Interrupt] >> 16);
  183. Offset = (USHORT)(Vector[Interrupt] & 0xffff);
  184. //
  185. // Emulate the specified instruction stream and return the final status.
  186. //
  187. return XmEmulateStream(&XmContext, Segment, Offset, Context);
  188. }
  189. XM_STATUS
  190. XmEmulateStream (
  191. PRXM_CONTEXT P,
  192. IN USHORT Segment,
  193. IN USHORT Offset,
  194. IN OUT PXM86_CONTEXT Context
  195. )
  196. /*++
  197. Routine Description:
  198. This function establishes the specfied context and emulates the
  199. specified instruction stream until exit conditions are reached..
  200. Arguments:
  201. Segment - Supplies the segment in which to start execution.
  202. Offset - Supplies the offset within the code segment to start
  203. execution.
  204. Context - Supplies a pointer to an x86 context structure.
  205. Return Value:
  206. The emulation completion status.
  207. --*/
  208. {
  209. XM_STATUS Status;
  210. //
  211. // Set the x86 emulator registers from the specified context.
  212. //
  213. P->Gpr[EAX].Exx = Context->Eax;
  214. P->Gpr[ECX].Exx = Context->Ecx;
  215. P->Gpr[EDX].Exx = Context->Edx;
  216. P->Gpr[EBX].Exx = Context->Ebx;
  217. P->Gpr[EBP].Exx = Context->Ebp;
  218. P->Gpr[ESI].Exx = Context->Esi;
  219. P->Gpr[EDI].Exx = Context->Edi;
  220. P->SegmentRegister[DS] = Context->SegDs;
  221. P->SegmentRegister[ES] = Context->SegEs;
  222. //
  223. // Set the code segment, offset within segment, and emulate code.
  224. //
  225. P->SegmentRegister[CS] = Segment;
  226. P->Eip = Offset;
  227. if ((Status = setjmp(&P->JumpBuffer[0])) == 0) {
  228. //
  229. // Emulate x86 instruction stream.
  230. //
  231. do {
  232. //
  233. // Initialize instruction decode variables.
  234. //
  235. P->ComputeOffsetAddress = FALSE;
  236. P->DataSegment = DS;
  237. P->LockPrefixActive = FALSE;
  238. P->OpaddrPrefixActive = FALSE;
  239. P->OpsizePrefixActive = FALSE;
  240. P->RepeatPrefixActive = FALSE;
  241. P->SegmentPrefixActive = FALSE;
  242. P->OpcodeControlTable = &XmOpcodeControlTable1[0];
  243. #if defined(XM_DEBUG)
  244. P->OpcodeNameTable = &XmOpcodeNameTable1[0];
  245. #endif
  246. //
  247. // Get the next byte from the instruction stream and decode
  248. // operands. If the byte is a prefix or an escape, then the
  249. // next byte will be decoded. Decoding continues until an
  250. // opcode byte is reached with a terminal decode condition.
  251. //
  252. // N.B. There is no checking for legitimate sequences of prefix
  253. // and/or two byte opcode escapes. Redundant or invalid
  254. // prefixes or two byte escape opcodes have no effect and
  255. // are benign.
  256. //
  257. do {
  258. P->CurrentOpcode = XmGetCodeByte(P);
  259. #if defined(XM_DEBUG)
  260. if ((XmDebugFlags & TRACE_INSTRUCTIONS) != 0) {
  261. DEBUG_PRINT(("\n%04lx %s %02lx ",
  262. P->Eip - 1,
  263. P->OpcodeNameTable[P->CurrentOpcode],
  264. (ULONG)P->CurrentOpcode));
  265. }
  266. #endif
  267. P->OpcodeControl = P->OpcodeControlTable[P->CurrentOpcode];
  268. P->FunctionIndex = P->OpcodeControl.FunctionIndex;
  269. } while (XmOperandDecodeTable[P->OpcodeControl.FormatType](P) == FALSE);
  270. //
  271. // Emulate the instruction.
  272. //
  273. XmTraceFlags(P);
  274. XmOpcodeFunctionTable[P->FunctionIndex](P);
  275. XmTraceFlags(P);
  276. XmTraceRegisters(P);
  277. #if defined(XM_DEBUG)
  278. if ((XmDebugFlags & TRACE_SINGLE_STEP) != 0) {
  279. DEBUG_PRINT(("\n"));
  280. DbgBreakPoint();
  281. }
  282. #endif
  283. } while (TRUE);
  284. }
  285. //
  286. // Set the x86 return context to the current emulator registers.
  287. //
  288. Context->Eax = P->Gpr[EAX].Exx;
  289. Context->Ecx = P->Gpr[ECX].Exx;
  290. Context->Edx = P->Gpr[EDX].Exx;
  291. Context->Ebx = P->Gpr[EBX].Exx;
  292. Context->Ebp = P->Gpr[EBP].Exx;
  293. Context->Esi = P->Gpr[ESI].Exx;
  294. Context->Edi = P->Gpr[EDI].Exx;
  295. return Status;
  296. }