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.

461 lines
10 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. dosmem.c
  5. Abstract:
  6. This module contains routines for allocating and freeing DOS memory.
  7. Author:
  8. Neil Sandlin (neilsa) 12-Dec-1996
  9. Notes:
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #include "softpc.h"
  15. #include <malloc.h>
  16. #include <xlathlp.h>
  17. #define DOSERR_NOT_ENOUGH_MEMORY 8
  18. #define DOSERR_INVALID_BLOCK 9
  19. MEM_DPMI DosMemHead = { NULL, 0, &DosMemHead, &DosMemHead, 0};
  20. VOID
  21. DpmiAllocateDosMem(
  22. VOID
  23. )
  24. /*++
  25. Routine Description:
  26. This routine allocates a block of DOS memory. The client is switched
  27. to V86 mode, and DOS is called to allocate the memory. Then a selector
  28. is allocated for the PM app to reference the memory.
  29. Arguments:
  30. None.
  31. Return Value:
  32. None.
  33. --*/
  34. {
  35. DECLARE_LocalVdmContext;
  36. PMEM_DPMI DosMemBlock;
  37. CLIENT_REGS SaveRegs;
  38. USHORT Sel;
  39. USHORT Seg;
  40. ULONG ParaSize = getBX();
  41. ULONG MemSize = ((ULONG)ParaSize) << 4;
  42. USHORT DosError = 0;
  43. USHORT SizeLargest = 0;
  44. SAVE_CLIENT_REGS(SaveRegs);
  45. if (WOWAllocSeg) {
  46. PUCHAR VdmStackPointer;
  47. ULONG NewSP;
  48. //
  49. // WOW is doing the allocation
  50. //
  51. BuildStackFrame(4, &VdmStackPointer, &NewSP);
  52. setCS(WOWAllocSeg);
  53. setIP(WOWAllocFunc);
  54. *(PDWORD16)(VdmStackPointer-4) = MemSize;
  55. *(PWORD16)(VdmStackPointer-6) = (USHORT) (PmBopFe >> 16);
  56. *(PWORD16)(VdmStackPointer-8) = (USHORT) PmBopFe;
  57. setSP((WORD)NewSP);
  58. host_simulate();
  59. Sel = getAX();
  60. Seg = getDX();
  61. if (!Sel) {
  62. DosError = DOSERR_NOT_ENOUGH_MEMORY;
  63. }
  64. } else {
  65. USHORT SelCount;
  66. //
  67. // DOS is doing the allocation
  68. // First get a mem_block to track the allocation
  69. //
  70. DosMemBlock = malloc(sizeof(MEM_DPMI));
  71. if (!DosMemBlock) {
  72. // Couldn't get the MEM_DPMI
  73. DosError = DOSERR_NOT_ENOUGH_MEMORY;
  74. } else {
  75. //
  76. // Next allocate the selector array
  77. //
  78. SelCount = (USHORT) ((MemSize+65535)>>16);
  79. Sel = ALLOCATE_SELECTORS(SelCount);
  80. if (!Sel) {
  81. // Couldn't get the selectors
  82. DosError = DOSERR_NOT_ENOUGH_MEMORY;
  83. free(DosMemBlock);
  84. } else {
  85. //
  86. // Now have DOS allocate the memory
  87. //
  88. DpmiSwitchToRealMode();
  89. setBX((WORD)ParaSize);
  90. setAX(0x4800);
  91. DPMI_EXEC_INT(0x21);
  92. if (getCF()) {
  93. USHORT i;
  94. // Couldn't get the memory
  95. DosError = getAX();
  96. SizeLargest = getBX();
  97. for (i = 0; i < SelCount; i++, Sel+=8) {
  98. FreeSelector(Sel);
  99. }
  100. free(DosMemBlock);
  101. } else {
  102. ULONG Base;
  103. //
  104. // Got the block. Save the allocation info, and set
  105. // up the descriptors
  106. //
  107. Seg = getAX();
  108. Base = ((ULONG)Seg) << 4;
  109. DosMemBlock->Address = (PVOID)Seg;
  110. DosMemBlock->Length = (ULONG)ParaSize;
  111. DosMemBlock->Sel = Sel;
  112. DosMemBlock->SelCount = SelCount;
  113. INSERT_BLOCK(DosMemBlock, DosMemHead);
  114. SetDescriptorArray(Sel, Base, MemSize);
  115. }
  116. DpmiSwitchToProtectedMode();
  117. }
  118. }
  119. }
  120. SET_CLIENT_REGS(SaveRegs);
  121. if (DosError) {
  122. setAX(DosError);
  123. setBX(SizeLargest);
  124. setCF(1);
  125. } else {
  126. setDX(Sel);
  127. setAX(Seg);
  128. setCF(0);
  129. }
  130. }
  131. VOID
  132. DpmiFreeDosMem(
  133. VOID
  134. )
  135. /*++
  136. Routine Description:
  137. This routine frees a block of DOS memory.
  138. Arguments:
  139. None.
  140. Return Value:
  141. None.
  142. --*/
  143. {
  144. DECLARE_LocalVdmContext;
  145. PMEM_DPMI DosMemBlock;
  146. CLIENT_REGS SaveRegs;
  147. USHORT Sel = getDX();
  148. USHORT DosError = 0;
  149. SAVE_CLIENT_REGS(SaveRegs);
  150. if (WOWFreeSeg) {
  151. PUCHAR VdmStackPointer;
  152. ULONG NewSP;
  153. //
  154. // WOW is doing the free
  155. //
  156. BuildStackFrame(3, &VdmStackPointer, &NewSP);
  157. setCS(WOWFreeSeg);
  158. setIP(WOWFreeFunc);
  159. *(PWORD16)(VdmStackPointer-2) = Sel;
  160. *(PWORD16)(VdmStackPointer-4) = (USHORT) (PmBopFe >> 16);
  161. *(PWORD16)(VdmStackPointer-6) = (USHORT) PmBopFe;
  162. setSP((WORD)NewSP);
  163. host_simulate();
  164. Sel = getAX();
  165. if (!Sel) {
  166. DosError = DOSERR_INVALID_BLOCK;
  167. }
  168. } else {
  169. USHORT i;
  170. DosError = DOSERR_INVALID_BLOCK; // assume failure
  171. //
  172. // DOS is doing the free
  173. // First find the mem_block for this allocation
  174. //
  175. DosMemBlock = DosMemHead.Next;
  176. while(DosMemBlock != &DosMemHead) {
  177. if (DosMemBlock->Sel == Sel) {
  178. DpmiSwitchToRealMode();
  179. setES((WORD)DosMemBlock->Address);
  180. setAX(0x4900);
  181. DPMI_EXEC_INT(0x21);
  182. if (getCF()) {
  183. USHORT i;
  184. // Couldn't free the memory
  185. DosError = getAX();
  186. } else {
  187. for (i = 0; i < DosMemBlock->SelCount; i++, Sel+=8) {
  188. FreeSelector(Sel);
  189. }
  190. DosError = 0;
  191. }
  192. DpmiSwitchToProtectedMode();
  193. DELETE_BLOCK(DosMemBlock);
  194. free(DosMemBlock);
  195. break;
  196. }
  197. DosMemBlock = DosMemBlock->Next;
  198. }
  199. }
  200. SET_CLIENT_REGS(SaveRegs);
  201. if (DosError) {
  202. setAX(DosError);
  203. setCF(1);
  204. } else {
  205. setCF(0);
  206. }
  207. }
  208. VOID
  209. DpmiSizeDosMem(
  210. VOID
  211. )
  212. /*++
  213. Routine Description:
  214. This routine calls DOS to resize a DOS memory block, or to get
  215. the largest available block.
  216. Arguments:
  217. None.
  218. Return Value:
  219. None.
  220. --*/
  221. {
  222. DECLARE_LocalVdmContext;
  223. PMEM_DPMI DosMemBlock;
  224. CLIENT_REGS SaveRegs;
  225. USHORT Sel = getDX();
  226. ULONG ParaSize = getBX();
  227. ULONG MemSize = ((ULONG)ParaSize) << 4;
  228. USHORT DosError = 0;
  229. SAVE_CLIENT_REGS(SaveRegs);
  230. if (WOWFreeSeg) {
  231. //
  232. // WOW is doing the resize
  233. //
  234. // Not implemented
  235. DosError = DOSERR_NOT_ENOUGH_MEMORY;
  236. } else {
  237. USHORT SelCount;
  238. USHORT i;
  239. //
  240. // DOS is doing the resize
  241. // Find the mem_block for this allocation
  242. // First see if we need a new selector array
  243. //
  244. DosError = DOSERR_INVALID_BLOCK; // assume failure
  245. DosMemBlock = DosMemHead.Next;
  246. while(DosMemBlock != &DosMemHead) {
  247. if (DosMemBlock->Sel == Sel) {
  248. USHORT NewSel = 0;
  249. USHORT NewSelCount = 0;
  250. //
  251. // If we have to grow the selector array, make sure
  252. // we can grow it in place
  253. //
  254. SelCount = (USHORT) ((MemSize+65535)>>16);
  255. if (SelCount > DosMemBlock->SelCount) {
  256. USHORT TmpSel;
  257. NewSel = Sel+(DosMemBlock->SelCount*8);
  258. NewSelCount = SelCount - DosMemBlock->SelCount;
  259. //
  260. // First check to see if the selectors are really all free
  261. //
  262. for (i=0,TmpSel = NewSel; i < NewSelCount; i++, TmpSel+=8) {
  263. if (!IS_SELECTOR_FREE(TmpSel)) {
  264. DosError = DOSERR_NOT_ENOUGH_MEMORY;
  265. goto dpmi_size_error;
  266. }
  267. }
  268. //
  269. // Now attempt to remove them off the free list
  270. //
  271. for (i=0; i < NewSelCount; i++, NewSel+=8) {
  272. if (!RemoveFreeSelector(NewSel)) {
  273. // If this happens, we must have a bogus free
  274. // selector list
  275. DosError = DOSERR_NOT_ENOUGH_MEMORY;
  276. goto dpmi_size_error;
  277. }
  278. }
  279. }
  280. DpmiSwitchToRealMode();
  281. setBX((WORD)ParaSize);
  282. setES((WORD)DosMemBlock->Address);
  283. setAX(0x4A00);
  284. DPMI_EXEC_INT(0x21);
  285. if (getCF()) {
  286. USHORT i;
  287. // Couldn't resize the memory
  288. DosError = getAX();
  289. // Free selectors, if we got new ones
  290. if (NewSelCount) {
  291. for (i = 0; i < NewSelCount; i++, NewSel+=8) {
  292. FreeSelector(NewSel);
  293. }
  294. }
  295. } else {
  296. ULONG Base;
  297. //
  298. // Resized the block. Update the allocation info, and set
  299. // up the descriptors
  300. //
  301. if (SelCount < DosMemBlock->SelCount) {
  302. USHORT OldSel = Sel+SelCount*8;
  303. USHORT OldSelCount = DosMemBlock->SelCount - SelCount;
  304. //
  305. // Count of selectors has shrunk. Free 'em up.
  306. //
  307. for (i = 0; i < OldSelCount; i++, OldSel+=8) {
  308. FreeSelector(OldSel);
  309. }
  310. }
  311. DosMemBlock->Length = (ULONG)ParaSize;
  312. DosMemBlock->SelCount = SelCount;
  313. Base = ((ULONG)DosMemBlock->Address) << 4;
  314. SetDescriptorArray(Sel, Base, MemSize);
  315. DosError = 0;
  316. }
  317. DpmiSwitchToProtectedMode();
  318. break;
  319. }
  320. DosMemBlock = DosMemBlock->Next;
  321. }
  322. }
  323. dpmi_size_error:
  324. SET_CLIENT_REGS(SaveRegs);
  325. if (DosError) {
  326. setAX(DosError);
  327. setCF(1);
  328. } else {
  329. setCF(0);
  330. }
  331. }