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.

449 lines
10 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Copyright (c) 1992 Digital Equipment Corporation
  4. Module Name:
  5. alignem.c
  6. Abstract:
  7. This module implements the code necessary to emulate unaligned data
  8. references.
  9. Author:
  10. David N. Cutler (davec) 17-Jun-1991
  11. Joe Notarangelo 14-May-1992
  12. Environment:
  13. Kernel mode only.
  14. Revision History:
  15. --*/
  16. #include "ki.h"
  17. //
  18. // Function prototypes for emulation routines
  19. //
  20. ULONGLONG
  21. KiEmulateLoadLong(
  22. IN PULONG UnalignedAddress
  23. );
  24. ULONGLONG
  25. KiEmulateLoadQuad(
  26. IN PUQUAD UnalignedAddress
  27. );
  28. ULONGLONG
  29. KiEmulateLoadFloatIEEESingle(
  30. IN PULONG UnalignedAddress
  31. );
  32. ULONGLONG
  33. KiEmulateLoadFloatIEEEDouble(
  34. IN PUQUAD UnalignedAddress
  35. );
  36. VOID
  37. KiEmulateStoreLong(
  38. IN PULONG UnalignedAddress,
  39. IN ULONGLONG Data
  40. );
  41. VOID
  42. KiEmulateStoreQuad(
  43. IN PUQUAD UnalignedAddress,
  44. IN ULONGLONG Data
  45. );
  46. VOID
  47. KiEmulateStoreFloatIEEESingle(
  48. IN PULONG UnalignedAddress,
  49. IN ULONGLONG Data
  50. );
  51. VOID
  52. KiEmulateStoreFloatIEEEDouble(
  53. IN PUQUAD UnalignedAddress,
  54. IN ULONGLONG Data
  55. );
  56. VOID
  57. KiEnablePALAlignmentFixups(
  58. VOID
  59. );
  60. VOID
  61. KiDisablePALAlignmentFixups(
  62. VOID
  63. );
  64. VOID
  65. KiProfileInterrupt(
  66. IN KPROFILE_SOURCE ProfileSource,
  67. IN PKTRAP_FRAME TrapFrame
  68. );
  69. VOID
  70. KiEnableAlignmentExceptions(
  71. VOID
  72. )
  73. /*++
  74. Routine Description:
  75. Enables alignment exceptions on the current processor by
  76. disabling automatic PAL code alignment fixups. PAL is
  77. called to turn off automatic fixups only if CPU is
  78. 21164 or greater.
  79. Arguments:
  80. None
  81. Return Value:
  82. None
  83. --*/
  84. {
  85. if (KeProcessorLevel >= PROCESSOR_ALPHA_21164) {
  86. KiDisablePALAlignmentFixups();
  87. }
  88. }
  89. VOID
  90. KiDisableAlignmentExceptions(
  91. VOID
  92. )
  93. /*++
  94. Routine Description:
  95. Disables alignment exceptions on the current processor by
  96. enabling automatic PAL code alignment fixups. PAL is
  97. called to turn on automatic fixups only if CPU is
  98. 21164 or greater and KiEnableAlignmentFaultExceptions==0
  99. If KiEnableAlignmentFaultExceptions is either 1 or 2, then
  100. the kernel always needs to see alignment faults, so PAL
  101. automatic alignment fixups should not be enabled
  102. Arguments:
  103. None
  104. Return Value:
  105. None
  106. --*/
  107. {
  108. if ((KeProcessorLevel >= PROCESSOR_ALPHA_21164) &&
  109. (KiEnableAlignmentFaultExceptions == 0)) {
  110. KiEnablePALAlignmentFixups();
  111. }
  112. }
  113. BOOLEAN
  114. KiEmulateReference (
  115. IN OUT PEXCEPTION_RECORD ExceptionRecord,
  116. IN OUT PKEXCEPTION_FRAME ExceptionFrame,
  117. IN OUT PKTRAP_FRAME TrapFrame
  118. )
  119. /*++
  120. Routine Description:
  121. Routine emulates an unaligned data reference from user part
  122. of the address space.
  123. Arguments:
  124. ExceptionRecord - Supplies a pointer to the exception record.
  125. ExceptionFrame - Supplies a pointer to an exception frame.
  126. TrapFrame - Supplies a pointer to a trap frame
  127. Return Value:
  128. True is returned if reference is successfully emulated,
  129. otherwise False is returned.
  130. --*/
  131. {
  132. ULONGLONG Data;
  133. PVOID EffectiveAddress;
  134. PVOID ExceptionAddress;
  135. ULONG Fa;
  136. ULONG Opcode;
  137. KPROCESSOR_MODE PreviousMode;
  138. ULONG Ra;
  139. KIRQL OldIrql;
  140. //
  141. // Call out to profile interrupt if alignment profiling is active
  142. //
  143. if (KiProfileAlignmentFixup) {
  144. if (++KiProfileAlignmentFixupCount >= KiProfileAlignmentFixupInterval) {
  145. KeRaiseIrql(PROFILE_LEVEL, &OldIrql);
  146. KiProfileAlignmentFixupCount = 0;
  147. KiProfileInterrupt(ProfileAlignmentFixup, TrapFrame);
  148. KeLowerIrql(OldIrql);
  149. }
  150. }
  151. //
  152. // Save original exception address in case another exception occurs
  153. //
  154. ExceptionAddress = ExceptionRecord->ExceptionAddress;
  155. //
  156. // The ExceptionInformation in the ExceptionRecord has already
  157. // recorded information we need to emulate the access.
  158. //
  159. // ExceptionInformation:
  160. // [0] = opcode
  161. // [1] = destination register
  162. // [2] = effective address of access
  163. Opcode = (ULONG)ExceptionRecord->ExceptionInformation[0];
  164. Ra = (ULONG)ExceptionRecord->ExceptionInformation[1];
  165. Fa = Ra + 32; // convert to floating register name for floating opcodes
  166. EffectiveAddress = (PVOID)ExceptionRecord->ExceptionInformation[2];
  167. //
  168. // Capture previous mode from trap frame not current thread.
  169. //
  170. PreviousMode = (KPROCESSOR_MODE)(((PSR *)(&TrapFrame->Psr))->MODE);
  171. //
  172. // Any exception that occurs during the attempted emulation will cause
  173. // the emulation to be aborted. The new exception code and information
  174. // will be copied to the original exception record and FALSE will be
  175. // returned. If the unaligned access was not from kernel mode then
  176. // probe the effective address before performing the emulation.
  177. //
  178. try {
  179. switch (Opcode) {
  180. //
  181. // load longword
  182. //
  183. case LDL_OP:
  184. if( PreviousMode != KernelMode ){
  185. ProbeForRead( EffectiveAddress,
  186. sizeof(LONG),
  187. sizeof(UCHAR) );
  188. }
  189. Data = KiEmulateLoadLong( EffectiveAddress );
  190. KiSetRegisterValue( Ra,
  191. Data,
  192. ExceptionFrame,
  193. TrapFrame );
  194. break;
  195. //
  196. // load quadword
  197. //
  198. case LDQ_OP:
  199. if( PreviousMode != KernelMode ){
  200. ProbeForRead( EffectiveAddress,
  201. sizeof(LONGLONG),
  202. sizeof(UCHAR) );
  203. }
  204. Data = KiEmulateLoadQuad( EffectiveAddress );
  205. KiSetRegisterValue( Ra,
  206. Data,
  207. ExceptionFrame,
  208. TrapFrame );
  209. break;
  210. //
  211. // load IEEE single float
  212. //
  213. case LDS_OP:
  214. if( PreviousMode != KernelMode ){
  215. ProbeForRead( EffectiveAddress,
  216. sizeof(float),
  217. sizeof(UCHAR) );
  218. }
  219. Data = KiEmulateLoadFloatIEEESingle( EffectiveAddress );
  220. KiSetRegisterValue( Fa,
  221. Data,
  222. ExceptionFrame,
  223. TrapFrame );
  224. break;
  225. //
  226. // load IEEE double float
  227. //
  228. case LDT_OP:
  229. if( PreviousMode != KernelMode ){
  230. ProbeForRead( EffectiveAddress,
  231. sizeof(DOUBLE),
  232. sizeof(UCHAR) );
  233. }
  234. Data = KiEmulateLoadFloatIEEEDouble( EffectiveAddress );
  235. KiSetRegisterValue( Fa,
  236. Data,
  237. ExceptionFrame,
  238. TrapFrame );
  239. break;
  240. //
  241. // Load word unsigned.
  242. //
  243. case LDWU_OP :
  244. if (PreviousMode != KernelMode) {
  245. ProbeForRead(EffectiveAddress,
  246. sizeof(SHORT),
  247. sizeof(UCHAR));
  248. }
  249. Data = (ULONGLONG)*(UNALIGNED USHORT *)EffectiveAddress;
  250. KiSetRegisterValue(Ra,
  251. Data,
  252. ExceptionFrame,
  253. TrapFrame);
  254. break;
  255. //
  256. // store longword
  257. //
  258. case STL_OP:
  259. if( PreviousMode != KernelMode ){
  260. ProbeForWrite( EffectiveAddress,
  261. sizeof(LONG),
  262. sizeof(UCHAR) );
  263. }
  264. Data = KiGetRegisterValue( Ra,
  265. ExceptionFrame,
  266. TrapFrame );
  267. KiEmulateStoreLong( EffectiveAddress, (ULONG)Data );
  268. break;
  269. //
  270. // store quadword
  271. //
  272. case STQ_OP:
  273. if( PreviousMode != KernelMode ){
  274. ProbeForWrite( EffectiveAddress,
  275. sizeof(LONGLONG),
  276. sizeof(UCHAR) );
  277. }
  278. Data = KiGetRegisterValue( Ra,
  279. ExceptionFrame,
  280. TrapFrame );
  281. KiEmulateStoreQuad( EffectiveAddress, Data );
  282. break;
  283. //
  284. // store IEEE float single
  285. //
  286. case STS_OP:
  287. if( PreviousMode != KernelMode ){
  288. ProbeForWrite( EffectiveAddress,
  289. sizeof(float),
  290. sizeof(UCHAR) );
  291. }
  292. Data = KiGetRegisterValue( Fa,
  293. ExceptionFrame,
  294. TrapFrame );
  295. KiEmulateStoreFloatIEEESingle( EffectiveAddress, Data );
  296. break;
  297. //
  298. // store IEEE float double
  299. //
  300. case STT_OP:
  301. if( PreviousMode != KernelMode ){
  302. ProbeForWrite( EffectiveAddress,
  303. sizeof(DOUBLE),
  304. sizeof(UCHAR) );
  305. }
  306. Data = KiGetRegisterValue( Fa,
  307. ExceptionFrame,
  308. TrapFrame );
  309. KiEmulateStoreFloatIEEEDouble( EffectiveAddress, Data );
  310. break;
  311. //
  312. // Store word.
  313. //
  314. case STW_OP :
  315. if (PreviousMode != KernelMode) {
  316. ProbeForWrite(EffectiveAddress,
  317. sizeof(SHORT),
  318. sizeof(UCHAR));
  319. }
  320. Data = KiGetRegisterValue(Ra,
  321. ExceptionFrame,
  322. TrapFrame);
  323. *(UNALIGNED USHORT *)EffectiveAddress = (USHORT)Data;
  324. break;
  325. //
  326. // all other instructions are not emulated
  327. //
  328. default:
  329. return FALSE;
  330. }
  331. TrapFrame->Fir += 4;
  332. return TRUE;
  333. } except (KiCopyInformation(ExceptionRecord,
  334. (GetExceptionInformation())->ExceptionRecord)) {
  335. //
  336. // Preserve the original exception address
  337. //
  338. ExceptionRecord->ExceptionAddress = ExceptionAddress;
  339. return FALSE;
  340. }
  341. }