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.

1277 lines
23 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. Int31.c
  5. Abstract:
  6. This module provides the int 31 API for dpmi
  7. Author:
  8. Neil Sandlin (neilsa) 23-Nov-1996
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #include "softpc.h"
  14. #include "xlathlp.h"
  15. VOID Int31NotImplemented(VOID);
  16. VOID Int31SelectorManagement(VOID);
  17. VOID Int31DOSMemoryManagement(VOID);
  18. VOID Int31InterruptManagement(VOID);
  19. VOID Int31Translation(VOID);
  20. VOID Int31Function4xx(VOID);
  21. VOID Int31MemoryManagement(VOID);
  22. VOID Int31PageLocking(VOID);
  23. VOID Int31DemandPageTuning(VOID);
  24. VOID Int31VirtualIntState(VOID);
  25. VOID Int31DbgRegSupport(VOID);
  26. //
  27. // Local constants
  28. //
  29. #define MAX_DPMI_MAJOR_FUNCTION 0xb
  30. typedef VOID (*APIFUNCTION)(VOID);
  31. APIFUNCTION DpmiMajorFunctionTable[MAX_DPMI_MAJOR_FUNCTION+1] = {
  32. Int31SelectorManagement , // Selector_Management ;[0]
  33. Int31DOSMemoryManagement, // DOS_Mem_Mgt ;[1]
  34. Int31InterruptManagement, // Int_Serv ;[2]
  35. Int31Translation , // Trans_Serv ;[3]
  36. Int31Function4xx , // Get_Version ;[4]
  37. Int31MemoryManagement , // Mem_Managment ;[5]
  38. Int31PageLocking , // Page_Lock ;[6]
  39. Int31DemandPageTuning , // Demand_Page_Tuning ;[7]
  40. Int31NotImplemented , // Phys_Addr_Mapping ;[8]
  41. Int31VirtualIntState , // Virt_Interrrupt_State ;[9]
  42. Int31NotImplemented , // Not_Supported ;[A]
  43. Int31DbgRegSupport , // Debug_Register_Support ;[B]
  44. };
  45. VOID
  46. DpmiInt31Entry(
  47. VOID
  48. )
  49. /*++
  50. Routine Description:
  51. This routine is invoked when the caller has issued an int31.
  52. Arguments:
  53. None
  54. Return Value:
  55. None.
  56. --*/
  57. {
  58. DECLARE_LocalVdmContext;
  59. ULONG DpmiMajorCode = getAH();
  60. PUCHAR StackPointer;
  61. //
  62. // Pop ds from stack
  63. //
  64. StackPointer = VdmMapFlat(getSS(), (*GetSPRegister)(), VDM_PM);
  65. setDS(*(PWORD16)StackPointer);
  66. (*SetSPRegister)((*GetSPRegister)() + 2);
  67. //
  68. // Take the iret frame off the stack before we do the operation. This
  69. // way we have the stack pointer set up to the same place as we would
  70. // if this was a kernel mode dpmi host.
  71. //
  72. SimulateIret(RESTORE_FLAGS);
  73. setCF(0); // assume success
  74. if (DpmiMajorCode <= MAX_DPMI_MAJOR_FUNCTION) {
  75. (*DpmiMajorFunctionTable[DpmiMajorCode])();
  76. } else {
  77. setCF(1);
  78. }
  79. }
  80. VOID
  81. DpmiInt31Call(
  82. VOID
  83. )
  84. /*++
  85. Routine Description:
  86. This routine dispatches to the appropriate routine to perform the
  87. actual translation of the api
  88. Arguments:
  89. None
  90. Return Value:
  91. None.
  92. --*/
  93. {
  94. DECLARE_LocalVdmContext;
  95. ULONG DpmiMajorCode = getAH();
  96. PUCHAR StackPointer;
  97. //
  98. // Pop ds from stack
  99. //
  100. StackPointer = VdmMapFlat(getSS(), (*GetSPRegister)(), VDM_PM);
  101. setDS(*(PWORD16)StackPointer);
  102. (*SetSPRegister)((*GetSPRegister)() + 2);
  103. setCF(0); // assume success
  104. if (DpmiMajorCode <= MAX_DPMI_MAJOR_FUNCTION) {
  105. (*DpmiMajorFunctionTable[DpmiMajorCode])();
  106. } else {
  107. setCF(1);
  108. }
  109. }
  110. VOID
  111. Int31NotImplemented(
  112. VOID
  113. )
  114. /*++
  115. Routine Description:
  116. This routine handles int 31 functions that aren't implemented on NT.
  117. It just returns carry to the app.
  118. Arguments:
  119. None
  120. Return Value:
  121. TRUE - The function has been completed
  122. --*/
  123. {
  124. DECLARE_LocalVdmContext;
  125. setCF(1);
  126. }
  127. VOID
  128. Int31SelectorManagement(
  129. VOID
  130. )
  131. /*++
  132. Routine Description:
  133. This routine handles Int31 00xx functions.
  134. Arguments:
  135. None
  136. Return Value:
  137. None
  138. --*/
  139. {
  140. DECLARE_LocalVdmContext;
  141. USHORT Sel;
  142. USHORT NewSel;
  143. UCHAR Func = getAL();
  144. LDT_ENTRY UNALIGNED *Descriptor;
  145. USHORT Access;
  146. ULONG Base;
  147. USHORT Count;
  148. ULONG Limit;
  149. static UCHAR ReservedSelectors[16] = {0};
  150. //
  151. // First, validate the selector
  152. //
  153. if ((Func >= 4) && (Func <= 0xC)) {
  154. Sel = getBX() & SEL_INDEX_MASK;
  155. //
  156. // Make sure the selector in question is allocated
  157. //
  158. if (((Sel <= SEL_DPMI_LAST) && (!ReservedSelectors[Sel>>3])) ||
  159. (Sel > LdtMaxSel) ||
  160. ((Sel > SEL_DPMI_LAST) && IS_SELECTOR_FREE(Sel))) {
  161. setCF(1);
  162. return;
  163. }
  164. }
  165. switch(Func) {
  166. //
  167. // Allocate Selectors
  168. //
  169. case 0:
  170. Count = getCX();
  171. Sel = ALLOCATE_SELECTORS(Count);
  172. if (!Sel || !Count) {
  173. setCF(1);
  174. break;
  175. }
  176. setAX(Sel);
  177. while(Count--) {
  178. SetDescriptor(Sel, 0, 0, STD_DATA);
  179. Sel+=8;
  180. }
  181. break;
  182. //
  183. // Free Selector
  184. //
  185. case 1:
  186. Sel = getBX() & SEL_INDEX_MASK;
  187. if (Sel <= SEL_DPMI_LAST) {
  188. if (!ReservedSelectors[Sel>>3]) {
  189. setCF(1);
  190. } else {
  191. ReservedSelectors[Sel>>3] = 0;
  192. }
  193. break;
  194. }
  195. if (!FreeSelector(Sel)) {
  196. setCF(1);
  197. }
  198. if (getCF() == 0) {
  199. // Zero out segment registers if it contains what we just freed
  200. // shielint: fs, gs, ss??? kernel will fix fs and gs for us. SS is unlikely
  201. // to have the freed selector. If yes, the app is gone anyway.
  202. if (getBX() == getDS()) {
  203. setDS(0);
  204. }
  205. if (getBX() == getES()) {
  206. setES(0);
  207. }
  208. }
  209. break;
  210. //
  211. // Segment to Descriptor
  212. //
  213. case 2:
  214. Sel = SegmentToSelector(getBX(), STD_DATA);
  215. if (!Sel) {
  216. setCF(1);
  217. } else {
  218. setAX(Sel);
  219. }
  220. break;
  221. //
  222. // Get Next Selector Increment value
  223. //
  224. case 3:
  225. setAX(8);
  226. break;
  227. //
  228. // Lock functions unimplemented on NT
  229. //
  230. case 4:
  231. case 5:
  232. break;
  233. //
  234. // Get Descriptor Base
  235. //
  236. case 6:
  237. Base = GET_SELECTOR_BASE(Sel);
  238. setDX((USHORT)Base);
  239. setCX((USHORT)(Base >> 16));
  240. break;
  241. //
  242. // Set Descriptor Base
  243. //
  244. case 7:
  245. SetDescriptorBase(Sel, (((ULONG)getCX())<<16) | getDX());
  246. break;
  247. //
  248. // Set Segment Limit
  249. //
  250. case 8:
  251. Limit = ((ULONG)getCX()) << 16 | getDX();
  252. if (Limit < 0x100000) { // < 1Mb?
  253. Ldt[Sel>>3].HighWord.Bits.Granularity = 0;
  254. } else {
  255. if ((Limit & 0xfff) != 0xfff) {
  256. // Limit > 1MB, but not page aligned. Return error
  257. setCF(1);
  258. break;
  259. }
  260. Ldt[Sel>>3].HighWord.Bits.Granularity = 1;
  261. }
  262. SET_SELECTOR_LIMIT(Sel, Limit);
  263. SetShadowDescriptorEntries(Sel, 1);
  264. FLUSH_SELECTOR_CACHE(Sel, 1);
  265. break;
  266. //
  267. // Set Descriptor Access
  268. //
  269. case 9:
  270. Access = getCX();
  271. //
  272. // verify that they aren't setting "System", and that its ring3
  273. //
  274. if ((Access & 0x70) != 0x70) {
  275. setCF(1);
  276. break;
  277. }
  278. SET_SELECTOR_ACCESS(Sel, Access);
  279. SetShadowDescriptorEntries(Sel, 1);
  280. FLUSH_SELECTOR_CACHE(Sel, 1);
  281. break;
  282. //
  283. // Create data alias
  284. //
  285. case 0xA:
  286. if (!IS_SELECTOR_READABLE(Sel)) {
  287. setCF(1);
  288. break;
  289. }
  290. NewSel = ALLOCATE_SELECTOR();
  291. if (!NewSel) {
  292. setCF(1);
  293. break;
  294. }
  295. Ldt[NewSel>>3] = Ldt[Sel>>3];
  296. Ldt[NewSel>>3].HighWord.Bytes.Flags1 &= (AB_PRESENT | AB_DPL3);
  297. Ldt[NewSel>>3].HighWord.Bytes.Flags1 |= (AB_DATA | AB_WRITE);
  298. SetShadowDescriptorEntries(NewSel, 1);
  299. FLUSH_SELECTOR_CACHE(NewSel, 1);
  300. setAX(NewSel);
  301. break;
  302. //
  303. // Get Descriptor
  304. //
  305. case 0xB:
  306. Descriptor = VdmMapFlat(getES(), (*GetDIRegister)(), VDM_PM);
  307. *Descriptor = Ldt[Sel>>3];
  308. break;
  309. //
  310. // Set Descriptor
  311. //
  312. case 0xC:
  313. Descriptor = VdmMapFlat(getES(), (*GetDIRegister)(), VDM_PM);
  314. //
  315. // verify that this isn't a System descriptor, and that its ring3
  316. //
  317. if (!(Descriptor->HighWord.Bits.Type & 0x10) ||
  318. ((Descriptor->HighWord.Bits.Dpl & 3) != 3)) {
  319. setCF(1);
  320. return;
  321. }
  322. Ldt[Sel>>3] = *Descriptor;
  323. SetShadowDescriptorEntries(Sel, 1);
  324. FLUSH_SELECTOR_CACHE(Sel, 1);
  325. break;
  326. //
  327. // Allocate Specific Sel
  328. //
  329. case 0xD:
  330. Sel = getBX() & ~7;
  331. if ((Sel > SEL_DPMI_LAST) || ReservedSelectors[Sel>>3]) {
  332. setCF(1);
  333. } else {
  334. ReservedSelectors[Sel>>3] = 1;
  335. }
  336. break;
  337. default:
  338. setCF(1);
  339. }
  340. return;
  341. }
  342. VOID
  343. Int31DOSMemoryManagement(
  344. VOID
  345. )
  346. /*++
  347. Routine Description:
  348. This routine handles Int31 01xx functions.
  349. The functionality is implemented in dosmem.c.
  350. Arguments:
  351. None
  352. Return Value:
  353. None
  354. --*/
  355. {
  356. DECLARE_LocalVdmContext;
  357. switch(getAL()) {
  358. //
  359. // Allocate DOS memory block
  360. //
  361. case 0:
  362. DpmiAllocateDosMem();
  363. break;
  364. //
  365. // Free DOS memory block
  366. //
  367. case 1:
  368. DpmiFreeDosMem();
  369. break;
  370. //
  371. // Resize DOS memory block
  372. //
  373. case 2:
  374. DpmiSizeDosMem();
  375. break;
  376. }
  377. }
  378. VOID
  379. Int31InterruptManagement(
  380. VOID
  381. )
  382. /*++
  383. Routine Description:
  384. This routine handles Int31 02xx functions.
  385. Arguments:
  386. None
  387. Return Value:
  388. None
  389. --*/
  390. {
  391. DECLARE_LocalVdmContext;
  392. UCHAR IntNumber = getBL();
  393. PWORD16 pIvtEntry;
  394. switch(getAL()) {
  395. //
  396. // Get Real Mode Interrupt Vector
  397. //
  398. case 0:
  399. pIvtEntry = (PWORD16) (IntelBase + IntNumber*4);
  400. setDX(*pIvtEntry++);
  401. setCX(*pIvtEntry);
  402. break;
  403. //
  404. // Set Real Mode Interrupt Vector
  405. //
  406. case 1:
  407. pIvtEntry = (PWORD16) (IntelBase + IntNumber*4);
  408. *pIvtEntry++ = getDX();
  409. *pIvtEntry = getCX();
  410. break;
  411. //
  412. // Get exception handler Vector
  413. //
  414. case 2: {
  415. PVDM_FAULTHANDLER Handlers = DpmiFaultHandlers;
  416. if (IntNumber >= 32) {
  417. setCF(1);
  418. break;
  419. }
  420. setCX(Handlers[IntNumber].CsSelector);
  421. (*SetDXRegister)(Handlers[IntNumber].Eip);
  422. break;
  423. }
  424. //
  425. // Set exception handler Vector
  426. //
  427. case 3:
  428. if (!SetFaultHandler(IntNumber, getCX(), (*GetDXRegister)())){
  429. setCF(1);
  430. }
  431. break;
  432. //
  433. // Get Protect Mode Interrupt Vector
  434. //
  435. case 4: {
  436. PVDM_INTERRUPTHANDLER Handlers = DpmiInterruptHandlers;
  437. setCX(Handlers[IntNumber].CsSelector);
  438. (*SetDXRegister)(Handlers[IntNumber].Eip);
  439. break;
  440. }
  441. //
  442. // Set Protect Mode Interrupt Vector
  443. //
  444. case 5:
  445. if (!SetProtectedModeInterrupt(IntNumber, getCX(), (*GetDXRegister)(),
  446. (USHORT)(Frame32 ? VDM_INT_32 : VDM_INT_16))) {
  447. setCF(1);
  448. }
  449. break;
  450. }
  451. }
  452. VOID
  453. Int31Translation(
  454. VOID
  455. )
  456. /*++
  457. Routine Description:
  458. This routine handles Int31 03xx functions.
  459. The functionality is implemented in modesw.c.
  460. Arguments:
  461. None
  462. Return Value:
  463. None
  464. --*/
  465. {
  466. DECLARE_LocalVdmContext;
  467. switch(getAL()) {
  468. //
  469. // Simulate Real Mode Interrupt
  470. // Call Real Mode Procedure with Far Return Frame
  471. // Call Real Mode Procedure with Iret Frame
  472. //
  473. case 0:
  474. case 1:
  475. case 2:
  476. DpmiRMCall(getAL());
  477. break;
  478. //
  479. // Allocate Real Mode Call-Back Address
  480. //
  481. case 3:
  482. DpmiAllocateRMCallBack();
  483. break;
  484. //
  485. // Free Real Mode Call-Back Address
  486. //
  487. case 4:
  488. DpmiFreeRMCallBack();
  489. break;
  490. //
  491. // Get State Save/Restore Addresses
  492. //
  493. case 5:
  494. setAX(0);
  495. setBX((USHORT)(DosxRmSaveRestoreState>>16));
  496. setCX((USHORT)DosxRmSaveRestoreState);
  497. setSI((USHORT)(DosxPmSaveRestoreState>>16));
  498. (*SetDIRegister)(DosxPmSaveRestoreState & 0x0000FFFF);
  499. break;
  500. //
  501. // Get Raw Mode Switch Addresses
  502. //
  503. case 6:
  504. setBX((USHORT)(DosxRmRawModeSwitch>>16));
  505. setCX((USHORT)DosxRmRawModeSwitch);
  506. setSI((USHORT)(DosxPmRawModeSwitch>>16));
  507. (*SetDIRegister)(DosxPmRawModeSwitch & 0x0000FFFF);
  508. break;
  509. }
  510. }
  511. VOID
  512. Int31Function4xx(
  513. VOID
  514. )
  515. /*++
  516. Routine Description:
  517. This routine handles Int31 04xx functions.
  518. Arguments:
  519. None
  520. Return Value:
  521. None
  522. --*/
  523. {
  524. DECLARE_LocalVdmContext;
  525. USHORT Sel;
  526. switch(getAL()) {
  527. //
  528. // Get Version
  529. //
  530. case 0:
  531. setAX(I31VERSION);
  532. setBX(I31FLAGS);
  533. setCL(idCpuType);
  534. setDX((I31MasterPIC << 8) | I31SlavePIC);
  535. break;
  536. //
  537. // INTERNAL NT FUNCTION: WowAllocSelectors
  538. // This function is equivalent to DPMI func 0000,
  539. // except that it skips the step of initializing the
  540. // descriptors.
  541. //
  542. case 0xf1:
  543. Sel = ALLOCATE_WOW_SELECTORS(getCX());
  544. if (!Sel) {
  545. setCF(1);
  546. // We fall thru to make sure AX is set to 0 in the failure case.
  547. }
  548. setAX(Sel);
  549. break;
  550. //
  551. // INTERNAL NT FUNCTION: WowSetDescriptor
  552. // This function assumes that the local LDT has already
  553. // been set in the client. All that needs to be done
  554. // is an update of dpmi32 entries, as well as sending
  555. // it to the x86 ntoskrnl.
  556. //
  557. case 0xf2:
  558. Sel = getBX() & ~7;
  559. if (Sel > LdtMaxSel) {
  560. setCF(1);
  561. break;
  562. }
  563. SetShadowDescriptorEntries(Sel, getCX());
  564. // no need to flush the cache on risc since the ldt was changed
  565. // from the 16-bit side, and has thus already been flushed
  566. break;
  567. //
  568. // INTERNAL NT FUNCTION: WowSetLowMemFuncs
  569. // Wow is passing us the address of GlobalDOSAlloc, GlobalDOSFree
  570. // so that we can support the DPMI Dos memory management functions
  571. //
  572. case 0xf3:
  573. WOWAllocSeg = getBX();
  574. WOWAllocFunc = getDX();
  575. WOWFreeSeg = getSI();
  576. WOWFreeFunc = getDI();
  577. break;
  578. }
  579. }
  580. VOID
  581. Int31MemoryManagement(
  582. VOID
  583. )
  584. /*++
  585. Routine Description:
  586. This routine handles Int31 05xx functions.
  587. Arguments:
  588. None
  589. Return Value:
  590. None
  591. --*/
  592. {
  593. DECLARE_LocalVdmContext;
  594. PMEM_DPMI pMem;
  595. switch(getAL()) {
  596. //
  597. // Get Free Memory Information
  598. //
  599. case 0:
  600. DpmiGetMemoryInfo();
  601. break;
  602. //
  603. // Allocate Memory Block
  604. //
  605. case 1:
  606. pMem = DpmiAllocateXmem(((ULONG)getBX() << 16) | getCX());
  607. if (!pMem) {
  608. setCF(1);
  609. break;
  610. }
  611. //
  612. // Return the information about the block
  613. //
  614. setBX((USHORT)((ULONG)pMem->Address >> 16));
  615. setCX((USHORT)((ULONG)pMem->Address & 0x0000FFFF));
  616. setSI((USHORT)((ULONG)pMem >> 16));
  617. setDI((USHORT)((ULONG)pMem & 0x0000FFFF));
  618. break;
  619. //
  620. // Free Memory Block
  621. //
  622. case 2:
  623. pMem = (PMEM_DPMI)(((ULONG)getSI() << 16) | getDI());
  624. if (!DpmiIsXmemHandle(pMem) || !DpmiFreeXmem(pMem)) {
  625. setCF(1);
  626. }
  627. break;
  628. //
  629. // Resize Memory Block
  630. //
  631. case 3: {
  632. ULONG ulMemSize;
  633. ulMemSize = ((ULONG)getBX() << 16) | getCX();
  634. //
  635. // Not allowed to resize to 0
  636. //
  637. if ( ulMemSize != 0 ) {
  638. pMem = (PMEM_DPMI)(((ULONG)getSI() << 16) | getDI());
  639. if (!DpmiReallocateXmem(pMem, ulMemSize) ) {
  640. setCF(1);
  641. break;
  642. }
  643. //
  644. // Return the information about the block
  645. //
  646. setBX((USHORT)((ULONG)pMem->Address >> 16));
  647. setCX((USHORT)((ULONG)pMem->Address & 0x0000FFFF));
  648. }
  649. else
  650. {
  651. setCF(1);
  652. }
  653. break;
  654. }
  655. }
  656. }
  657. VOID
  658. Int31PageLocking(
  659. VOID
  660. )
  661. /*++
  662. Routine Description:
  663. This routine handles Int31 06xx functions.
  664. Arguments:
  665. None
  666. Return Value:
  667. None
  668. --*/
  669. {
  670. DECLARE_LocalVdmContext;
  671. switch(getAL()) {
  672. //
  673. // Lock functions not implemented
  674. //
  675. case 0:
  676. case 1:
  677. case 2:
  678. case 3:
  679. break;
  680. //
  681. // Get Page Size
  682. //
  683. case 4:
  684. setBX(0);
  685. setCX(0x1000);
  686. break;
  687. }
  688. }
  689. VOID
  690. Int31DemandPageTuning(
  691. VOID
  692. )
  693. /*++
  694. Routine Description:
  695. This routine handles Int31 07xx functions.
  696. Arguments:
  697. None
  698. Return Value:
  699. None
  700. --*/
  701. {
  702. DECLARE_LocalVdmContext;
  703. ULONG Addr = (getBX()<<16 | getCX()) + IntelBase;
  704. ULONG Count = getSI()<<16 | getDI();
  705. if (Count) {
  706. switch(getAL()) {
  707. //
  708. // Mark Page as Demand Paging Candidate
  709. //
  710. case 0:
  711. // Addr, Count expressed in 4k pages
  712. Addr <<= 12;
  713. Count <<= 12;
  714. case 2:
  715. VirtualUnlock((PVOID)Addr, Count);
  716. break;
  717. //
  718. // Discard Page Contents
  719. //
  720. case 1:
  721. // Addr, Count expressed in 4k pages
  722. Addr <<= 12;
  723. Count <<= 12;
  724. case 3:
  725. VirtualAlloc((PVOID)Addr, Count, MEM_RESET, PAGE_READWRITE);
  726. break;
  727. default:
  728. setCF(1);
  729. }
  730. }
  731. }
  732. VOID
  733. Int31VirtualIntState(
  734. VOID
  735. )
  736. /*++
  737. Routine Description:
  738. This routine handles Int31 09xx functions.
  739. Arguments:
  740. None
  741. Return Value:
  742. None
  743. --*/
  744. {
  745. DECLARE_LocalVdmContext;
  746. BOOL bVIF = *(ULONG *)(IntelBase+FIXED_NTVDMSTATE_LINEAR) & VDM_VIRTUAL_INTERRUPTS;
  747. switch(getAL()) {
  748. //
  749. // Get and disable Virtual Interrupt State
  750. //
  751. case 0:
  752. setEFLAGS(getEFLAGS() & ~EFLAGS_IF_MASK);
  753. break;
  754. //
  755. // Get and enable Virtual Interrupt State
  756. //
  757. case 1:
  758. setEFLAGS(getEFLAGS() | EFLAGS_IF_MASK);
  759. break;
  760. case 2:
  761. break;
  762. default:
  763. setCF(1);
  764. return;
  765. }
  766. if (bVIF) {
  767. setAL(1);
  768. } else {
  769. setAL(0);
  770. }
  771. }
  772. VOID
  773. Int31DbgRegSupport(
  774. VOID
  775. )
  776. /*++
  777. Routine Description:
  778. This routine handles Int31 0bxx functions.
  779. Arguments:
  780. None
  781. Return Value:
  782. None
  783. --*/
  784. {
  785. DECLARE_LocalVdmContext;
  786. #ifndef _X86_
  787. setCF(1);
  788. #else
  789. ULONG DebugRegisters[6];
  790. USHORT Handle;
  791. ULONG Mask;
  792. ULONG Size;
  793. ULONG Type;
  794. UCHAR Func = getAL();
  795. #define DBG_TYPE_EXECUTE 0
  796. #define DBG_TYPE_WRITE 1
  797. #define DBG_TYPE_READWRITE 2
  798. #define DBG_DR6 4
  799. #define DBG_DR7 5
  800. #define DR7_LE 0x100
  801. #define DR7_L0 0x01
  802. #define DR7_L1 0x04
  803. #define DR7_L2 0x10
  804. #define DR7_L3 0x40
  805. //
  806. // Debugging ntvdm under NTSD affects the values of the debug register
  807. // context, so defining the following value turns on some debugging
  808. // code
  809. //
  810. //#define DEBUGGING_DEBUGREGS 1
  811. if (!DpmiGetDebugRegisters(DebugRegisters)) {
  812. setCF(1);
  813. return;
  814. }
  815. #ifdef DEBUGGING_DEBUGREGS
  816. {
  817. char szMsg[256];
  818. wsprintf(szMsg, " DR0-3=%.8X %.8X %.8X %.8X DR6,7=%.8X %.8X\n",
  819. DebugRegisters[0],
  820. DebugRegisters[1],
  821. DebugRegisters[2],
  822. DebugRegisters[3],
  823. DebugRegisters[DBG_DR6],
  824. DebugRegisters[DBG_DR7]);
  825. OutputDebugString(szMsg);
  826. }
  827. #endif
  828. if (Func != 0) {
  829. Handle = getBX();
  830. //
  831. // point at the local enable bit for this handle in DR7
  832. //
  833. Mask = (DR7_L0 << Handle*2);
  834. if ((Handle >= 4) ||
  835. (!(DebugRegisters[DBG_DR7] & Mask))) {
  836. // Invalid Handle
  837. setCF(1);
  838. return;
  839. }
  840. }
  841. switch(Func) {
  842. //
  843. // Set Debug Watchpoint
  844. //
  845. case 0:
  846. for (Handle = 0, Mask = 3; Handle < 4; Handle++, Mask <<= 2) {
  847. if (!(DebugRegisters[DBG_DR7] & Mask)) {
  848. //
  849. // found a free register
  850. //
  851. //
  852. // Set the linear address
  853. //
  854. DebugRegisters[Handle] = (((ULONG)getBX()) << 16) + getCX();
  855. Size = getDL();
  856. Type = getDH();
  857. if (Type == DBG_TYPE_EXECUTE) {
  858. // force size to be 1 for execute
  859. Size = 1;
  860. }
  861. if ((Size > 4) || (Size == 3) || (!Size) || (Type > 2)) {
  862. // error: invalid parameter
  863. break;
  864. }
  865. //
  866. // convert size to appropriate bits in DR7
  867. //
  868. Size--;
  869. Size <<= (18 + Handle*4);
  870. //
  871. // convert type to appropriate bits in DR7
  872. //
  873. if (Type == DBG_TYPE_READWRITE) {
  874. Type++;
  875. }
  876. Type <<= (16 + Handle*4);
  877. Mask = 0xf << (16 + Handle*4);
  878. //
  879. // Set the appropriate Len, R/W, and enable bits in DR7
  880. // Also set the common global and local enable bits.
  881. //
  882. DebugRegisters[DBG_DR7] &= ~Mask;
  883. DebugRegisters[DBG_DR7] |= (Size | Type | (DR7_L0 << Handle*2));
  884. DebugRegisters[DBG_DR7] |= DR7_LE;
  885. //
  886. // Clear triggered bit for this BP
  887. //
  888. DebugRegisters[DBG_DR6] &= ~(1 << Handle);
  889. #ifdef DEBUGGING_DEBUGREGS
  890. {
  891. char szMsg[256];
  892. wsprintf(szMsg, "Int31 Setting DBGREG %d, Location %.8X, DR7=%.8X\n",
  893. Handle, DebugRegisters[Handle], DebugRegisters[DBG_DR7]);
  894. OutputDebugString(szMsg);
  895. }
  896. #endif
  897. if (DpmiSetDebugRegisters(DebugRegisters)) {
  898. return;
  899. }
  900. break;
  901. }
  902. }
  903. setCF(1);
  904. break;
  905. //
  906. // Clear Debug Watchpoint
  907. //
  908. case 1:
  909. //
  910. // clear enabled and triggered bits for this BP
  911. //
  912. DebugRegisters[DBG_DR7] &= ~Mask;
  913. DebugRegisters[DBG_DR6] &= (1 << Handle);
  914. DebugRegisters[Handle] = 0;
  915. //
  916. // Check to see if this clears all BP's (all local enable bits
  917. // clear), and disable common enable bit if so
  918. //
  919. if (!(DebugRegisters[DBG_DR7] & (DR7_L0 | DR7_L1 | DR7_L2 | DR7_L3))) {
  920. DebugRegisters[DBG_DR7] &= ~DR7_LE;
  921. }
  922. #ifdef DEBUGGING_DEBUGREGS
  923. {
  924. char szMsg[256];
  925. wsprintf(szMsg, "Int31 Clearing DBGREG %d, DR7=%.8X\n",
  926. Handle, DebugRegisters[DBG_DR7]);
  927. OutputDebugString(szMsg);
  928. }
  929. #endif
  930. if (!DpmiSetDebugRegisters(DebugRegisters)) {
  931. setCF(1);
  932. }
  933. break;
  934. //
  935. // Get State of Debug Watchpoint
  936. //
  937. case 2:
  938. if (DebugRegisters[DBG_DR6] & (1 << Handle)) {
  939. setAX(1);
  940. } else {
  941. setAX(0);
  942. }
  943. #ifdef DEBUGGING_DEBUGREGS
  944. {
  945. char szMsg[256];
  946. wsprintf(szMsg, "Int31 Query on DBGREG %d returns %d\n", Handle, getAX());
  947. OutputDebugString(szMsg);
  948. }
  949. #endif
  950. break;
  951. //
  952. // Reset Debug Watchpoint
  953. //
  954. case 3:
  955. DebugRegisters[DBG_DR6] &= ~(1 << Handle);
  956. #ifdef DEBUGGING_DEBUGREGS
  957. {
  958. char szMsg[256];
  959. wsprintf(szMsg, "Int31 Resetting DBGREG %d\n", Handle);
  960. OutputDebugString(szMsg);
  961. }
  962. #endif
  963. if (!DpmiSetDebugRegisters(DebugRegisters)) {
  964. setCF(1);
  965. }
  966. break;
  967. default:
  968. setCF(1);
  969. }
  970. #endif
  971. }