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.

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