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.

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