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.

909 lines
18 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. dpmiselr.c
  5. Abstract:
  6. This is the code for maintaining descriptor data for dpmi32.
  7. Author:
  8. Dave Hart (davehart) 11-Apr-1993
  9. Notes:
  10. Revision History:
  11. 09-Feb-1994 (daveh)
  12. Moved here from not386.c.
  13. 31-Jul-1995 (neilsa)
  14. Merged with x86 source
  15. 12-Dec-1995 (neilsa)
  16. Wrote VdmAddDescriptorMapping(), GetDescriptorMapping
  17. --*/
  18. #include "precomp.h"
  19. #pragma hdrstop
  20. #include "softpc.h"
  21. #include "malloc.h"
  22. #ifndef _X86_
  23. PDESC_MAPPING pDescMappingHead = NULL;
  24. #endif // _X86_
  25. USHORT selLDTFree = 0;
  26. VOID
  27. DpmiSetDescriptorEntry(
  28. VOID
  29. )
  30. /*++
  31. Routine Description:
  32. This function is called via BOP by dosx to set the flataddress
  33. array and, if on x86, the real LDT maintained by the kernel.
  34. Arguments:
  35. None
  36. Return Value:
  37. None.
  38. --*/
  39. {
  40. DECLARE_LocalVdmContext;
  41. USHORT SelCount;
  42. USHORT SelStart;
  43. SelStart = getAX();
  44. if (SelStart % 8) {
  45. return;
  46. }
  47. SelCount = getCX();
  48. SetShadowDescriptorEntries(SelStart, SelCount);
  49. // no need to flush the cache on risc since the ldt was changed
  50. // from the 16-bit side, and has thus already been flushed
  51. }
  52. VOID
  53. SetDescriptor(
  54. USHORT Sel,
  55. ULONG Base,
  56. ULONG Limit,
  57. USHORT Access
  58. )
  59. /*++
  60. Routine Description:
  61. Arguments:
  62. None
  63. Return Value:
  64. None.
  65. --*/
  66. {
  67. SET_SELECTOR_ACCESS(Sel, Access);
  68. SET_SELECTOR_LIMIT(Sel, Limit);
  69. SetDescriptorBase(Sel, Base);
  70. }
  71. VOID
  72. SetDescriptorBase(
  73. USHORT Sel,
  74. ULONG Base
  75. )
  76. /*++
  77. Routine Description:
  78. Arguments:
  79. None
  80. Return Value:
  81. None.
  82. --*/
  83. {
  84. LDT_ENTRY UNALIGNED *Descriptor;
  85. // make it qword aligned
  86. Sel &= SEL_INDEX_MASK;
  87. Descriptor = &Ldt[Sel>>3];
  88. Descriptor->BaseLow = (WORD) Base;
  89. Descriptor->HighWord.Bytes.BaseMid = (BYTE) (Base >> 16);
  90. Descriptor->HighWord.Bytes.BaseHi = (BYTE) (Base >> 24);
  91. SetShadowDescriptorEntries(Sel, 1);
  92. FLUSH_SELECTOR_CACHE(Sel, 1);
  93. }
  94. VOID
  95. SetShadowDescriptorEntries(
  96. USHORT SelStart,
  97. USHORT SelCount
  98. )
  99. /*++
  100. Routine Description:
  101. This function takes as a parameter an array of descriptors
  102. directly out of the LDT in the clients address space.
  103. For each descriptor in the array, it does three things:
  104. - It extracts the descriptor base and sets it into the FlatAddress
  105. array. This value may be adjusted on RISC platforms to account
  106. for DIB.DRV (see VdmAddDescriptorMapping).
  107. - It extracts the selector limit, and adjusts the limit in the
  108. descriptor itself if the values would cause the descriptor to
  109. be able to access kernel address space (see note below). On debug
  110. builds, the limit is also copied to the Limit array.
  111. - On x86 builds, it calls DpmiSetX86Descriptor() to write the
  112. descriptor down to the real LDT in the kernel. On RISC builds,
  113. it calls down to the emulator to flush compiled LDT entries.
  114. Arguments:
  115. SelStart - Selector which identifies the first descriptor
  116. SelCount - number of descriptors to process
  117. Descriptors -> first descriptor in LDT
  118. Return Value:
  119. None.
  120. --*/
  121. {
  122. USHORT i;
  123. ULONG Base;
  124. ULONG Limit;
  125. USHORT Sel = SelStart;
  126. for (i = 0; i < SelCount; i++, Sel+=8) {
  127. // form Base and Limit values
  128. Base = GET_SELECTOR_BASE(Sel);
  129. Limit = GET_SELECTOR_LIMIT(Sel);
  130. //
  131. // Do NOT remove the following code. There are several apps that
  132. // choose arbitrarily high limits for theirs selectors. This works
  133. // under windows 3.1, but NT won't allow us to do that.
  134. // The following code fixes the limits for such selectors.
  135. // Note: if the base is > 0x7FFEFFFF, the selector set will fail
  136. //
  137. if (Base !=0) {
  138. if ((Limit > 0x7FFEFFFF) || (Base + Limit > 0x7FFEFFFF)) {
  139. Limit = 0x7FFEFFFF - (Base + 0xFFF);
  140. SET_SELECTOR_LIMIT(Sel, Limit);
  141. }
  142. }
  143. if ((Sel >> 3) != 0) {
  144. #ifndef _X86_
  145. {
  146. ULONG BaseOrig = Base;
  147. Base = GetDescriptorMapping(Sel, Base);
  148. if (BaseOrig == Base) {
  149. Base += (ULONG)IntelBase;
  150. }
  151. }
  152. #endif
  153. FlatAddress[Sel >> 3] = Base;
  154. #if DBG
  155. SelectorLimit[Sel >> 3] = Limit;
  156. #endif
  157. }
  158. }
  159. #ifdef _X86_
  160. if (!DpmiSetX86Descriptor(SelStart, SelCount)) {
  161. return;
  162. }
  163. #endif
  164. }
  165. #ifndef _X86_
  166. VOID
  167. FlushSelectorCache(
  168. USHORT SelStart,
  169. USHORT SelCount
  170. )
  171. {
  172. DECLARE_LocalVdmContext;
  173. USHORT SelEnd;
  174. USHORT Sel;
  175. USHORT i;
  176. VdmTraceEvent(VDMTR_TYPE_DPMI | DPMI_GENERIC, SelStart, SelCount);
  177. //
  178. // The emulator compiles LDT entries, so we need to flush them
  179. // out
  180. //
  181. for (i = 0, Sel = SelStart; i < SelCount; i++, Sel += 8) {
  182. VdmFlushCache(LdtSel, Sel & SEL_INDEX_MASK, 8, VDM_PM);
  183. }
  184. SelEnd = SelStart + SelCount*8;
  185. Sel = getCS();
  186. if ((Sel >= SelStart) && (Sel < SelEnd)) {
  187. setCS(Sel);
  188. }
  189. Sel = getDS();
  190. if ((Sel >= SelStart) && (Sel < SelEnd)) {
  191. setDS(Sel);
  192. }
  193. Sel = getES();
  194. if ((Sel >= SelStart) && (Sel < SelEnd)) {
  195. setES(Sel);
  196. }
  197. Sel = getFS();
  198. if ((Sel >= SelStart) && (Sel < SelEnd)) {
  199. setFS(Sel);
  200. }
  201. Sel = getGS();
  202. if ((Sel >= SelStart) && (Sel < SelEnd)) {
  203. setGS(Sel);
  204. }
  205. Sel = getSS();
  206. if ((Sel >= SelStart) && (Sel < SelEnd)) {
  207. setSS(Sel);
  208. }
  209. }
  210. #endif
  211. //
  212. // Descriptor Mapping functions (RISC ONLY)
  213. //
  214. #ifndef _X86_
  215. BOOL
  216. VdmAddDescriptorMapping(
  217. USHORT SelectorStart,
  218. USHORT SelectorCount,
  219. ULONG LdtBase,
  220. ULONG Flat
  221. )
  222. /*++
  223. Routine Description:
  224. This function was added to support the DIB.DRV implementation on RISC.
  225. When an app uses DIB.DRV, then the situation arises where the Intel
  226. linear base address + the flat address of the start of the Intel address
  227. space does NOT equal the flat address of the memory. This happens when
  228. the VdmAddVirtualMemory() api is used to set up an additional layer of
  229. indirection for memory addressing in the emulator.
  230. But there is more to the story. When app wants to use CreateDIBSection
  231. via WinG we also need to map selectors, thus this routine should not
  232. depend upon DpmiSetDesctriptorEntry being called afterwards. Thus, we go
  233. and zap the flat address table with the new address.
  234. Arguments:
  235. SelectorStart, Count - range of selectors involved in the mapping
  236. LdtBase - Intel base of start of range
  237. Flat - True flat address base to be used for these selectors
  238. Return Value:
  239. This function returns TRUE on success, or FALSE for failure (out of mem)
  240. --*/
  241. {
  242. PDESC_MAPPING pdm;
  243. USHORT i;
  244. if ((pdm = (PDESC_MAPPING) malloc(sizeof (DESC_MAPPING))) == NULL)
  245. return FALSE;
  246. pdm->Sel = SelectorStart &= SEL_INDEX_MASK;
  247. pdm->SelCount = SelectorCount;
  248. pdm->LdtBase = LdtBase;
  249. pdm->FlatBase = Flat;
  250. pdm->pNext = pDescMappingHead;
  251. pDescMappingHead = pdm;
  252. // this code does what essentially desctribed in comment above
  253. for (i = 0; i < SelectorCount; ++i) {
  254. FlatAddress[(SelectorStart >> 3) + i] = Flat + 65536 * i;
  255. }
  256. return TRUE;
  257. }
  258. ULONG
  259. GetDescriptorMapping(
  260. USHORT sel,
  261. ULONG LdtBase
  262. )
  263. /*++
  264. Routine Description:
  265. Arguments:
  266. sel - the selector for which the base should be returned
  267. LdtBase - the base for this selector as is set currently in the LDT
  268. Return Value:
  269. The true flat address for the specified selector.
  270. --*/
  271. {
  272. PDESC_MAPPING pdm, pdmprev;
  273. ULONG Base = LdtBase;
  274. sel &= SEL_INDEX_MASK; // and off lower 3 bits
  275. pdm = pDescMappingHead;
  276. while (pdm) {
  277. if ((sel >= pdm->Sel) && (sel < (pdm->Sel + pdm->SelCount*8))) {
  278. //
  279. // We found a mapping for this selector. Now check to see if
  280. // the ldt base still matches the base when the mapping was
  281. // created.
  282. //
  283. if (LdtBase == (pdm->LdtBase + 65536*((sel-pdm->Sel)/8))) {
  284. //
  285. // The mapping appears still valid. Return the remapped address
  286. //
  287. return (pdm->FlatBase + 65536*((sel-pdm->Sel)/8));
  288. } else {
  289. //
  290. // The ldt base doesn't match the mapping, so the mapping
  291. // must be obselete. Free the mapping here.
  292. //
  293. if (pdm == pDescMappingHead) {
  294. //
  295. // mapping is the first in the list
  296. //
  297. pDescMappingHead = pdm->pNext;
  298. } else {
  299. pdmprev->pNext = pdm->pNext;
  300. }
  301. free(pdm);
  302. }
  303. break;
  304. }
  305. pdmprev = pdm;
  306. pdm = pdm->pNext;
  307. }
  308. return Base;
  309. }
  310. #endif // _X86_
  311. //
  312. // LDT Management routines
  313. //
  314. VOID
  315. DpmiInitLDT(
  316. VOID
  317. )
  318. /*++
  319. Routine Description:
  320. This routine stores the flat address for the LDT table in the 16bit
  321. land (pointed to by selGDT in 16bit land).
  322. It also initializes the free selector chain.
  323. Arguments:
  324. None
  325. Return Value:
  326. None.
  327. --*/
  328. {
  329. DECLARE_LocalVdmContext;
  330. USHORT Sel;
  331. //
  332. // Get the new LDT location
  333. //
  334. LdtSel = getAX();
  335. Ldt = (PVOID)VdmMapFlat(LdtSel, 0, VDM_PM);
  336. LdtMaxSel = getCX();
  337. if (!LdtUserSel) {
  338. LdtUserSel = getDI() & SEL_INDEX_MASK;
  339. }
  340. //
  341. // Initialize the LDT free list
  342. //
  343. selLDTFree = LdtUserSel;
  344. for (Sel = selLDTFree; Sel < (LdtMaxSel & SEL_INDEX_MASK); Sel += 8) {
  345. NEXT_FREE_SEL(Sel) = Sel+8;
  346. MARK_SELECTOR_FREE(Sel);
  347. }
  348. NEXT_FREE_SEL(Sel) = 0xffff;
  349. }
  350. VOID
  351. DpmiResetLDTUserBase(
  352. VOID
  353. )
  354. /*++
  355. Routine Description:
  356. This routine can hopefully be eliminated at a later date. The flow of
  357. dosx initialization has made this necessary. What happens is this:
  358. Earlier, dosx has called up to dpmi32 to initialize the LDT (DpmiInitLDT),
  359. where it sets the start of the user are of the LDT, and from there,
  360. sets up the linked list of free LDT entries. But after that time, and
  361. before an app is run, there are pieces of dosx code which allocate
  362. selectors that are not transient. In particular, DXNETBIO does an
  363. AllocateLowSegment(), which is totally unecessary on NT, but it a
  364. bit tricky to rework. So what is happening here is a reset of the
  365. start of the user area of the LDT to permanently reserve any selectors
  366. that are not free.
  367. Arguments:
  368. None
  369. Return Value:
  370. None.
  371. --*/
  372. {
  373. LdtUserSel = selLDTFree;
  374. }
  375. VOID
  376. DpmiAllocateSelectors(
  377. VOID
  378. )
  379. //
  380. // This routine is called via BOP by those routines in DOSX
  381. // that still need to allocate selectors.
  382. //
  383. {
  384. DECLARE_LocalVdmContext;
  385. USHORT Sel;
  386. Sel = ALLOCATE_SELECTORS(getAX());
  387. if (!Sel) {
  388. setCF(1);
  389. } else {
  390. setAX(Sel);
  391. setCF(0);
  392. }
  393. }
  394. VOID
  395. DpmiFreeSelector(
  396. VOID
  397. )
  398. //
  399. // This routine is called via BOP by those routines in DOSX
  400. // that still need to free selectors.
  401. //
  402. {
  403. DECLARE_LocalVdmContext;
  404. if (FreeSelector(getAX())) {
  405. setCF(0);
  406. } else {
  407. setCF(1);
  408. }
  409. }
  410. BOOL
  411. RemoveFreeSelector(
  412. USHORT Sel
  413. )
  414. /*++
  415. Routine Description:
  416. This routine removes a specific selector from the free
  417. selector chain.
  418. Arguments:
  419. Sel - the selector to be aquired
  420. Return Value:
  421. Returns TRUE if the function was successful, FALSE if it
  422. was an invalid selector (not free)
  423. --*/
  424. {
  425. if (!IS_SELECTOR_FREE(Sel)) {
  426. return FALSE;
  427. }
  428. if (Sel == selLDTFree) {
  429. //
  430. // we are removing the head of the list
  431. //
  432. selLDTFree = NEXT_FREE_SEL(Sel);
  433. } else {
  434. USHORT SelTest;
  435. USHORT SelPrev = 0;
  436. SelTest = selLDTFree;
  437. while (SelTest != Sel) {
  438. if (SelTest == 0xffff) {
  439. // End of list
  440. return FALSE;
  441. }
  442. SelPrev = SelTest;
  443. SelTest = NEXT_FREE_SEL(SelTest);
  444. }
  445. NEXT_FREE_SEL(SelPrev) = NEXT_FREE_SEL(Sel);
  446. }
  447. MARK_SELECTOR_ALLOCATED(Sel);
  448. return TRUE;
  449. }
  450. USHORT
  451. AllocateSelectors(
  452. USHORT Count,
  453. BOOL bWow
  454. )
  455. /*++
  456. Routine Description:
  457. This routine allocates selectors from the free selector chain.
  458. Arguments:
  459. Count - number of selectors needed. If this is more than 1, then
  460. all selectors will be contiguous
  461. bWow - if true, then use an allocation scheme that is more typical
  462. of win31 behavior. This is to avoid problems where winapps
  463. accidentally rely on the value of selectors
  464. Return Value:
  465. Returns the starting selector of the block, or zero if the
  466. allocation failed.
  467. --*/
  468. {
  469. USHORT Sel;
  470. if (!Count || (Count>=(LdtMaxSel>>3))) {
  471. return 0;
  472. }
  473. if (Count == 1) {
  474. //
  475. // Allocating 1 selector
  476. //
  477. if ((Sel = selLDTFree) != 0xffff) {
  478. // Move next selector to head of list
  479. selLDTFree = NEXT_FREE_SEL(Sel);
  480. MARK_SELECTOR_ALLOCATED(Sel);
  481. return (Sel | SEL_LDT3);
  482. }
  483. } else {
  484. //
  485. // Allocating a selector block
  486. //
  487. // *******************************************************
  488. // The strategy of allocating selectors has been modified to
  489. // give preference to selector values above 1000h. This is an
  490. // attempt to emulate typical values that are returned by win31.
  491. // -neilsa
  492. //
  493. // Some DPMI DOS applications demand that all selectors(no matter it comes
  494. // from AllocateLDTSelector or this function) be contiguous, so
  495. // the strategy for WOW doesn't work for DPMI DOS applications.
  496. // For this reason, a new parameter is added so the caller can control
  497. // where to start searching for free selectors.
  498. // -williamh
  499. //
  500. #define SEL_START_HI 0x1000
  501. USHORT SelTest;
  502. USHORT SelStart = LdtUserSel;
  503. USHORT SelEnd = LdtMaxSel;
  504. BOOL bAllFree;
  505. if (bWow) {
  506. SelStart = SEL_START_HI;
  507. }
  508. asrestart:
  509. for (Sel = SelStart; Sel < (SelEnd - Count*8); Sel += 8) {
  510. bAllFree = TRUE;
  511. for (SelTest = Sel; SelTest < Sel + Count*8; SelTest += 8) {
  512. if (!IS_SELECTOR_FREE(SelTest)) {
  513. bAllFree = FALSE;
  514. break;
  515. }
  516. }
  517. if (bAllFree) {
  518. //
  519. // Found a block. Now we need to peel off the chain from
  520. // the free list
  521. //
  522. int i;
  523. for (i = 0, SelTest = Sel; i < Count; i++, SelTest+=8) {
  524. RemoveFreeSelector(SelTest);
  525. }
  526. return (Sel | SEL_LDT3);
  527. }
  528. }
  529. if (bWow && (SelEnd == LdtMaxSel)) {
  530. //
  531. // First pass for WOW complete, do it again
  532. //
  533. SelStart = LdtUserSel;
  534. SelEnd = SEL_START_HI + Count;
  535. goto asrestart;
  536. }
  537. }
  538. return 0;
  539. }
  540. BOOL
  541. FreeSelector(
  542. USHORT Sel
  543. )
  544. /*++
  545. Routine Description:
  546. This routine returns a selector to the free selector chain.
  547. Arguments:
  548. Sel - the selector to be freed
  549. Return Value:
  550. Returns TRUE if the function was successful, FALSE if it
  551. was an invalid selector (already free, reserved selector)
  552. --*/
  553. {
  554. if ((Sel < LdtUserSel) || (Sel > LdtMaxSel) ||
  555. IS_SELECTOR_FREE(Sel)) {
  556. //
  557. // invalid selector
  558. //
  559. return FALSE;
  560. }
  561. //
  562. // chain selector to head of free list
  563. //
  564. NEXT_FREE_SEL(Sel) = selLDTFree;
  565. selLDTFree = Sel & SEL_INDEX_MASK;
  566. MARK_SELECTOR_FREE(Sel);
  567. return TRUE;
  568. }
  569. USHORT
  570. FindSelector(
  571. ULONG Base,
  572. UCHAR Access
  573. )
  574. /*++
  575. Routine Description:
  576. This routine looks for a selector that matches the base and access
  577. rights passed as arguments.
  578. Arguments:
  579. Base - Base address to compare.
  580. Access- Access rights byte to compare.
  581. Return Value:
  582. Returns the selector that matches, or zero if the
  583. allocation failed.
  584. --*/
  585. {
  586. USHORT Sel;
  587. ULONG Limit;
  588. for (Sel = LdtUserSel; Sel < LdtMaxSel; Sel+=8) {
  589. if (!IS_SELECTOR_FREE(Sel)) {
  590. GET_SHADOW_SELECTOR_LIMIT(Sel, Limit);
  591. if ((Limit == 0xffff) && (Base == GET_SELECTOR_BASE(Sel)) &&
  592. ((Access & ~AB_ACCESSED) ==
  593. (Ldt[Sel>>3].HighWord.Bytes.Flags1 & ~AB_ACCESSED))) {
  594. return (Sel | SEL_LDT3);
  595. }
  596. }
  597. }
  598. return 0;
  599. }
  600. USHORT
  601. SegmentToSelector(
  602. USHORT Segment,
  603. USHORT Access
  604. )
  605. /*++
  606. Routine Description:
  607. This routine either finds or creates selector that can access the
  608. specified low memory segment.
  609. Arguments:
  610. Segment- Paragraph segment address
  611. Access - Access rights
  612. Return Value:
  613. Returns the selector that matches, or zero if the
  614. allocation failed.
  615. --*/
  616. {
  617. ULONG Base = ((ULONG) Segment) << 4;
  618. USHORT Sel;
  619. if (!(Sel = FindSelector(Base, (UCHAR)Access))) {
  620. if (Sel = ALLOCATE_SELECTOR()) {
  621. SetDescriptor(Sel, Base, 0xffff, Access);
  622. }
  623. }
  624. return Sel;
  625. }
  626. VOID
  627. SetDescriptorArray(
  628. USHORT Sel,
  629. ULONG Base,
  630. ULONG MemSize
  631. )
  632. /*++
  633. Routine Description:
  634. This routine allocates a set of descriptors to cover the specified
  635. memory block. The descriptors are initialized as follows:
  636. The first descriptor points at the whole block, then all subsequent
  637. descriptors have a limit of 64k except for the final one, which has
  638. a limit of block size MOD 64k.
  639. Arguments:
  640. Sel, Base, Memsize define the range of the selector array
  641. Return Value:
  642. none
  643. --*/
  644. {
  645. USHORT SelCount;
  646. if (MemSize) {
  647. MemSize--; // now a descriptor limit
  648. }
  649. SelCount = (USHORT) ((MemSize>>16) + 1);
  650. SetDescriptor(Sel, Base, MemSize, STD_DATA);
  651. while(--SelCount) {
  652. Sel += 8;
  653. MemSize -= 0x10000; // subtract 64k
  654. Base += 0x10000;
  655. SetDescriptor(Sel,
  656. Base,
  657. (SelCount==1) ? MemSize : 0xffff,
  658. STD_DATA);
  659. }
  660. }