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.

916 lines
20 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. modesw.c
  5. Abstract:
  6. This module provides support for performing mode switching on the 32 bit
  7. side.
  8. Author:
  9. Dave Hastings (daveh) 24-Nov-1992
  10. Revision History:
  11. Neil Sandlin (neilsa) 31-Jul-1995 - Updates for the 486 emulator
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #include "softpc.h"
  16. RMCB_INFO DpmiRmcb[MAX_RMCBS];
  17. USHORT RMCallBackBopSeg;
  18. USHORT RMCallBackBopOffset;
  19. #define SAVE_ALT_REGS(Regs) { \
  20. Regs.Eip = getEIP(); \
  21. Regs.Esp = getESP(); \
  22. Regs.Cs = getCS(); \
  23. Regs.Ds = getDS(); \
  24. Regs.Es = getES(); \
  25. Regs.Fs = getFS(); \
  26. Regs.Gs = getGS(); \
  27. Regs.Ss = getSS(); \
  28. }
  29. #define SET_ALT_REGS(Regs) { \
  30. setEIP(Regs.Eip); \
  31. setESP(Regs.Esp); \
  32. setCS(Regs.Cs); \
  33. setDS(Regs.Ds); \
  34. setES(Regs.Es); \
  35. setFS(Regs.Fs); \
  36. setGS(Regs.Gs); \
  37. setSS(Regs.Ss); \
  38. }
  39. typedef struct _ALT_REGS {
  40. ULONG Eip;
  41. ULONG Esp;
  42. USHORT Cs;
  43. USHORT Ss;
  44. USHORT Es;
  45. USHORT Ds;
  46. USHORT Fs;
  47. USHORT Gs;
  48. } ALT_REGS, *PALT_REGS;
  49. ALT_REGS AltRegs = {0};
  50. VOID
  51. DpmiSetAltRegs(
  52. VOID
  53. )
  54. {
  55. DECLARE_LocalVdmContext;
  56. SAVE_ALT_REGS(AltRegs);
  57. }
  58. VOID
  59. SetV86Exec(
  60. VOID
  61. )
  62. /*++
  63. Routine Description:
  64. This routine performs a mode switch to real (v86) mode.
  65. Arguments:
  66. None.
  67. Return Value:
  68. None.
  69. --*/
  70. {
  71. DECLARE_LocalVdmContext;
  72. setMSW(getMSW() & ~MSW_PE);
  73. #ifndef _X86_
  74. //BUGBUG This is a workaround to reload a 64k limit into SS for the
  75. // emulator, now that we are in real mode.
  76. // Not doing this would cause the emulator to do a hardware reset
  77. setSS_BASE_LIMIT_AR(getSS_BASE(), 0xffff, getSS_AR());
  78. #else
  79. //
  80. // If we have v86 mode fast IF emulation set the RealInstruction bit
  81. //
  82. if (VdmFeatureBits & V86_VIRTUAL_INT_EXTENSIONS) {
  83. _asm {
  84. mov eax,FIXED_NTVDMSTATE_LINEAR ; get pointer to VDM State
  85. lock or dword ptr [eax], dword ptr RI_BIT_MASK
  86. }
  87. } else {
  88. _asm {
  89. mov eax,FIXED_NTVDMSTATE_LINEAR ; get pointer to VDM State
  90. lock and dword ptr [eax], dword ptr ~RI_BIT_MASK
  91. }
  92. }
  93. //
  94. // turn on real mode bit
  95. //
  96. _asm {
  97. mov eax,FIXED_NTVDMSTATE_LINEAR ; get pointer to VDM State
  98. lock or dword ptr [eax], dword ptr RM_BIT_MASK
  99. }
  100. #endif
  101. setEFLAGS((getEFLAGS() & ~(EFLAGS_RF_MASK | EFLAGS_NT_MASK)));
  102. DBGTRACE(VDMTR_TYPE_DPMI | DPMI_IN_V86, 0, 0);
  103. }
  104. VOID
  105. SetPMExec(
  106. VOID
  107. )
  108. /*++
  109. Routine Description:
  110. This routine performs a mode switch to protected mode.
  111. Arguments:
  112. None.
  113. Return Value:
  114. None.
  115. --*/
  116. {
  117. DECLARE_LocalVdmContext;
  118. setMSW(getMSW() | MSW_PE);
  119. #ifndef _X86_
  120. //BUGBUG This is a workaround to make sure the emulator goes back
  121. // to privilege level 3 now that we are in protect mode.
  122. // Not doing this would cause an access violation in dpmi32.
  123. setCPL(3);
  124. #else
  125. //
  126. // If we have fast if emulation in PM set the RealInstruction bit
  127. //
  128. if (VdmFeatureBits & PM_VIRTUAL_INT_EXTENSIONS) {
  129. _asm {
  130. mov eax,FIXED_NTVDMSTATE_LINEAR ; get pointer to VDM State
  131. lock or dword ptr [eax], dword ptr RI_BIT_MASK
  132. }
  133. } else {
  134. _asm {
  135. mov eax, FIXED_NTVDMSTATE_LINEAR ; get pointer to VDM State
  136. lock and dword ptr [eax], dword ptr ~RI_BIT_MASK
  137. }
  138. }
  139. //
  140. // Turn off real mode bit
  141. //
  142. _asm {
  143. mov eax,FIXED_NTVDMSTATE_LINEAR ; get pointer to VDM State
  144. lock and dword ptr [eax], dword ptr ~RM_BIT_MASK
  145. }
  146. #endif
  147. setEFLAGS((getEFLAGS() & ~(EFLAGS_RF_MASK | EFLAGS_NT_MASK)));
  148. DBGTRACE(VDMTR_TYPE_DPMI | DPMI_IN_PM, 0, 0);
  149. }
  150. VOID
  151. switch_to_protected_mode(
  152. VOID
  153. )
  154. /*++
  155. Routine Description:
  156. This routine is called via BOP from DOSX to transition to
  157. protected mode.
  158. Arguments:
  159. None
  160. Return Value:
  161. None.
  162. --*/
  163. {
  164. DECLARE_LocalVdmContext;
  165. PCHAR StackPointer;
  166. StackPointer = VdmMapFlat(getSS(), getSP(), getMODE());
  167. setCS(*(PUSHORT)(StackPointer + 12));
  168. setEIP(*(PULONG)(StackPointer + 8));
  169. setSS(*(PUSHORT)(StackPointer + 6));
  170. setESP(*(PULONG)(StackPointer + 2));
  171. setDS(*(PUSHORT)(StackPointer));
  172. //
  173. // don't zero the segment selectors. If the caller has a bad segment
  174. // selector, the kernel will fix it for us. This function may be
  175. // called directly from app (thru dosx) and the segment registers may
  176. // have be setup. We certainly don't want to destroy them.
  177. // (To make transportation tycoon work.)
  178. //
  179. // setES((USHORT)0);
  180. // setGS((USHORT)0);
  181. // setFS((USHORT)0);
  182. SetPMExec();
  183. }
  184. VOID
  185. switch_to_real_mode(
  186. VOID
  187. )
  188. /*++
  189. Routine Description:
  190. This routine services the switch to real mode bop. It is included in
  191. DPMI.c so that all of the mode switching services are in the same place
  192. Arguments:
  193. None
  194. Return Value:
  195. None.
  196. --*/
  197. {
  198. DECLARE_LocalVdmContext;
  199. PCHAR StackPointer;
  200. StackPointer = VdmMapFlat(getSS(), getSP(), getMODE());
  201. LastLockedPMStackESP = getESP();
  202. LastLockedPMStackSS = getSS();
  203. setDS(*(PUSHORT)(StackPointer));
  204. setESP((ULONG) *(PUSHORT)(StackPointer + 2));
  205. setSS(*(PUSHORT)(StackPointer + 4));
  206. setEIP((ULONG) *(PUSHORT)(StackPointer + 6));
  207. setCS(*(PUSHORT)(StackPointer + 8));
  208. SetV86Exec();
  209. }
  210. VOID
  211. DpmiSwitchToRealMode(
  212. VOID
  213. )
  214. /*++
  215. Routine Description:
  216. This routine is called internally from DPMI32 (i.e. Int21map)
  217. to switch to real mode.
  218. Arguments:
  219. None.
  220. Return Value:
  221. None.
  222. --*/
  223. {
  224. DECLARE_LocalVdmContext;
  225. PWORD16 Data;
  226. // HACK ALERT
  227. Data = (PWORD16) VdmMapFlat(DosxRmCodeSegment, 4, VDM_V86);
  228. *(Data) = DosxStackSegment;
  229. LastLockedPMStackESP = getESP();
  230. LastLockedPMStackSS = getSS();
  231. setCS(DosxRmCodeSegment);
  232. SetV86Exec();
  233. }
  234. VOID
  235. DpmiSwitchToProtectedMode(
  236. VOID
  237. )
  238. /*++
  239. Routine Description:
  240. This routine is called internally from DPMI32 (i.e. Int21map)
  241. to switch to real mode.
  242. Arguments:
  243. None.
  244. Return Value:
  245. None.
  246. --*/
  247. {
  248. DECLARE_LocalVdmContext;
  249. PWORD16 Data;
  250. // HACK ALERT
  251. Data = (PWORD16) VdmMapFlat(DosxRmCodeSegment, 4, VDM_V86);
  252. *(Data) = 0xb7;
  253. setESP(LastLockedPMStackESP);
  254. setSS(LastLockedPMStackSS);
  255. SetPMExec();
  256. }
  257. VOID
  258. DpmiAllocateRMCallBack(
  259. VOID
  260. )
  261. /*++
  262. Routine Description:
  263. Service 03/03 -- Allocate Real Mode Call-Back Address
  264. In: ax = selector to use to point to rm stack
  265. ds:si -> pMode CS:IP to be called when rMode
  266. call-back address executed
  267. es:di -> client register structure to be updated
  268. when call-back address executed
  269. NOTE: client's DS and ES register values are on stack
  270. Out: cx:dx -> SEGMENT:offset of real mode call-back hook
  271. CY clear if successful, CY set if can't allocate
  272. call back
  273. --*/
  274. {
  275. DECLARE_LocalVdmContext;
  276. int i;
  277. for (i=0; i<MAX_RMCBS; i++) {
  278. if (!DpmiRmcb[i].bInUse) {
  279. break;
  280. }
  281. }
  282. if (i == MAX_RMCBS) {
  283. // no more rmcbs
  284. setCF(1);
  285. return;
  286. }
  287. DpmiRmcb[i].StackSel = ALLOCATE_SELECTOR();
  288. if (!DpmiRmcb[i].StackSel) {
  289. // no more selectors
  290. setCF(1);
  291. return;
  292. }
  293. SetDescriptor(DpmiRmcb[i].StackSel, 0, 0xffff, STD_DATA);
  294. DpmiRmcb[i].bInUse = TRUE;
  295. DpmiRmcb[i].StrucSeg = getES(); // get client ES register
  296. DpmiRmcb[i].StrucOffset = (*GetDIRegister)();
  297. DpmiRmcb[i].ProcSeg = getDS();
  298. DpmiRmcb[i].ProcOffset = (*GetSIRegister)();
  299. setCX(RMCallBackBopSeg - i);
  300. setDX(RMCallBackBopOffset + (i*16));
  301. setCF(0);
  302. }
  303. VOID
  304. DpmiFreeRMCallBack(
  305. VOID
  306. )
  307. /*++
  308. Routine Description:
  309. Service 03/04 -- Free Real Mode Call-Back Address
  310. In: cx:dx -> SEGMENT:offset of rMode call-back to free
  311. Out: CY clear if successful, CY set if failure
  312. ax = utility selector which should be freed
  313. --*/
  314. {
  315. DECLARE_LocalVdmContext;
  316. USHORT i = RMCallBackBopSeg - getCX();
  317. if ((i >= MAX_RMCBS) || !DpmiRmcb[i].bInUse) {
  318. // already free or invalid callback address
  319. setCF(1);
  320. return;
  321. }
  322. DpmiRmcb[i].bInUse = FALSE;
  323. FreeSelector(DpmiRmcb[i].StackSel);
  324. setCF(0);
  325. }
  326. VOID
  327. GetRMClientRegs(
  328. PDPMI_RMCALLSTRUCT pcs
  329. )
  330. {
  331. DECLARE_LocalVdmContext;
  332. pcs->Edi = getEDI();
  333. pcs->Esi = getESI();
  334. pcs->Ebp = getEBP();
  335. pcs->Ebx = getEBX();
  336. pcs->Edx = getEDX();
  337. pcs->Ecx = getECX();
  338. pcs->Eax = getEAX();
  339. pcs->Flags = (WORD) getEFLAGS();
  340. pcs->Es = getES();
  341. pcs->Ds = getDS();
  342. pcs->Fs = getFS();
  343. pcs->Gs = getGS();
  344. }
  345. VOID
  346. SetRMClientRegs(
  347. PDPMI_RMCALLSTRUCT pcs
  348. )
  349. {
  350. DECLARE_LocalVdmContext;
  351. setEDI(pcs->Edi);
  352. setESI(pcs->Esi);
  353. setEBP(pcs->Ebp);
  354. setEBX(pcs->Ebx);
  355. setEDX(pcs->Edx);
  356. setECX(pcs->Ecx);
  357. setEAX(pcs->Eax);
  358. setEFLAGS((getEFLAGS()&0xffff0000) + (ULONG)pcs->Flags);
  359. setES(pcs->Es);
  360. setDS(pcs->Ds);
  361. setFS(pcs->Fs);
  362. setGS(pcs->Gs);
  363. }
  364. VOID
  365. DpmiRMCallBackCall(
  366. VOID
  367. )
  368. /*++
  369. Routine Description:
  370. This routine gets control when the application executes the
  371. callback address allocated by DPMI func 0x303. Its job is
  372. to switch the processor into protect mode as defined by the
  373. DPMI spec.
  374. Arguments:
  375. None.
  376. Return Value:
  377. None.
  378. --*/
  379. {
  380. DECLARE_LocalVdmContext;
  381. PDPMI_RMCALLSTRUCT pcs;
  382. ULONG StackBase;
  383. ULONG CurBase;
  384. BOOL bStackBaseRestore = FALSE;
  385. USHORT StackSel;
  386. PUCHAR VdmStackPointer;
  387. ULONG NewSP;
  388. USHORT i = RMCallBackBopSeg - getCS();
  389. if ((i >= MAX_RMCBS) || !DpmiRmcb[i].bInUse) {
  390. // already free or invalid callback address
  391. return;
  392. }
  393. //
  394. // Point ip back to BOP (per dpmi)
  395. //
  396. setIP(getIP()-4);
  397. pcs = (PDPMI_RMCALLSTRUCT) VdmMapFlat(DpmiRmcb[i].StrucSeg,
  398. DpmiRmcb[i].StrucOffset,
  399. VDM_PM);
  400. GetRMClientRegs(pcs);
  401. pcs->Ip = getIP();
  402. pcs->Cs = getCS();
  403. pcs->Sp = getSP();
  404. pcs->Ss = getSS();
  405. // Win31 saves DS-GS on the stack here.
  406. StackBase = (ULONG)(pcs->Ss<<4);
  407. StackSel = DpmiRmcb[i].StackSel;
  408. CurBase = GET_SELECTOR_BASE(StackSel);
  409. if (StackBase != CurBase) {
  410. bStackBaseRestore = TRUE;
  411. SetDescriptorBase(StackSel, StackBase);
  412. }
  413. setESI(getSP());
  414. setEDI(DpmiRmcb[i].StrucOffset);
  415. DpmiSwitchToProtectedMode();
  416. BeginUseLockedPMStack();
  417. setDS(DpmiRmcb[i].StackSel);
  418. setES(DpmiRmcb[i].StrucSeg);
  419. BuildStackFrame(3, &VdmStackPointer, &NewSP);
  420. if (Frame32) {
  421. *(PDWORD16)(VdmStackPointer-4) = 0x202;
  422. *(PDWORD16)(VdmStackPointer-8) = PmBopFe >> 16;
  423. *(PDWORD16)(VdmStackPointer-12) = PmBopFe & 0x0000FFFF;
  424. setESP(NewSP);
  425. } else {
  426. *(PWORD16)(VdmStackPointer-2) = 0x202;
  427. *(PWORD16)(VdmStackPointer-4) = (USHORT) (PmBopFe >> 16);
  428. *(PWORD16)(VdmStackPointer-6) = (USHORT) PmBopFe;
  429. setSP((WORD)NewSP);
  430. }
  431. setEIP(DpmiRmcb[i].ProcOffset);
  432. setCS(DpmiRmcb[i].ProcSeg);
  433. #ifndef _X86_
  434. // preserve iopl
  435. setEFLAGS(getEFLAGS() | 0x3000);
  436. #endif
  437. DBGTRACE(VDMTR_TYPE_DPMI | DPMI_REFLECT_TO_PM, 0, 0);
  438. host_simulate(); // execute PM callback
  439. //
  440. // restore stack descriptor if need be
  441. //
  442. if (bStackBaseRestore) {
  443. SetDescriptorBase(StackSel, CurBase);
  444. }
  445. pcs = (PDPMI_RMCALLSTRUCT) VdmMapFlat(getES(),
  446. (*GetDIRegister)(),
  447. VDM_PM);
  448. // win31 restores GS-DS here. Is this only for End_Nest_Exec?
  449. EndUseLockedPMStack();
  450. DpmiSwitchToRealMode();
  451. SetRMClientRegs(pcs);
  452. setSP(pcs->Sp);
  453. setSS(pcs->Ss);
  454. setCS(pcs->Cs);
  455. setIP(pcs->Ip);
  456. }
  457. VOID
  458. DpmiReflectIntrToPM(
  459. VOID
  460. )
  461. /*++
  462. Routine Description:
  463. This routine gets control when a real mode interrupt is executed that is hooked
  464. in protected mode. The responsibility of this routine is to switch into PM, reflect
  465. the interrupt, and return to real mode.
  466. The actual interrupt number is encoded into CS by subtracting the interrupt number
  467. from the normal dosx real mode code segment. IP is then adjusted accordingly to
  468. point to the same place.
  469. Arguments:
  470. None.
  471. Return Value:
  472. None.
  473. --*/
  474. {
  475. DECLARE_LocalVdmContext;
  476. PUCHAR VdmCodePointer;
  477. ULONG IntNumber;
  478. PUCHAR VdmStackPointer;
  479. ULONG NewSP;
  480. ULONG ISRFlags;
  481. ULONG SaveEFlags = getEFLAGS();
  482. USHORT SaveBP;
  483. ALT_REGS RMSave;
  484. IntNumber = (ULONG) (HIWORD(DosxRMReflector) - getCS());
  485. SAVE_ALT_REGS(RMSave);
  486. DpmiSwitchToProtectedMode();
  487. setES((USHORT)0);
  488. setDS((USHORT)0);
  489. setFS((USHORT)0);
  490. setGS((USHORT)0);
  491. BeginUseLockedPMStack();
  492. if (DpmiSwIntHandler(IntNumber) && BuildStackFrame(3, &VdmStackPointer, &NewSP)) {
  493. //
  494. // Put unsimulate bop on the stack so we get control after the handler's iret
  495. //
  496. if (Frame32) {
  497. *(PDWORD16)(VdmStackPointer-4) = getEFLAGS();
  498. *(PDWORD16)(VdmStackPointer-8) = PmBopFe >> 16;
  499. *(PDWORD16)(VdmStackPointer-12) = PmBopFe & 0x0000FFFF;
  500. setESP(NewSP);
  501. } else {
  502. *(PWORD16)(VdmStackPointer-2) = LOWORD(getEFLAGS());
  503. *(PWORD16)(VdmStackPointer-4) = (USHORT) (PmBopFe >> 16);
  504. *(PWORD16)(VdmStackPointer-6) = (USHORT) PmBopFe;
  505. setSP((WORD)NewSP);
  506. }
  507. // Do special case processing for int24
  508. if (IntNumber == 0x24) {
  509. SaveBP = getBP();
  510. setBP(SegmentToSelector(SaveBP, STD_DATA));
  511. }
  512. DBGTRACE(VDMTR_TYPE_DPMI | DPMI_REFLECT_TO_PM, 0, 0);
  513. host_simulate(); // execute interrupt
  514. if (IntNumber == 0x24) {
  515. setBP(SaveBP);
  516. }
  517. //
  518. // simulate an iret for the frame generated by the SwIntHandler
  519. //
  520. if (Frame32) {
  521. setEIP(*(PDWORD16)(VdmStackPointer));
  522. setCS((USHORT)*(PDWORD16)(VdmStackPointer+4));
  523. setEFLAGS(*(PDWORD16)(VdmStackPointer+8));
  524. setESP(getESP()+12);
  525. } else {
  526. setIP(*(PWORD16)(VdmStackPointer));
  527. setCS(*(PWORD16)(VdmStackPointer+2));
  528. setEFLAGS((getEFLAGS()&0xffff0000) + *(PWORD16)(VdmStackPointer+4));
  529. setSP(getSP()+6);
  530. }
  531. ISRFlags = getEFLAGS();
  532. }
  533. EndUseLockedPMStack();
  534. DpmiSwitchToRealMode();
  535. //
  536. // do the final iret back to the app
  537. //
  538. setESP(RMSave.Esp);
  539. setSS(RMSave.Ss);
  540. setDS(RMSave.Ds);
  541. setES(RMSave.Es);
  542. setFS(RMSave.Fs);
  543. setGS(RMSave.Gs);
  544. SimulateIret(PASS_FLAGS);
  545. }
  546. VOID
  547. DpmiReflectIntrToV86(
  548. VOID
  549. )
  550. /*++
  551. Routine Description:
  552. This routine gets control when the end of the interrupt chain is reached
  553. in protected mode. The responsibility of this routine is to switch into V86 mode,
  554. reflect the interrupt, and return to protected mode.
  555. Arguments:
  556. None.
  557. Return Value:
  558. None.
  559. --*/
  560. {
  561. DECLARE_LocalVdmContext;
  562. PUCHAR VdmCodePointer;
  563. ULONG IntNumber;
  564. PUCHAR VdmStackPointer;
  565. USHORT SaveSS, SaveSP;
  566. USHORT SaveCS, SaveIP;
  567. ALT_REGS PMSave;
  568. ULONG IntHandler;
  569. VdmCodePointer = VdmMapFlat(getCS(), getIP(), VDM_PM);
  570. IntNumber = (ULONG) *VdmCodePointer;
  571. if (DispatchPMInt((UCHAR)IntNumber)) {
  572. return;
  573. }
  574. SAVE_ALT_REGS(PMSave);
  575. DpmiSwitchToRealMode();
  576. //
  577. // find a safe stack to run on in v86 mode
  578. //
  579. SaveSS = getSS();
  580. SaveSP = getSP();
  581. SWITCH_TO_DOSX_RMSTACK();
  582. //
  583. // Put unsimulate bop on the stack so we get control after the handler's iret
  584. //
  585. VdmStackPointer = VdmMapFlat(getSS(), getSP(), VDM_V86);
  586. SaveCS = getCS();
  587. SaveIP = getIP();
  588. *(PWORD16)(VdmStackPointer-2) = LOWORD(getEFLAGS());
  589. *(PWORD16)(VdmStackPointer-4) = (USHORT) (RmBopFe >> 16);
  590. *(PWORD16)(VdmStackPointer-6) = (USHORT) RmBopFe;
  591. setSP(getSP() - 6);
  592. IntHandler = *(PDWORD16) (IntelBase + IntNumber*4);
  593. setIP(LOWORD(IntHandler));
  594. setCS(HIWORD(IntHandler));
  595. DBGTRACE(VDMTR_TYPE_DPMI | DPMI_REFLECT_TO_V86, 0, 0);
  596. host_simulate(); // execute interrupt
  597. setIP(SaveIP);
  598. setCS(SaveCS);
  599. setSP(SaveSP);
  600. setSS(SaveSS);
  601. SWITCH_FROM_DOSX_RMSTACK();
  602. DpmiSwitchToProtectedMode();
  603. //
  604. // do the final iret back to the app
  605. //
  606. setESP(PMSave.Esp);
  607. setSS(PMSave.Ss);
  608. setDS(PMSave.Ds);
  609. setES(PMSave.Es);
  610. setFS(PMSave.Fs);
  611. setGS(PMSave.Gs);
  612. SimulateIret(PASS_FLAGS);
  613. }
  614. VOID
  615. DpmiRMCall(
  616. UCHAR mode
  617. )
  618. /*++
  619. Routine Description:
  620. This routine gets control when an Int31 func 300-302 is executed.
  621. The responsibility of this routine is to switch into V86 mode,
  622. reflect the interrupt, and return to protected mode.
  623. Arguments:
  624. None.
  625. Return Value:
  626. None.
  627. --*/
  628. {
  629. DECLARE_LocalVdmContext;
  630. CLIENT_REGS SaveRegs;
  631. PDPMI_RMCALLSTRUCT pcs;
  632. BOOL bUsingOurStack;
  633. PUCHAR RmStackPointer, PmStackPointer;
  634. USHORT CopyLen;
  635. ULONG PmSp = (*GetSPRegister)();
  636. pcs = (PDPMI_RMCALLSTRUCT) VdmMapFlat(getES(),
  637. (*GetDIRegister)(),
  638. VDM_PM);
  639. SAVE_CLIENT_REGS(SaveRegs);
  640. DpmiSwitchToRealMode();
  641. //
  642. // This bop will get us back from host_simulate
  643. //
  644. setCS((USHORT)(RmBopFe >> 16));
  645. setIP((USHORT)RmBopFe);
  646. SetRMClientRegs(pcs);
  647. if (!pcs->Ss && !pcs->Sp) {
  648. SWITCH_TO_DOSX_RMSTACK();
  649. bUsingOurStack = TRUE;
  650. } else {
  651. setSS(pcs->Ss);
  652. setSP(pcs->Sp);
  653. bUsingOurStack = FALSE;
  654. }
  655. if (CopyLen = LOWORD(SaveRegs.Ecx)) {
  656. CopyLen *= 2;
  657. setSP(getSP() - CopyLen);
  658. PmStackPointer = VdmMapFlat(SaveRegs.Ss, PmSp, VDM_PM);
  659. RmStackPointer = VdmMapFlat(getSS(), getSP(), VDM_V86);
  660. RtlCopyMemory(RmStackPointer, PmStackPointer, CopyLen);
  661. }
  662. //
  663. // switch on MODE
  664. //
  665. switch(mode) {
  666. case 0:
  667. // Simulate Int
  668. EmulateV86Int((UCHAR)SaveRegs.Ebx);
  669. break;
  670. case 1:
  671. // Call with FAR return frame
  672. SimulateFarCall(pcs->Cs, pcs->Ip);
  673. break;
  674. case 2:
  675. // Call with IRET frame
  676. SimulateCallWithIretFrame(pcs->Cs, pcs->Ip);
  677. break;
  678. }
  679. DBGTRACE(VDMTR_TYPE_DPMI | DPMI_REFLECT_TO_V86, 0, 0);
  680. host_simulate(); // execute interrupt
  681. if (bUsingOurStack) {
  682. SWITCH_FROM_DOSX_RMSTACK();
  683. }
  684. GetRMClientRegs(pcs);
  685. DpmiSwitchToProtectedMode();
  686. SET_CLIENT_REGS(SaveRegs);
  687. setCF(0); // function successful
  688. }