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.

553 lines
12 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. if ((USHORT)SelIndex > (LdtMaxSel >> 3)) {
  149. ASSERT(0);
  150. return FALSE;
  151. }
  152. Limit = (ULONG) (Ldt[SelIndex].HighWord.Bits.LimitHi << 16) |
  153. Ldt[SelIndex].LimitLow;
  154. //
  155. // Make it paged aligned if not 4G size stack.
  156. //
  157. if (Ldt[SelIndex].HighWord.Bits.Granularity) {
  158. Limit = (Limit << 12) | 0xfff;
  159. }
  160. if (Limit != 0xffffffff) Limit++;
  161. if (Ldt[SelIndex].HighWord.Bits.Default_Big) {
  162. VdmSp = getESP();
  163. } else {
  164. VdmSp = getSP();
  165. }
  166. if (CurrentAppFlags) {
  167. StackOffset = StackUnits*sizeof(DWORD);
  168. } else {
  169. StackOffset = StackUnits*sizeof(WORD);
  170. }
  171. NewSP = VdmSp - StackOffset;
  172. bExpandDown = (BOOL) (Ldt[SelIndex].HighWord.Bits.Type & 4);
  173. if ((StackOffset > VdmSp) ||
  174. (!bExpandDown && (VdmSp > Limit)) ||
  175. (bExpandDown && (NewSP < Limit))) {
  176. // failed limit check
  177. ASSERT(0);
  178. rc = FALSE;
  179. }
  180. *pNewSP = NewSP;
  181. VdmStackPointer = VdmMapFlat(SegSs, VdmSp, VDM_PM);
  182. *pVdmStackPointer = VdmStackPointer;
  183. return rc;
  184. }
  185. VOID
  186. EmulateV86Int(
  187. UCHAR InterruptNumber
  188. )
  189. /*++
  190. Routine Description:
  191. This routine is responsible for simulating a real mode interrupt. It
  192. uses the real mode IVT at 0:0.
  193. Arguments:
  194. IntNumber - interrupt vector number
  195. Eflags - client flags to save on the stack
  196. --*/
  197. {
  198. DECLARE_LocalVdmContext;
  199. PVDM_INTERRUPTHANDLER Handlers = DpmiInterruptHandlers;
  200. PUCHAR VdmStackPointer;
  201. PWORD16 pIVT;
  202. USHORT VdmSP;
  203. USHORT NewCS;
  204. USHORT NewIP;
  205. ULONG Eflags = getEFLAGS();
  206. VdmStackPointer = VdmMapFlat(getSS(), 0, VDM_V86);
  207. VdmSP = getSP() - 2;
  208. *(PWORD16)(VdmStackPointer+VdmSP) = (WORD) Eflags;
  209. VdmSP -= 2;
  210. *(PWORD16)(VdmStackPointer+VdmSP) = (WORD) getCS();
  211. VdmSP -= 2;
  212. *(PWORD16)(VdmStackPointer+VdmSP) = (WORD) getIP();
  213. setSP(VdmSP);
  214. //
  215. // See if this interrupt is hooked in protect mode, and if we should
  216. // reflect there instead.
  217. //
  218. if (Handlers[InterruptNumber].Flags & VDM_INT_HOOKED) {
  219. NewCS = (USHORT) (DosxRMReflector >> 16);
  220. NewIP = (USHORT) DosxRMReflector;
  221. //
  222. // now encode the interrupt number into CS
  223. //
  224. NewCS -= (USHORT) InterruptNumber;
  225. NewIP += (USHORT) (InterruptNumber*16);
  226. } else {
  227. PWORD16 pIvtEntry = (PWORD16) (IntelBase + InterruptNumber*4);
  228. NewIP = *pIvtEntry++;
  229. NewCS = *pIvtEntry;
  230. }
  231. setIP(NewIP);
  232. setCS(NewCS);
  233. //
  234. // Turn off flags like the hardware would
  235. //
  236. setEFLAGS(Eflags & ~(EFLAGS_TF_MASK | EFLAGS_IF_MASK));
  237. }
  238. VOID
  239. SimulateFarCall(
  240. USHORT Seg,
  241. ULONG Offset
  242. )
  243. {
  244. DECLARE_LocalVdmContext;
  245. PUCHAR VdmStackPointer;
  246. USHORT VdmSP;
  247. if (getMODE() == VDM_V86) {
  248. VdmStackPointer = VdmMapFlat(getSS(), 0, VDM_V86);
  249. VdmSP = getSP() - 2;
  250. *(PWORD16)(VdmStackPointer+VdmSP) = (WORD) getCS();
  251. VdmSP -= 2;
  252. *(PWORD16)(VdmStackPointer+VdmSP) = (WORD) getIP();
  253. setSP(VdmSP);
  254. setCS(Seg);
  255. setIP((USHORT)Offset);
  256. } else {
  257. DbgBreakPoint();
  258. }
  259. }
  260. VOID
  261. SimulateCallWithIretFrame(
  262. USHORT Seg,
  263. ULONG Offset
  264. )
  265. {
  266. DECLARE_LocalVdmContext;
  267. PUCHAR VdmStackPointer;
  268. USHORT VdmSP;
  269. if (getMODE() == VDM_V86) {
  270. VdmStackPointer = VdmMapFlat(getSS(), 0, VDM_V86);
  271. VdmSP = getSP() - 2;
  272. *(PWORD16)(VdmStackPointer+VdmSP) = (WORD) getEFLAGS();
  273. VdmSP -= 2;
  274. *(PWORD16)(VdmStackPointer+VdmSP) = (WORD) getCS();
  275. VdmSP -= 2;
  276. *(PWORD16)(VdmStackPointer+VdmSP) = (WORD) getIP();
  277. setSP(VdmSP);
  278. setCS(Seg);
  279. setIP((USHORT)Offset);
  280. } else {
  281. DbgBreakPoint();
  282. }
  283. }
  284. VOID
  285. SimulateIret(
  286. IRET_BEHAVIOR fdsp
  287. )
  288. /*++
  289. Routine Description:
  290. This routine simulates an IRET. The passed parameter specifies
  291. how the flags are to be treated. In many situations, we pass the
  292. value of the flags along, thus throwing away the flags on the stack.
  293. In the case of PASS_FLAGS, we:
  294. - clear all but the interrupt and trace flags in the caller's
  295. original flags
  296. - combine in the flags returned by the interrupt service routine.
  297. This will cause us to return to the original routine with
  298. interrupts on if they were on when the interrupt occured, or
  299. if the ISR returned with them on.
  300. Arguments:
  301. fdsp - takes the value RESTORE_FLAGS, PASS_FLAGS or PASS_CARRY_FLAG
  302. PASS_CARRY_FLAG_16 is a special value to indicate that this
  303. iret will always be on a 16-bit iret frame.
  304. --*/
  305. {
  306. DECLARE_LocalVdmContext;
  307. USHORT SegSs;
  308. ULONG VdmSp;
  309. ULONG VdmStackPointer;
  310. USHORT Flags;
  311. SegSs = getSS();
  312. if (getMODE() == VDM_V86) {
  313. VdmSp = getSP() + 6;
  314. VdmStackPointer = (ULONG) VdmMapFlat(SegSs, VdmSp, VDM_V86);
  315. setCS(*(PWORD16)(VdmStackPointer - 4));
  316. setIP(*(PWORD16)(VdmStackPointer - 6));
  317. Flags = *(PWORD16)(VdmStackPointer - 2);
  318. } else {
  319. if (Frame32 && (fdsp!=PASS_CARRY_FLAG_16)) {
  320. if (SEGMENT_IS_BIG(SegSs)) {
  321. VdmSp = getESP();
  322. } else {
  323. VdmSp = getSP();
  324. }
  325. VdmSp += 12;
  326. VdmStackPointer = (ULONG) VdmMapFlat(SegSs, VdmSp, VDM_PM);
  327. setCS(*(PWORD16)(VdmStackPointer - 8));
  328. setEIP(*(PDWORD16)(VdmStackPointer - 12));
  329. Flags = *(PWORD16)(VdmStackPointer - 4);
  330. } else {
  331. VdmSp = getSP() + 6;
  332. VdmStackPointer = (ULONG) VdmMapFlat(SegSs, VdmSp, VDM_PM);
  333. setCS(*(PWORD16)(VdmStackPointer - 4));
  334. setIP(*(PWORD16)(VdmStackPointer - 6));
  335. Flags = *(PWORD16)(VdmStackPointer - 2);
  336. }
  337. }
  338. switch(fdsp) {
  339. case RESTORE_FLAGS:
  340. break;
  341. case PASS_FLAGS:
  342. Flags = (Flags & 0x300) | getSTATUS();
  343. break;
  344. case PASS_CARRY_FLAG:
  345. case PASS_CARRY_FLAG_16:
  346. Flags = (Flags & ~1) | (getSTATUS() & 1);
  347. break;
  348. }
  349. setSTATUS(Flags);
  350. setESP(VdmSp);
  351. }
  352. #if 0 // Disable the code for now
  353. USHORT
  354. AllocatePMStack(
  355. USHORT MemSize
  356. )
  357. /*++
  358. Routine Description:
  359. This routine allocates PM stack.
  360. Arguments:
  361. MemSize - Must be less than 64k
  362. Return Value:
  363. if successful, selector of the PM stack
  364. otherwise 0
  365. --*/
  366. {
  367. PMEM_DPMI pMem;
  368. pMem = DpmiAllocateXmem(MemSize);
  369. if (pMem) {
  370. pMem->SelCount = 1;
  371. pMem->Sel = ALLOCATE_SELECTORS(1);
  372. if (!pMem->Sel) {
  373. pMem->SelCount = 0;
  374. DpmiFreeXmem(pMem);
  375. pMem = NULL;
  376. } else {
  377. SetDescriptorArray(pMem->Sel, (ULONG)pMem->Address, MemSize);
  378. }
  379. }
  380. if (pMem) {
  381. return pMem->Sel;
  382. } else {
  383. return (USHORT)0;
  384. }
  385. }
  386. VOID
  387. FreePMStack(
  388. USHORT Sel
  389. )
  390. /*++
  391. Routine Description:
  392. This routine releases PM stack
  393. Arguments:
  394. Sel - Selector of the PM stack to be freed.
  395. Return Value:
  396. None.
  397. --*/
  398. {
  399. PMEM_DPMI pMem;
  400. if (pMem = DpmiFindXmem(Sel)) {
  401. while(pMem->SelCount--) {
  402. FreeSelector(Sel);
  403. Sel+=8;
  404. }
  405. DpmiFreeXmem(pMem);
  406. }
  407. }
  408. #endif