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.

624 lines
16 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. trapc.c
  5. Abstract:
  6. This module contains some trap handling code written in C.
  7. Only by the kernel.
  8. Author:
  9. Ken Reneris 6-9-93
  10. Revision History:
  11. --*/
  12. #include "ki.h"
  13. NTSTATUS
  14. Ki386CheckDivideByZeroTrap (
  15. IN PKTRAP_FRAME UserFrame
  16. );
  17. VOID
  18. KipWorkAroundCompiler (
  19. USHORT * StatusWord,
  20. USHORT * ControlWord
  21. );
  22. #ifdef ALLOC_PRAGMA
  23. #pragma alloc_text(PAGE, Ki386CheckDivideByZeroTrap)
  24. #endif
  25. #define REG(field) ((ULONG)(&((KTRAP_FRAME *)0)->field))
  26. #define GETREG(frame,reg) ((PULONG) (((ULONG) frame)+reg))[0]
  27. typedef struct {
  28. UCHAR RmDisplaceOnly; // RM of displacment only, no base reg
  29. UCHAR RmSib; // RM of SIB
  30. UCHAR RmDisplace; // bit mask of RMs which have a displacement
  31. UCHAR Disp; // sizeof displacement (in bytes)
  32. } KMOD, *PKMOD;
  33. static UCHAR RM32[] = {
  34. /* 000 */ REG(Eax),
  35. /* 001 */ REG(Ecx),
  36. /* 010 */ REG(Edx),
  37. /* 011 */ REG(Ebx),
  38. /* 100 */ REG(HardwareEsp),
  39. /* 101 */ REG(Ebp), // SIB
  40. /* 110 */ REG(Esi),
  41. /* 111 */ REG(Edi)
  42. };
  43. static UCHAR RM8[] = {
  44. /* 000 */ REG(Eax), // al
  45. /* 001 */ REG(Ecx), // cl
  46. /* 010 */ REG(Edx), // dl
  47. /* 011 */ REG(Ebx), // bl
  48. /* 100 */ REG(Eax) + 1, // ah
  49. /* 101 */ REG(Ecx) + 1, // ch
  50. /* 110 */ REG(Edx) + 1, // dh
  51. /* 111 */ REG(Ebx) + 1 // bh
  52. };
  53. static KMOD MOD32[] = {
  54. /* 00 */ 5, 4, 0x20, 4,
  55. /* 01 */ 0xff, 4, 0xff, 1,
  56. /* 10 */ 0xff, 4, 0xff, 4,
  57. /* 11 */ 0xff, 0xff, 0x00, 0
  58. } ;
  59. static struct {
  60. UCHAR Opcode1, Opcode2; // instruction opcode
  61. UCHAR ModRm, type; // if 2nd part of opcode is encoded in ModRm
  62. } NoWaitNpxInstructions[] = {
  63. /* FNINIT */ 0xDB, 0xE3, 0, 1,
  64. /* FNCLEX */ 0xDB, 0xE2, 0, 1,
  65. /* FNSTENV */ 0xD9, 0x06, 1, 1,
  66. /* FNSAVE */ 0xDD, 0x06, 1, 1,
  67. /* FNSTCW */ 0xD9, 0x07, 1, 2,
  68. /* FNSTSW */ 0xDD, 0x07, 1, 3,
  69. /* FNSTSW AX*/ 0xDF, 0xE0, 0, 4,
  70. 0x00, 0x00, 0, 1
  71. };
  72. NTSTATUS
  73. Ki386CheckDivideByZeroTrap (
  74. IN PKTRAP_FRAME UserFrame
  75. )
  76. /*++
  77. Routine Description:
  78. This function gains control when the x86 processor generates a
  79. divide by zero trap. The x86 design generates such a trap on
  80. divide by zero and on division overflows. In order to determine
  81. which expection code to dispatch, the divisor of the "div" or "idiv"
  82. instruction needs to be inspected.
  83. Arguments:
  84. UserFrame - Trap frame of the divide by zero trap
  85. Return Value:
  86. exception code dispatch
  87. --*/
  88. {
  89. ULONG operandsize, operandmask, i, accum;
  90. PUCHAR istream, pRM;
  91. UCHAR ibyte, rm;
  92. PKMOD Mod;
  93. BOOLEAN fPrefix;
  94. NTSTATUS status;
  95. status = STATUS_INTEGER_DIVIDE_BY_ZERO;
  96. if (UserFrame->SegCs == KGDT_R0_CODE) {
  97. //
  98. // Divide by zero exception from Kernel Mode?
  99. // Likely bad hardware interrupt and the device or vector table
  100. // is corrupt. Bugcheck NOW so we can figure out what went wrong.
  101. // If we try and proceed, then we'll likely fault in reading the
  102. // top of user space, and then double fault (page fault in the
  103. // div zero handler.) -- This is a debugging consideration.
  104. // You can't put breakpoints on the trap labels so this is hard
  105. // to debug.
  106. //
  107. KeBugCheck (UNEXPECTED_KERNEL_MODE_TRAP);
  108. }
  109. //
  110. // read instruction prefixes
  111. //
  112. fPrefix = TRUE;
  113. pRM = RM32;
  114. operandsize = 4;
  115. operandmask = 0xffffffff;
  116. ibyte = 0;
  117. istream = (PUCHAR) UserFrame->Eip;
  118. try {
  119. while (fPrefix) {
  120. ibyte = ProbeAndReadUchar(istream);
  121. istream++;
  122. switch (ibyte) {
  123. case 0x2e: // cs override
  124. case 0x36: // ss override
  125. case 0x3e: // ds override
  126. case 0x26: // es override
  127. case 0x64: // fs override
  128. case 0x65: // gs override
  129. case 0xF3: // rep
  130. case 0xF2: // rep
  131. case 0xF0: // lock
  132. break;
  133. case 0x66:
  134. // 16 bit operand override
  135. operandsize = 2;
  136. operandmask = 0xffff;
  137. break;
  138. case 0x67:
  139. // 16 bit address size override
  140. // this is some non-flat code
  141. goto try_exit;
  142. default:
  143. fPrefix = FALSE;
  144. break;
  145. }
  146. }
  147. //
  148. // Check instruction opcode
  149. //
  150. if (ibyte != 0xf7 && ibyte != 0xf6) {
  151. // this is not a DIV or IDIV opcode
  152. goto try_exit;
  153. }
  154. if (ibyte == 0xf6) {
  155. // this is a byte div or idiv
  156. operandsize = 1;
  157. operandmask = 0xff;
  158. }
  159. //
  160. // Get Mod R/M
  161. //
  162. ibyte = ProbeAndReadUchar (istream);
  163. istream++;
  164. Mod = MOD32 + (ibyte >> 6);
  165. rm = ibyte & 7;
  166. //
  167. // put register values into accum
  168. //
  169. if (operandsize == 1 && (ibyte & 0xc0) == 0xc0) {
  170. pRM = RM8;
  171. }
  172. accum = 0;
  173. if (rm != Mod->RmDisplaceOnly) {
  174. if (rm == Mod->RmSib) {
  175. // get SIB
  176. ibyte = ProbeAndReadUchar(istream);
  177. istream++;
  178. i = (ibyte >> 3) & 7;
  179. if (i != 4) {
  180. accum = GETREG(UserFrame, RM32[i]);
  181. accum = accum << (ibyte >> 6); // apply scaler
  182. }
  183. i = ibyte & 7;
  184. accum = accum + GETREG(UserFrame, RM32[i]);
  185. } else {
  186. // get register's value
  187. accum = GETREG(UserFrame, pRM[rm]);
  188. }
  189. }
  190. //
  191. // apply displacement to accum
  192. //
  193. if (Mod->RmDisplace & (1 << rm)) {
  194. if (Mod->Disp == 4) {
  195. i = ProbeAndReadUlong ((PULONG) istream);
  196. } else {
  197. ibyte = ProbeAndReadChar ((PCHAR)istream);
  198. i = (signed long) ((signed char) ibyte); // sign extend
  199. }
  200. accum += i;
  201. }
  202. //
  203. // if this is an effective address, go get the data value
  204. //
  205. if (Mod->Disp && accum) {
  206. switch (operandsize) {
  207. case 1: accum = ProbeAndReadUchar((PUCHAR) accum); break;
  208. case 2: accum = ProbeAndReadUshort((PUSHORT) accum); break;
  209. case 4: accum = ProbeAndReadUlong((PULONG) accum); break;
  210. }
  211. }
  212. //
  213. // accum now contains the instruction operand, see if the
  214. // operand was really a zero
  215. //
  216. if (accum & operandmask) {
  217. // operand was non-zero, must be an overflow
  218. status = STATUS_INTEGER_OVERFLOW;
  219. }
  220. try_exit: ;
  221. } except (EXCEPTION_EXECUTE_HANDLER) {
  222. // do nothing...
  223. }
  224. return status;
  225. }
  226. UCHAR
  227. KiNextIStreamByte (
  228. IN PKTRAP_FRAME UserFrame,
  229. IN PUCHAR *istream
  230. )
  231. /*++
  232. Routine Description:
  233. Reads the next byte from the istream pointed to by the UserFrame, and
  234. advances the EIP.
  235. Note: this function works for 32 bit code only
  236. --*/
  237. {
  238. UCHAR ibyte;
  239. if (UserFrame->SegCs == KGDT_R0_CODE) {
  240. ibyte = **istream;
  241. } else {
  242. ibyte = ProbeAndReadUchar (*istream);
  243. }
  244. *istream += 1;
  245. return ibyte;
  246. }
  247. BOOLEAN
  248. Ki386CheckDelayedNpxTrap (
  249. IN PKTRAP_FRAME UserFrame,
  250. IN PFX_SAVE_AREA NpxFrame
  251. )
  252. /*++
  253. Routine Description:
  254. This function gains control from the Trap07 handler. It examines
  255. the user mode instruction to see if it's a NoWait NPX instruction.
  256. Such instructions do not generate floating point exceptions - this
  257. check needs to be done due to the way 80386/80387 systems are
  258. implemented. Such machines will generate a floating point exception
  259. interrupt when the kernel performs an FRSTOR to reload the thread's
  260. NPX context. If the thread's next instruction is a NoWait style
  261. instruction, then we clear the exception or emulate the instruction.
  262. AND... due to a different 80386/80387 "feature" the kernel needs
  263. to use FWAIT at times which can causes 80487's to generate delayed
  264. exceptions that can lead to the same problem described above.
  265. Arguments:
  266. UserFrame - Trap frame of the exception
  267. NpxFrame - Thread's NpxFrame (WARNING: does not have NpxState)
  268. Interrupts are disabled
  269. Return Value:
  270. FALSE - Dispatch NPX exception to user mode
  271. TRUE - Exception handled, continue
  272. --*/
  273. {
  274. EXCEPTION_RECORD ExceptionRecord;
  275. UCHAR ibyte1, ibyte2 = 0, inmodrm, status;
  276. USHORT StatusWord, ControlWord, UsersWord;
  277. PUCHAR istream;
  278. BOOLEAN fPrefix;
  279. UCHAR rm;
  280. PKMOD Mod;
  281. ULONG accum, i;
  282. status = 0;
  283. //
  284. // read instruction prefixes
  285. //
  286. fPrefix = TRUE;
  287. istream = (PUCHAR) UserFrame->Eip;
  288. try {
  289. do {
  290. ibyte1 = KiNextIStreamByte (UserFrame, &istream);
  291. switch (ibyte1) {
  292. case 0x2e: // cs override
  293. case 0x36: // ss override
  294. case 0x3e: // ds override
  295. case 0x26: // es override
  296. case 0x64: // fs override
  297. case 0x65: // gs override
  298. break;
  299. default:
  300. fPrefix = FALSE;
  301. break;
  302. }
  303. } while (fPrefix);
  304. //
  305. // Check for coprocessor NoWait NPX instruction
  306. //
  307. ibyte2 = KiNextIStreamByte (UserFrame, &istream);
  308. inmodrm = (ibyte2 >> 3) & 0x7;
  309. for (i=0; NoWaitNpxInstructions[i].Opcode1; i++) {
  310. if (NoWaitNpxInstructions[i].Opcode1 == ibyte1) {
  311. //
  312. // first opcode byte matched - check second part of opcode
  313. //
  314. if (NoWaitNpxInstructions[i].ModRm) {
  315. //
  316. // modrm only applies for opcode in range 0-0xbf
  317. //
  318. if (((ibyte2 & 0xc0) != 0xc0) &&
  319. (NoWaitNpxInstructions[i].Opcode2 == inmodrm)) {
  320. //
  321. // This is a no-wait NPX instruction
  322. //
  323. status = NoWaitNpxInstructions[i].type;
  324. break;
  325. }
  326. } else {
  327. if (NoWaitNpxInstructions[i].Opcode2 == ibyte2) {
  328. //
  329. // This is a no-wait NPX instruction
  330. //
  331. status = NoWaitNpxInstructions[i].type;
  332. break;
  333. }
  334. }
  335. }
  336. }
  337. } except (EXCEPTION_EXECUTE_HANDLER) {
  338. // do nothing...
  339. }
  340. if (status == 0) {
  341. //
  342. // Dispatch coprocessor exception to user mode
  343. //
  344. return FALSE;
  345. }
  346. if (status == 1) {
  347. //
  348. // Ignore pending exception, user mode instruction does not trap
  349. // on pending execptions and it will clear/mask the pending exceptions
  350. //
  351. _asm {
  352. mov eax, cr0
  353. and eax, NOT (CR0_MP+CR0_EM+CR0_TS)
  354. mov cr0, eax
  355. }
  356. NpxFrame->Cr0NpxState &= ~CR0_TS;
  357. return TRUE;
  358. }
  359. //
  360. // This is either FNSTSW or FNSTCW. Both of these instructions get
  361. // a value from the coprocessor without effecting the pending exception
  362. // state. To do this we emulate the instructions.
  363. //
  364. //
  365. // Read the coprocessors Status & Control word state, then re-enable
  366. // interrupts. (it's safe to context switch after that point)
  367. //
  368. //
  369. // NOTE: The new compiler is generating a FWAIT at the
  370. // entry to the try/except block if it sees inline
  371. // fp instructions, even if they are only control word accesses.
  372. // put this stuff in another function to fool it.
  373. //
  374. KipWorkAroundCompiler (&StatusWord, &ControlWord);
  375. if (status == 4) {
  376. //
  377. // Emulate FNSTSW AX
  378. //
  379. UserFrame->Eip = (ULONG)istream;
  380. UserFrame->Eax = (UserFrame->Eax & 0xFFFF0000) | StatusWord;
  381. return TRUE;
  382. }
  383. if (status == 2) {
  384. UsersWord = ControlWord;
  385. } else {
  386. UsersWord = StatusWord;
  387. }
  388. try {
  389. //
  390. // (PERFNOTE: the operand decode code should really share code with
  391. // KiCheckDivideByZeroTrap, but this is a late change therefore the
  392. // code was copied to keep the impact of the change localized)
  393. //
  394. //
  395. // decode Mod/RM byte
  396. //
  397. Mod = MOD32 + (ibyte2 >> 6);
  398. rm = ibyte2 & 7;
  399. //
  400. // Decode the instruction's word pointer into accum
  401. //
  402. accum = 0;
  403. if (rm != Mod->RmDisplaceOnly) {
  404. if (rm == Mod->RmSib) {
  405. // get SIB
  406. ibyte1 = KiNextIStreamByte (UserFrame, &istream);
  407. i = (ibyte1 >> 3) & 7;
  408. if (i != 4) {
  409. accum = GETREG(UserFrame, RM32[i]);
  410. accum = accum << (ibyte1 >> 6); // apply scaler
  411. }
  412. i = ibyte1 & 7;
  413. accum = accum + GETREG(UserFrame, RM32[i]);
  414. } else {
  415. // get register's value
  416. accum = GETREG(UserFrame, RM32[rm]);
  417. }
  418. }
  419. //
  420. // apply displacement to accum
  421. //
  422. if (Mod->RmDisplace & (1 << rm)) {
  423. if (Mod->Disp == 4) {
  424. i = (KiNextIStreamByte (UserFrame, &istream) << 0) |
  425. (KiNextIStreamByte (UserFrame, &istream) << 8) |
  426. (KiNextIStreamByte (UserFrame, &istream) << 16) |
  427. (KiNextIStreamByte (UserFrame, &istream) << 24);
  428. } else {
  429. ibyte1 = KiNextIStreamByte (UserFrame, &istream);
  430. i = (signed long) ((signed char) ibyte1); // sign extend
  431. }
  432. accum += i;
  433. }
  434. //
  435. // Set the word pointer
  436. //
  437. if (UserFrame->SegCs == KGDT_R0_CODE) {
  438. *((PUSHORT) accum) = UsersWord;
  439. } else {
  440. ProbeAndWriteUshort ((PUSHORT) accum, UsersWord);
  441. }
  442. UserFrame->Eip = (ULONG)istream;
  443. } except (KiCopyInformation(&ExceptionRecord,
  444. (GetExceptionInformation())->ExceptionRecord)) {
  445. //
  446. // Faulted addressing user's memory.
  447. // Set the address of the exception to the current program address
  448. // and raise the exception by calling the exception dispatcher.
  449. //
  450. ExceptionRecord.ExceptionAddress = (PVOID)(UserFrame->Eip);
  451. KiDispatchException(
  452. &ExceptionRecord,
  453. NULL, // ExceptionFrame
  454. UserFrame,
  455. UserMode,
  456. TRUE
  457. );
  458. }
  459. return TRUE;
  460. }
  461. //
  462. // Code description is above. We do this here to stop the compiler
  463. // from putting fwait in the try/except block
  464. //
  465. // Read the coprocessor's Status & Control word state, then re-enable
  466. // interrupts. (it's safe to context switch after that point)
  467. //
  468. //
  469. VOID
  470. KipWorkAroundCompiler (
  471. IN PUSHORT StatusWord,
  472. IN PUSHORT ControlWord
  473. )
  474. {
  475. USHORT sw;
  476. USHORT cw;
  477. sw = *StatusWord;
  478. cw = *ControlWord;
  479. _asm {
  480. mov eax, cr0
  481. mov ecx, eax
  482. and eax, NOT (CR0_MP+CR0_EM+CR0_TS)
  483. mov cr0, eax
  484. fnstsw sw
  485. fnstcw cw
  486. mov cr0, ecx
  487. sti
  488. }
  489. *StatusWord = sw;
  490. *ControlWord = cw;
  491. }