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.

910 lines
18 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. // Necessary to prevent loads of invalid selectors in FastEnterPM
  174. //
  175. setES((USHORT)0);
  176. setGS((USHORT)0);
  177. setFS((USHORT)0);
  178. SetPMExec();
  179. }
  180. VOID
  181. switch_to_real_mode(
  182. VOID
  183. )
  184. /*++
  185. Routine Description:
  186. This routine services the switch to real mode bop. It is included in
  187. DPMI.c so that all of the mode switching services are in the same place
  188. Arguments:
  189. None
  190. Return Value:
  191. None.
  192. --*/
  193. {
  194. DECLARE_LocalVdmContext;
  195. PCHAR StackPointer;
  196. StackPointer = VdmMapFlat(getSS(), getSP(), getMODE());
  197. LastLockedPMStackESP = getESP();
  198. LastLockedPMStackSS = getSS();
  199. setDS(*(PUSHORT)(StackPointer));
  200. setESP((ULONG) *(PUSHORT)(StackPointer + 2));
  201. setSS(*(PUSHORT)(StackPointer + 4));
  202. setEIP((ULONG) *(PUSHORT)(StackPointer + 6));
  203. setCS(*(PUSHORT)(StackPointer + 8));
  204. SetV86Exec();
  205. }
  206. VOID
  207. DpmiSwitchToRealMode(
  208. VOID
  209. )
  210. /*++
  211. Routine Description:
  212. This routine is called internally from DPMI32 (i.e. Int21map)
  213. to switch to real mode.
  214. Arguments:
  215. None.
  216. Return Value:
  217. None.
  218. --*/
  219. {
  220. DECLARE_LocalVdmContext;
  221. PWORD16 Data;
  222. // HACK ALERT
  223. Data = (PWORD16) VdmMapFlat(DosxRmCodeSegment, 4, VDM_V86);
  224. *(Data) = DosxStackSegment;
  225. LastLockedPMStackESP = getESP();
  226. LastLockedPMStackSS = getSS();
  227. setCS(DosxRmCodeSegment);
  228. SetV86Exec();
  229. }
  230. VOID
  231. DpmiSwitchToProtectedMode(
  232. VOID
  233. )
  234. /*++
  235. Routine Description:
  236. This routine is called internally from DPMI32 (i.e. Int21map)
  237. to switch to real mode.
  238. Arguments:
  239. None.
  240. Return Value:
  241. None.
  242. --*/
  243. {
  244. DECLARE_LocalVdmContext;
  245. PWORD16 Data;
  246. // HACK ALERT
  247. Data = (PWORD16) VdmMapFlat(DosxRmCodeSegment, 4, VDM_V86);
  248. *(Data) = 0xb7;
  249. setESP(LastLockedPMStackESP);
  250. setSS(LastLockedPMStackSS);
  251. SetPMExec();
  252. }
  253. VOID
  254. DpmiAllocateRMCallBack(
  255. VOID
  256. )
  257. /*++
  258. Routine Description:
  259. Service 03/03 -- Allocate Real Mode Call-Back Address
  260. In: ax = selector to use to point to rm stack
  261. ds:si -> pMode CS:IP to be called when rMode
  262. call-back address executed
  263. es:di -> client register structure to be updated
  264. when call-back address executed
  265. NOTE: client's DS and ES register values are on stack
  266. Out: cx:dx -> SEGMENT:offset of real mode call-back hook
  267. CY clear if successful, CY set if can't allocate
  268. call back
  269. --*/
  270. {
  271. DECLARE_LocalVdmContext;
  272. int i;
  273. for (i=0; i<MAX_RMCBS; i++) {
  274. if (!DpmiRmcb[i].bInUse) {
  275. break;
  276. }
  277. }
  278. if (i == MAX_RMCBS) {
  279. // no more rmcbs
  280. setCF(1);
  281. return;
  282. }
  283. DpmiRmcb[i].StackSel = ALLOCATE_SELECTOR();
  284. if (!DpmiRmcb[i].StackSel) {
  285. // no more selectors
  286. setCF(1);
  287. return;
  288. }
  289. SetDescriptor(DpmiRmcb[i].StackSel, 0, 0xffff, STD_DATA);
  290. DpmiRmcb[i].bInUse = TRUE;
  291. DpmiRmcb[i].StrucSeg = getES(); // get client ES register
  292. DpmiRmcb[i].StrucOffset = (*GetDIRegister)();
  293. DpmiRmcb[i].ProcSeg = getDS();
  294. DpmiRmcb[i].ProcOffset = (*GetSIRegister)();
  295. setCX(RMCallBackBopSeg - i);
  296. setDX(RMCallBackBopOffset + (i*16));
  297. setCF(0);
  298. }
  299. VOID
  300. DpmiFreeRMCallBack(
  301. VOID
  302. )
  303. /*++
  304. Routine Description:
  305. Service 03/04 -- Free Real Mode Call-Back Address
  306. In: cx:dx -> SEGMENT:offset of rMode call-back to free
  307. Out: CY clear if successful, CY set if failure
  308. ax = utility selector which should be freed
  309. --*/
  310. {
  311. DECLARE_LocalVdmContext;
  312. USHORT i = RMCallBackBopSeg - getCX();
  313. if ((i >= MAX_RMCBS) || !DpmiRmcb[i].bInUse) {
  314. // already free or invalid callback address
  315. setCF(1);
  316. return;
  317. }
  318. DpmiRmcb[i].bInUse = FALSE;
  319. FreeSelector(DpmiRmcb[i].StackSel);
  320. setCF(0);
  321. }
  322. VOID
  323. GetRMClientRegs(
  324. PDPMI_RMCALLSTRUCT pcs
  325. )
  326. {
  327. DECLARE_LocalVdmContext;
  328. pcs->Edi = getEDI();
  329. pcs->Esi = getESI();
  330. pcs->Ebp = getEBP();
  331. pcs->Ebx = getEBX();
  332. pcs->Edx = getEDX();
  333. pcs->Ecx = getECX();
  334. pcs->Eax = getEAX();
  335. pcs->Flags = (WORD) getEFLAGS();
  336. pcs->Es = getES();
  337. pcs->Ds = getDS();
  338. pcs->Fs = getFS();
  339. pcs->Gs = getGS();
  340. }
  341. VOID
  342. SetRMClientRegs(
  343. PDPMI_RMCALLSTRUCT pcs
  344. )
  345. {
  346. DECLARE_LocalVdmContext;
  347. setEDI(pcs->Edi);
  348. setESI(pcs->Esi);
  349. setEBP(pcs->Ebp);
  350. setEBX(pcs->Ebx);
  351. setEDX(pcs->Edx);
  352. setECX(pcs->Ecx);
  353. setEAX(pcs->Eax);
  354. setEFLAGS((getEFLAGS()&0xffff0000) + (ULONG)pcs->Flags);
  355. setES(pcs->Es);
  356. setDS(pcs->Ds);
  357. setFS(pcs->Fs);
  358. setGS(pcs->Gs);
  359. }
  360. VOID
  361. DpmiRMCallBackCall(
  362. VOID
  363. )
  364. /*++
  365. Routine Description:
  366. This routine gets control when the application executes the
  367. callback address allocated by DPMI func 0x303. Its job is
  368. to switch the processor into protect mode as defined by the
  369. DPMI spec.
  370. Arguments:
  371. None.
  372. Return Value:
  373. None.
  374. --*/
  375. {
  376. DECLARE_LocalVdmContext;
  377. PDPMI_RMCALLSTRUCT pcs;
  378. ULONG StackBase;
  379. ULONG CurBase;
  380. BOOL bStackBaseRestore = FALSE;
  381. USHORT StackSel;
  382. PUCHAR VdmStackPointer;
  383. ULONG NewSP;
  384. USHORT i = RMCallBackBopSeg - getCS();
  385. if ((i >= MAX_RMCBS) || !DpmiRmcb[i].bInUse) {
  386. // already free or invalid callback address
  387. return;
  388. }
  389. //
  390. // Point ip back to BOP (per dpmi)
  391. //
  392. setIP(getIP()-4);
  393. pcs = (PDPMI_RMCALLSTRUCT) VdmMapFlat(DpmiRmcb[i].StrucSeg,
  394. DpmiRmcb[i].StrucOffset,
  395. VDM_PM);
  396. GetRMClientRegs(pcs);
  397. pcs->Ip = getIP();
  398. pcs->Cs = getCS();
  399. pcs->Sp = getSP();
  400. pcs->Ss = getSS();
  401. // Win31 saves DS-GS on the stack here.
  402. StackBase = (ULONG)(pcs->Ss<<4);
  403. StackSel = DpmiRmcb[i].StackSel;
  404. CurBase = GET_SELECTOR_BASE(StackSel);
  405. if (StackBase != CurBase) {
  406. bStackBaseRestore = TRUE;
  407. SetDescriptorBase(StackSel, StackBase);
  408. }
  409. setESI(getSP());
  410. setEDI(DpmiRmcb[i].StrucOffset);
  411. DpmiSwitchToProtectedMode();
  412. BeginUseLockedPMStack();
  413. setDS(DpmiRmcb[i].StackSel);
  414. setES(DpmiRmcb[i].StrucSeg);
  415. BuildStackFrame(3, &VdmStackPointer, &NewSP);
  416. if (Frame32) {
  417. *(PDWORD16)(VdmStackPointer-4) = 0x202;
  418. *(PDWORD16)(VdmStackPointer-8) = PmBopFe >> 16;
  419. *(PDWORD16)(VdmStackPointer-12) = PmBopFe & 0x0000FFFF;
  420. setESP(NewSP);
  421. } else {
  422. *(PWORD16)(VdmStackPointer-2) = 0x202;
  423. *(PWORD16)(VdmStackPointer-4) = (USHORT) (PmBopFe >> 16);
  424. *(PWORD16)(VdmStackPointer-6) = (USHORT) PmBopFe;
  425. setSP((WORD)NewSP);
  426. }
  427. setEIP(DpmiRmcb[i].ProcOffset);
  428. setCS(DpmiRmcb[i].ProcSeg);
  429. #ifndef _X86_
  430. // preserve iopl
  431. setEFLAGS(getEFLAGS() | 0x3000);
  432. #endif
  433. DBGTRACE(VDMTR_TYPE_DPMI | DPMI_REFLECT_TO_PM, 0, 0);
  434. host_simulate(); // execute PM callback
  435. //
  436. // restore stack descriptor if need be
  437. //
  438. if (bStackBaseRestore) {
  439. SetDescriptorBase(StackSel, CurBase);
  440. }
  441. pcs = (PDPMI_RMCALLSTRUCT) VdmMapFlat(getES(),
  442. (*GetDIRegister)(),
  443. VDM_PM);
  444. // win31 restores GS-DS here. Is this only for End_Nest_Exec?
  445. EndUseLockedPMStack();
  446. DpmiSwitchToRealMode();
  447. SetRMClientRegs(pcs);
  448. setSP(pcs->Sp);
  449. setSS(pcs->Ss);
  450. setCS(pcs->Cs);
  451. setIP(pcs->Ip);
  452. }
  453. VOID
  454. DpmiReflectIntrToPM(
  455. VOID
  456. )
  457. /*++
  458. Routine Description:
  459. This routine gets control when a real mode interrupt is executed that is hooked
  460. in protected mode. The responsibility of this routine is to switch into PM, reflect
  461. the interrupt, and return to real mode.
  462. The actual interrupt number is encoded into CS by subtracting the interrupt number
  463. from the normal dosx real mode code segment. IP is then adjusted accordingly to
  464. point to the same place.
  465. Arguments:
  466. None.
  467. Return Value:
  468. None.
  469. --*/
  470. {
  471. DECLARE_LocalVdmContext;
  472. PUCHAR VdmCodePointer;
  473. ULONG IntNumber;
  474. PUCHAR VdmStackPointer;
  475. ULONG NewSP;
  476. ULONG ISRFlags;
  477. ULONG SaveEFlags = getEFLAGS();
  478. USHORT SaveBP;
  479. ALT_REGS RMSave;
  480. IntNumber = (ULONG) (HIWORD(DosxRMReflector) - getCS());
  481. SAVE_ALT_REGS(RMSave);
  482. DpmiSwitchToProtectedMode();
  483. setES((USHORT)0);
  484. setDS((USHORT)0);
  485. setFS((USHORT)0);
  486. setGS((USHORT)0);
  487. BeginUseLockedPMStack();
  488. DpmiSwIntHandler(IntNumber);
  489. //
  490. // Put unsimulate bop on the stack so we get control after the handler's iret
  491. //
  492. BuildStackFrame(3, &VdmStackPointer, &NewSP);
  493. if (Frame32) {
  494. *(PDWORD16)(VdmStackPointer-4) = getEFLAGS();
  495. *(PDWORD16)(VdmStackPointer-8) = PmBopFe >> 16;
  496. *(PDWORD16)(VdmStackPointer-12) = PmBopFe & 0x0000FFFF;
  497. setESP(NewSP);
  498. } else {
  499. *(PWORD16)(VdmStackPointer-2) = LOWORD(getEFLAGS());
  500. *(PWORD16)(VdmStackPointer-4) = (USHORT) (PmBopFe >> 16);
  501. *(PWORD16)(VdmStackPointer-6) = (USHORT) PmBopFe;
  502. setSP((WORD)NewSP);
  503. }
  504. // Do special case processing for int24
  505. if (IntNumber == 0x24) {
  506. SaveBP = getBP();
  507. setBP(SegmentToSelector(SaveBP, STD_DATA));
  508. }
  509. DBGTRACE(VDMTR_TYPE_DPMI | DPMI_REFLECT_TO_PM, 0, 0);
  510. host_simulate(); // execute interrupt
  511. if (IntNumber == 0x24) {
  512. setBP(SaveBP);
  513. }
  514. //
  515. // simulate an iret for the frame generated by the SwIntHandler
  516. //
  517. if (Frame32) {
  518. setEIP(*(PDWORD16)(VdmStackPointer));
  519. setCS((USHORT)*(PDWORD16)(VdmStackPointer+4));
  520. setEFLAGS(*(PDWORD16)(VdmStackPointer+8));
  521. setESP(getESP()+12);
  522. } else {
  523. setIP(*(PWORD16)(VdmStackPointer));
  524. setCS(*(PWORD16)(VdmStackPointer+2));
  525. setEFLAGS((getEFLAGS()&0xffff0000) + *(PWORD16)(VdmStackPointer+4));
  526. setSP(getSP()+6);
  527. }
  528. ISRFlags = getEFLAGS();
  529. EndUseLockedPMStack();
  530. DpmiSwitchToRealMode();
  531. //
  532. // do the final iret back to the app
  533. //
  534. setESP(RMSave.Esp);
  535. setSS(RMSave.Ss);
  536. setDS(RMSave.Ds);
  537. setES(RMSave.Es);
  538. setFS(RMSave.Fs);
  539. setGS(RMSave.Gs);
  540. SimulateIret(PASS_FLAGS);
  541. }
  542. VOID
  543. DpmiReflectIntrToV86(
  544. VOID
  545. )
  546. /*++
  547. Routine Description:
  548. This routine gets control when the end of the interrupt chain is reached
  549. in protected mode. The responsibility of this routine is to switch into V86 mode,
  550. reflect the interrupt, and return to protected mode.
  551. Arguments:
  552. None.
  553. Return Value:
  554. None.
  555. --*/
  556. {
  557. DECLARE_LocalVdmContext;
  558. PUCHAR VdmCodePointer;
  559. ULONG IntNumber;
  560. PUCHAR VdmStackPointer;
  561. USHORT SaveSS, SaveSP;
  562. USHORT SaveCS, SaveIP;
  563. ALT_REGS PMSave;
  564. ULONG IntHandler;
  565. VdmCodePointer = VdmMapFlat(getCS(), getIP(), VDM_PM);
  566. IntNumber = (ULONG) *VdmCodePointer;
  567. if (DispatchPMInt((UCHAR)IntNumber)) {
  568. return;
  569. }
  570. SAVE_ALT_REGS(PMSave);
  571. DpmiSwitchToRealMode();
  572. //
  573. // find a safe stack to run on in v86 mode
  574. //
  575. SaveSS = getSS();
  576. SaveSP = getSP();
  577. SWITCH_TO_DOSX_RMSTACK();
  578. //
  579. // Put unsimulate bop on the stack so we get control after the handler's iret
  580. //
  581. VdmStackPointer = VdmMapFlat(getSS(), getSP(), VDM_V86);
  582. SaveCS = getCS();
  583. SaveIP = getIP();
  584. *(PWORD16)(VdmStackPointer-2) = LOWORD(getEFLAGS());
  585. *(PWORD16)(VdmStackPointer-4) = (USHORT) (RmBopFe >> 16);
  586. *(PWORD16)(VdmStackPointer-6) = (USHORT) RmBopFe;
  587. setSP(getSP() - 6);
  588. IntHandler = *(PDWORD16) (IntelBase + IntNumber*4);
  589. setIP(LOWORD(IntHandler));
  590. setCS(HIWORD(IntHandler));
  591. DBGTRACE(VDMTR_TYPE_DPMI | DPMI_REFLECT_TO_V86, 0, 0);
  592. host_simulate(); // execute interrupt
  593. setIP(SaveIP);
  594. setCS(SaveCS);
  595. setSP(SaveSP);
  596. setSS(SaveSS);
  597. SWITCH_FROM_DOSX_RMSTACK();
  598. DpmiSwitchToProtectedMode();
  599. //
  600. // do the final iret back to the app
  601. //
  602. setESP(PMSave.Esp);
  603. setSS(PMSave.Ss);
  604. setDS(PMSave.Ds);
  605. setES(PMSave.Es);
  606. setFS(PMSave.Fs);
  607. setGS(PMSave.Gs);
  608. SimulateIret(PASS_FLAGS);
  609. }
  610. VOID
  611. DpmiRMCall(
  612. UCHAR mode
  613. )
  614. /*++
  615. Routine Description:
  616. This routine gets control when an Int31 func 300-302 is executed.
  617. The responsibility of this routine is to switch into V86 mode,
  618. reflect the interrupt, and return to protected mode.
  619. Arguments:
  620. None.
  621. Return Value:
  622. None.
  623. --*/
  624. {
  625. DECLARE_LocalVdmContext;
  626. CLIENT_REGS SaveRegs;
  627. PDPMI_RMCALLSTRUCT pcs;
  628. BOOL bUsingOurStack;
  629. PUCHAR RmStackPointer, PmStackPointer;
  630. USHORT CopyLen;
  631. ULONG PmSp = (*GetSPRegister)();
  632. pcs = (PDPMI_RMCALLSTRUCT) VdmMapFlat(getES(),
  633. (*GetDIRegister)(),
  634. VDM_PM);
  635. SAVE_CLIENT_REGS(SaveRegs);
  636. DpmiSwitchToRealMode();
  637. //
  638. // This bop will get us back from host_simulate
  639. //
  640. setCS((USHORT)(RmBopFe >> 16));
  641. setIP((USHORT)RmBopFe);
  642. SetRMClientRegs(pcs);
  643. if (!pcs->Ss && !pcs->Sp) {
  644. SWITCH_TO_DOSX_RMSTACK();
  645. bUsingOurStack = TRUE;
  646. } else {
  647. setSS(pcs->Ss);
  648. setSP(pcs->Sp);
  649. bUsingOurStack = FALSE;
  650. }
  651. if (CopyLen = LOWORD(SaveRegs.Ecx)) {
  652. CopyLen *= 2;
  653. setSP(getSP() - CopyLen);
  654. PmStackPointer = VdmMapFlat(SaveRegs.Ss, PmSp, VDM_PM);
  655. RmStackPointer = VdmMapFlat(getSS(), getSP(), VDM_V86);
  656. RtlCopyMemory(RmStackPointer, PmStackPointer, CopyLen);
  657. }
  658. //
  659. // switch on MODE
  660. //
  661. switch(mode) {
  662. case 0:
  663. // Simulate Int
  664. EmulateV86Int((UCHAR)SaveRegs.Ebx);
  665. break;
  666. case 1:
  667. // Call with FAR return frame
  668. SimulateFarCall(pcs->Cs, pcs->Ip);
  669. break;
  670. case 2:
  671. // Call with IRET frame
  672. SimulateCallWithIretFrame(pcs->Cs, pcs->Ip);
  673. break;
  674. }
  675. DBGTRACE(VDMTR_TYPE_DPMI | DPMI_REFLECT_TO_V86, 0, 0);
  676. host_simulate(); // execute interrupt
  677. if (bUsingOurStack) {
  678. SWITCH_FROM_DOSX_RMSTACK();
  679. }
  680. GetRMClientRegs(pcs);
  681. DpmiSwitchToProtectedMode();
  682. SET_CLIENT_REGS(SaveRegs);
  683. setCF(0); // function successful
  684. }