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.

871 lines
23 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. vdmldt.c
  5. Abstract:
  6. This module contains code for the process and thread ldt support for NTVDM
  7. Author:
  8. Dave Hastings (daveh) 20 May 1991
  9. Revision History:
  10. --*/
  11. #include "vdmp.h"
  12. #include <ntvdmp.h>
  13. //
  14. // Internal constants
  15. //
  16. #define DESCRIPTOR_GRAN 0x00800000
  17. #define DESCRIPTOR_NP 0x00008000
  18. #define DESCRIPTOR_SYSTEM 0x00001000
  19. #define DESCRIPTOR_CONFORM 0x00001C00
  20. #define DESCRIPTOR_DPL 0x00006000
  21. #define DESCRIPTOR_TYPEDPL 0x00007F00
  22. extern KMUTEX LdtMutex;
  23. PLDT_ENTRY
  24. PspCreateLdt (
  25. IN PLDT_ENTRY Ldt,
  26. IN ULONG Offset,
  27. IN ULONG Size,
  28. IN ULONG AllocationSize
  29. );
  30. BOOLEAN
  31. VdmpIsDescriptorValid(
  32. IN PLDT_ENTRY Descriptor
  33. );
  34. #ifdef ALLOC_PRAGMA
  35. #pragma alloc_text(PAGE, VdmpSetLdtEntries)
  36. #pragma alloc_text(PAGE, VdmpSetProcessLdtInfo)
  37. #pragma alloc_text(PAGE, VdmpIsDescriptorValid)
  38. #endif
  39. BOOLEAN
  40. VdmpIsDescriptorValid(
  41. IN PLDT_ENTRY Descriptor
  42. )
  43. /*++
  44. Routine Description:
  45. This function determines if the supplied descriptor is valid to put
  46. into a process Ldt. For the descriptor to be valid it must have the
  47. following characteristics:
  48. Base + Limit < MM_HIGHEST_USER_ADDRESS
  49. otherwise Base = 0
  50. Type must be
  51. ReadWrite, ReadOnly, ExecuteRead, ExecuteOnly, or Invalid
  52. big or small
  53. normal or grow down
  54. Not a system descriptor (system bit is 1 == application)
  55. This rules out all gates, etc
  56. Not conforming
  57. DPL must be 3
  58. Arguments:
  59. Descriptor -- Supplies a pointer to the descriptor to check
  60. Return Value:
  61. True if the descriptor is valid (note: valid to put into an LDT. This
  62. includes Invalid descriptors)
  63. False if not
  64. --*/
  65. {
  66. ULONG Base, Limit;
  67. PAGED_CODE();
  68. //
  69. // if descriptor is an invalid descriptor
  70. //
  71. if ( (Descriptor->HighWord.Bits.Type == 0) &&
  72. (Descriptor->HighWord.Bits.Dpl == 0) ) {
  73. return TRUE;
  74. }
  75. Base = Descriptor->BaseLow | (Descriptor->HighWord.Bytes.BaseMid << 16) |
  76. (Descriptor->HighWord.Bytes.BaseHi << 24);
  77. Limit = Descriptor->LimitLow | (Descriptor->HighWord.Bits.LimitHi << 16);
  78. //
  79. // Only have to check for present selectors
  80. //
  81. if (Descriptor->HighWord.Bits.Pres) {
  82. ULONG ActualLimit;
  83. ActualLimit = (Limit << (Descriptor->HighWord.Bits.Granularity *
  84. 12)) + 0xFFF * Descriptor->HighWord.Bits.Granularity;
  85. if ( (PVOID)Base > MM_HIGHEST_USER_ADDRESS ) {
  86. //DbgPrint("vdmIsValidDesc: Base > 2G, base = %x limit = %x\n", Base, ActualLimit);
  87. return FALSE;
  88. }
  89. if (Base > (Base + ActualLimit)) {
  90. //DbgPrint("vdmIsValidDesc: Base > Base + Limit base = %x limit = %x\n", Base, ActualLimit);
  91. return FALSE;
  92. }
  93. if((PVOID)(Base + ActualLimit) > MM_HIGHEST_USER_ADDRESS &&
  94. Base != 0) {
  95. //DbgPrint("vdmIsValidDesc: Base + limit > 2G, base = %x, limit = %x\n", Base, ActualLimit);
  96. return FALSE;
  97. }
  98. }
  99. //
  100. // See if we are a expand down data segment with a non-zero base.
  101. // This would break lazy segment loading if we let it get defined.
  102. //
  103. if ((Descriptor->HighWord.Bits.Type & 0x14) == 0x14 &&
  104. Base != 0 &&
  105. Descriptor->HighWord.Bits.Default_Big == 1) {
  106. //DbgPrint("vdmIsValidDesc: expand down\n");
  107. return FALSE;
  108. }
  109. //
  110. // Don't let the reserved field be set.
  111. // Always set to DPL 3
  112. //
  113. Descriptor->HighWord.Bits.Reserved_0 = 0;
  114. Descriptor->HighWord.Bits.Dpl = 3;
  115. //
  116. // if descriptor is a system descriptor (which includes gates)
  117. // if bit 4 of the Type field is 0, then it's a system descriptor,
  118. // and we don't like it.
  119. //
  120. if (!(Descriptor->HighWord.Bits.Type & 0x10)) {
  121. //DbgPrint("vdmIsValidDesc: System Desc\n");
  122. return FALSE;
  123. }
  124. //
  125. // if descriptor is conforming code
  126. //
  127. if (((Descriptor->HighWord.Bits.Type & 0x18) == 0x18) &&
  128. (Descriptor->HighWord.Bits.Type & 0x4)) {
  129. //DbgPrint("vdmIsValidDesc: Conforming code\n");
  130. return FALSE;
  131. }
  132. return TRUE;
  133. }
  134. NTSTATUS
  135. VdmpSetLdtEntries(
  136. IN ULONG Selector0,
  137. IN ULONG Entry0Low,
  138. IN ULONG Entry0Hi,
  139. IN ULONG Selector1,
  140. IN ULONG Entry1Low,
  141. IN ULONG Entry1Hi
  142. )
  143. /*++
  144. Routine Description:
  145. This routine sets up to two selectors in the current process's LDT.
  146. The LDT will be grown as necessary. A selector value of 0 indicates
  147. that the specified selector was not passed (allowing the setting of
  148. a single selector).
  149. Arguments:
  150. Selector0 -- Supplies the number of the first descriptor to set
  151. Entry0Low -- Supplies the low 32 bits of the descriptor
  152. Entry0Hi -- Supplies the high 32 bits of the descriptor
  153. Selector1 -- Supplies the number of the first descriptor to set
  154. Entry1Low -- Supplies the low 32 bits of the descriptor
  155. Entry1Hi -- Supplies the high 32 bits of the descriptor
  156. Return Value:
  157. TBS
  158. --*/
  159. {
  160. ULONG LdtSize, AllocatedSize;
  161. NTSTATUS Status;
  162. PEPROCESS Process;
  163. LDT_ENTRY Descriptor;
  164. PLDT_ENTRY Ldt, OldLdt;
  165. PLDTINFORMATION ProcessLdtInformation;
  166. LONG MutexState;
  167. PAGED_CODE();
  168. //
  169. // Verify the selectors. We do not allow selectors that point into
  170. // Kernel space, system selectors, or conforming code selectors
  171. //
  172. //
  173. // Verify the selectors
  174. //
  175. if ((Selector0 & 0xFFFF0000) || (Selector1 & 0xFFFF0000)) {
  176. return STATUS_INVALID_LDT_DESCRIPTOR;
  177. }
  178. // Change the selector values to indexes into the LDT
  179. Selector0 = Selector0 & ~(RPL_MASK | SELECTOR_TABLE_INDEX);
  180. Selector1 = Selector1 & ~(RPL_MASK | SELECTOR_TABLE_INDEX);
  181. //
  182. // Verify descriptor 0
  183. //
  184. if (Selector0) {
  185. *((PULONG)(&Descriptor)) = Entry0Low;
  186. *(((PULONG)(&Descriptor)) + 1) = Entry0Hi;
  187. if (!VdmpIsDescriptorValid(&Descriptor)) {
  188. return STATUS_INVALID_LDT_DESCRIPTOR;
  189. }
  190. }
  191. //
  192. // Verify descriptor 1
  193. //
  194. if (Selector1) {
  195. *((PULONG)(&Descriptor)) = Entry1Low;
  196. *(((PULONG)(&Descriptor)) + 1) = Entry1Hi;
  197. if (!VdmpIsDescriptorValid(&Descriptor)) {
  198. return STATUS_INVALID_LDT_DESCRIPTOR;
  199. }
  200. }
  201. //
  202. // Acquire the LDT mutex.
  203. //
  204. Status = KeWaitForSingleObject(
  205. &LdtMutex,
  206. Executive,
  207. KernelMode,
  208. FALSE,
  209. NULL
  210. );
  211. if (!NT_SUCCESS (Status)) {
  212. return Status;
  213. }
  214. //
  215. // Figure out how large the LDT needs to be
  216. //
  217. if (Selector0 > Selector1) {
  218. LdtSize = Selector0 + sizeof(LDT_ENTRY);
  219. } else {
  220. LdtSize = Selector1 + sizeof(LDT_ENTRY);
  221. }
  222. Process = PsGetCurrentProcess();
  223. ProcessLdtInformation = Process->LdtInformation;
  224. //
  225. // Most of the time, the process will already have an LDT, and it
  226. // will be large enough. for this, we just set the descriptors and
  227. // return
  228. //
  229. if (ProcessLdtInformation) {
  230. //
  231. // If the LDT descriptor does not have to be modified.
  232. //
  233. if (ProcessLdtInformation->Size >= LdtSize) {
  234. if (Selector0) {
  235. *((PULONG)(&Descriptor)) = Entry0Low;
  236. *(((PULONG)(&Descriptor)) + 1) = Entry0Hi;
  237. Ke386SetDescriptorProcess(
  238. &(Process->Pcb),
  239. Selector0,
  240. Descriptor
  241. );
  242. }
  243. if (Selector1) {
  244. *((PULONG)(&Descriptor)) = Entry1Low;
  245. *(((PULONG)(&Descriptor)) + 1) = Entry1Hi;
  246. Ke386SetDescriptorProcess(
  247. &(Process->Pcb),
  248. Selector1,
  249. Descriptor
  250. );
  251. }
  252. MutexState = KeReleaseMutex( &LdtMutex, FALSE );
  253. ASSERT(( MutexState == 0 ));
  254. return STATUS_SUCCESS;
  255. //
  256. // Else if the Ldt will fit in the memory currently allocated
  257. //
  258. } else if (ProcessLdtInformation->AllocatedSize >= LdtSize) {
  259. //
  260. // First remove the LDT. This will allow us to edit the memory.
  261. // We will then put the LDT back. Since we have to change the
  262. // limit anyway, it would take two calls to the kernel ldt
  263. // management minimum to set the descriptors. Each of those calls
  264. // would stall all of the processors in an MP system. If we
  265. // didn't remove the ldt first, and we were setting two descriptors,
  266. // we would have to call the LDT management 3 times (once per
  267. // descriptor, and once to change the limit of the LDT).
  268. //
  269. Ke386SetLdtProcess(
  270. &(Process->Pcb),
  271. NULL,
  272. 0L
  273. );
  274. //
  275. // Set the Descriptors in the LDT
  276. //
  277. if (Selector0) {
  278. *((PULONG)(&(ProcessLdtInformation->Ldt[Selector0/sizeof(LDT_ENTRY)]))) = Entry0Low;
  279. *((PULONG)(&(ProcessLdtInformation->Ldt[Selector0/sizeof(LDT_ENTRY)])) + 1) =
  280. Entry0Hi;
  281. }
  282. if (Selector1) {
  283. *((PULONG)(&(ProcessLdtInformation->Ldt[Selector1/sizeof(LDT_ENTRY)]))) = Entry1Low;
  284. *((PULONG)(&(ProcessLdtInformation->Ldt[Selector1/sizeof(LDT_ENTRY)])) + 1) =
  285. Entry1Hi;
  286. }
  287. //
  288. // Set the LDT for the process
  289. //
  290. ProcessLdtInformation->Size = LdtSize;
  291. Ke386SetLdtProcess(
  292. &(Process->Pcb),
  293. ProcessLdtInformation->Ldt,
  294. ProcessLdtInformation->Size
  295. );
  296. MutexState = KeReleaseMutex (&LdtMutex, FALSE);
  297. ASSERT ((MutexState == 0));
  298. return STATUS_SUCCESS;
  299. //
  300. // Otherwise, we have to grow the LDT allocation
  301. //
  302. }
  303. }
  304. //
  305. // If the process does not yet have an LDT information structure,
  306. // allocate and attach one.
  307. //
  308. OldLdt = NULL;
  309. if (!Process->LdtInformation) {
  310. ProcessLdtInformation = ExAllocatePoolWithTag (NonPagedPool,
  311. sizeof(LDTINFORMATION),
  312. 'dLsP');
  313. if (ProcessLdtInformation == NULL) {
  314. goto SetLdtEntriesCleanup;
  315. }
  316. Process->LdtInformation = ProcessLdtInformation;
  317. ProcessLdtInformation->Size = 0L;
  318. ProcessLdtInformation->AllocatedSize = 0L;
  319. ProcessLdtInformation->Ldt = NULL;
  320. }
  321. //
  322. // Now, we either need to create or grow an LDT, so allocate some
  323. // memory, and copy as necessary
  324. //
  325. AllocatedSize = (LdtSize + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
  326. Ldt = ExAllocatePoolWithTag (NonPagedPool,
  327. AllocatedSize,
  328. 'dLsP');
  329. if (Ldt) {
  330. RtlZeroMemory (Ldt,
  331. AllocatedSize);
  332. } else {
  333. goto SetLdtEntriesCleanup;
  334. }
  335. if (ProcessLdtInformation->Ldt) {
  336. //
  337. // copy the contents of the old ldt
  338. //
  339. RtlCopyMemory (Ldt,
  340. ProcessLdtInformation->Ldt,
  341. ProcessLdtInformation->Size);
  342. Status = PsChargeProcessNonPagedPoolQuota (Process,
  343. AllocatedSize);
  344. if (!NT_SUCCESS (Status)) {
  345. ExFreePool (Ldt);
  346. Ldt = NULL;
  347. } else {
  348. PsReturnProcessNonPagedPoolQuota (Process,
  349. ProcessLdtInformation->AllocatedSize);
  350. }
  351. if (Ldt == NULL) {
  352. goto SetLdtEntriesCleanup;
  353. }
  354. } else {
  355. Status = PsChargeProcessNonPagedPoolQuota (Process,
  356. AllocatedSize);
  357. if (!NT_SUCCESS (Status)) {
  358. ExFreePool (Ldt);
  359. Ldt = NULL;
  360. }
  361. if (Ldt == NULL) {
  362. goto SetLdtEntriesCleanup;
  363. }
  364. }
  365. OldLdt = ProcessLdtInformation->Ldt;
  366. ProcessLdtInformation->Size = LdtSize;
  367. ProcessLdtInformation->AllocatedSize = AllocatedSize;
  368. ProcessLdtInformation->Ldt = Ldt;
  369. //
  370. // Set the descriptors in the LDT
  371. //
  372. if (Selector0) {
  373. *((PULONG)(&(ProcessLdtInformation->Ldt[Selector0/sizeof(LDT_ENTRY)]))) = Entry0Low;
  374. *((PULONG)(&(ProcessLdtInformation->Ldt[Selector0/sizeof(LDT_ENTRY)])) + 1) =
  375. Entry0Hi;
  376. }
  377. if (Selector1) {
  378. *((PULONG)(&(ProcessLdtInformation->Ldt[Selector1/sizeof(LDT_ENTRY)]))) = Entry1Low;
  379. *((PULONG)(&(ProcessLdtInformation->Ldt[Selector1/sizeof(LDT_ENTRY)])) + 1) =
  380. Entry1Hi;
  381. }
  382. //
  383. // Set the LDT for the process
  384. //
  385. Ke386SetLdtProcess (&Process->Pcb,
  386. ProcessLdtInformation->Ldt,
  387. ProcessLdtInformation->Size);
  388. //
  389. // Cleanup and exit
  390. //
  391. Status = STATUS_SUCCESS;
  392. SetLdtEntriesCleanup:
  393. MutexState = KeReleaseMutex (&LdtMutex, FALSE);
  394. ASSERT (MutexState == 0);
  395. if (OldLdt) {
  396. ExFreePool(OldLdt);
  397. }
  398. return Status;
  399. }
  400. NTSTATUS
  401. VdmpSetProcessLdtInfo(
  402. IN PPROCESS_LDT_INFORMATION LdtInformation,
  403. IN ULONG LdtInformationLength
  404. )
  405. /*++
  406. Routine Description:
  407. This function alters the ldt for a specified process. It can alter
  408. portions of the LDT, or the whole LDT. If an Ldt is created or
  409. grown, the specified process will be charged the quota for the LDT.
  410. Each descriptor that is set will be verified.
  411. Arguments:
  412. LdtInformation - Supplies a pointer to a record that contains the
  413. information to set. This pointer has already been probed, but since
  414. it is a usermode pointer, accesses must be guarded by try-except.
  415. LdtInformationLength - Supplies the length of the record that contains
  416. the information to set.
  417. Return Value:
  418. NTSTATUS.
  419. --*/
  420. {
  421. PEPROCESS Process = PsGetCurrentProcess();
  422. NTSTATUS Status;
  423. PLDT_ENTRY OldLdt = NULL;
  424. ULONG OldSize = 0;
  425. ULONG AllocatedSize;
  426. ULONG Size;
  427. ULONG MutexState;
  428. ULONG LdtOffset;
  429. PLDT_ENTRY CurrentDescriptor;
  430. PPROCESS_LDT_INFORMATION LdtInfo=NULL;
  431. PLDTINFORMATION ProcessLdtInfo;
  432. PLDT_ENTRY Ldt;
  433. PAGED_CODE();
  434. if ( LdtInformationLength < (ULONG)sizeof( PROCESS_LDT_INFORMATION)) {
  435. return STATUS_INFO_LENGTH_MISMATCH;
  436. }
  437. Status = STATUS_SUCCESS;
  438. //
  439. // Allocate a local buffer to capture the ldt information to
  440. //
  441. LdtInfo = ExAllocatePoolWithTag (NonPagedPool,
  442. LdtInformationLength,
  443. 'ldmV');
  444. if (LdtInfo == NULL) {
  445. return STATUS_INSUFFICIENT_RESOURCES;
  446. }
  447. try {
  448. //
  449. // Copy the information the user is supplying
  450. //
  451. RtlCopyMemory (LdtInfo,
  452. LdtInformation,
  453. LdtInformationLength);
  454. } except (EXCEPTION_EXECUTE_HANDLER) {
  455. Status = GetExceptionCode ();
  456. ExFreePool (LdtInfo);
  457. }
  458. //
  459. // If the capture didn't succeed
  460. //
  461. if (!NT_SUCCESS (Status)) {
  462. if (Status == STATUS_ACCESS_VIOLATION) {
  463. return STATUS_SUCCESS;
  464. } else {
  465. return Status;
  466. }
  467. }
  468. //
  469. // Verify that the Start and Length are plausible
  470. //
  471. if (LdtInfo->Start & 0xFFFF0000) {
  472. ExFreePool (LdtInfo);
  473. return STATUS_INVALID_LDT_OFFSET;
  474. }
  475. if (LdtInfo->Length & 0xFFFF0000) {
  476. ExFreePool (LdtInfo);
  477. return STATUS_INVALID_LDT_SIZE;
  478. }
  479. //
  480. // Insure that the buffer is large enough to contain the specified number
  481. // of selectors.
  482. //
  483. if (LdtInformationLength - sizeof (PROCESS_LDT_INFORMATION) + sizeof (LDT_ENTRY) < LdtInfo->Length) {
  484. ExFreePool (LdtInfo);
  485. return STATUS_INFO_LENGTH_MISMATCH;
  486. }
  487. //
  488. // The info to set must be an integral number of selectors
  489. //
  490. if (LdtInfo->Length % sizeof (LDT_ENTRY)) {
  491. ExFreePool (LdtInfo);
  492. return STATUS_INVALID_LDT_SIZE;
  493. }
  494. //
  495. // The beginning of the info must be on a selector boundary
  496. //
  497. if (LdtInfo->Start % sizeof (LDT_ENTRY)) {
  498. ExFreePool (LdtInfo);
  499. return STATUS_INVALID_LDT_OFFSET;
  500. }
  501. //
  502. // Verify all of the descriptors.
  503. //
  504. for (CurrentDescriptor = LdtInfo->LdtEntries;
  505. (PCHAR)CurrentDescriptor < (PCHAR)LdtInfo->LdtEntries + LdtInfo->Length;
  506. CurrentDescriptor++) {
  507. if (!VdmpIsDescriptorValid (CurrentDescriptor)) {
  508. ExFreePool (LdtInfo);
  509. return STATUS_INVALID_LDT_DESCRIPTOR;
  510. }
  511. }
  512. //
  513. // Acquire the Ldt Mutex
  514. //
  515. Status = KeWaitForSingleObject (&LdtMutex,
  516. Executive,
  517. KernelMode,
  518. FALSE,
  519. NULL);
  520. if (!NT_SUCCESS (Status)) {
  521. ExFreePool (LdtInfo);
  522. return Status;
  523. }
  524. ProcessLdtInfo = Process->LdtInformation;
  525. //
  526. // If the process doesn't have an Ldt information structure, allocate
  527. // one and attach it to the process
  528. //
  529. if (ProcessLdtInfo == NULL) {
  530. ProcessLdtInfo = ExAllocatePoolWithTag (NonPagedPool,
  531. sizeof(LDTINFORMATION),
  532. 'dLsP');
  533. if (ProcessLdtInfo == NULL) {
  534. goto SetInfoCleanup;
  535. }
  536. RtlZeroMemory (ProcessLdtInfo, sizeof (LDTINFORMATION));
  537. Process->LdtInformation = ProcessLdtInfo;
  538. }
  539. //
  540. // If we are supposed to remove the LDT
  541. //
  542. if (LdtInfo->Length == 0) {
  543. //
  544. // Remove the process' Ldt
  545. //
  546. if (ProcessLdtInfo->Ldt) {
  547. OldSize = ProcessLdtInfo->AllocatedSize;
  548. OldLdt = ProcessLdtInfo->Ldt;
  549. ProcessLdtInfo->AllocatedSize = 0;
  550. ProcessLdtInfo->Size = 0;
  551. ProcessLdtInfo->Ldt = NULL;
  552. Ke386SetLdtProcess (&Process->Pcb,
  553. NULL,
  554. 0);
  555. PsReturnProcessNonPagedPoolQuota (Process, OldSize);
  556. }
  557. } else if ( ProcessLdtInfo->Ldt == NULL ) {
  558. //
  559. // Create a new Ldt for the process
  560. //
  561. //
  562. // Allocate an integral number of pages for the LDT.
  563. //
  564. ASSERT(((PAGE_SIZE % 2) == 0));
  565. AllocatedSize = (LdtInfo->Start + LdtInfo->Length + PAGE_SIZE - 1) &
  566. ~(PAGE_SIZE - 1);
  567. Size = LdtInfo->Start + LdtInfo->Length;
  568. Ldt = PspCreateLdt (LdtInfo->LdtEntries,
  569. LdtInfo->Start,
  570. Size,
  571. AllocatedSize);
  572. if (Ldt == NULL) {
  573. Status = STATUS_INSUFFICIENT_RESOURCES;
  574. goto SetInfoCleanup;
  575. }
  576. Status = PsChargeProcessNonPagedPoolQuota (Process,
  577. AllocatedSize);
  578. if (!NT_SUCCESS (Status)) {
  579. ExFreePool (Ldt);
  580. Ldt = NULL;
  581. goto SetInfoCleanup;
  582. }
  583. ProcessLdtInfo->Ldt = Ldt;
  584. ProcessLdtInfo->Size = Size;
  585. ProcessLdtInfo->AllocatedSize = AllocatedSize;
  586. Ke386SetLdtProcess (&Process->Pcb,
  587. ProcessLdtInfo->Ldt,
  588. ProcessLdtInfo->Size);
  589. } else if (LdtInfo->Length + LdtInfo->Start > ProcessLdtInfo->Size) {
  590. //
  591. // Grow the process' Ldt
  592. //
  593. if (LdtInfo->Length + LdtInfo->Start > ProcessLdtInfo->AllocatedSize) {
  594. //
  595. // Current Ldt allocation is not large enough, so create a
  596. // new larger Ldt
  597. //
  598. OldSize = ProcessLdtInfo->AllocatedSize;
  599. Size = LdtInfo->Start + LdtInfo->Length;
  600. AllocatedSize = (Size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
  601. Ldt = PspCreateLdt (ProcessLdtInfo->Ldt,
  602. 0,
  603. OldSize,
  604. AllocatedSize);
  605. if (Ldt == NULL) {
  606. Status = STATUS_INSUFFICIENT_RESOURCES;
  607. goto SetInfoCleanup;
  608. }
  609. Status = PsChargeProcessNonPagedPoolQuota (Process,
  610. AllocatedSize);
  611. if (!NT_SUCCESS (Status)) {
  612. ExFreePool (Ldt);
  613. Ldt = NULL;
  614. goto SetInfoCleanup;
  615. }
  616. PsReturnProcessNonPagedPoolQuota (Process,
  617. OldSize);
  618. //
  619. // Swap Ldt information
  620. //
  621. OldLdt = ProcessLdtInfo->Ldt;
  622. ProcessLdtInfo->Ldt = Ldt;
  623. ProcessLdtInfo->Size = Size;
  624. ProcessLdtInfo->AllocatedSize = AllocatedSize;
  625. //
  626. // Put new selectors into the new ldt
  627. //
  628. RtlCopyMemory ((PCHAR)(ProcessLdtInfo->Ldt) + LdtInfo->Start,
  629. LdtInfo->LdtEntries,
  630. LdtInfo->Length);
  631. Ke386SetLdtProcess (&Process->Pcb,
  632. ProcessLdtInfo->Ldt,
  633. ProcessLdtInfo->Size);
  634. } else {
  635. //
  636. // Current Ldt allocation is large enough
  637. //
  638. ProcessLdtInfo->Size = LdtInfo->Length + LdtInfo->Start;
  639. Ke386SetLdtProcess (&Process->Pcb,
  640. ProcessLdtInfo->Ldt,
  641. ProcessLdtInfo->Size);
  642. //
  643. // Change the selectors in the table
  644. //
  645. for (LdtOffset = LdtInfo->Start, CurrentDescriptor = LdtInfo->LdtEntries;
  646. LdtOffset < LdtInfo->Start + LdtInfo->Length;
  647. LdtOffset += sizeof(LDT_ENTRY), CurrentDescriptor++) {
  648. Ke386SetDescriptorProcess (&Process->Pcb,
  649. LdtOffset,
  650. *CurrentDescriptor);
  651. }
  652. }
  653. } else {
  654. //
  655. // Simply changing some selectors
  656. //
  657. for (LdtOffset = LdtInfo->Start, CurrentDescriptor = LdtInfo->LdtEntries;
  658. LdtOffset < LdtInfo->Start + LdtInfo->Length;
  659. LdtOffset += sizeof(LDT_ENTRY), CurrentDescriptor++) {
  660. Ke386SetDescriptorProcess (&Process->Pcb,
  661. LdtOffset,
  662. *CurrentDescriptor);
  663. }
  664. Status = STATUS_SUCCESS;
  665. }
  666. SetInfoCleanup:
  667. MutexState = KeReleaseMutex (&LdtMutex, FALSE);
  668. ASSERT ((MutexState == 0));
  669. if (OldLdt != NULL) {
  670. ExFreePool (OldLdt);
  671. }
  672. if (LdtInfo != NULL) {
  673. ExFreePool (LdtInfo);
  674. }
  675. return Status;
  676. }