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.

460 lines
10 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. name-of-module-filename
  5. Abstract:
  6. This module contains the code for actually allocating memory for dpmi.
  7. It uses the same suballocation pool as the xms code
  8. Author:
  9. Dave Hastings (daveh) creation-date 09-Feb-1994
  10. Notes:
  11. These functions claim to return NTSTATUS. This is for commonality on
  12. x86 where we actually have an NTSTATUS to return. For this file, we
  13. simply logically invert the bool and return that. Callers of these
  14. functions promise not to attach significance to the return values other
  15. than STATUS_SUCCESS.
  16. Revision History:
  17. --*/
  18. #include "precomp.h"
  19. #pragma hdrstop
  20. #include <softpc.h>
  21. #include <suballoc.h>
  22. #include <xmsexp.h>
  23. PVOID gpLastAlloc = NULL;
  24. BOOL gbUseIncrementalAlloc = FALSE;
  25. SYSTEM_BASIC_INFORMATION gSystemBasicInfo;
  26. #define ALIGN_ALLOCATION_GRANULARITY(p) \
  27. (((p) + gSystemBasicInfo.AllocationGranularity - 1) & ~(gSystemBasicInfo.AllocationGranularity - 1))
  28. VOID
  29. DpmiSetIncrementalAlloc(
  30. BOOL bUseIncrementalAlloc
  31. )
  32. {
  33. NTSTATUS Status;
  34. gbUseIncrementalAlloc = FALSE;
  35. gpLastAlloc = NULL;
  36. // if worse comes to worse -- and we can't query system info,
  37. // we use conventional allocation strategy
  38. if (bUseIncrementalAlloc) {
  39. Status = NtQuerySystemInformation(SystemBasicInformation,
  40. &gSystemBasicInfo,
  41. sizeof(gSystemBasicInfo),
  42. NULL);
  43. if (NT_SUCCESS(Status)) {
  44. gbUseIncrementalAlloc = TRUE;
  45. }
  46. }
  47. }
  48. PVOID
  49. DpmiFindNextAddress(
  50. ULONG ulSize
  51. )
  52. {
  53. NTSTATUS Status;
  54. MEMORY_BASIC_INFORMATION mbi;
  55. SIZE_T ReturnLength;
  56. PVOID pMem = gpLastAlloc;
  57. ULONG ulSizeCheck;
  58. //
  59. // adjust size for granularity alignment
  60. //
  61. ulSizeCheck = ALIGN_ALLOCATION_GRANULARITY(ulSize);
  62. do {
  63. //
  64. // adjust the address to align on granularity
  65. //
  66. pMem = (PVOID)ALIGN_ALLOCATION_GRANULARITY((ULONG_PTR)pMem);
  67. Status = NtQueryVirtualMemory(NtCurrentProcess(),
  68. pMem,
  69. MemoryBasicInformation,
  70. &mbi,
  71. sizeof(mbi),
  72. &ReturnLength);
  73. if (!NT_SUCCESS(Status)) {
  74. return(NULL);
  75. }
  76. //
  77. // after the query -- step forward
  78. //
  79. if ((MEM_FREE & mbi.State) && (ulSizeCheck <= mbi.RegionSize)) {
  80. // try to reserve it then
  81. Status = NtAllocateVirtualMemory(NtCurrentProcess(),
  82. &pMem,
  83. 0,
  84. &ulSize,
  85. MEM_RESERVE,
  86. PAGE_READWRITE);
  87. if (!NT_SUCCESS(Status)) {
  88. //
  89. // we can't reserve the memory - get out, use "normal" allocation
  90. break;
  91. }
  92. return(pMem);
  93. }
  94. pMem = (PVOID)((ULONG_PTR)mbi.BaseAddress + mbi.RegionSize);
  95. } while ((ULONG_PTR)pMem < (ULONG_PTR)gSystemBasicInfo.MaximumUserModeAddress);
  96. return(NULL);
  97. }
  98. NTSTATUS
  99. DpmiAllocateVirtualMemory(
  100. PVOID *Address,
  101. PULONG Size
  102. )
  103. /*++
  104. Routine Description:
  105. This routine allocates a chunk of extended memory for dpmi.
  106. Arguments:
  107. Address -- Supplies a pointer to the Address. This is filled in
  108. if the allocation is successfull
  109. Size -- Supplies the size to allocate
  110. Return Value:
  111. STATUS_SUCCESS if successfull.
  112. --*/
  113. {
  114. PVOID pMem = NULL;
  115. NTSTATUS Status;
  116. if (NULL != gpLastAlloc && gbUseIncrementalAlloc) {
  117. // try to find a piece of memory that is beyond this gpLastAlloc
  118. pMem = DpmiFindNextAddress(*Size);
  119. }
  120. AllocRetry:
  121. Status = NtAllocateVirtualMemory(NtCurrentProcess(),
  122. &pMem,
  123. 0,
  124. Size,
  125. MEM_COMMIT,
  126. PAGE_READWRITE);
  127. if (NT_SUCCESS(Status)) {
  128. if (gbUseIncrementalAlloc) {
  129. gpLastAlloc = (PVOID)((ULONG_PTR)pMem + *Size);
  130. }
  131. *Address = pMem;
  132. return(Status);
  133. }
  134. if (pMem != NULL) {
  135. pMem = NULL;
  136. goto AllocRetry;
  137. }
  138. return(Status);
  139. }
  140. NTSTATUS
  141. DpmiFreeVirtualMemory(
  142. PVOID *Address,
  143. PULONG Size
  144. )
  145. /*++
  146. Routine Description:
  147. This function frees memory for dpmi. It is returned to the suballocation
  148. pool.
  149. Arguments:
  150. Address -- Supplies the address of the block to free
  151. Size -- Supplies the size of the block to free
  152. Return Value:
  153. STATUS_SUCCESS if successful
  154. --*/
  155. {
  156. return NtFreeVirtualMemory(
  157. NtCurrentProcess(),
  158. Address,
  159. Size,
  160. MEM_RELEASE
  161. );
  162. }
  163. VOID
  164. DpmiCopyMemory(
  165. ULONG NewAddress,
  166. ULONG OldAddress,
  167. ULONG Size
  168. )
  169. /*++
  170. Routine Description:
  171. This function copies a block of memory from one location to another. It
  172. assumes that the old block of memory is about to be freed. As it copies,
  173. it discards the contents of the pages of the original block to reduce
  174. paging.
  175. Arguments:
  176. OldAddress -- Supplies the original address for the block
  177. Size -- Supplies the size in bytes to be copied
  178. NewAddress -- Supplies the pointer to the place to return the new address
  179. Return Value:
  180. none
  181. --*/
  182. {
  183. ULONG tmpsize;
  184. #define SEGMENT_SIZE 0x4000
  185. // first page align the copy
  186. if (OldAddress & (SEGMENT_SIZE-1)) {
  187. tmpsize = SEGMENT_SIZE - (OldAddress & (SEGMENT_SIZE-1));
  188. if (tmpsize > Size) {
  189. tmpsize = Size;
  190. }
  191. CopyMemory((PVOID)NewAddress, (PVOID)OldAddress, tmpsize);
  192. NewAddress += tmpsize;
  193. OldAddress += tmpsize;
  194. Size -= tmpsize;
  195. }
  196. while(Size >= SEGMENT_SIZE) {
  197. CopyMemory((PVOID)NewAddress, (PVOID)OldAddress, SEGMENT_SIZE);
  198. VirtualAlloc((PVOID)OldAddress, SEGMENT_SIZE, MEM_RESERVE, PAGE_READWRITE);
  199. NewAddress += SEGMENT_SIZE;
  200. OldAddress += SEGMENT_SIZE;
  201. Size -= SEGMENT_SIZE;
  202. }
  203. if (Size) {
  204. CopyMemory((PVOID)NewAddress, (PVOID)OldAddress, Size);
  205. }
  206. }
  207. NTSTATUS
  208. DpmiReallocateVirtualMemory(
  209. PVOID OldAddress,
  210. ULONG OldSize,
  211. PVOID *NewAddress,
  212. PULONG NewSize
  213. )
  214. /*++
  215. Routine Description:
  216. This function reallocates a block of memory for DPMI.
  217. Arguments:
  218. OldAddress -- Supplies the original address for the block
  219. OldSize -- Supplies the original size for the address
  220. NewAddress -- Supplies the pointer to the place to return the new
  221. address
  222. NewSize -- Supplies the new size
  223. Return Value:
  224. STATUS_SUCCESS if successfull
  225. --*/
  226. {
  227. ULONG SizeChange;
  228. ULONG BlockAddress;
  229. ULONG NewPages, OldPages;
  230. NTSTATUS Status;
  231. #define FOUR_K (1024 * 4)
  232. NewPages = (*NewSize + FOUR_K - 1) / FOUR_K;
  233. OldPages = (OldSize + FOUR_K - 1) / FOUR_K;
  234. if ((NewPages == OldPages) || (NewPages < OldPages)) {
  235. *NewAddress = OldAddress;
  236. return STATUS_SUCCESS;
  237. }
  238. BlockAddress = 0;
  239. Status = NtAllocateVirtualMemory(
  240. NtCurrentProcess(),
  241. (PVOID)&BlockAddress,
  242. 0L,
  243. NewSize,
  244. MEM_COMMIT,
  245. PAGE_READWRITE
  246. );
  247. if (!NT_SUCCESS(Status)) {
  248. #if DBG
  249. OutputDebugString("DPMI: DpmiAllocateXmem failed to get memory block\n");
  250. #endif
  251. return Status;
  252. }
  253. *NewAddress = (PVOID) BlockAddress;
  254. //
  255. // Copy data to new block (choose smaller of the two sizes)
  256. //
  257. if (*NewSize > OldSize) {
  258. SizeChange = OldSize;
  259. } else {
  260. SizeChange = *NewSize;
  261. }
  262. DpmiCopyMemory((ULONG)BlockAddress, (ULONG)OldAddress, SizeChange);
  263. //
  264. // Free up the old block
  265. //
  266. BlockAddress = (ULONG) OldAddress;
  267. SizeChange = OldSize;
  268. NtFreeVirtualMemory(
  269. NtCurrentProcess(),
  270. (PVOID)&(OldAddress),
  271. &SizeChange,
  272. MEM_RELEASE
  273. );
  274. return Status;
  275. }
  276. VOID
  277. DpmiGetMemoryInfo(
  278. VOID
  279. )
  280. /*++
  281. Routine Description:
  282. This routine returns information about memory to the dos extender
  283. Arguments:
  284. None
  285. Return Value:
  286. None.
  287. --*/
  288. {
  289. DECLARE_LocalVdmContext;
  290. MEMORYSTATUS MemStatus;
  291. PDPMIMEMINFO MemInfo;
  292. DWORD dwLargestFree;
  293. //
  294. // Get a pointer to the return structure
  295. //
  296. MemInfo = (PDPMIMEMINFO)Sim32GetVDMPointer(
  297. ((ULONG)getES()) << 16,
  298. 1,
  299. TRUE
  300. );
  301. (CHAR *)MemInfo += (*GetDIRegister)();
  302. //
  303. // Initialize the structure
  304. //
  305. RtlFillMemory(MemInfo, sizeof(DPMIMEMINFO), 0xFF);
  306. //
  307. // Get the information on memory
  308. //
  309. MemStatus.dwLength = sizeof(MEMORYSTATUS);
  310. GlobalMemoryStatus(&MemStatus);
  311. //
  312. // Return the information
  313. //
  314. //
  315. // Calculate the largest free block. This information is not returned
  316. // by NT, so we take a percentage based on the allowable commit charge for
  317. // the process. This is really what dwAvailPageFile is. But we limit
  318. // that value to a maximum of 15meg, since some apps (e.g. pdox45.dos)
  319. // can't handle more.
  320. //
  321. // Filled in MaxUnlocked,MaxLocked,UnlockedPages fields in this structute.
  322. // Director 4.0 get completlely confused if these fields are -1.
  323. // MaxUnlocked is correct based on LargestFree. The other two are fake
  324. // and match values on a real WFW machine. I have no way of making them
  325. // any better than this at this point. Who cares it makes director happy.
  326. //
  327. // sudeepb 01-Mar-1995.
  328. dwLargestFree = (((MemStatus.dwAvailPageFile*4)/5)/4096)*4096;
  329. MemInfo->LargestFree = (dwLargestFree < 15*ONE_MB) ?
  330. dwLargestFree : 15*ONE_MB;
  331. MemInfo->MaxUnlocked = MemInfo->LargestFree/4096;
  332. MemInfo->MaxLocked = 0xb61;
  333. MemInfo->AddressSpaceSize = MemStatus.dwTotalVirtual / 4096;
  334. MemInfo->UnlockedPages = 0xb68;
  335. MemInfo->FreePages = MemStatus.dwAvailPhys / 4096;
  336. MemInfo->PhysicalPages = MemStatus.dwTotalPhys / 4096;
  337. MemInfo->FreeAddressSpace = MemStatus.dwAvailVirtual / 4096;
  338. MemInfo->PageFileSize = MemStatus.dwTotalPageFile / 4096;
  339. }