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.

938 lines
29 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. context.c
  5. Abstract:
  6. Context conversion routines for ia64 hardware to ia32 context records
  7. Author:
  8. 03-Feb-2000 Charles Spriakis - Intel (v-cspira)
  9. Revision History:
  10. --*/
  11. #define _WOW64CPUAPI_
  12. #ifdef _X86_
  13. #include "ia6432.h"
  14. #else
  15. #define _NTDDK_
  16. #include <nt.h>
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. #include "wow64.h"
  20. #include "wow64cpu.h"
  21. #include "ia64cpu.h"
  22. #include <kxia64.h>
  23. #endif
  24. //
  25. // This is to prevent this library from linking to wow64 to use wow64!Wow64LogPrint
  26. //
  27. #if defined(LOGPRINT)
  28. #undef LOGPRINT
  29. #endif
  30. #define LOGPRINT(_x_) CpupDebugPrint _x_
  31. //
  32. // Used to mask the MxCSR from the FSR and FCR registers
  33. //
  34. #define WOW64_MXCSR_CONTROL_MASK 0xffC0
  35. #define WOW64_MXCSR_STATUS_MASK 0x3f
  36. VOID
  37. CpupDebugPrint(
  38. IN ULONG_PTR Flags,
  39. IN PCHAR Format,
  40. ...);
  41. BOOL
  42. MapDbgSlotIa64ToX86(
  43. UINT Slot,
  44. ULONG64 Ipsr,
  45. ULONG64 DbD,
  46. ULONG64 DbD1,
  47. ULONG64 DbI,
  48. ULONG64 DbI1,
  49. ULONG* Dr7,
  50. ULONG* Dr);
  51. void
  52. MapDbgSlotX86ToIa64(
  53. UINT Slot,
  54. ULONG Dr7,
  55. ULONG Dr,
  56. ULONG64* Ipsr,
  57. ULONG64* DbD,
  58. ULONG64* DbD1,
  59. ULONG64* DbI,
  60. ULONG64* DbI1);
  61. ASSERTNAME;
  62. VOID
  63. Wow64CtxFromIa64(
  64. IN ULONG Ia32ContextFlags,
  65. IN PCONTEXT ContextIa64,
  66. IN OUT PCONTEXT32 ContextX86
  67. )
  68. /*++
  69. Routine Description:
  70. This function copies the context from an ia64 context record into
  71. the context of an ia32 record (based on the hardware iVE register
  72. mappings). This function is ment to be easily usabale by various
  73. get/set context routines (such as those exported by wow64cpu.dll).
  74. Arguments:
  75. Ia32ContextFlags - Specifies which ia32 context to copy
  76. ContextIa64 - Supplies an the ia64 context buffer that is the source
  77. for the copy into the ia32 context area
  78. ContextX86 - This is an X86 context which will receive the context
  79. information from the ia64 context record passed in above
  80. Return Value:
  81. None.
  82. --*/
  83. {
  84. FLOAT128 tmpFloat[NUMBER_OF_387REGS];
  85. if (Ia32ContextFlags & CONTEXT_IA64) {
  86. LOGPRINT((ERRORLOG, "Wow64CtxFromIa64: Request with ia64 context flags (0x%x) FAILED\n", Ia32ContextFlags));
  87. ASSERT((Ia32ContextFlags & CONTEXT_IA64) == 0);
  88. }
  89. if ((Ia32ContextFlags & CONTEXT32_CONTROL) == CONTEXT32_CONTROL) {
  90. //
  91. // And the control stuff
  92. //
  93. ContextX86->Ebp = (ULONG)ContextIa64->IntTeb;
  94. ContextX86->SegCs = KGDT_R3_CODE|3;
  95. ContextX86->Eip = (ULONG)ContextIa64->StIIP;
  96. ContextX86->SegSs = KGDT_R3_DATA|3;
  97. ContextX86->Esp = (ULONG)ContextIa64->IntSp;
  98. ContextX86->EFlags = (ULONG)ContextIa64->Eflag;
  99. }
  100. if ((Ia32ContextFlags & CONTEXT32_INTEGER) == CONTEXT32_INTEGER) {
  101. //
  102. // Now for the integer state...
  103. //
  104. ContextX86->Edi = (ULONG)ContextIa64->IntT6;
  105. ContextX86->Esi = (ULONG)ContextIa64->IntT5;
  106. ContextX86->Ebx = (ULONG)ContextIa64->IntT4;
  107. ContextX86->Edx = (ULONG)ContextIa64->IntT3;
  108. ContextX86->Ecx = (ULONG)ContextIa64->IntT2;
  109. ContextX86->Eax = (ULONG)ContextIa64->IntV0;
  110. }
  111. if ((Ia32ContextFlags & CONTEXT32_SEGMENTS) == CONTEXT32_SEGMENTS) {
  112. //
  113. // These are constants (and constants are used on ia32->ia64
  114. // transition, not saved values) so make our life easy...
  115. //
  116. ContextX86->SegGs = 0;
  117. ContextX86->SegEs = KGDT_R3_DATA|3;
  118. ContextX86->SegDs = KGDT_R3_DATA|3;
  119. ContextX86->SegSs = KGDT_R3_DATA|3;
  120. ContextX86->SegFs = KGDT_R3_TEB|3;
  121. ContextX86->SegCs = KGDT_R3_CODE|3;
  122. }
  123. if ((Ia32ContextFlags & CONTEXT32_EXTENDED_REGISTERS) == CONTEXT32_EXTENDED_REGISTERS) {
  124. PFXSAVE_FORMAT_WX86 xmmi = (PFXSAVE_FORMAT_WX86) ContextX86->ExtendedRegisters;
  125. LOGPRINT((TRACELOG, "Wow64CtxFromIa64: Request to convert extended fp registers\n"));
  126. xmmi->ControlWord = (USHORT)(ContextIa64->StFCR & 0xffff);
  127. xmmi->StatusWord = (USHORT)(ContextIa64->StFSR & 0xffff);
  128. xmmi->TagWord = (USHORT)(ContextIa64->StFSR >> 16) & 0xffff;
  129. xmmi->ErrorOpcode = (USHORT)(ContextIa64->StFIR >> 48);
  130. xmmi->ErrorOffset = (ULONG) (ContextIa64->StFIR & 0xffffffff);
  131. xmmi->ErrorSelector = (ULONG) (ContextIa64->StFIR >> 32);
  132. xmmi->DataOffset = (ULONG) (ContextIa64->StFDR & 0xffffffff);
  133. xmmi->DataSelector = (ULONG) (ContextIa64->StFDR >> 32);
  134. // MXCsr has both control and status in it
  135. xmmi->MXCsr = (ULONG) (((ContextIa64->StFCR >> 32) & WOW64_MXCSR_CONTROL_MASK) |
  136. ((ContextIa64->StFSR >> 32) & WOW64_MXCSR_STATUS_MASK));
  137. //
  138. // Copy over the FP registers. Even though this is the new
  139. // FXSAVE format with 16-bytes for each register, need to
  140. // convert from spill/fill format to 80-bit double extended format
  141. //
  142. Wow64CopyIa64FromSpill((PFLOAT128) &(ContextIa64->FltT2),
  143. (PFLOAT128) xmmi->RegisterArea,
  144. NUMBER_OF_387REGS);
  145. //
  146. // Rotate the registers appropriately
  147. //
  148. Wow64RotateFpTop(ContextIa64->StFSR, (PFLOAT128) xmmi->RegisterArea);
  149. //
  150. // Finally copy the xmmi registers
  151. //
  152. Wow64CopyXMMIFromIa64Byte16(&(ContextIa64->FltS4),
  153. xmmi->Reserved3,
  154. NUMBER_OF_XMMI_REGS);
  155. }
  156. if ((Ia32ContextFlags & CONTEXT32_FLOATING_POINT) == CONTEXT32_FLOATING_POINT) {
  157. LOGPRINT((TRACELOG, "Wow64CtxFromIa64: Request to convert fp registers\n"));
  158. //
  159. // Copy over the floating point status/control stuff
  160. //
  161. ContextX86->FloatSave.ControlWord = (ULONG)(ContextIa64->StFCR & 0xffff);
  162. ContextX86->FloatSave.StatusWord = (ULONG)(ContextIa64->StFSR & 0xffff);
  163. ContextX86->FloatSave.TagWord = (ULONG)(ContextIa64->StFSR >> 16) & 0xffff;
  164. ContextX86->FloatSave.ErrorOffset = (ULONG)(ContextIa64->StFIR & 0xffffffff);
  165. ContextX86->FloatSave.ErrorSelector = (ULONG)(ContextIa64->StFIR >> 32);
  166. ContextX86->FloatSave.DataOffset = (ULONG)(ContextIa64->StFDR & 0xffffffff);
  167. ContextX86->FloatSave.DataSelector = (ULONG)(ContextIa64->StFDR >> 32);
  168. //
  169. // Copy over the FP registers into temporary space
  170. // Even though this is the new
  171. // FXSAVE format with 16-bytes for each register, need to
  172. // convert from spill/fill format to 80-bit double extended format
  173. //
  174. Wow64CopyIa64FromSpill((PFLOAT128) &(ContextIa64->FltT2),
  175. (PFLOAT128) tmpFloat,
  176. NUMBER_OF_387REGS);
  177. //
  178. // Rotate the registers appropriately
  179. //
  180. Wow64RotateFpTop(ContextIa64->StFSR, tmpFloat);
  181. //
  182. // And put them in the older FNSAVE format (packed 10 byte values)
  183. //
  184. Wow64CopyFpFromIa64Byte16(tmpFloat,
  185. ContextX86->FloatSave.RegisterArea,
  186. NUMBER_OF_387REGS);
  187. }
  188. if ((Ia32ContextFlags & CONTEXT32_DEBUG_REGISTERS) == CONTEXT32_DEBUG_REGISTERS) {
  189. // Ia64 -> X86
  190. BOOL Valid = TRUE;
  191. LOGPRINT((TRACELOG, "Wow64CtxFromIa64: Request to convert debug registers\n"));
  192. #if 0 // XXX olegk - enable after clarifying problems with exceptions
  193. Valid &= MapDbgSlotIa64ToX86(0, ContextIa64->StIPSR, ContextIa64->DbD0, ContextIa64->DbD1, ContextIa64->DbI0, ContextIa64->DbI1, &ContextX86->Dr7, &ContextX86->Dr0);
  194. Valid &= MapDbgSlotIa64ToX86(1, ContextIa64->StIPSR, ContextIa64->DbD2, ContextIa64->DbD3, ContextIa64->DbI2, ContextIa64->DbI3, &ContextX86->Dr7, &ContextX86->Dr1);
  195. Valid &= MapDbgSlotIa64ToX86(2, ContextIa64->StIPSR, ContextIa64->DbD4, ContextIa64->DbD5, ContextIa64->DbI4, ContextIa64->DbI5, &ContextX86->Dr7, &ContextX86->Dr2);
  196. Valid &= MapDbgSlotIa64ToX86(3, ContextIa64->StIPSR, ContextIa64->DbD6, ContextIa64->DbD7, ContextIa64->DbI6, ContextIa64->DbI7, &ContextX86->Dr7, &ContextX86->Dr3);
  197. if (!Valid) {
  198. LOGPRINT((ERRORLOG, "Wasn't able to map IA64 debug registers consistently!\n"));
  199. }
  200. #endif // XXX olegk
  201. }
  202. ContextX86->ContextFlags = Ia32ContextFlags;
  203. }
  204. VOID
  205. Wow64CtxToIa64(
  206. IN ULONG Ia32ContextFlags,
  207. IN PCONTEXT32 ContextX86,
  208. IN OUT PCONTEXT ContextIa64
  209. )
  210. /*++
  211. Routine Description:
  212. This function copies the context from an ia32 context record into
  213. the context of an ia64 record (based on the hardware iVE register
  214. mappings). This function is ment to be easily usabale by various
  215. get/set context routines (such as those exported by wow64cpu.dll).
  216. Arguments:
  217. Ia32ContextFlags - Specifies which ia32 context to copy
  218. ContextX86 - Supplies an the X86 context buffer that is the source
  219. for the copy into the ia64 context area
  220. ContextIa64 - This is an ia64 context which will receive the context
  221. information from the x86 context record passed in above
  222. Return Value:
  223. None.
  224. --*/
  225. {
  226. FLOAT128 tmpFloat[NUMBER_OF_387REGS];
  227. if (Ia32ContextFlags & CONTEXT_IA64) {
  228. LOGPRINT((ERRORLOG, "Wow64CtxToIa64: Request with ia64 context flags (0x%x) FAILED\n", Ia32ContextFlags));
  229. ASSERT((Ia32ContextFlags & CONTEXT_IA64) == 0);
  230. }
  231. if ((Ia32ContextFlags & CONTEXT32_CONTROL) == CONTEXT32_CONTROL) {
  232. //
  233. // And the control stuff
  234. //
  235. ContextIa64->IntTeb = ContextX86->Ebp;
  236. ContextIa64->StIIP = ContextX86->Eip;
  237. ContextIa64->IntSp = ContextX86->Esp;
  238. ContextIa64->Eflag = ContextX86->EFlags;
  239. //
  240. // The segments (cs and ds) are a constant, so reset them.
  241. // gr17 has LDT and TSS, so might as well reset
  242. // all of them while we're at it...
  243. // These values are forced in during a transition (see simulate.s)
  244. // so there is no point to trying to get cute and actually
  245. // pass in the values from the X86 context record
  246. //
  247. ContextIa64->IntT8 = ((KGDT_LDT|3) << 32)
  248. | ((KGDT_R3_DATA|3) << 16)
  249. | (KGDT_R3_CODE|3);
  250. }
  251. if ((Ia32ContextFlags & CONTEXT32_INTEGER) == CONTEXT32_INTEGER) {
  252. //
  253. // Now for the integer state...
  254. //
  255. ContextIa64->IntT6 = ContextX86->Edi;
  256. ContextIa64->IntT5 = ContextX86->Esi;
  257. ContextIa64->IntT4 = ContextX86->Ebx;
  258. ContextIa64->IntT3 = ContextX86->Edx;
  259. ContextIa64->IntT2 = ContextX86->Ecx;
  260. ContextIa64->IntV0 = ContextX86->Eax;
  261. }
  262. if ((Ia32ContextFlags & CONTEXT32_SEGMENTS) == CONTEXT32_SEGMENTS) {
  263. //
  264. // These are constants (and constants are used on ia32->ia64
  265. // transition, not saved values) so make our life easy...
  266. // These values are forced in during a transition (see simulate.s)
  267. // so there is no point to trying to get cute and actually
  268. // pass in the values from the X86 context record
  269. //
  270. ContextIa64->IntT7 = ((KGDT_R3_TEB|3) << 32)
  271. | ((KGDT_R3_DATA|3) << 16)
  272. | (KGDT_R3_DATA|3);
  273. }
  274. if ((Ia32ContextFlags & CONTEXT32_EXTENDED_REGISTERS) == CONTEXT32_EXTENDED_REGISTERS) {
  275. PFXSAVE_FORMAT_WX86 xmmi = (PFXSAVE_FORMAT_WX86) ContextX86->ExtendedRegisters;
  276. LOGPRINT((TRACELOG, "Wow64CtxToIa64: Request to convert extended fp registers\n"));
  277. //
  278. // And copy over the floating point status/control stuff
  279. //
  280. ContextIa64->StFCR = (xmmi->ControlWord & 0xffff) |
  281. (((ULONGLONG) xmmi->MXCsr & WOW64_MXCSR_CONTROL_MASK) << 32);
  282. ContextIa64->StFSR = (xmmi->StatusWord & 0xffff) |
  283. ((xmmi->TagWord & 0xffff) << 16) |
  284. (((ULONGLONG) xmmi->MXCsr & WOW64_MXCSR_STATUS_MASK) << 32);
  285. ContextIa64->StFIR = (xmmi->ErrorOffset & 0xffffffff) |
  286. (xmmi->ErrorSelector << 32);
  287. ContextIa64->StFDR = (xmmi->DataOffset & 0xffffffff) |
  288. (xmmi->DataSelector << 32);
  289. //
  290. // Don't touch the original ia32 context. Make a copy.
  291. //
  292. memcpy(tmpFloat, xmmi->RegisterArea,
  293. NUMBER_OF_387REGS * sizeof(FLOAT128));
  294. //
  295. // Rotate registers back since st0 is not necessarily f8
  296. //
  297. {
  298. ULONGLONG RotateFSR = (NUMBER_OF_387REGS -
  299. ((ContextIa64->StFSR >> 11) & 0x7)) << 11;
  300. Wow64RotateFpTop(RotateFSR, tmpFloat);
  301. }
  302. //
  303. // Copy over the FP registers. Even though this is the new
  304. // FXSAVE format with 16-bytes for each register, need to
  305. // convert to spill/fill format from 80-bit double extended format
  306. //
  307. Wow64CopyIa64ToFill((PFLOAT128) tmpFloat,
  308. (PFLOAT128) &(ContextIa64->FltT2),
  309. NUMBER_OF_387REGS);
  310. //
  311. // Copy over the xmmi registers and convert them into a format
  312. // that spill/fill can use
  313. //
  314. Wow64CopyXMMIToIa64Byte16(xmmi->Reserved3,
  315. &(ContextIa64->FltS4),
  316. NUMBER_OF_XMMI_REGS);
  317. }
  318. if ((Ia32ContextFlags & CONTEXT32_FLOATING_POINT) == CONTEXT32_FLOATING_POINT) {
  319. LOGPRINT((TRACELOG, "Wow64CtxToIa64: Request to convert fp registers\n"));
  320. //
  321. // Copy over the floating point status/control stuff
  322. // Leave the MXCSR stuff alone
  323. //
  324. ContextIa64->StFCR = (ContextIa64->StFCR & 0xffffffffffffe040i64) |
  325. (ContextX86->FloatSave.ControlWord & 0xffff);
  326. ContextIa64->StFSR = (ContextIa64->StFSR & 0xffffffff00000000i64) |
  327. (ContextX86->FloatSave.StatusWord & 0xffff) |
  328. ((ContextX86->FloatSave.TagWord & 0xffff) << 16);
  329. ContextIa64->StFIR = (ContextX86->FloatSave.ErrorOffset & 0xffffffff) |
  330. (ContextX86->FloatSave.ErrorSelector << 32);
  331. ContextIa64->StFDR = (ContextX86->FloatSave.DataOffset & 0xffffffff) |
  332. (ContextX86->FloatSave.DataSelector << 32);
  333. //
  334. // Copy over the FP registers from packed 10-byte format
  335. // to 16-byte format
  336. //
  337. Wow64CopyFpToIa64Byte16(ContextX86->FloatSave.RegisterArea,
  338. tmpFloat,
  339. NUMBER_OF_387REGS);
  340. //
  341. // Rotate registers back since st0 is not necessarily f8
  342. //
  343. {
  344. ULONGLONG RotateFSR = (NUMBER_OF_387REGS -
  345. ((ContextIa64->StFSR >> 11) & 0x7)) << 11;
  346. Wow64RotateFpTop(RotateFSR, tmpFloat);
  347. }
  348. //
  349. // Now convert from 80 bit extended format to fill/spill format
  350. //
  351. Wow64CopyIa64ToFill((PFLOAT128) tmpFloat,
  352. (PFLOAT128) &(ContextIa64->FltT2),
  353. NUMBER_OF_387REGS);
  354. }
  355. if ((Ia32ContextFlags & CONTEXT32_DEBUG_REGISTERS) == CONTEXT32_DEBUG_REGISTERS) {
  356. LOGPRINT((TRACELOG, "Wow64CtxToIa64: Request to convert debug registers\n"));
  357. #if 0 // XXX olegk - enable after clarifying exception problems
  358. //ContextIa64->ContextFlags |= CONTEXT_DEBUG;
  359. // X86 -> Ia64
  360. MapDbgSlotX86ToIa64(0, ContextX86->Dr7, ContextX86->Dr0, &ContextIa64->StIPSR, &ContextIa64->DbD0, &ContextIa64->DbD1, &ContextIa64->DbI0, &ContextIa64->DbI1);
  361. MapDbgSlotX86ToIa64(1, ContextX86->Dr7, ContextX86->Dr1, &ContextIa64->StIPSR, &ContextIa64->DbD2, &ContextIa64->DbD3, &ContextIa64->DbI2, &ContextIa64->DbI3);
  362. MapDbgSlotX86ToIa64(2, ContextX86->Dr7, ContextX86->Dr2, &ContextIa64->StIPSR, &ContextIa64->DbD4, &ContextIa64->DbD5, &ContextIa64->DbI4, &ContextIa64->DbI5);
  363. MapDbgSlotX86ToIa64(3, ContextX86->Dr7, ContextX86->Dr3, &ContextIa64->StIPSR, &ContextIa64->DbD6, &ContextIa64->DbD7, &ContextIa64->DbI6, &ContextIa64->DbI7);
  364. #endif // XXX olegk
  365. }
  366. }
  367. //
  368. // The ia64 world uses ldfe, stfe to read/write the fp registers. These
  369. // instructions ld/st 16 bytes at a time. Thus, the fp registers are
  370. // packed in 16byte chunks. Alas, the ia32 world uses 10bytes per fp register
  371. // and packs those together (as part of fnstore). So... Need to convert between
  372. // the ia64 packed values and the ia32 packed values. Hence these
  373. // two routines and their weird sounding names.
  374. //
  375. //
  376. // This allows the compiler to be more efficient in copying 10 bytes
  377. // without over copying...
  378. //
  379. #pragma pack(push, 2)
  380. typedef struct _ia32fpbytes {
  381. ULONG significand_low;
  382. ULONG significand_high;
  383. USHORT exponent;
  384. } IA32FPBYTES, *PIA32FPBYTES;
  385. #pragma pack(pop)
  386. VOID
  387. Wow64CopyFpFromIa64Byte16(
  388. IN PVOID Byte16Fp,
  389. IN OUT PVOID Byte10Fp,
  390. IN ULONG NumRegs)
  391. {
  392. ULONG i;
  393. PIA32FPBYTES from, to;
  394. from = (PIA32FPBYTES) Byte16Fp;
  395. to = (PIA32FPBYTES) Byte10Fp;
  396. for (i = 0; i < NumRegs; i++) {
  397. *to = *from;
  398. from = (PIA32FPBYTES) (((UINT_PTR) from) + 16);
  399. to = (PIA32FPBYTES) (((UINT_PTR) to) + 10);
  400. }
  401. }
  402. VOID
  403. Wow64CopyFpToIa64Byte16(
  404. IN PVOID Byte10Fp,
  405. IN OUT PVOID Byte16Fp,
  406. IN ULONG NumRegs)
  407. {
  408. ULONG i;
  409. PIA32FPBYTES from, to; // UNALIGNED
  410. from = (PIA32FPBYTES) Byte10Fp;
  411. to = (PIA32FPBYTES) Byte16Fp;
  412. for (i = 0; i < NumRegs; i++) {
  413. *to = *from;
  414. from = (PIA32FPBYTES) (((UINT_PTR) from) + 10);
  415. to = (PIA32FPBYTES) (((UINT_PTR) to) + 16);
  416. }
  417. }
  418. //
  419. // Alas, nothing is easy. The ia32 xmmi instructions use 16 bytes and pack
  420. // them as nice 16 byte structs. Unfortunately, ia64 handles it as 2 8-byte
  421. // values (using just the mantissa part). So, another conversion is required
  422. //
  423. VOID
  424. Wow64CopyXMMIToIa64Byte16(
  425. IN PVOID ByteXMMI,
  426. IN OUT PVOID Byte16Fp,
  427. IN ULONG NumRegs)
  428. {
  429. ULONG i;
  430. UNALIGNED ULONGLONG *from;
  431. ULONGLONG *to;
  432. from = (PULONGLONG) ByteXMMI;
  433. to = (PULONGLONG) Byte16Fp;
  434. //
  435. // although we have NumRegs xmmi registers, each register is 16 bytes
  436. // wide. This code does things in 8-byte chunks, so total
  437. // number of times to do things is 2 * NumRegs...
  438. //
  439. NumRegs *= 2;
  440. for (i = 0; i < NumRegs; i++) {
  441. *to++ = *from++; // Copy over the mantissa part
  442. *to++ = 0x1003e; // Force the exponent part
  443. // (see ia64 eas, ia32 FP section - 6.2.7
  444. // for where this magic number comes from)
  445. }
  446. }
  447. VOID
  448. Wow64CopyXMMIFromIa64Byte16(
  449. IN PVOID Byte16Fp,
  450. IN OUT PVOID ByteXMMI,
  451. IN ULONG NumRegs)
  452. {
  453. ULONG i;
  454. ULONGLONG *from;
  455. UNALIGNED ULONGLONG *to;
  456. from = (PULONGLONG) Byte16Fp;
  457. to = (PULONGLONG) ByteXMMI;
  458. //
  459. // although we have NumRegs xmmi registers, each register is 16 bytes
  460. // wide. This code does things in 8-byte chunks, so total
  461. // number of times to do things is 2 * NumRegs...
  462. //
  463. NumRegs *= 2;
  464. for (i = 0; i < NumRegs; i++) {
  465. *to++ = *from++; // Copy over the mantissa part
  466. from++; // Skip over the exponent part
  467. }
  468. }
  469. VOID
  470. Wow64RotateFpTop(
  471. IN ULONGLONG Ia64_FSR,
  472. IN OUT FLOAT128 UNALIGNED *ia32FxSave)
  473. /*++
  474. Routine Description:
  475. On transition from ia64 mode to ia32 (and back), the f8-f15 registers
  476. contain the st[0] to st[7] fp stack values. Alas, these values don't
  477. map one-one, so the FSR.top bits are used to determine which ia64
  478. register has the top of stack. We then need to rotate these registers
  479. since ia32 context is expecting st[0] to be the first fp register (as
  480. if FSR.top is zero). This routine only works on full 16-byte ia32
  481. saved fp data (such as from ExtendedRegisters - the FXSAVE format).
  482. Other routines can convert this into the older FNSAVE format.
  483. Arguments:
  484. Ia64_FSR - The ia64 FSR register. Has the FSR.top needed for this routine
  485. ia32FxSave - The ia32 fp stack (in FXSAVE format). Each ia32 fp register
  486. uses 16 bytes.
  487. Return Value:
  488. None.
  489. --*/
  490. {
  491. ULONG top = (ULONG) ((Ia64_FSR >> 11) & 0x7);
  492. if (top) {
  493. FLOAT128 tmpFloat[NUMBER_OF_387REGS];
  494. ULONG i;
  495. for (i = 0; i < NUMBER_OF_387REGS; i++) {
  496. tmpFloat[i] = ia32FxSave[i];
  497. }
  498. for (i = 0; i < NUMBER_OF_387REGS; i++) {
  499. ia32FxSave[i] = tmpFloat[(i + top) % NUMBER_OF_387REGS];
  500. }
  501. }
  502. }
  503. //
  504. // And now for the final yuck... The ia64 context for floating point
  505. // is saved/loaded using spill/fill instructions. This format is different
  506. // than the 10-byte fp format so we need a conversion routine from spill/fill
  507. // to/from 10byte fp
  508. //
  509. VOID
  510. Wow64CopyIa64FromSpill(
  511. IN PFLOAT128 SpillArea,
  512. IN OUT FLOAT128 UNALIGNED *ia64Fp,
  513. IN ULONG NumRegs)
  514. /*++
  515. Routine Description:
  516. This function copies fp values from the ia64 spill/fill format
  517. into the ia64 80-bit format. The exponent needs to be adjusted
  518. according to the EAS (5-12) regarding Memory to Floating-Point
  519. Register Data Translation (in the IA-64 floating point chapter).
  520. Conversion to 80-bit format is performed correctly for values
  521. that could have been supported representations in the IA-32 stack
  522. double-extended floating-point format (80-bit format): normal
  523. numbers that fit in the 80-bit format, NaNs (QNaNs or SNaNs -
  524. not quietized), infinity, zero, and double-extended denormals.
  525. Arguments:
  526. SpillArea - The ia64 area that has the spill format for fp
  527. ia64Fp - The location which will get the ia64 fp in 80-bit
  528. double-extended format
  529. NumRegs - Number of registers to convert
  530. Return Value:
  531. None.
  532. --*/
  533. {
  534. ULONG i;
  535. for (i = 0; i < NumRegs; i++) {
  536. ULONG64 Sign = ((SpillArea->HighPart >> 17) & 0x01);
  537. ULONG64 Significand = SpillArea->LowPart;
  538. ULONG64 Exponent = SpillArea->HighPart & 0x1ffff;
  539. //
  540. // Convert from 17-bit exponent of 82-bit format to
  541. // 15-bit exponent of 80-bit format. This method is the
  542. // same method the hardware follows (keep the bottom 14 bits
  543. // and the msb bit, dropping bits [15:14] from the 82-bit format)
  544. // See ia64 Vol 1 Figure 5-9 near page 5-12...
  545. //
  546. ia64Fp->HighPart = (Exponent & 0x3fff) | // Lower 14 bits
  547. ((Exponent & 0x10000) >> 2) | // and msb of exp
  548. (Sign << 15); // then the sign
  549. ia64Fp->LowPart = Significand;
  550. ia64Fp++;
  551. SpillArea++;
  552. }
  553. }
  554. VOID
  555. Wow64CopyIa64ToFill(
  556. IN FLOAT128 UNALIGNED *ia64Fp,
  557. IN OUT PFLOAT128 FillArea,
  558. IN ULONG NumRegs)
  559. /*++
  560. Routine Description:
  561. This function copies fp values from the ia64 80-bit format
  562. into the fill/spill format used by the os for save/restore
  563. of the ia64 context. The only magic here is putting back some
  564. values that get truncated when converting from spill/fill to
  565. 80-bits. The exponent needs to be adjusted according to the
  566. EAS (5-12) regarding Memory to Floating Point Register Data
  567. Translation in the ia64 floating point chapter
  568. Arguments:
  569. ia64Fp - The ia64 fp in 80-bit double-extended format
  570. FillArea - The ia64 area that will get the fill format for fp
  571. for the copy into the ia64 context area
  572. NumRegs - Number of registers to convert
  573. Return Value:
  574. None.
  575. --*/
  576. {
  577. ULONG i;
  578. for (i = 0; i < NumRegs; i++) {
  579. ULONG64 Sign = ((ia64Fp->HighPart >> 15) & 0x01);
  580. ULONG64 Significand = ia64Fp->LowPart;
  581. ULONG64 Exponent = ia64Fp->HighPart & 0x7fff;
  582. if (Exponent)
  583. {
  584. if (Exponent == 0x7fff) // Infinity
  585. {
  586. Exponent = 0x1ffff;
  587. }
  588. else
  589. {
  590. ULONGLONG Rebias = 0xffff-0x3fff;
  591. Exponent += Rebias;
  592. }
  593. }
  594. FillArea->LowPart = Significand;
  595. FillArea->HighPart = (Sign << 17) | (Exponent & 0x1ffff);
  596. ia64Fp++;
  597. FillArea++;
  598. }
  599. }
  600. //
  601. // Debug registers conversion
  602. //
  603. // XXX olegk - uncrease to 4 in future
  604. // (and then remove appropriate check at MapDbgSlotIa64ToX86)
  605. #define IA64_REG_MAX_DATA_BREAKPOINTS 2
  606. // Debug register flags.
  607. #define IA64_DBR_RDWR 0xC000000000000000ui64
  608. #define IA64_DBR_RD 0x8000000000000000ui64
  609. #define IA64_DBR_WR 0x4000000000000000ui64
  610. #define IA64_DBR_EXEC 0x8000000000000000ui64
  611. #define IA64_DBG_MASK_MASK 0x00FFFFFFFFFFFFFFui64
  612. #define IA64_DBG_REG_PLM_USER 0x0800000000000000ui64
  613. #define IA64_DBG_REG_PLM_ALL 0x0F00000000000000ui64
  614. #define X86_DR7_LOCAL_EXACT_ENABLE 0x100
  615. ULONG
  616. MapDbgSlotIa64ToX86_GetSize(ULONG64 Db1, BOOL* Valid)
  617. {
  618. ULONG64 Size = (~Db1 & IA64_DBG_MASK_MASK);
  619. if (Size > 3)
  620. {
  621. *Valid = FALSE;
  622. }
  623. return (ULONG)Size;
  624. }
  625. void
  626. MapDbgSlotIa64ToX86_InvalidateAddr(ULONG64 Db, BOOL* Valid)
  627. {
  628. if (Db != (ULONG64)(ULONG)Db)
  629. {
  630. *Valid = FALSE;
  631. }
  632. }
  633. ULONG
  634. MapDbgSlotIa64ToX86_ExecTypeSize(
  635. UINT Slot,
  636. ULONG64 Db,
  637. ULONG64 Db1,
  638. BOOL* Valid)
  639. {
  640. ULONG TypeSize;
  641. if (!(Db1 >> 63))
  642. {
  643. *Valid = FALSE;
  644. }
  645. TypeSize = (MapDbgSlotIa64ToX86_GetSize(Db1, Valid) << 2);
  646. MapDbgSlotIa64ToX86_InvalidateAddr(Db, Valid);
  647. return TypeSize;
  648. }
  649. ULONG
  650. MapDbgSlotIa64ToX86_DataTypeSize(
  651. UINT Slot,
  652. ULONG64 Db,
  653. ULONG64 Db1,
  654. BOOL* Valid)
  655. {
  656. ULONG TypeSize = (ULONG)(Db1 >> 62);
  657. if ((TypeSize != 1) && (TypeSize != 3))
  658. {
  659. *Valid = FALSE;
  660. }
  661. TypeSize |= (MapDbgSlotIa64ToX86_GetSize(Db1, Valid) << 2);
  662. MapDbgSlotIa64ToX86_InvalidateAddr(Db, Valid);
  663. return TypeSize;
  664. }
  665. BOOL
  666. MapDbgSlotIa64ToX86(
  667. UINT Slot,
  668. ULONG64 Ipsr,
  669. ULONG64 DbD,
  670. ULONG64 DbD1,
  671. ULONG64 DbI,
  672. ULONG64 DbI1,
  673. ULONG* Dr7,
  674. ULONG* Dr)
  675. {
  676. BOOL DataValid = TRUE, ExecValid = TRUE, Valid = TRUE;
  677. ULONG DataTypeSize, ExecTypeSize;
  678. // XXX olegk - remove this after IA64_REG_MAX_DATA_BREAKPOINTS will be changed to 4
  679. if (Slot >= IA64_REG_MAX_DATA_BREAKPOINTS)
  680. {
  681. return TRUE;
  682. }
  683. DataTypeSize = MapDbgSlotIa64ToX86_DataTypeSize(Slot, DbD, DbD1, &DataValid);
  684. ExecTypeSize = MapDbgSlotIa64ToX86_ExecTypeSize(Slot, DbI, DbI1, &ExecValid);
  685. if (DataValid)
  686. {
  687. if (!ExecValid)
  688. {
  689. *Dr = (ULONG)DbD;
  690. *Dr7 |= (X86_DR7_LOCAL_EXACT_ENABLE |
  691. (1 << Slot * 2) |
  692. (DataTypeSize << (16 + Slot * 4)));
  693. return !DbI && !DbI1;
  694. }
  695. }
  696. else if (ExecValid)
  697. {
  698. *Dr = (ULONG)DbI;
  699. *Dr7 |= (X86_DR7_LOCAL_EXACT_ENABLE |
  700. (1 << Slot * 2) |
  701. (ExecTypeSize << (16 + Slot * 4)));
  702. return !DbD && !DbD1;
  703. }
  704. *Dr7 &= ~(X86_DR7_LOCAL_EXACT_ENABLE |
  705. (0xf << (16 + Slot * 4)) |
  706. (1 << Slot * 2));
  707. if (!DbD && !DbD1 && !DbI && !DbI1)
  708. {
  709. *Dr = 0;
  710. return TRUE;
  711. }
  712. *Dr = ~(ULONG)0;
  713. return FALSE;
  714. }
  715. void
  716. MapDbgSlotX86ToIa64(
  717. UINT Slot,
  718. ULONG Dr7,
  719. ULONG Dr,
  720. ULONG64* Ipsr,
  721. ULONG64* DbD,
  722. ULONG64* DbD1,
  723. ULONG64* DbI,
  724. ULONG64* DbI1)
  725. {
  726. UINT TypeSize;
  727. ULONG64 Control;
  728. if (!(Dr7 & (1 << Slot * 2)))
  729. {
  730. return;
  731. }
  732. if (Dr == ~(ULONG)0)
  733. {
  734. return;
  735. }
  736. TypeSize = Dr7 >> (16 + Slot * 4);
  737. Control = (IA64_DBG_REG_PLM_USER | IA64_DBG_MASK_MASK) &
  738. ~(ULONG64)(TypeSize >> 2);
  739. switch (TypeSize & 0x3)
  740. {
  741. case 0x0: // Exec
  742. *DbI1 = Control | IA64_DBR_EXEC;
  743. *DbI = Dr;
  744. break;
  745. case 0x1: // Write
  746. *DbD1 = Control | IA64_DBR_WR;
  747. *DbD = Dr;
  748. break;
  749. case 0x3: // Read/Write
  750. *DbD1 = Control | IA64_DBR_RD | IA64_DBR_WR;
  751. *DbD = Dr;
  752. break;
  753. default:
  754. return;
  755. }
  756. *Ipsr |= (1i64 << PSR_DB);
  757. }