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.

550 lines
11 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. Stack.c
  5. Abstract:
  6. This module implements routines for manipulating the 16 bit stack
  7. Author:
  8. Dave Hastings (daveh) 24-Nov-1992
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #include "softpc.h"
  14. #if 0 // Disable the code for now
  15. VOID
  16. FreePMStack(
  17. USHORT Sel
  18. );
  19. USHORT
  20. AllocatePMStack(
  21. USHORT MemSize
  22. );
  23. #endif
  24. VOID
  25. DpmiPushRmInt(
  26. USHORT InterruptNumber
  27. )
  28. /*++
  29. Routine Description:
  30. This routine pushes an interrupt frame on the stack and sets up cs:ip
  31. for the specified interrupt.
  32. Arguments:
  33. InterruptNumber -- Specifies the index of the interrupt
  34. Return Value:
  35. None.
  36. --*/
  37. {
  38. DECLARE_LocalVdmContext;
  39. PWORD16 StackPointer;
  40. ULONG IntHandler;
  41. // bugbug stack wrap???
  42. ASSERT((getSP() > 6));
  43. ASSERT((!(getMSW() & MSW_PE)));
  44. StackPointer = (PWORD16)VdmMapFlat(getSS(), getSP(), VDM_V86);
  45. *(StackPointer - 3) = (USHORT)(RmBopFe & 0x0000FFFF);
  46. *(StackPointer - 2) = (USHORT)(RmBopFe >> 16);
  47. *(StackPointer - 1) = getSTATUS();
  48. setSP(getSP() - 6);
  49. IntHandler = *(PDWORD16) (IntelBase + InterruptNumber*4);
  50. setIP(LOWORD(IntHandler));
  51. setCS(HIWORD(IntHandler));
  52. }
  53. VOID
  54. BeginUseLockedPMStack(
  55. VOID
  56. )
  57. /*++
  58. Routine Description:
  59. This routine switches to the protected DPMI stack as specified by
  60. the DPMI spec. We remember the original values of EIP and ESP in
  61. global variables if we are at level zero. This allows us to correctly
  62. return to a 32 bit routine if we are dispatching a 16-bit interrupt
  63. frame.
  64. --*/
  65. {
  66. DECLARE_LocalVdmContext;
  67. #if 0 // Disabled for now
  68. if (LockedPMStackSel == 0) {
  69. LockedPMStackSel = AllocatePMStack(LockedPMStackOffset); // LockedPMStackOffset is acturally the size
  70. LockedPMStackCount = 0;
  71. //
  72. // Note the stack allocation may still fail. In this case, the setSS() will set SS selector
  73. // to zero and the error will be catched during BuildStackFrame() call
  74. //
  75. }
  76. #endif
  77. if (!LockedPMStackCount++) {
  78. DBGTRACE(VDMTR_TYPE_DPMI | DPMI_SWITCH_STACKS, (USHORT)LockedPMStackSel, LockedPMStackOffset);
  79. PMLockOrigEIP = getEIP();
  80. PMLockOrigSS = getSS();
  81. PMLockOrigESP = getESP();
  82. setSS(LockedPMStackSel);
  83. setESP(LockedPMStackOffset);
  84. }
  85. }
  86. BOOL
  87. EndUseLockedPMStack(
  88. VOID
  89. )
  90. /*++
  91. Routine Description:
  92. This routine switches the stack back off the protected DPMI stack,
  93. if we are popping off the last frame on the stack.
  94. Return Value:
  95. TRUE if the stack was switched back, FALSE otherwise
  96. --*/
  97. {
  98. DECLARE_LocalVdmContext;
  99. if (!--LockedPMStackCount) {
  100. //
  101. // We probably should free the PM stack except the one passed from DOSX??
  102. //
  103. DBGTRACE(VDMTR_TYPE_DPMI | DPMI_SWITCH_STACKS, (USHORT)PMLockOrigSS, PMLockOrigESP);
  104. setEIP(PMLockOrigEIP);
  105. setSS((WORD)PMLockOrigSS);
  106. setESP(PMLockOrigESP);
  107. return TRUE;
  108. }
  109. return FALSE;
  110. }
  111. BOOL
  112. BuildStackFrame(
  113. ULONG StackUnits,
  114. PUCHAR *pVdmStackPointer,
  115. ULONG *pNewSP
  116. )
  117. /*++
  118. Routine Description:
  119. This routine builds stack frames for the caller. It figures if it needs
  120. to use a 16 or 32-bit frame, and adjusts SP or ESP appropriately based
  121. on the number of "stack units". It also returns a flat pointer to the
  122. top of the frame to the caller.
  123. Arguments:
  124. StackUnits = number of registers needed to be saved on the frame. For
  125. example, 3 is how many elements there are on an iret frame
  126. (flags, cs, ip)
  127. Return Value:
  128. This function returns TRUE on success, FALSE on failure
  129. VdmStackPointer - flat address pointing to the "top" of the frame
  130. Notes:
  131. BUGBUG This routine doesn't check for stack faults or 'UP' direction
  132. stacks
  133. --*/
  134. {
  135. DECLARE_LocalVdmContext;
  136. USHORT SegSs;
  137. ULONG VdmSp;
  138. PUCHAR VdmStackPointer;
  139. ULONG StackOffset;
  140. ULONG Limit;
  141. ULONG SelIndex;
  142. ULONG NewSP;
  143. BOOL bExpandDown;
  144. BOOL rc;
  145. rc = TRUE;
  146. SegSs = getSS();
  147. SelIndex = (SegSs & ~0x7)/sizeof(LDT_ENTRY);
  148. Limit = (ULONG) (Ldt[SelIndex].HighWord.Bits.LimitHi << 16) |
  149. Ldt[SelIndex].LimitLow;
  150. //
  151. // Make it paged aligned if not 4G size stack.
  152. //
  153. if (Ldt[SelIndex].HighWord.Bits.Granularity) {
  154. Limit = (Limit << 12) | 0xfff;
  155. }
  156. if (Limit != 0xffffffff) Limit++;
  157. if (Ldt[SelIndex].HighWord.Bits.Default_Big) {
  158. VdmSp = getESP();
  159. } else {
  160. VdmSp = getSP();
  161. }
  162. if (CurrentAppFlags) {
  163. StackOffset = StackUnits*sizeof(DWORD);
  164. } else {
  165. StackOffset = StackUnits*sizeof(WORD);
  166. }
  167. NewSP = VdmSp - StackOffset;
  168. bExpandDown = (BOOL) (Ldt[SelIndex].HighWord.Bits.Type & 4);
  169. if ((StackOffset > VdmSp) ||
  170. (!bExpandDown && (VdmSp > Limit)) ||
  171. (bExpandDown && (NewSP < Limit))) {
  172. // failed limit check
  173. ASSERT(0);
  174. rc = FALSE;
  175. }
  176. *pNewSP = NewSP;
  177. VdmStackPointer = VdmMapFlat(SegSs, VdmSp, VDM_PM);
  178. *pVdmStackPointer = VdmStackPointer;
  179. return rc;
  180. }
  181. VOID
  182. EmulateV86Int(
  183. UCHAR InterruptNumber
  184. )
  185. /*++
  186. Routine Description:
  187. This routine is responsible for simulating a real mode interrupt. It
  188. uses the real mode IVT at 0:0.
  189. Arguments:
  190. IntNumber - interrupt vector number
  191. Eflags - client flags to save on the stack
  192. --*/
  193. {
  194. DECLARE_LocalVdmContext;
  195. PVDM_INTERRUPTHANDLER Handlers = DpmiInterruptHandlers;
  196. PUCHAR VdmStackPointer;
  197. PWORD16 pIVT;
  198. USHORT VdmSP;
  199. USHORT NewCS;
  200. USHORT NewIP;
  201. ULONG Eflags = getEFLAGS();
  202. VdmStackPointer = VdmMapFlat(getSS(), 0, VDM_V86);
  203. VdmSP = getSP() - 2;
  204. *(PWORD16)(VdmStackPointer+VdmSP) = (WORD) Eflags;
  205. VdmSP -= 2;
  206. *(PWORD16)(VdmStackPointer+VdmSP) = (WORD) getCS();
  207. VdmSP -= 2;
  208. *(PWORD16)(VdmStackPointer+VdmSP) = (WORD) getIP();
  209. setSP(VdmSP);
  210. //
  211. // See if this interrupt is hooked in protect mode, and if we should
  212. // reflect there instead.
  213. //
  214. if (Handlers[InterruptNumber].Flags & VDM_INT_HOOKED) {
  215. NewCS = (USHORT) (DosxRMReflector >> 16);
  216. NewIP = (USHORT) DosxRMReflector;
  217. //
  218. // now encode the interrupt number into CS
  219. //
  220. NewCS -= (USHORT) InterruptNumber;
  221. NewIP += (USHORT) (InterruptNumber*16);
  222. } else {
  223. PWORD16 pIvtEntry = (PWORD16) (IntelBase + InterruptNumber*4);
  224. NewIP = *pIvtEntry++;
  225. NewCS = *pIvtEntry;
  226. }
  227. setIP(NewIP);
  228. setCS(NewCS);
  229. //
  230. // Turn off flags like the hardware would
  231. //
  232. setEFLAGS(Eflags & ~(EFLAGS_TF_MASK | EFLAGS_IF_MASK));
  233. }
  234. VOID
  235. SimulateFarCall(
  236. USHORT Seg,
  237. ULONG Offset
  238. )
  239. {
  240. DECLARE_LocalVdmContext;
  241. PUCHAR VdmStackPointer;
  242. USHORT VdmSP;
  243. if (getMODE() == VDM_V86) {
  244. VdmStackPointer = VdmMapFlat(getSS(), 0, VDM_V86);
  245. VdmSP = getSP() - 2;
  246. *(PWORD16)(VdmStackPointer+VdmSP) = (WORD) getCS();
  247. VdmSP -= 2;
  248. *(PWORD16)(VdmStackPointer+VdmSP) = (WORD) getIP();
  249. setSP(VdmSP);
  250. setCS(Seg);
  251. setIP((USHORT)Offset);
  252. } else {
  253. DbgBreakPoint();
  254. }
  255. }
  256. VOID
  257. SimulateCallWithIretFrame(
  258. USHORT Seg,
  259. ULONG Offset
  260. )
  261. {
  262. DECLARE_LocalVdmContext;
  263. PUCHAR VdmStackPointer;
  264. USHORT VdmSP;
  265. if (getMODE() == VDM_V86) {
  266. VdmStackPointer = VdmMapFlat(getSS(), 0, VDM_V86);
  267. VdmSP = getSP() - 2;
  268. *(PWORD16)(VdmStackPointer+VdmSP) = (WORD) getEFLAGS();
  269. VdmSP -= 2;
  270. *(PWORD16)(VdmStackPointer+VdmSP) = (WORD) getCS();
  271. VdmSP -= 2;
  272. *(PWORD16)(VdmStackPointer+VdmSP) = (WORD) getIP();
  273. setSP(VdmSP);
  274. setCS(Seg);
  275. setIP((USHORT)Offset);
  276. } else {
  277. DbgBreakPoint();
  278. }
  279. }
  280. VOID
  281. SimulateIret(
  282. IRET_BEHAVIOR fdsp
  283. )
  284. /*++
  285. Routine Description:
  286. This routine simulates an IRET. The passed parameter specifies
  287. how the flags are to be treated. In many situations, we pass the
  288. value of the flags along, thus throwing away the flags on the stack.
  289. In the case of PASS_FLAGS, we:
  290. - clear all but the interrupt and trace flags in the caller's
  291. original flags
  292. - combine in the flags returned by the interrupt service routine.
  293. This will cause us to return to the original routine with
  294. interrupts on if they were on when the interrupt occured, or
  295. if the ISR returned with them on.
  296. Arguments:
  297. fdsp - takes the value RESTORE_FLAGS, PASS_FLAGS or PASS_CARRY_FLAG
  298. PASS_CARRY_FLAG_16 is a special value to indicate that this
  299. iret will always be on a 16-bit iret frame.
  300. --*/
  301. {
  302. DECLARE_LocalVdmContext;
  303. USHORT SegSs;
  304. ULONG VdmSp;
  305. ULONG VdmStackPointer;
  306. USHORT Flags;
  307. SegSs = getSS();
  308. if (getMODE() == VDM_V86) {
  309. VdmSp = getSP() + 6;
  310. VdmStackPointer = (ULONG) VdmMapFlat(SegSs, VdmSp, VDM_V86);
  311. setCS(*(PWORD16)(VdmStackPointer - 4));
  312. setIP(*(PWORD16)(VdmStackPointer - 6));
  313. Flags = *(PWORD16)(VdmStackPointer - 2);
  314. } else {
  315. if (Frame32 && (fdsp!=PASS_CARRY_FLAG_16)) {
  316. if (SEGMENT_IS_BIG(SegSs)) {
  317. VdmSp = getESP();
  318. } else {
  319. VdmSp = getSP();
  320. }
  321. VdmSp += 12;
  322. VdmStackPointer = (ULONG) VdmMapFlat(SegSs, VdmSp, VDM_PM);
  323. setCS(*(PWORD16)(VdmStackPointer - 8));
  324. setEIP(*(PDWORD16)(VdmStackPointer - 12));
  325. Flags = *(PWORD16)(VdmStackPointer - 4);
  326. } else {
  327. VdmSp = getSP() + 6;
  328. VdmStackPointer = (ULONG) VdmMapFlat(SegSs, VdmSp, VDM_PM);
  329. setCS(*(PWORD16)(VdmStackPointer - 4));
  330. setIP(*(PWORD16)(VdmStackPointer - 6));
  331. Flags = *(PWORD16)(VdmStackPointer - 2);
  332. }
  333. }
  334. switch(fdsp) {
  335. case RESTORE_FLAGS:
  336. break;
  337. case PASS_FLAGS:
  338. Flags = (Flags & 0x300) | getSTATUS();
  339. break;
  340. case PASS_CARRY_FLAG:
  341. case PASS_CARRY_FLAG_16:
  342. Flags = (Flags & ~1) | (getSTATUS() & 1);
  343. break;
  344. }
  345. setSTATUS(Flags);
  346. setESP(VdmSp);
  347. }
  348. #if 0 // Disable the code for now
  349. USHORT
  350. AllocatePMStack(
  351. USHORT MemSize
  352. )
  353. /*++
  354. Routine Description:
  355. This routine allocates PM stack.
  356. Arguments:
  357. MemSize - Must be less than 64k
  358. Return Value:
  359. if successful, selector of the PM stack
  360. otherwise 0
  361. --*/
  362. {
  363. PMEM_DPMI pMem;
  364. pMem = DpmiAllocateXmem(MemSize);
  365. if (pMem) {
  366. pMem->SelCount = 1;
  367. pMem->Sel = ALLOCATE_SELECTORS(1);
  368. if (!pMem->Sel) {
  369. pMem->SelCount = 0;
  370. DpmiFreeXmem(pMem);
  371. pMem = NULL;
  372. } else {
  373. SetDescriptorArray(pMem->Sel, (ULONG)pMem->Address, MemSize);
  374. }
  375. }
  376. if (pMem) {
  377. return pMem->Sel;
  378. } else {
  379. return (USHORT)0;
  380. }
  381. }
  382. VOID
  383. FreePMStack(
  384. USHORT Sel
  385. )
  386. /*++
  387. Routine Description:
  388. This routine releases PM stack
  389. Arguments:
  390. Sel - Selector of the PM stack to be freed.
  391. Return Value:
  392. None.
  393. --*/
  394. {
  395. PMEM_DPMI pMem;
  396. if (pMem = DpmiFindXmem(Sel)) {
  397. while(pMem->SelCount--) {
  398. FreeSelector(Sel);
  399. Sel+=8;
  400. }
  401. DpmiFreeXmem(pMem);
  402. }
  403. }
  404. #endif